Skip to content

Commit 64bf6ab

Browse files
authored
Merge pull request #140 from sympy/cloud-ndb
Migrate to Cloud NDB to prepare for Python3 upgrade
2 parents b332d90 + 6235252 commit 64bf6ab

File tree

11 files changed

+132
-49
lines changed

11 files changed

+132
-49
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@ my/
3030

3131
# Backup files
3232
*~
33+
34+
# IntelliJ/Jetbrains
35+
.idea

.travis.yml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,34 @@ virtualenv:
77

88
before_install:
99
- npm install -g casperjs
10-
install: pip install -r requirements.txt
10+
- pip install nose
11+
install:
12+
- pip install -r requirements.txt -t lib/
13+
- pip install -r local_requirements.txt
1114

1215
before_script:
16+
- openssl aes-256-cbc -K $encrypted_2fd045226a67_key -iv $encrypted_2fd045226a67_iv
17+
-in client-secret.json.enc -out client-secret.json -d
1318
- cd ..
1419
- wget https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.90.zip -nv
1520
- unzip -q google_appengine_1.9.90.zip
1621
- export SDK_LOCATION="$(pwd)/google_appengine"
1722
- cd $TRAVIS_BUILD_DIR
1823
- python $SDK_LOCATION/dev_appserver.py --skip_sdk_update_check 1 . &
1924
- sleep 10
25+
2026
script:
21-
- python travis.py
27+
- PYTHONPATH='.' nosetests app/test -vv
28+
- casperjs test app/test
2229

2330
before_deploy:
24-
- openssl aes-256-cbc -K $encrypted_2fd045226a67_key -iv $encrypted_2fd045226a67_iv
25-
-in client-secret.json.enc -out ../client-secret.json -d
2631
- version=$(if [ ! -z "$TRAVIS_TAG" ]; then echo $(cut -d'-' -f2 <<<"$TRAVIS_TAG"); else echo "$TRAVIS_BRANCH"; fi)
2732
- echo "Version = $version"
2833
deploy:
2934
provider: gae
30-
keyfile: "../client-secret.json"
35+
keyfile: "client-secret.json"
3136
project: sympy-gamma-hrd
37+
skip_cleanup: true
3238
no_promote: true
3339
version: "$version"
3440
on:

README.rst

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ We use submodules to include external libraries in sympy_gamma::
4646
This is sufficient to clone appropriate repositories in correct versions
4747
into sympy_gamma (see git documentation on submodules for information).
4848

49+
Install Dependencies
50+
--------------------
51+
52+
The project depends on some third-party libraries that are not on the list
53+
of built-in libraries (in app.yaml) bundled with the runtime, to install them
54+
run the following command.::
55+
56+
pip install -r requirements.txt -t lib/
57+
58+
Some libraries although available on app engine runtime, but needs to be
59+
installed locally for development.
60+
61+
Ref: https://cloud.google.com/appengine/docs/standard/python/tools/using-libraries-python-27#local_development ::
62+
63+
pip install -r local_requirements.txt
64+
4965
Development server
5066
------------------
5167

@@ -173,6 +189,24 @@ NumPy version), change ``app.yaml.template`` and generate again. The
173189
Travis-CI script uses this to generate and deploy testing/production
174190
versions automatically.
175191

192+
193+
Running Tests
194+
-------------
195+
196+
To be able to run tests, make sure you have testing libraries installed::
197+
198+
npm install -g casperjs
199+
pip install nose
200+
201+
To run unit tests::
202+
203+
PYTHONPATH='.' nosetests app/test -vv
204+
205+
To run PhantomJS Tests::
206+
207+
casperjs test app/test
208+
209+
176210
Pulling changes
177211
---------------
178212

app.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ libraries:
2929
version: "1.6.1"
3030
- name: ssl
3131
version: "latest"
32+
- name: grpcio
33+
version: "1.0.0"
34+
35+
env_variables:
36+
GOOGLE_APPLICATION_CREDENTIALS: "client-secret.json"

app/models.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
from google.appengine.ext import ndb
1+
import six
2+
# https://github.com/googleapis/python-ndb/issues/249#issuecomment-560957294
3+
six.moves.reload_module(six)
4+
5+
from google.cloud import ndb
6+
7+
ndb_client = ndb.Client()
8+
29

310
class Query(ndb.Model):
411
text = ndb.StringProperty()

app/views.py

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from google.appengine.api import users
77
from google.appengine.runtime import DeadlineExceededError
88

9-
from logic.logic import SymPyGamma, mathjax_latex
9+
from logic.logic import SymPyGamma
1010

1111
import settings
1212
import models
@@ -19,6 +19,12 @@
1919
import datetime
2020
import traceback
2121

22+
import logging
23+
24+
25+
ndb_client = models.ndb_client
26+
27+
2228
LIVE_URL = '<a href="https://live.sympy.org">SymPy Live</a>'
2329
LIVE_PROMOTION_MESSAGES = [
2430
'Need more control? Try ' + LIVE_URL + '.',
@@ -180,8 +186,9 @@ def index(request, user):
180186
form = SearchForm()
181187

182188
if user:
183-
history = models.Query.query(models.Query.user_id==user.user_id())
184-
history = history.order(-models.Query.date).fetch(10)
189+
with ndb_client.context():
190+
history = models.Query.query(models.Query.user_id == user.user_id())
191+
history = history.order(-models.Query.date).fetch(10)
185192
else:
186193
history = None
187194

@@ -193,9 +200,23 @@ def index(request, user):
193200
"examples": EXAMPLES
194201
})
195202

203+
204+
def user_exists_and_input_not_present(user, input):
205+
with ndb_client.context():
206+
return (user and not models.Query.query(
207+
models.Query.text == input,
208+
models.Query.user_id == user.user_id()).get())
209+
210+
211+
def input_exists(input):
212+
with ndb_client.context():
213+
return models.Query.query(models.Query.text == input).get()
214+
215+
196216
@app_meta
197217
@authenticate
198218
def input(request, user):
219+
logging.info('Got the input from user')
199220
if request.method == "GET":
200221
form = SearchForm(request.GET)
201222
if form.is_valid():
@@ -214,15 +235,18 @@ def input(request, user):
214235
"output": "Can't handle the input."
215236
}]
216237

217-
if (user and not models.Query.query(
218-
models.Query.text==input,
219-
models.Query.user_id==user.user_id()).get()):
220-
query = models.Query(text=input, user_id=user.user_id())
221-
query.put()
222-
elif not models.Query.query(models.Query.text==input).get():
223-
query = models.Query(text=input, user_id=None)
224-
query.put()
225-
238+
if user_exists_and_input_not_present(user, input):
239+
logging.info('User exists and input not present')
240+
with ndb_client.context():
241+
query = models.Query(text=input, user_id=user.user_id())
242+
logging.info('query: %s' % query)
243+
query.put()
244+
elif not input_exists(input):
245+
logging.info('Input does not exists')
246+
with ndb_client.context():
247+
query = models.Query(text=input, user_id=None)
248+
logging.info('query: %s' % query)
249+
query.put()
226250

227251
# For some reason the |random tag always returns the same result
228252
return ("result.html", {
@@ -362,17 +386,25 @@ def get_card_full(request, card_name):
362386
return response
363387

364388

389+
def find_text_query(query):
390+
with ndb_client.context():
391+
return models.Query.query(models.Query.text == query.text)
392+
393+
365394
def remove_query(request, qid):
366395
user = users.get_current_user()
367396

368397
if user:
369-
query = models.ndb.Key(urlsafe=qid).get()
398+
with ndb_client.context():
399+
query = models.ndb.Key(urlsafe=qid).get()
370400

371-
if not models.Query.query(models.Query.text==query.text):
372-
query.user_id = None
373-
query.put()
401+
if not find_text_query(query):
402+
with ndb_client.context():
403+
query.user_id = None
404+
query.put()
374405
else:
375-
query.key.delete()
406+
with ndb_client.context():
407+
query.key.delete()
376408

377409
response = {
378410
'result': 'success',

appengine_config.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import os
2+
import pkg_resources
3+
from google.appengine.ext import vendor
4+
5+
# Set path to your libraries folder.
6+
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'lib')
7+
# path = 'lib'
8+
# Add libraries installed in the path folder.
9+
vendor.add(path)
10+
# Add libraries to pkg_resources working set to find the distribution.
11+
pkg_resources.working_set.add_entry(path)

local_requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
numpy==1.6.1
2+
protobuf
3+
enum34

main.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@
99

1010
from django.core.wsgi import get_wsgi_application
1111

12-
application = get_wsgi_application()
12+
# https://cloud.google.com/appengine/docs/standard/python/issue-requests#requests
13+
import requests_toolbelt.adapters.appengine
14+
# Use the App Engine Requests adapter. This makes sure that Requests uses URLFetch.
15+
requests_toolbelt.adapters.appengine.monkeypatch()
1316

17+
application = get_wsgi_application()

requirements.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
django==1.11
2-
numpy==1.6.1
1+
googleapis_common_protos
2+
google-cloud-ndb
3+
requests-toolbelt

0 commit comments

Comments
 (0)