diff --git a/appengine/standard/flask/hello_world/.gitignore b/appengine/standard/flask/hello_world/.gitignore new file mode 100644 index 00000000000..a65b41774ad --- /dev/null +++ b/appengine/standard/flask/hello_world/.gitignore @@ -0,0 +1 @@ +lib diff --git a/appengine/standard/flask/hello_world/README.md b/appengine/standard/flask/hello_world/README.md new file mode 100644 index 00000000000..04ec9402ab1 --- /dev/null +++ b/appengine/standard/flask/hello_world/README.md @@ -0,0 +1,11 @@ +# App Engine Standard Flask Hello World + +This sample shows how to use [Flask](http://flask.pocoo.org/) with Google App +Engine Standard. + +Before running or deploying this application, install the dependencies using +[pip](http://pip.readthedocs.io/en/stable/): + + pip install -t lib -r requirements.txt + +For more information, see the [App Engine Standard README](../../README.md) diff --git a/appengine/standard/flask/hello_world/app.yaml b/appengine/standard/flask/hello_world/app.yaml new file mode 100644 index 00000000000..f041d384c05 --- /dev/null +++ b/appengine/standard/flask/hello_world/app.yaml @@ -0,0 +1,7 @@ +runtime: python27 +api_version: 1 +threadsafe: true + +handlers: +- url: /.* + script: main.app diff --git a/appengine/standard/flask/hello_world/appengine_config.py b/appengine/standard/flask/hello_world/appengine_config.py new file mode 100644 index 00000000000..c903d9a0ac5 --- /dev/null +++ b/appengine/standard/flask/hello_world/appengine_config.py @@ -0,0 +1,18 @@ +# Copyright 2016 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.appengine.ext import vendor + +# Add any libraries installed in the "lib" folder. +vendor.add('lib') diff --git a/appengine/standard/flask/hello_world/main.py b/appengine/standard/flask/hello_world/main.py new file mode 100644 index 00000000000..6e5a9d82fd1 --- /dev/null +++ b/appengine/standard/flask/hello_world/main.py @@ -0,0 +1,34 @@ +# Copyright 2016 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START app] +import logging + +from flask import Flask + + +app = Flask(__name__) + + +@app.route('/') +def hello(): + return 'Hello World!' + + +@app.errorhandler(500) +def server_error(e): + # Log the error and stacktrace. + logging.exception('An error occurred during a request.') + return 'An internal error occurred.', 500 +# [END app] diff --git a/appengine/standard/flask/hello_world/main_test.py b/appengine/standard/flask/hello_world/main_test.py new file mode 100644 index 00000000000..ab6db4fe5df --- /dev/null +++ b/appengine/standard/flask/hello_world/main_test.py @@ -0,0 +1,27 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + + +@pytest.fixture +def app(): + import main + main.app.testing = True + return main.app.test_client() + + +def test_index(app): + r = app.get('/') + assert r.status_code == 200 diff --git a/appengine/standard/flask/hello_world/requirements.txt b/appengine/standard/flask/hello_world/requirements.txt new file mode 100644 index 00000000000..c96594356e7 --- /dev/null +++ b/appengine/standard/flask/hello_world/requirements.txt @@ -0,0 +1 @@ +Flask==0.11 diff --git a/appengine/standard/flask/tutorial/.gitignore b/appengine/standard/flask/tutorial/.gitignore new file mode 100644 index 00000000000..a65b41774ad --- /dev/null +++ b/appengine/standard/flask/tutorial/.gitignore @@ -0,0 +1 @@ +lib diff --git a/appengine/standard/flask/tutorial/README.md b/appengine/standard/flask/tutorial/README.md new file mode 100644 index 00000000000..46f841935ec --- /dev/null +++ b/appengine/standard/flask/tutorial/README.md @@ -0,0 +1,11 @@ +# App Engine Standard Flask Tutorial App + +This sample shows how to use [Flask](http://flask.pocoo.org/) to handle +requests, forms, templates, and static files on Google App Engine Standard. + +Before running or deploying this application, install the dependencies using +[pip](http://pip.readthedocs.io/en/stable/): + + pip install -t lib -r requirements.txt + +For more information, see the [App Engine Standard README](../../README.md) diff --git a/appengine/standard/flask/tutorial/app.yaml b/appengine/standard/flask/tutorial/app.yaml new file mode 100644 index 00000000000..862e62b5273 --- /dev/null +++ b/appengine/standard/flask/tutorial/app.yaml @@ -0,0 +1,11 @@ +runtime: python27 +api_version: 1 +threadsafe: true + +# [START handlers] +handlers: +- url: /static + static_dir: static +- url: /.* + script: main.app +# [END handlers] diff --git a/appengine/standard/flask/tutorial/appengine_config.py b/appengine/standard/flask/tutorial/appengine_config.py new file mode 100644 index 00000000000..c903d9a0ac5 --- /dev/null +++ b/appengine/standard/flask/tutorial/appengine_config.py @@ -0,0 +1,18 @@ +# Copyright 2016 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from google.appengine.ext import vendor + +# Add any libraries installed in the "lib" folder. +vendor.add('lib') diff --git a/appengine/standard/flask/tutorial/main.py b/appengine/standard/flask/tutorial/main.py new file mode 100644 index 00000000000..47d56209a2d --- /dev/null +++ b/appengine/standard/flask/tutorial/main.py @@ -0,0 +1,56 @@ +# Copyright 2016 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START app] +import logging + +# [START imports] +from flask import Flask, render_template, request +# [END imports] + +app = Flask(__name__) + + +# [START form] +@app.route('/form') +def form(): + return render_template('form.html') +# [END form] + + +# [START submitted] +@app.route('/submitted', methods=['POST']) +def submitted_form(): + name = request.form['name'] + email = request.form['email'] + site = request.form['site_url'] + comments = request.form['comments'] + + # [END submitted] + # [START render_template] + return render_template( + 'submitted_form.html', + name=name, + email=email, + site=site, + comments=comments) + # [END render_template] + + +@app.errorhandler(500) +def server_error(e): + # Log the error and stacktrace. + logging.exception('An error occurred during a request.') + return 'An internal error occurred.', 500 +# [END app] diff --git a/appengine/standard/flask/tutorial/main_test.py b/appengine/standard/flask/tutorial/main_test.py new file mode 100644 index 00000000000..9dbd16c9458 --- /dev/null +++ b/appengine/standard/flask/tutorial/main_test.py @@ -0,0 +1,38 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest + + +@pytest.fixture +def app(): + import main + main.app.testing = True + return main.app.test_client() + + +def test_form(app): + r = app.get('/form') + assert r.status_code == 200 + assert 'Submit a form' in r.data.decode('utf-8') + + +def test_submitted_form(app): + r = app.post('/submitted', data={ + 'name': 'Inigo Montoya', + 'email': 'inigo@example.com', + 'site_url': 'http://example.com', + 'comments': ''}) + assert r.status_code == 200 + assert 'Inigo Montoya' in r.data.decode('utf-8') diff --git a/appengine/standard/flask/tutorial/requirements.txt b/appengine/standard/flask/tutorial/requirements.txt new file mode 100644 index 00000000000..c96594356e7 --- /dev/null +++ b/appengine/standard/flask/tutorial/requirements.txt @@ -0,0 +1 @@ +Flask==0.11 diff --git a/appengine/standard/flask/tutorial/static/style.css b/appengine/standard/flask/tutorial/static/style.css new file mode 100644 index 00000000000..378932a78f9 --- /dev/null +++ b/appengine/standard/flask/tutorial/static/style.css @@ -0,0 +1,3 @@ +.pagetitle { + color: #800080; +} diff --git a/appengine/standard/flask/tutorial/templates/form.html b/appengine/standard/flask/tutorial/templates/form.html new file mode 100644 index 00000000000..159752799e8 --- /dev/null +++ b/appengine/standard/flask/tutorial/templates/form.html @@ -0,0 +1,26 @@ + + + Submit a form + + + +
+
+

Submit a form

+
+
+
+ +
+ +
+ +
+ +
+ +
+
+
+ + diff --git a/appengine/standard/flask/tutorial/templates/submitted_form.html b/appengine/standard/flask/tutorial/templates/submitted_form.html new file mode 100644 index 00000000000..54c87766489 --- /dev/null +++ b/appengine/standard/flask/tutorial/templates/submitted_form.html @@ -0,0 +1,23 @@ + + + Submitted form + + + +
+
+

Form submitted

+
+
+

Thanks for your submission, {{name}}!

+

Here's a review of the information that you sent:

+

+ Name: {{name}}
+ Email: {{email}}
+ Website URL: {{site}}
+ Comments: {{comments}} +

+
+
+ + diff --git a/nox.py b/nox.py index 806984bfe85..7980569104f 100644 --- a/nox.py +++ b/nox.py @@ -117,13 +117,12 @@ def run_tests_in_sesssion( if skip_flaky: pytest_args.append('-m not slow and not flaky') - if sample_directories is None: - # session.posargs is any leftover arguments from the command line, - # which allows users to run a particular test instead of all of them. - if session.posargs: - sample_directories = session.posargs - else: - sample_directories = collect_sample_dirs('.', TESTS_BLACKLIST) + # session.posargs is any leftover arguments from the command line, + # which allows users to run a particular test instead of all of them. + if session.posargs: + sample_directories = session.posargs + elif sample_directories is None: + sample_directories = collect_sample_dirs('.', TESTS_BLACKLIST) if changed_only: changed_files = get_changed_files()