Skip to content

Commit 4127784

Browse files
authored
Use decorator to memoize. (GoogleCloudPlatform#598)
* Use decorator to memoize. This is to avoid adding complexity unrelated to what's being explained, when the snippet of code is included in a doc. * Clear memoization before tests.
1 parent c619e66 commit 4127784

File tree

6 files changed

+88
-21
lines changed

6 files changed

+88
-21
lines changed

appengine/bigquery/main_flask.py

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Sample appengine app demonstrating 3-legged oauth."""
2+
import cgi
3+
import json
4+
import os
5+
import sys
6+
7+
from flask import Flask
8+
9+
from googleapiclient.discovery import build
10+
11+
from oauth2client.appengine import OAuth2DecoratorFromClientSecrets
12+
13+
# The project id whose datasets you'd like to list
14+
PROJECTID = '<myproject_id>'
15+
16+
# Create the method decorator for oauth.
17+
decorator = OAuth2DecoratorFromClientSecrets(
18+
os.path.join(os.path.dirname(__file__), 'client_secrets.json'),
19+
scope='https://www.googleapis.com/auth/bigquery')
20+
21+
# Create the bigquery api client
22+
service = build('bigquery', 'v2')
23+
24+
# Create the Flask app
25+
app = Flask(__name__)
26+
app.config['DEBUG'] = True
27+
28+
# Create the endpoint to receive oauth flow callbacks
29+
app.route(decorator.callback_path)(decorator.callback_handler())
30+
31+
32+
@app.route('/')
33+
@decorator.oauth_required
34+
def list_datasets():
35+
"""Lists the datasets in PROJECTID"""
36+
http = decorator.http()
37+
datasets = service.datasets()
38+
39+
try:
40+
response = datasets.list(projectId=PROJECTID).execute(http)
41+
42+
return ('<h3>Datasets.list raw response:</h3>'
43+
'<pre>%s</pre>' % json.dumps(response, sort_keys=True,
44+
indent=4, separators=(',', ': ')))
45+
except:
46+
e = cgi.escape(sys.exc_info()[0], True)
47+
return '<p>Error: %s</p>' % e
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../../channels-api-deprecation-1e958c196e99.json

appengine/standard/firebase/firetactoe/firetactoe.py

+25-18
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
"""Tic Tac Toe with the Firebase API"""
1616

1717
import base64
18+
try:
19+
from functools import lru_cache
20+
except ImportError:
21+
from functools32 import lru_cache
1822
import json
1923
import os
2024
import re
@@ -51,33 +55,36 @@
5155
app = flask.Flask(__name__)
5256

5357

54-
def _get_firebase_db_url(_memo={}):
58+
# Memoize the value, to avoid parsing the code snippet every time
59+
@lru_cache()
60+
def _get_firebase_db_url():
5561
"""Grabs the databaseURL from the Firebase config snippet. Regex looks
5662
scary, but all it is doing is pulling the 'databaseURL' field from the
5763
Firebase javascript snippet"""
58-
if 'dburl' not in _memo:
59-
# Memoize the value, to avoid parsing the code snippet every time
60-
regex = re.compile(r'\bdatabaseURL\b.*?["\']([^"\']+)')
61-
cwd = os.path.dirname(__file__)
64+
regex = re.compile(r'\bdatabaseURL\b.*?["\']([^"\']+)')
65+
cwd = os.path.dirname(__file__)
66+
try:
6267
with open(os.path.join(cwd, 'templates', _FIREBASE_CONFIG)) as f:
6368
url = next(regex.search(line) for line in f if regex.search(line))
64-
_memo['dburl'] = url.group(1)
65-
return _memo['dburl']
69+
except StopIteration:
70+
raise ValueError(
71+
'Error parsing databaseURL. Please copy Firebase web snippet '
72+
'into templates/{}'.format(_FIREBASE_CONFIG))
73+
return url.group(1)
6674

6775

76+
# Memoize the authorized http, to avoid fetching new access tokens
77+
@lru_cache()
6878
# [START authed_http]
69-
def _get_http(_memo={}):
79+
def _get_http():
7080
"""Provides an authed http object."""
71-
if 'http' not in _memo:
72-
# Memoize the authorized http, to avoid fetching new access tokens
73-
http = httplib2.Http()
74-
# Use application default credentials to make the Firebase calls
75-
# https://firebase.google.com/docs/reference/rest/database/user-auth
76-
creds = GoogleCredentials.get_application_default().create_scoped(
77-
_FIREBASE_SCOPES)
78-
creds.authorize(http)
79-
_memo['http'] = http
80-
return _memo['http']
81+
http = httplib2.Http()
82+
# Use application default credentials to make the Firebase calls
83+
# https://firebase.google.com/docs/reference/rest/database/user-auth
84+
creds = GoogleCredentials.get_application_default().create_scoped(
85+
_FIREBASE_SCOPES)
86+
creds.authorize(http)
87+
return http
8188
# [END authed_http]
8289

8390

appengine/standard/firebase/firetactoe/firetactoe_test.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ def request(self, url, method, content='', *args, **kwargs):
4343
@pytest.fixture
4444
def app(testbed, monkeypatch, login):
4545
# Don't let the _get_http function memoize its value
46-
orig_get_http = firetactoe._get_http
47-
monkeypatch.setattr(firetactoe, '_get_http', lambda: orig_get_http({}))
46+
firetactoe._get_http.cache_clear()
4847

4948
# Provide a test firebase config. The following will set the databaseURL
5049
# databaseURL: "http://firebase.com/test-db-url"
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
flask==0.11.1
22
requests==2.11.1
33
requests_toolbelt==0.7.0
4-
oauth2client==4.0.0
4+
oauth2client==2.2.0
5+
functools32==3.2.3.post2 ; python_version < '3'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script src="https://www.gstatic.com/firebasejs/3.4.1/firebase.js"></script>
2+
<script>
3+
// Initialize Firebase
4+
var config = {
5+
apiKey: "AIzaSyC3gJDK1r-8nZuJGdmXntJR4E8cqH8qSTk",
6+
authDomain: "channels-api-deprecation.firebaseapp.com",
7+
databaseURL: "https://channels-api-deprecation.firebaseio.com",
8+
storageBucket: "channels-api-deprecation.appspot.com",
9+
messagingSenderId: "542117602304"
10+
};
11+
firebase.initializeApp(config);
12+
</script>

0 commit comments

Comments
 (0)