OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
| 5 import os |
| 6 |
| 7 def IsDevServer(): |
| 8 return os.environ.get('SERVER_SOFTWARE', '').find('Development') == 0 |
| 9 |
5 # This will attempt to import the actual App Engine modules, and if it fails, | 10 # This will attempt to import the actual App Engine modules, and if it fails, |
6 # they will be replaced with fake modules. This is useful during testing. | 11 # they will be replaced with fake modules. This is useful during testing. |
7 try: | 12 try: |
8 import google.appengine.ext.blobstore as blobstore | 13 import google.appengine.ext.blobstore as blobstore |
9 from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty | 14 from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty |
10 import google.appengine.ext.db as db | 15 import google.appengine.ext.db as db |
11 import google.appengine.ext.webapp as webapp | 16 import google.appengine.ext.webapp as webapp |
12 import google.appengine.api.files as files | 17 import google.appengine.api.files as files |
13 import google.appengine.api.memcache as memcache | 18 import google.appengine.api.memcache as memcache |
14 import google.appengine.api.urlfetch as urlfetch | 19 import google.appengine.api.urlfetch as urlfetch |
15 # Default to a 5 minute cache timeout. | |
16 CACHE_TIMEOUT = 300 | |
17 except ImportError: | 20 except ImportError: |
18 # Cache for one second because zero means cache forever. | |
19 CACHE_TIMEOUT = 1 | |
20 import re | 21 import re |
21 from StringIO import StringIO | 22 from StringIO import StringIO |
22 | 23 |
23 FAKE_URL_FETCHER_CONFIGURATION = None | 24 FAKE_URL_FETCHER_CONFIGURATION = None |
24 | 25 |
25 def ConfigureFakeUrlFetch(configuration): | 26 def ConfigureFakeUrlFetch(configuration): |
26 """|configuration| is a dictionary mapping strings to fake urlfetch classes. | 27 """|configuration| is a dictionary mapping strings to fake urlfetch classes. |
27 A fake urlfetch class just needs to have a fetch method. The keys of the | 28 A fake urlfetch class just needs to have a fetch method. The keys of the |
28 dictionary are treated as regex, and they are matched with the URL to | 29 dictionary are treated as regex, and they are matched with the URL to |
29 determine which fake urlfetch is used. | 30 determine which fake urlfetch is used. |
(...skipping 11 matching lines...) Expand all Loading... |
41 return v | 42 return v |
42 return None | 43 return None |
43 | 44 |
44 class _RPC(object): | 45 class _RPC(object): |
45 def __init__(self, result=None): | 46 def __init__(self, result=None): |
46 self.result = result | 47 self.result = result |
47 | 48 |
48 def get_result(self): | 49 def get_result(self): |
49 return self.result | 50 return self.result |
50 | 51 |
| 52 def wait(self): |
| 53 pass |
| 54 |
51 class FakeUrlFetch(object): | 55 class FakeUrlFetch(object): |
52 """A fake urlfetch module that uses the current | 56 """A fake urlfetch module that uses the current |
53 |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers. | 57 |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers. |
54 """ | 58 """ |
55 class DownloadError(Exception): | 59 class DownloadError(Exception): |
56 pass | 60 pass |
57 | 61 |
58 class _Response(object): | 62 class _Response(object): |
59 def __init__(self, content): | 63 def __init__(self, content): |
60 self.content = content | 64 self.content = content |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
123 | 127 |
124 def GetBlobKeys(self): | 128 def GetBlobKeys(self): |
125 return _BLOBS.keys() | 129 return _BLOBS.keys() |
126 | 130 |
127 def finalize(self, filename): | 131 def finalize(self, filename): |
128 pass | 132 pass |
129 | 133 |
130 files = FakeFiles() | 134 files = FakeFiles() |
131 | 135 |
132 class InMemoryMemcache(object): | 136 class InMemoryMemcache(object): |
133 """A fake memcache that does nothing. | 137 """An in-memory memcache implementation. |
134 """ | 138 """ |
| 139 def __init__(self): |
| 140 self._namespaces = {} |
| 141 |
135 class Client(object): | 142 class Client(object): |
136 def set_multi_async(self, mapping, namespace='', time=0): | 143 def set_multi_async(self, mapping, namespace='', time=0): |
137 return | 144 for k, v in mapping.iteritems(): |
| 145 memcache.set(k, v, namespace=namespace, time=time) |
138 | 146 |
139 def get_multi_async(self, keys, namespace='', time=0): | 147 def get_multi_async(self, keys, namespace='', time=0): |
140 return _RPC(result=dict((k, None) for k in keys)) | 148 return _RPC(result=dict( |
| 149 (k, memcache.get(k, namespace=namespace, time=time)) for k in keys)) |
141 | 150 |
142 def set(self, key, value, namespace='', time=0): | 151 def set(self, key, value, namespace='', time=0): |
143 return | 152 self._GetNamespace(namespace)[key] = value |
144 | 153 |
145 def get(self, key, namespace='', time=0): | 154 def get(self, key, namespace='', time=0): |
146 return None | 155 return self._GetNamespace(namespace).get(key) |
147 | 156 |
148 def delete(self, key, namespace): | 157 def delete(self, key, namespace=''): |
149 return | 158 self._GetNamespace(namespace).pop(key, None) |
| 159 |
| 160 def delete_multi(self, keys, namespace=''): |
| 161 for k in keys: |
| 162 self.delete(k, namespace=namespace) |
| 163 |
| 164 def _GetNamespace(self, namespace): |
| 165 if namespace not in self._namespaces: |
| 166 self._namespaces[namespace] = {} |
| 167 return self._namespaces[namespace] |
150 | 168 |
151 memcache = InMemoryMemcache() | 169 memcache = InMemoryMemcache() |
152 | 170 |
153 class webapp(object): | 171 class webapp(object): |
154 class RequestHandler(object): | 172 class RequestHandler(object): |
155 """A fake webapp.RequestHandler class for Handler to extend. | 173 """A fake webapp.RequestHandler class for Handler to extend. |
156 """ | 174 """ |
157 def __init__(self, request, response): | 175 def __init__(self, request, response): |
158 self.request = request | 176 self.request = request |
159 self.response = response | 177 self.response = response |
160 self.response.status = 200 | 178 self.response.status = 200 |
161 | 179 |
162 def redirect(self, path, permanent=False): | 180 def redirect(self, path, permanent=False): |
163 self.response.status = 301 if permanent else 302 | 181 self.response.status = 301 if permanent else 302 |
164 self.response.headers['Location'] = path | 182 self.response.headers['Location'] = path |
165 | 183 |
166 class _Db_Result(object): | 184 class _Db_Result(object): |
167 def __init__(self, data): | 185 def __init__(self, data): |
168 self._data = data | 186 self._data = data |
169 | 187 |
170 class _Result(object): | 188 class _Result(object): |
171 def __init__(self, value): | 189 def __init__(self, value): |
172 self.value = value | 190 self.value = value |
173 | 191 |
174 def get(self): | 192 def get(self): |
175 return self._Result(self._data) | 193 return self._Result(self._data) |
176 | 194 |
177 class db(object): | 195 class db(object): |
178 _store = {} | 196 _store = {} |
| 197 |
179 class StringProperty(object): | 198 class StringProperty(object): |
180 pass | 199 pass |
181 | 200 |
| 201 class BlobProperty(object): |
| 202 pass |
| 203 |
| 204 class Key(object): |
| 205 def __init__(self, key): |
| 206 self._key = key |
| 207 |
| 208 @staticmethod |
| 209 def from_path(model_name, path): |
| 210 return db.Key('%s/%s' % (model_name, path)) |
| 211 |
| 212 def __eq__(self, obj): |
| 213 return self.__class__ == obj.__class__ and self._key == obj._key |
| 214 |
| 215 def __hash__(self): |
| 216 return hash(self._key) |
| 217 |
| 218 def __str__(self): |
| 219 return str(self._key) |
| 220 |
182 class Model(object): | 221 class Model(object): |
183 def __init__(self, key_='', value=''): | 222 key = None |
184 self._key = key_ | 223 |
185 self._value = value | 224 def __init__(self, **optargs): |
| 225 cls = self.__class__ |
| 226 for k, v in optargs.iteritems(): |
| 227 assert hasattr(cls, k), '%s does not define property %s' % ( |
| 228 cls.__name__, k) |
| 229 setattr(self, k, v) |
186 | 230 |
187 @staticmethod | 231 @staticmethod |
188 def gql(query, key): | 232 def gql(query, key): |
189 return _Db_Result(db._store.get(key, None)) | 233 return _Db_Result(db._store.get(key)) |
190 | 234 |
191 def put(self): | 235 def put(self): |
192 db._store[self._key] = self._value | 236 db._store[self.key_] = self.value |
| 237 |
| 238 @staticmethod |
| 239 def get_async(key): |
| 240 return _RPC(result=db._store.get(key)) |
| 241 |
| 242 @staticmethod |
| 243 def delete_async(key): |
| 244 db._store.pop(key, None) |
| 245 return _RPC() |
| 246 |
| 247 @staticmethod |
| 248 def put_async(value): |
| 249 db._store[value.key] = value |
| 250 return _RPC() |
193 | 251 |
194 class BlobReferenceProperty(object): | 252 class BlobReferenceProperty(object): |
195 pass | 253 pass |
OLD | NEW |