|
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 |