15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)def IsDeadlineExceededError(error): 63551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) '''A general way of determining whether |error| is a DeadlineExceededError, 73551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) since there are 3 different types thrown by AppEngine and we might as well 83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) handle them all the same way. For more info see: 93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) https://developers.google.com/appengine/articles/deadlineexceedederrors 103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) ''' 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return type(error).__name__ == 'DeadlineExceededError' 12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)def IsDownloadError(error): 15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return type(error).__name__ == 'DownloadError' 163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This will attempt to import the actual App Engine modules, and if it fails, 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# they will be replaced with fake modules. This is useful during testing. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)try: 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci import google.appengine.api.app_identity as app_identity 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) import google.appengine.api.files as files 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) import google.appengine.api.logservice as logservice 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) import google.appengine.api.memcache as memcache 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci import google.appengine.api.taskqueue as taskqueue 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) import google.appengine.api.urlfetch as urlfetch 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import google.appengine.ext.blobstore as blobstore 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import google.appengine.ext.db as db 30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) import webapp2 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)except ImportError: 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) import re 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) from StringIO import StringIO 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAKE_URL_FETCHER_CONFIGURATION = None 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ConfigureFakeUrlFetch(configuration): 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """|configuration| is a dictionary mapping strings to fake urlfetch classes. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A fake urlfetch class just needs to have a fetch method. The keys of the 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dictionary are treated as regex, and they are matched with the URL to 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) determine which fake urlfetch is used. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) global FAKE_URL_FETCHER_CONFIGURATION 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FAKE_URL_FETCHER_CONFIGURATION = dict( 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (re.compile(k), v) for k, v in configuration.iteritems()) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _GetConfiguration(key): 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not FAKE_URL_FETCHER_CONFIGURATION: 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise ValueError('No fake fetch paths have been configured. ' 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'See ConfigureFakeUrlFetch in appengine_wrappers.py.') 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for k, v in FAKE_URL_FETCHER_CONFIGURATION.iteritems(): 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if k.match(key): 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return v 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) raise ValueError('No configuration found for %s' % key) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class _RPC(object): 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, result=None): 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.result = result 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def get_result(self): 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.result 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def wait(self): 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) pass 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci class FakeAppIdentity(object): 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci """A fake app_identity module that returns no access tokens.""" 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def get_access_token(self, scope): 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return (None, None) 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci app_identity = FakeAppIdentity() 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class FakeUrlFetch(object): 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A fake urlfetch module that uses the current 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) class DownloadError(Exception): 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) pass 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class _Response(object): 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, content): 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.content = content 82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.headers = {'Content-Type': 'none'} 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.status_code = 200 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def fetch(self, url, **kwargs): 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) url = url.split('?', 1)[0] 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response = self._Response(_GetConfiguration(url).fetch(url)) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if response.content is None: 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) response.status_code = 404 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return response 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def create_rpc(self, **kwargs): 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return _RPC() 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def make_fetch_call(self, rpc, url, **kwargs): 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rpc.result = self.fetch(url) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) urlfetch = FakeUrlFetch() 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _BLOBS = {} 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class FakeBlobstore(object): 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) class BlobNotFoundError(Exception): 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pass 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class BlobReader(object): 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, blob_key): 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._data = _BLOBS[blob_key].getvalue() 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def read(self): 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._data 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) blobstore = FakeBlobstore() 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class FakeFileInterface(object): 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This class allows a StringIO object to be used in a with block like a 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) file. 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, io): 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._io = io 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __exit__(self, *args): 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def write(self, data): 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._io.write(data) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __enter__(self, *args): 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._io 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class FakeFiles(object): 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _next_blobstore_key = 0 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class blobstore(object): 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @staticmethod 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def create(): 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FakeFiles._next_blobstore_key += 1 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FakeFiles._next_blobstore_key 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @staticmethod 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def get_blob_key(filename): 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return filename 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def open(self, filename, mode): 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _BLOBS[filename] = StringIO() 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FakeFileInterface(_BLOBS[filename]) 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetBlobKeys(self): 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return _BLOBS.keys() 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def finalize(self, filename): 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) files = FakeFiles() 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) class Logservice(object): 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AUTOFLUSH_ENABLED = True 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def flush(self): 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) pass 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) logservice = Logservice() 160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class InMemoryMemcache(object): 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) """An in-memory memcache implementation. 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __init__(self): 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._namespaces = {} 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class Client(object): 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def set_multi_async(self, mapping, namespace='', time=0): 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for k, v in mapping.iteritems(): 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) memcache.set(k, v, namespace=namespace, time=time) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def get_multi_async(self, keys, namespace='', time=0): 173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return _RPC(result=dict( 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) (k, memcache.get(k, namespace=namespace, time=time)) for k in keys)) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def set(self, key, value, namespace='', time=0): 177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._GetNamespace(namespace)[key] = value 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def get(self, key, namespace='', time=0): 180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return self._GetNamespace(namespace).get(key) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def delete(self, key, namespace=''): 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._GetNamespace(namespace).pop(key, None) 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def delete_multi(self, keys, namespace=''): 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for k in keys: 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.delete(k, namespace=namespace) 188c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 189c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def _GetNamespace(self, namespace): 190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if namespace not in self._namespaces: 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._namespaces[namespace] = {} 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return self._namespaces[namespace] 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcache = InMemoryMemcache() 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 196f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) class webapp2(object): 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class RequestHandler(object): 198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) """A fake webapp2.RequestHandler class for Handler to extend. 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, request, response): 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.request = request 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.response = response 2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.response.status = 200 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def redirect(self, path, permanent=False): 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.response.status = 301 if permanent else 302 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.response.headers['Location'] = path 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class _Db_Result(object): 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, data): 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._data = data 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class _Result(object): 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, value): 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.value = value 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def get(self): 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._Result(self._data) 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class db(object): 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _store = {} 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class StringProperty(object): 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) class BlobProperty(object): 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) pass 228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 229c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) class Key(object): 230c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __init__(self, key): 231c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._key = key 232c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 233c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @staticmethod 234c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def from_path(model_name, path): 235c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return db.Key('%s/%s' % (model_name, path)) 236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __eq__(self, obj): 238c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return self.__class__ == obj.__class__ and self._key == obj._key 239c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 240c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __hash__(self): 241c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return hash(self._key) 242c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __str__(self): 244c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return str(self._key) 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class Model(object): 247c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) key = None 248c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 249c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __init__(self, **optargs): 250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cls = self.__class__ 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for k, v in optargs.iteritems(): 252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) assert hasattr(cls, k), '%s does not define property %s' % ( 253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) cls.__name__, k) 254c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) setattr(self, k, v) 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @staticmethod 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def gql(query, key): 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return _Db_Result(db._store.get(key)) 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def put(self): 261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) db._store[self.key_] = self.value 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 263c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @staticmethod 264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def get_async(key): 265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return _RPC(result=db._store.get(key)) 266c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 267c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @staticmethod 268c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def delete_async(key): 269c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) db._store.pop(key, None) 270c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return _RPC() 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @staticmethod 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def put_async(value): 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) db._store[value.key] = value 275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return _RPC() 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class BlobReferenceProperty(object): 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci # Executes any queued tasks synchronously as they are queued. 2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci _task_runner = None 2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def SetTaskRunnerForTest(task_runner): 2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci global _task_runner 2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci _task_runner = task_runner 2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci class SynchronousTaskQueue(object): 2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci class Task(object): 2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def __init__(self, url=None, params={}): 2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.url_ = url 2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self.params_ = params 2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def GetUrl(self): 2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return self.url_ 2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def GetCommit(self): 2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return self.params_.get('commit') 2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci class Queue(object): 3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def __init__(self, name='default'): 3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci pass 3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def add(self, task): 3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci global _task_runner 3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if _task_runner: 3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci _task_runner(task.GetUrl(), task.GetCommit()) 3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return _RPC() 3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci def purge(self): 3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return _RPC() 3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci taskqueue = SynchronousTaskQueue() 313