scripts/interactive.py
changeset 2024 43e5b515b71d
child 2039 07f46319d24f
equal deleted inserted replaced
2023:60eddc9ec8f2 2024:43e5b515b71d
       
     1 #!/usr/bin/python2.5
       
     2 #
       
     3 # Copyright 2009 the Melange authors.
       
     4 #
       
     5 # Licensed under the Apache License, Version 2.0 (the "License");
       
     6 # you may not use this file except in compliance with the License.
       
     7 # You may obtain a copy of the License at
       
     8 #
       
     9 #   http://www.apache.org/licenses/LICENSE-2.0
       
    10 #
       
    11 # Unless required by applicable law or agreed to in writing, software
       
    12 # distributed under the License is distributed on an "AS IS" BASIS,
       
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    14 # See the License for the specific language governing permissions and
       
    15 # limitations under the License.
       
    16 
       
    17 """This module supplies an interactive shell with remote api configured.
       
    18 
       
    19 Usage is simple:
       
    20 
       
    21 App Engine interactive console for srabbelier-melange
       
    22 >>> from soc.models.user import User
       
    23 >>> gen = lambda: User.all()
       
    24 >>> it = deepFetch(gen)
       
    25 >>> result = [i for i in it]
       
    26 """
       
    27 
       
    28 __authors__ = [
       
    29   '"Sverre Rabbelier" <sverre@rabbelier.nl>',
       
    30 ]
       
    31 
       
    32 
       
    33 
       
    34 import code
       
    35 import getpass
       
    36 import os
       
    37 import sys
       
    38 import sys
       
    39 
       
    40 
       
    41 def auth_func():
       
    42   """Returns a tuple with username and password.
       
    43   """
       
    44 
       
    45   return raw_input('Username:'), getpass.getpass('Password:')
       
    46 
       
    47 
       
    48 def deepFetch(queryGen,key=None,batchSize = 100):
       
    49   """Iterator that yields an entity in batches.
       
    50 
       
    51   Args:
       
    52     queryGen: should return a Query object
       
    53     key: used to .filter() for __key__
       
    54     batchSize: how many entities to retrieve in one datastore call
       
    55 
       
    56   Retrieved from http://tinyurl.com/d887ll (AppEngine cookbook).
       
    57   """
       
    58 
       
    59    # AppEngine will not fetch more than 1000 results
       
    60   batchSize = min(batchSize,1000)
       
    61 
       
    62   query = None
       
    63   done = False
       
    64   count = 0
       
    65 
       
    66   if key:
       
    67     key = db.Key(key)
       
    68 
       
    69   while not done:
       
    70     query = queryGen()
       
    71     if key:
       
    72       query.filter("__key__ > ",key)
       
    73     results = query.fetch(batchSize)
       
    74     for result in results:
       
    75       count += 1
       
    76       yield result
       
    77     if batchSize > len(results):
       
    78       done = True
       
    79     else:
       
    80       key = results[-1].key()
       
    81 
       
    82 
       
    83 def remote(args):
       
    84   """Starts a shell with the datastore as remote_api_stub.
       
    85   """
       
    86 
       
    87   from google.appengine.ext import db
       
    88   from google.appengine.ext.remote_api import remote_api_stub
       
    89 
       
    90   app_id = args[0]
       
    91 
       
    92   if len(args) > 1:
       
    93     host = args[1]
       
    94   else:
       
    95     host = '%s.appspot.com' % app_id
       
    96 
       
    97   remote_api_stub.ConfigureRemoteDatastore(app_id, '/remote_api', auth_func, host)
       
    98 
       
    99   context = {
       
   100       'deepFetch': deepFetch,
       
   101   }
       
   102 
       
   103   code.interact('App Engine interactive console for %s' % (app_id,), None, context)
       
   104 
       
   105 
       
   106 def main(args):
       
   107   """Sets up the sys.path and environment for development.
       
   108   """
       
   109 
       
   110   here = os.path.abspath(__file__)
       
   111   here = os.path.join(os.path.dirname(here), '..')
       
   112   here = os.path.normpath(here)
       
   113 
       
   114   appengine_location = os.path.join(here, 'thirdparty', 'google_appengine')
       
   115 
       
   116   extra_paths = [here,
       
   117                  os.path.join(appengine_location, 'lib', 'django'),
       
   118                  os.path.join(appengine_location, 'lib', 'webob'),
       
   119                  os.path.join(appengine_location, 'lib', 'yaml', 'lib'),
       
   120                  appengine_location,
       
   121                  os.path.join(here, 'app'),
       
   122                 ]
       
   123 
       
   124   sys.path = extra_paths + sys.path
       
   125 
       
   126   os.environ['SERVER_SOFTWARE'] = 'Development Interactive Shell'
       
   127 
       
   128   import main as app_main
       
   129 
       
   130   remote(args)
       
   131 
       
   132 
       
   133 if __name__ == '__main__':
       
   134   if len(sys.argv) < 2:
       
   135     print "Usage: %s app_id [host]" % (sys.argv[0],)
       
   136     sys.exit(1)
       
   137 
       
   138   main(sys.argv[1:])
       
   139