Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / common / extensions / docs / server2 / appengine_wrappers.py
blob734fdfe7e3a311e2eace635681b1169655fc6730
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
3 # found in the LICENSE file.
5 import os
7 from app_yaml_helper import AppYamlHelper
9 def GetAppVersion():
10 if 'CURRENT_VERSION_ID' in os.environ:
11 # The version ID looks like 2-0-25.36712548, we only want the 2-0-25.
12 return os.environ['CURRENT_VERSION_ID'].split('.', 1)[0]
13 # Not running on appengine, get it from the app.yaml file ourselves.
14 app_yaml_path = os.path.join(os.path.split(__file__)[0], 'app.yaml')
15 with open(app_yaml_path, 'r') as app_yaml:
16 return AppYamlHelper.ExtractVersion(app_yaml.read())
18 def IsDeadlineExceededError(error):
19 '''A general way of determining whether |error| is a DeadlineExceededError,
20 since there are 3 different types thrown by AppEngine and we might as well
21 handle them all the same way. For more info see:
22 https://developers.google.com/appengine/articles/deadlineexceedederrors
23 '''
24 return error.__class__.__name__ == 'DeadlineExceededError'
26 # This will attempt to import the actual App Engine modules, and if it fails,
27 # they will be replaced with fake modules. This is useful during testing.
28 try:
29 import google.appengine.api.files as files
30 import google.appengine.api.logservice as logservice
31 import google.appengine.api.memcache as memcache
32 import google.appengine.api.urlfetch as urlfetch
33 import google.appengine.ext.blobstore as blobstore
34 from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty
35 import google.appengine.ext.db as db
36 import webapp2
37 except ImportError:
38 import re
39 from StringIO import StringIO
41 FAKE_URL_FETCHER_CONFIGURATION = None
43 def ConfigureFakeUrlFetch(configuration):
44 """|configuration| is a dictionary mapping strings to fake urlfetch classes.
45 A fake urlfetch class just needs to have a fetch method. The keys of the
46 dictionary are treated as regex, and they are matched with the URL to
47 determine which fake urlfetch is used.
48 """
49 global FAKE_URL_FETCHER_CONFIGURATION
50 FAKE_URL_FETCHER_CONFIGURATION = dict(
51 (re.compile(k), v) for k, v in configuration.iteritems())
53 def _GetConfiguration(key):
54 if not FAKE_URL_FETCHER_CONFIGURATION:
55 raise ValueError('No fake fetch paths have been configured. '
56 'See ConfigureFakeUrlFetch in appengine_wrappers.py.')
57 for k, v in FAKE_URL_FETCHER_CONFIGURATION.iteritems():
58 if k.match(key):
59 return v
60 raise ValueError('No configuration found for %s' % key)
62 class _RPC(object):
63 def __init__(self, result=None):
64 self.result = result
66 def get_result(self):
67 return self.result
69 def wait(self):
70 pass
72 class FakeUrlFetch(object):
73 """A fake urlfetch module that uses the current
74 |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers.
75 """
76 class DownloadError(Exception):
77 pass
79 class _Response(object):
80 def __init__(self, content):
81 self.content = content
82 self.headers = {'Content-Type': 'none'}
83 self.status_code = 200
85 def fetch(self, url, **kwargs):
86 url = url.split('?', 1)[0]
87 response = self._Response(_GetConfiguration(url).fetch(url))
88 if response.content is None:
89 response.status_code = 404
90 return response
92 def create_rpc(self):
93 return _RPC()
95 def make_fetch_call(self, rpc, url, **kwargs):
96 rpc.result = self.fetch(url)
97 urlfetch = FakeUrlFetch()
99 _BLOBS = {}
100 class FakeBlobstore(object):
101 class BlobNotFoundError(Exception):
102 pass
104 class BlobReader(object):
105 def __init__(self, blob_key):
106 self._data = _BLOBS[blob_key].getvalue()
108 def read(self):
109 return self._data
111 blobstore = FakeBlobstore()
113 class FakeFileInterface(object):
114 """This class allows a StringIO object to be used in a with block like a
115 file.
117 def __init__(self, io):
118 self._io = io
120 def __exit__(self, *args):
121 pass
123 def write(self, data):
124 self._io.write(data)
126 def __enter__(self, *args):
127 return self._io
129 class FakeFiles(object):
130 _next_blobstore_key = 0
131 class blobstore(object):
132 @staticmethod
133 def create():
134 FakeFiles._next_blobstore_key += 1
135 return FakeFiles._next_blobstore_key
137 @staticmethod
138 def get_blob_key(filename):
139 return filename
141 def open(self, filename, mode):
142 _BLOBS[filename] = StringIO()
143 return FakeFileInterface(_BLOBS[filename])
145 def GetBlobKeys(self):
146 return _BLOBS.keys()
148 def finalize(self, filename):
149 pass
151 files = FakeFiles()
153 class Logservice(object):
154 AUTOFLUSH_ENABLED = True
156 def flush(self):
157 pass
159 logservice = Logservice()
161 class InMemoryMemcache(object):
162 """An in-memory memcache implementation.
164 def __init__(self):
165 self._namespaces = {}
167 class Client(object):
168 def set_multi_async(self, mapping, namespace='', time=0):
169 for k, v in mapping.iteritems():
170 memcache.set(k, v, namespace=namespace, time=time)
172 def get_multi_async(self, keys, namespace='', time=0):
173 return _RPC(result=dict(
174 (k, memcache.get(k, namespace=namespace, time=time)) for k in keys))
176 def set(self, key, value, namespace='', time=0):
177 self._GetNamespace(namespace)[key] = value
179 def get(self, key, namespace='', time=0):
180 return self._GetNamespace(namespace).get(key)
182 def delete(self, key, namespace=''):
183 self._GetNamespace(namespace).pop(key, None)
185 def delete_multi(self, keys, namespace=''):
186 for k in keys:
187 self.delete(k, namespace=namespace)
189 def _GetNamespace(self, namespace):
190 if namespace not in self._namespaces:
191 self._namespaces[namespace] = {}
192 return self._namespaces[namespace]
194 memcache = InMemoryMemcache()
196 class webapp2(object):
197 class RequestHandler(object):
198 """A fake webapp2.RequestHandler class for Handler to extend.
200 def __init__(self, request, response):
201 self.request = request
202 self.response = response
203 self.response.status = 200
205 def redirect(self, path, permanent=False):
206 self.response.status = 301 if permanent else 302
207 self.response.headers['Location'] = path
209 class _Db_Result(object):
210 def __init__(self, data):
211 self._data = data
213 class _Result(object):
214 def __init__(self, value):
215 self.value = value
217 def get(self):
218 return self._Result(self._data)
220 class db(object):
221 _store = {}
223 class StringProperty(object):
224 pass
226 class BlobProperty(object):
227 pass
229 class Key(object):
230 def __init__(self, key):
231 self._key = key
233 @staticmethod
234 def from_path(model_name, path):
235 return db.Key('%s/%s' % (model_name, path))
237 def __eq__(self, obj):
238 return self.__class__ == obj.__class__ and self._key == obj._key
240 def __hash__(self):
241 return hash(self._key)
243 def __str__(self):
244 return str(self._key)
246 class Model(object):
247 key = None
249 def __init__(self, **optargs):
250 cls = self.__class__
251 for k, v in optargs.iteritems():
252 assert hasattr(cls, k), '%s does not define property %s' % (
253 cls.__name__, k)
254 setattr(self, k, v)
256 @staticmethod
257 def gql(query, key):
258 return _Db_Result(db._store.get(key))
260 def put(self):
261 db._store[self.key_] = self.value
263 @staticmethod
264 def get_async(key):
265 return _RPC(result=db._store.get(key))
267 @staticmethod
268 def delete_async(key):
269 db._store.pop(key, None)
270 return _RPC()
272 @staticmethod
273 def put_async(value):
274 db._store[value.key] = value
275 return _RPC()
277 class BlobReferenceProperty(object):
278 pass