From 9d819cef5faf7a22cb4fc8738de5f95c5531b2f5 Mon Sep 17 00:00:00 2001 From: Jinglun Dong <1683035+jinglundong@users.noreply.github.com> Date: Fri, 10 Mar 2023 02:18:11 +0000 Subject: [PATCH 1/9] Move samples of GAE Flex Python 3.8 and later to the default ./flexible directory. Update README.md files and some references. Remove the Python 3.7 and earlier examples from ./flexible directory. --- appengine/flexible/README.md | 12 +- appengine/flexible/analytics/README.md | 25 -- appengine/flexible/analytics/app.yaml | 25 -- appengine/flexible/analytics/main.py | 75 ----- appengine/flexible/analytics/main_test.py | 47 --- .../flexible/analytics/requirements-test.txt | 3 - appengine/flexible/analytics/requirements.txt | 4 - appengine/flexible/datastore/README.md | 24 -- appengine/flexible/datastore/app.yaml | 20 -- appengine/flexible/datastore/main.py | 82 ----- appengine/flexible/datastore/main_test.py | 24 -- .../flexible/datastore/requirements-test.txt | 1 - appengine/flexible/datastore/requirements.txt | 4 - appengine/flexible/disk/app.yaml | 20 -- appengine/flexible/disk/main.py | 74 ----- appengine/flexible/disk/main_test.py | 24 -- appengine/flexible/disk/requirements-test.txt | 1 - appengine/flexible/disk/requirements.txt | 3 - appengine/flexible/django_cloudsql/README.md | 25 -- appengine/flexible/django_cloudsql/app.yaml | 27 -- appengine/flexible/django_cloudsql/manage.py | 24 -- .../django_cloudsql/mysite/__init__.py | 0 .../django_cloudsql/mysite/settings.py | 180 ----------- .../flexible/django_cloudsql/mysite/urls.py | 25 -- .../flexible/django_cloudsql/mysite/wsgi.py | 22 -- .../django_cloudsql/noxfile_config.py | 39 --- .../django_cloudsql/polls/__init__.py | 0 .../flexible/django_cloudsql/polls/admin.py | 19 -- .../flexible/django_cloudsql/polls/apps.py | 19 -- .../flexible/django_cloudsql/polls/models.py | 28 -- .../django_cloudsql/polls/test_polls.py | 22 -- .../flexible/django_cloudsql/polls/urls.py | 21 -- .../flexible/django_cloudsql/polls/views.py | 19 -- .../django_cloudsql/requirements-test.txt | 2 - .../flexible/django_cloudsql/requirements.txt | 7 - .../flexible/extending_runtime/.dockerignore | 8 - .../flexible/extending_runtime/Dockerfile | 34 -- appengine/flexible/extending_runtime/app.yaml | 16 - appengine/flexible/extending_runtime/main.py | 46 --- .../flexible/extending_runtime/main_test.py | 31 -- .../extending_runtime/requirements-test.txt | 1 - .../extending_runtime/requirements.txt | 3 - appengine/flexible/hello_world/app.yaml | 5 +- appengine/flexible/hello_world/main.py | 4 +- appengine/flexible/hello_world/main_test.py | 4 +- .../hello_world/noxfile_config.py | 0 .../hello_world/requirements-test.txt | 2 +- .../flexible/hello_world/requirements.txt | 3 +- .../flexible/hello_world_django/.gitignore | 1 - .../flexible/hello_world_django/README.md | 63 ---- .../flexible/hello_world_django/app.yaml | 20 -- .../hello_world_django/helloworld/__init__.py | 0 .../hello_world_django/helloworld/views.py | 22 -- .../flexible/hello_world_django/manage.py | 24 -- .../project_name/__init__.py | 0 .../project_name/settings.py | 116 ------- .../hello_world_django/project_name/urls.py | 39 --- .../hello_world_django/project_name/wsgi.py | 30 -- .../hello_world_django/requirements-test.txt | 1 - .../hello_world_django/requirements.txt | 4 - appengine/flexible/metadata/app.yaml | 20 -- appengine/flexible/metadata/main.py | 68 ---- .../flexible/metadata/requirements-test.txt | 1 - appengine/flexible/metadata/requirements.txt | 4 - .../flexible/multiple_services/README.md | 67 ---- .../gateway-service/app.yaml | 24 -- .../multiple_services/gateway-service/main.py | 58 ---- .../gateway-service/requirements-test.txt | 1 - .../gateway-service/requirements.txt | 4 - .../gateway-service/services_config.py | 57 ---- .../multiple_services/static-service/app.yaml | 24 -- .../multiple_services/static-service/main.py | 46 --- .../static-service/requirements-test.txt | 1 - .../static-service/requirements.txt | 4 - .../static-service/static/index.html | 32 -- .../static-service/static/index.js | 36 --- .../static-service/static/style.css | 19 -- appengine/flexible/numpy/app.yaml | 20 -- appengine/flexible/numpy/main.py | 48 --- appengine/flexible/numpy/main_test.py | 24 -- .../flexible/numpy/requirements-test.txt | 1 - appengine/flexible/numpy/requirements.txt | 6 - appengine/flexible/pubsub/README.md | 76 ----- appengine/flexible/pubsub/app.yaml | 28 -- appengine/flexible/pubsub/main.py | 91 ------ appengine/flexible/pubsub/main_test.py | 69 ---- .../flexible/pubsub/requirements-test.txt | 1 - appengine/flexible/pubsub/requirements.txt | 4 - appengine/flexible/pubsub/sample_message.json | 5 - .../flexible/pubsub/templates/index.html | 36 --- appengine/flexible/scipy/.gitignore | 1 - appengine/flexible/scipy/README.md | 9 - appengine/flexible/scipy/app.yaml | 20 -- .../flexible/scipy/assets/google_logo.jpg | Bin 21568 -> 0 bytes appengine/flexible/scipy/main.py | 52 --- appengine/flexible/scipy/main_test.py | 30 -- appengine/flexible/scipy/noxfile_config.py | 38 --- .../flexible/scipy/requirements-test.txt | 1 - appengine/flexible/scipy/requirements.txt | 9 - appengine/flexible/static_files/README.md | 12 - appengine/flexible/static_files/app.yaml | 20 -- appengine/flexible/static_files/main.py | 42 --- appengine/flexible/static_files/main_test.py | 26 -- .../static_files/requirements-test.txt | 1 - .../flexible/static_files/requirements.txt | 3 - .../flexible/static_files/static/main.css | 21 -- .../static_files/templates/index.html | 29 -- appengine/flexible/storage/app.yaml | 9 +- appengine/flexible/storage/main.py | 34 +- appengine/flexible/storage/main_test.py | 18 +- appengine/flexible/storage/noxfile_config.py | 4 +- .../flexible/storage/requirements-test.txt | 3 +- appengine/flexible/storage/requirements.txt | 12 +- appengine/flexible/tasks/Dockerfile | 31 -- appengine/flexible/tasks/README.md | 115 ------- appengine/flexible/tasks/app.flexible.yaml | 20 -- appengine/flexible/tasks/app.yaml | 15 - .../tasks/create_app_engine_queue_task.py | 117 ------- .../create_app_engine_queue_task_test.py | 27 -- appengine/flexible/tasks/main.py | 41 --- appengine/flexible/tasks/main_test.py | 45 --- .../flexible/tasks/requirements-test.txt | 1 - appengine/flexible/tasks/requirements.txt | 4 - appengine/flexible/tasks/snippets.py | 303 ------------------ appengine/flexible/tasks/snippets_test.py | 127 -------- appengine/flexible/tasks/templates/index.html | 21 -- appengine/flexible/twilio/README.md | 34 -- appengine/flexible/twilio/app.yaml | 27 -- appengine/flexible/twilio/main.py | 87 ----- appengine/flexible/twilio/main_test.py | 77 ----- .../flexible/twilio/requirements-test.txt | 3 - appengine/flexible/twilio/requirements.txt | 4 - appengine/flexible/websockets/README.md | 11 - appengine/flexible/websockets/app.yaml | 36 --- appengine/flexible/websockets/main.py | 53 --- appengine/flexible/websockets/main_test.py | 82 ----- .../flexible/websockets/requirements-test.txt | 3 - .../flexible/websockets/requirements.txt | 5 - .../flexible/websockets/templates/index.html | 96 ------ appengine/flexible_ubuntu/README.md | 76 ----- .../flexible_ubuntu/hello_world/app.yaml | 34 -- appengine/flexible_ubuntu/hello_world/main.py | 32 -- .../flexible_ubuntu/hello_world/main_test.py | 24 -- .../hello_world/requirements-test.txt | 1 - .../hello_world/requirements.txt | 2 - appengine/flexible_ubuntu/storage/README.md | 37 --- appengine/flexible_ubuntu/storage/app.yaml | 28 -- appengine/flexible_ubuntu/storage/main.py | 87 ----- .../flexible_ubuntu/storage/main_test.py | 62 ---- .../flexible_ubuntu/storage/noxfile_config.py | 44 --- .../storage/requirements-test.txt | 2 - .../flexible_ubuntu/storage/requirements.txt | 4 - 152 files changed, 55 insertions(+), 4456 deletions(-) delete mode 100644 appengine/flexible/analytics/README.md delete mode 100644 appengine/flexible/analytics/app.yaml delete mode 100644 appengine/flexible/analytics/main.py delete mode 100644 appengine/flexible/analytics/main_test.py delete mode 100644 appengine/flexible/analytics/requirements-test.txt delete mode 100644 appengine/flexible/analytics/requirements.txt delete mode 100644 appengine/flexible/datastore/README.md delete mode 100644 appengine/flexible/datastore/app.yaml delete mode 100644 appengine/flexible/datastore/main.py delete mode 100644 appengine/flexible/datastore/main_test.py delete mode 100644 appengine/flexible/datastore/requirements-test.txt delete mode 100644 appengine/flexible/datastore/requirements.txt delete mode 100644 appengine/flexible/disk/app.yaml delete mode 100644 appengine/flexible/disk/main.py delete mode 100644 appengine/flexible/disk/main_test.py delete mode 100644 appengine/flexible/disk/requirements-test.txt delete mode 100644 appengine/flexible/disk/requirements.txt delete mode 100644 appengine/flexible/django_cloudsql/README.md delete mode 100644 appengine/flexible/django_cloudsql/app.yaml delete mode 100755 appengine/flexible/django_cloudsql/manage.py delete mode 100644 appengine/flexible/django_cloudsql/mysite/__init__.py delete mode 100644 appengine/flexible/django_cloudsql/mysite/settings.py delete mode 100644 appengine/flexible/django_cloudsql/mysite/urls.py delete mode 100644 appengine/flexible/django_cloudsql/mysite/wsgi.py delete mode 100644 appengine/flexible/django_cloudsql/noxfile_config.py delete mode 100644 appengine/flexible/django_cloudsql/polls/__init__.py delete mode 100644 appengine/flexible/django_cloudsql/polls/admin.py delete mode 100644 appengine/flexible/django_cloudsql/polls/apps.py delete mode 100644 appengine/flexible/django_cloudsql/polls/models.py delete mode 100644 appengine/flexible/django_cloudsql/polls/test_polls.py delete mode 100644 appengine/flexible/django_cloudsql/polls/urls.py delete mode 100644 appengine/flexible/django_cloudsql/polls/views.py delete mode 100644 appengine/flexible/django_cloudsql/requirements-test.txt delete mode 100644 appengine/flexible/django_cloudsql/requirements.txt delete mode 100644 appengine/flexible/extending_runtime/.dockerignore delete mode 100644 appengine/flexible/extending_runtime/Dockerfile delete mode 100644 appengine/flexible/extending_runtime/app.yaml delete mode 100644 appengine/flexible/extending_runtime/main.py delete mode 100644 appengine/flexible/extending_runtime/main_test.py delete mode 100644 appengine/flexible/extending_runtime/requirements-test.txt delete mode 100644 appengine/flexible/extending_runtime/requirements.txt rename appengine/{flexible_ubuntu => flexible}/hello_world/noxfile_config.py (100%) delete mode 100644 appengine/flexible/hello_world_django/.gitignore delete mode 100644 appengine/flexible/hello_world_django/README.md delete mode 100644 appengine/flexible/hello_world_django/app.yaml delete mode 100644 appengine/flexible/hello_world_django/helloworld/__init__.py delete mode 100644 appengine/flexible/hello_world_django/helloworld/views.py delete mode 100755 appengine/flexible/hello_world_django/manage.py delete mode 100644 appengine/flexible/hello_world_django/project_name/__init__.py delete mode 100644 appengine/flexible/hello_world_django/project_name/settings.py delete mode 100644 appengine/flexible/hello_world_django/project_name/urls.py delete mode 100644 appengine/flexible/hello_world_django/project_name/wsgi.py delete mode 100644 appengine/flexible/hello_world_django/requirements-test.txt delete mode 100644 appengine/flexible/hello_world_django/requirements.txt delete mode 100644 appengine/flexible/metadata/app.yaml delete mode 100644 appengine/flexible/metadata/main.py delete mode 100644 appengine/flexible/metadata/requirements-test.txt delete mode 100644 appengine/flexible/metadata/requirements.txt delete mode 100644 appengine/flexible/multiple_services/README.md delete mode 100644 appengine/flexible/multiple_services/gateway-service/app.yaml delete mode 100644 appengine/flexible/multiple_services/gateway-service/main.py delete mode 100644 appengine/flexible/multiple_services/gateway-service/requirements-test.txt delete mode 100644 appengine/flexible/multiple_services/gateway-service/requirements.txt delete mode 100644 appengine/flexible/multiple_services/gateway-service/services_config.py delete mode 100644 appengine/flexible/multiple_services/static-service/app.yaml delete mode 100644 appengine/flexible/multiple_services/static-service/main.py delete mode 100644 appengine/flexible/multiple_services/static-service/requirements-test.txt delete mode 100644 appengine/flexible/multiple_services/static-service/requirements.txt delete mode 100644 appengine/flexible/multiple_services/static-service/static/index.html delete mode 100644 appengine/flexible/multiple_services/static-service/static/index.js delete mode 100644 appengine/flexible/multiple_services/static-service/static/style.css delete mode 100644 appengine/flexible/numpy/app.yaml delete mode 100644 appengine/flexible/numpy/main.py delete mode 100644 appengine/flexible/numpy/main_test.py delete mode 100644 appengine/flexible/numpy/requirements-test.txt delete mode 100644 appengine/flexible/numpy/requirements.txt delete mode 100644 appengine/flexible/pubsub/README.md delete mode 100644 appengine/flexible/pubsub/app.yaml delete mode 100644 appengine/flexible/pubsub/main.py delete mode 100644 appengine/flexible/pubsub/main_test.py delete mode 100644 appengine/flexible/pubsub/requirements-test.txt delete mode 100644 appengine/flexible/pubsub/requirements.txt delete mode 100644 appengine/flexible/pubsub/sample_message.json delete mode 100644 appengine/flexible/pubsub/templates/index.html delete mode 100644 appengine/flexible/scipy/.gitignore delete mode 100644 appengine/flexible/scipy/README.md delete mode 100644 appengine/flexible/scipy/app.yaml delete mode 100644 appengine/flexible/scipy/assets/google_logo.jpg delete mode 100644 appengine/flexible/scipy/main.py delete mode 100644 appengine/flexible/scipy/main_test.py delete mode 100644 appengine/flexible/scipy/noxfile_config.py delete mode 100644 appengine/flexible/scipy/requirements-test.txt delete mode 100644 appengine/flexible/scipy/requirements.txt delete mode 100644 appengine/flexible/static_files/README.md delete mode 100644 appengine/flexible/static_files/app.yaml delete mode 100644 appengine/flexible/static_files/main.py delete mode 100644 appengine/flexible/static_files/main_test.py delete mode 100644 appengine/flexible/static_files/requirements-test.txt delete mode 100644 appengine/flexible/static_files/requirements.txt delete mode 100644 appengine/flexible/static_files/static/main.css delete mode 100644 appengine/flexible/static_files/templates/index.html delete mode 100644 appengine/flexible/tasks/Dockerfile delete mode 100644 appengine/flexible/tasks/README.md delete mode 100644 appengine/flexible/tasks/app.flexible.yaml delete mode 100644 appengine/flexible/tasks/app.yaml delete mode 100644 appengine/flexible/tasks/create_app_engine_queue_task.py delete mode 100644 appengine/flexible/tasks/create_app_engine_queue_task_test.py delete mode 100644 appengine/flexible/tasks/main.py delete mode 100644 appengine/flexible/tasks/main_test.py delete mode 100644 appengine/flexible/tasks/requirements-test.txt delete mode 100644 appengine/flexible/tasks/requirements.txt delete mode 100644 appengine/flexible/tasks/snippets.py delete mode 100644 appengine/flexible/tasks/snippets_test.py delete mode 100644 appengine/flexible/tasks/templates/index.html delete mode 100644 appengine/flexible/twilio/README.md delete mode 100644 appengine/flexible/twilio/app.yaml delete mode 100644 appengine/flexible/twilio/main.py delete mode 100644 appengine/flexible/twilio/main_test.py delete mode 100644 appengine/flexible/twilio/requirements-test.txt delete mode 100644 appengine/flexible/twilio/requirements.txt delete mode 100644 appengine/flexible/websockets/README.md delete mode 100644 appengine/flexible/websockets/app.yaml delete mode 100644 appengine/flexible/websockets/main.py delete mode 100644 appengine/flexible/websockets/main_test.py delete mode 100644 appengine/flexible/websockets/requirements-test.txt delete mode 100644 appengine/flexible/websockets/requirements.txt delete mode 100644 appengine/flexible/websockets/templates/index.html delete mode 100644 appengine/flexible_ubuntu/README.md delete mode 100644 appengine/flexible_ubuntu/hello_world/app.yaml delete mode 100644 appengine/flexible_ubuntu/hello_world/main.py delete mode 100644 appengine/flexible_ubuntu/hello_world/main_test.py delete mode 100644 appengine/flexible_ubuntu/hello_world/requirements-test.txt delete mode 100644 appengine/flexible_ubuntu/hello_world/requirements.txt delete mode 100644 appengine/flexible_ubuntu/storage/README.md delete mode 100644 appengine/flexible_ubuntu/storage/app.yaml delete mode 100644 appengine/flexible_ubuntu/storage/main.py delete mode 100644 appengine/flexible_ubuntu/storage/main_test.py delete mode 100644 appengine/flexible_ubuntu/storage/noxfile_config.py delete mode 100644 appengine/flexible_ubuntu/storage/requirements-test.txt delete mode 100644 appengine/flexible_ubuntu/storage/requirements.txt diff --git a/appengine/flexible/README.md b/appengine/flexible/README.md index 66e494ffaf4..a21487336b4 100644 --- a/appengine/flexible/README.md +++ b/appengine/flexible/README.md @@ -7,6 +7,9 @@ These are samples for using Python on Google App Engine Flexible Environment. These samples are typically referenced from the [docs](https://cloud.google.com/appengine/docs). +For code samples of Python version 3.7 and earlier, please check +https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine/flexible_python37_and_earlier. + See our other [Google Cloud Platform github repos](https://github.com/GoogleCloudPlatform) for sample applications and scaffolding for other frameworks and use cases. @@ -31,12 +34,9 @@ In general, the samples typically require: cd python-docs-samples/appengine/flexible ``` -4. Open a sample folder, create a virtualenv, install dependencies, and run the sample: +4. Follow https://cloud.google.com/python/docs/setup to set up a Python development environment. Then run: ``` - cd hello-world - virtualenv env - source env/bin/activate pip install -r requirements.txt python main.py ``` @@ -66,8 +66,8 @@ Some samples in this repositories may have special deployment instructions. Refe ## Contributing changes -* See [CONTRIBUTING.md](../CONTRIBUTING.md) +* See [CONTRIBUTING.md](../../CONTRIBUTING.md) ## Licensing -* See [LICENSE](../LICENSE) +* See [LICENSE](../../LICENSE) diff --git a/appengine/flexible/analytics/README.md b/appengine/flexible/analytics/README.md deleted file mode 100644 index 2646e144ed0..00000000000 --- a/appengine/flexible/analytics/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Google Analytics Measurement Protocol sample for Google App Engine Flexible - -[![Open in Cloud Shell][shell_img]][shell_link] - -[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png -[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/analytics/README.md - -This sample demonstrates how to use the [Google Analytics Measurement Protocol](https://developers.google.com/analytics/devguides/collection/protocol/v1/) (or any other SQL server) on [Google App Engine Flexible Environment](https://cloud.google.com/appengine). - -## Setup - -Before you can run or deploy the sample, you will need to do the following: - -1. Create a Google Analytics Property and obtain the Tracking ID. - -2. Update the environment variables in in ``app.yaml`` with your Tracking ID. - -## Running locally - -Refer to the [top-level README](../README.md) for instructions on running and deploying. - -You will need to set the following environment variables via your shell before running the sample: - - $ export GA_TRACKING_ID=[your Tracking ID] - $ python main.py diff --git a/appengine/flexible/analytics/app.yaml b/appengine/flexible/analytics/app.yaml deleted file mode 100644 index 0f5590d7058..00000000000 --- a/appengine/flexible/analytics/app.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2021 Google LLC -# -# 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. - -runtime: python -env: flex -entrypoint: gunicorn -b :$PORT main:app - -runtime_config: - python_version: 3 - -#[START gae_flex_analytics_env_variables] -env_variables: - GA_TRACKING_ID: your-tracking-id -#[END gae_flex_analytics_env_variables] diff --git a/appengine/flexible/analytics/main.py b/appengine/flexible/analytics/main.py deleted file mode 100644 index 93e631b4f47..00000000000 --- a/appengine/flexible/analytics/main.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2015 Google LLC. -# -# 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 gae_flex_analytics_track_event] -import logging -import os - -from flask import Flask -import requests - - -app = Flask(__name__) - - -# Environment variables are defined in app.yaml. -GA_TRACKING_ID = os.environ['GA_TRACKING_ID'] - - -def track_event(category, action, label=None, value=0): - data = { - 'v': '1', # API Version. - 'tid': GA_TRACKING_ID, # Tracking ID / Property ID. - # Anonymous Client Identifier. Ideally, this should be a UUID that - # is associated with particular user, device, or browser instance. - 'cid': '555', - 't': 'event', # Event hit type. - 'ec': category, # Event category. - 'ea': action, # Event action. - 'el': label, # Event label. - 'ev': value, # Event value, must be an integer - 'ua': 'Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14' - } - - response = requests.post( - 'https://www.google-analytics.com/collect', data=data) - - # If the request fails, this will raise a RequestException. Depending - # on your application's needs, this may be a non-error and can be caught - # by the caller. - response.raise_for_status() - - -@app.route('/') -def track_example(): - track_event( - category='Example', - action='test action') - return 'Event tracked.' - - -@app.errorhandler(500) -def server_error(e): - logging.exception('An error occurred during a request.') - return """ - An internal error occurred:
{}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host='127.0.0.1', port=8080, debug=True)
-# [END gae_flex_analytics_track_event]
diff --git a/appengine/flexible/analytics/main_test.py b/appengine/flexible/analytics/main_test.py
deleted file mode 100644
index d9540714df0..00000000000
--- a/appengine/flexible/analytics/main_test.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2016 Google LLC.
-#
-# 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 re
-
-import pytest
-import responses
-
-
-@pytest.fixture
-def app(monkeypatch):
- monkeypatch.setenv('GA_TRACKING_ID', '1234')
-
- import main
-
- main.app.testing = True
- return main.app.test_client()
-
-
-@responses.activate
-def test_tracking(app):
- responses.add(
- responses.POST,
- re.compile(r'.*'),
- body='{}',
- content_type='application/json')
-
- r = app.get('/')
-
- assert r.status_code == 200
- assert 'Event tracked' in r.data.decode('utf-8')
-
- assert len(responses.calls) == 1
- request_body = responses.calls[0].request.body
- assert 'tid=1234' in request_body
- assert 'ea=test+action' in request_body
diff --git a/appengine/flexible/analytics/requirements-test.txt b/appengine/flexible/analytics/requirements-test.txt
deleted file mode 100644
index 0dd3a1c6914..00000000000
--- a/appengine/flexible/analytics/requirements-test.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-pytest==7.0.1
-responses==0.17.0; python_version < '3.7'
-responses==0.20.0; python_version > '3.6'
diff --git a/appengine/flexible/analytics/requirements.txt b/appengine/flexible/analytics/requirements.txt
deleted file mode 100644
index 9fee7fc1fa3..00000000000
--- a/appengine/flexible/analytics/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-gunicorn==20.1.0
-requests[security]==2.27.1
diff --git a/appengine/flexible/datastore/README.md b/appengine/flexible/datastore/README.md
deleted file mode 100644
index 3a3a0b9e4bc..00000000000
--- a/appengine/flexible/datastore/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Python Google Cloud Datastore sample for Google App Engine Flexible Environment
-
-[![Open in Cloud Shell][shell_img]][shell_link]
-
-[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
-[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/datastore/README.md
-
-This sample demonstrates how to use [Google Cloud Datastore](https://cloud.google.com/datastore/) on [Google App Engine Flexible Environment](https://cloud.google.com/appengine).
-
-## Setup
-
-Before you can run or deploy the sample, you will need to enable the Cloud Datastore API in the [Google Developers Console](https://console.developers.google.com/project/_/apiui/apiview/datastore/overview).
-
-## Running locally
-
-Refer to the [top-level README](../README.md) for instructions on running and deploying.
-
-When running locally, you can use the [Google Cloud SDK](https://cloud.google.com/sdk) to provide authentication to use Google Cloud APIs:
-
- $ gcloud init
-
-Starting your application:
-
- $ python main.py
diff --git a/appengine/flexible/datastore/app.yaml b/appengine/flexible/datastore/app.yaml
deleted file mode 100644
index ca76f83fc3b..00000000000
--- a/appengine/flexible/datastore/app.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-runtime: python
-env: flex
-entrypoint: gunicorn -b :$PORT main:app
-
-runtime_config:
- python_version: 3
diff --git a/appengine/flexible/datastore/main.py b/appengine/flexible/datastore/main.py
deleted file mode 100644
index 2599fadfcab..00000000000
--- a/appengine/flexible/datastore/main.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 datetime
-import logging
-import socket
-
-from flask import Flask, request
-from google.cloud import datastore
-
-
-app = Flask(__name__)
-
-
-def is_ipv6(addr):
- """Checks if a given address is an IPv6 address."""
- try:
- socket.inet_pton(socket.AF_INET6, addr)
- return True
- except socket.error:
- return False
-
-
-# [START gae_flex_datastore_app]
-@app.route('/')
-def index():
- ds = datastore.Client()
-
- user_ip = request.remote_addr
-
- # Keep only the first two octets of the IP address.
- if is_ipv6(user_ip):
- user_ip = ':'.join(user_ip.split(':')[:2])
- else:
- user_ip = '.'.join(user_ip.split('.')[:2])
-
- entity = datastore.Entity(key=ds.key('visit'))
- entity.update({
- 'user_ip': user_ip,
- 'timestamp': datetime.datetime.now(tz=datetime.timezone.utc)
- })
-
- ds.put(entity)
- query = ds.query(kind='visit', order=('-timestamp',))
-
- results = []
- for x in query.fetch(limit=10):
- try:
- results.append('Time: {timestamp} Addr: {user_ip}'.format(**x))
- except KeyError:
- print("Error with result format, skipping entry.")
-
- output = 'Last 10 visits:\n{}'.format('\n'.join(results))
-
- return output, 200, {'Content-Type': 'text/plain; charset=utf-8'}
-# [END gae_flex_datastore_app]
-
-
-@app.errorhandler(500)
-def server_error(e):
- logging.exception('An error occurred during a request.')
- return """
- An internal error occurred: {}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/datastore/main_test.py b/appengine/flexible/datastore/main_test.py
deleted file mode 100644
index 840032fe9a7..00000000000
--- a/appengine/flexible/datastore/main_test.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 main
-
-
-def test_index():
- main.app.testing = True
- client = main.app.test_client()
-
- r = client.get('/', environ_base={'REMOTE_ADDR': '127.0.0.1'})
- assert r.status_code == 200
- assert 'Last 10 visits' in r.data.decode('utf-8')
diff --git a/appengine/flexible/datastore/requirements-test.txt b/appengine/flexible/datastore/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/datastore/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/datastore/requirements.txt b/appengine/flexible/datastore/requirements.txt
deleted file mode 100644
index 094e8f43b6b..00000000000
--- a/appengine/flexible/datastore/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-google-cloud-datastore==2.7.1
-gunicorn==20.1.0
diff --git a/appengine/flexible/disk/app.yaml b/appengine/flexible/disk/app.yaml
deleted file mode 100644
index ca76f83fc3b..00000000000
--- a/appengine/flexible/disk/app.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-runtime: python
-env: flex
-entrypoint: gunicorn -b :$PORT main:app
-
-runtime_config:
- python_version: 3
diff --git a/appengine/flexible/disk/main.py b/appengine/flexible/disk/main.py
deleted file mode 100644
index 1a1042f87c9..00000000000
--- a/appengine/flexible/disk/main.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 logging
-import os
-import socket
-
-from flask import Flask, request
-
-
-app = Flask(__name__)
-
-
-def is_ipv6(addr):
- """Checks if a given address is an IPv6 address."""
- try:
- socket.inet_pton(socket.AF_INET6, addr)
- return True
- except socket.error:
- return False
-
-
-# [START example]
-@app.route('/')
-def index():
- instance_id = os.environ.get('GAE_INSTANCE', '1')
-
- user_ip = request.remote_addr
-
- # Keep only the first two octets of the IP address.
- if is_ipv6(user_ip):
- user_ip = ':'.join(user_ip.split(':')[:2])
- else:
- user_ip = '.'.join(user_ip.split('.')[:2])
-
- with open('/tmp/seen.txt', 'a') as f:
- f.write('{}\n'.format(user_ip))
-
- with open('/tmp/seen.txt', 'r') as f:
- seen = f.read()
-
- output = """
-Instance: {}
-Seen:
-{}""".format(instance_id, seen)
-
- return output, 200, {'Content-Type': 'text/plain; charset=utf-8'}
-# [END example]
-
-
-@app.errorhandler(500)
-def server_error(e):
- logging.exception('An error occurred during a request.')
- return """
- An internal error occurred: {}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/disk/main_test.py b/appengine/flexible/disk/main_test.py
deleted file mode 100644
index fc7122968ff..00000000000
--- a/appengine/flexible/disk/main_test.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 main
-
-
-def test_index():
- main.app.testing = True
- client = main.app.test_client()
-
- r = client.get('/', environ_base={'REMOTE_ADDR': '127.0.0.1'})
- assert r.status_code == 200
- assert '127.0' in r.data.decode('utf-8')
diff --git a/appengine/flexible/disk/requirements-test.txt b/appengine/flexible/disk/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/disk/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/disk/requirements.txt b/appengine/flexible/disk/requirements.txt
deleted file mode 100644
index beeed7bed09..00000000000
--- a/appengine/flexible/disk/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-gunicorn==20.1.0
diff --git a/appengine/flexible/django_cloudsql/README.md b/appengine/flexible/django_cloudsql/README.md
deleted file mode 100644
index 7db87fd2797..00000000000
--- a/appengine/flexible/django_cloudsql/README.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Getting started with Django on Google Cloud Platform on App Engine Flexible
-
-[![Open in Cloud Shell][shell_img]][shell_link]
-
-[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
-[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/django_cloudsql/README.md
-
-This repository is an example of how to run a [Django](https://www.djangoproject.com/)
-app on Google App Engine Flexible Environment. It uses the
-[Writing your first Django app](https://docs.djangoproject.com/en/3.2/intro/tutorial01/) as the
-example app to deploy.
-
-
-# Tutorial
-See our [Running Django in the App Engine Flexible Environment](https://cloud.google.com/python/django/flexible-environment) tutorial for instructions for setting up and deploying this sample application.
-
-
-## Contributing changes
-
-* See [CONTRIBUTING.md](CONTRIBUTING.md)
-
-
-## Licensing
-
-* See [LICENSE](LICENSE)
diff --git a/appengine/flexible/django_cloudsql/app.yaml b/appengine/flexible/django_cloudsql/app.yaml
deleted file mode 100644
index c8460e5ed3d..00000000000
--- a/appengine/flexible/django_cloudsql/app.yaml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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 runtime]
-# [START gaeflex_py_django_app_yaml]
-runtime: python
-env: flex
-entrypoint: gunicorn -b :$PORT mysite.wsgi
-
-beta_settings:
- cloud_sql_instances: PROJECT_ID:REGION:INSTANCE_NAME
-
-runtime_config:
- python_version: 3.7
-# [END gaeflex_py_django_app_yaml]
-# [END runtime]
diff --git a/appengine/flexible/django_cloudsql/manage.py b/appengine/flexible/django_cloudsql/manage.py
deleted file mode 100755
index 89fb5ae5607..00000000000
--- a/appengine/flexible/django_cloudsql/manage.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 Google LLC.
-#
-# 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 os
-import sys
-
-if __name__ == "__main__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
-
- from django.core.management import execute_from_command_line
-
- execute_from_command_line(sys.argv)
diff --git a/appengine/flexible/django_cloudsql/mysite/__init__.py b/appengine/flexible/django_cloudsql/mysite/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/appengine/flexible/django_cloudsql/mysite/settings.py b/appengine/flexible/django_cloudsql/mysite/settings.py
deleted file mode 100644
index 66ba0692e0c..00000000000
--- a/appengine/flexible/django_cloudsql/mysite/settings.py
+++ /dev/null
@@ -1,180 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 io
-import os
-
-import environ
-from google.cloud import secretmanager
-
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-# [START gaeflex_py_django_secret_config]
-env = environ.Env(DEBUG=(bool, False))
-env_file = os.path.join(BASE_DIR, ".env")
-
-if os.path.isfile(env_file):
- # Use a local secret file, if provided
-
- env.read_env(env_file)
-# [START_EXCLUDE]
-elif os.getenv("TRAMPOLINE_CI", None):
- # Create local settings if running with CI, for unit testing
-
- placeholder = (
- f"SECRET_KEY=a\n"
- "GS_BUCKET_NAME=None\n"
- f"DATABASE_URL=sqlite://{os.path.join(BASE_DIR, 'db.sqlite3')}"
- )
- env.read_env(io.StringIO(placeholder))
-# [END_EXCLUDE]
-elif os.environ.get("GOOGLE_CLOUD_PROJECT", None):
- # Pull secrets from Secret Manager
- project_id = os.environ.get("GOOGLE_CLOUD_PROJECT")
-
- client = secretmanager.SecretManagerServiceClient()
- settings_name = os.environ.get("SETTINGS_NAME", "django_settings")
- name = f"projects/{project_id}/secrets/{settings_name}/versions/latest"
- payload = client.access_secret_version(name=name).payload.data.decode("UTF-8")
-
- env.read_env(io.StringIO(payload))
-else:
- raise Exception("No local .env or GOOGLE_CLOUD_PROJECT detected. No secrets found.")
-# [END gaeflex_py_django_secret_config]
-
-SECRET_KEY = env("SECRET_KEY")
-
-# SECURITY WARNING: don't run with debug turned on in production!
-# Change this to "False" when you are ready for production
-DEBUG = env("DEBUG")
-
-# SECURITY WARNING: App Engine's security features ensure that it is safe to
-# have ALLOWED_HOSTS = ['*'] when the app is deployed. If you deploy a Django
-# app not on App Engine, make sure to set an appropriate host here.
-ALLOWED_HOSTS = ["*"]
-
-# Application definition
-
-INSTALLED_APPS = (
- "django.contrib.admin",
- "django.contrib.auth",
- "django.contrib.contenttypes",
- "django.contrib.sessions",
- "django.contrib.messages",
- "django.contrib.staticfiles",
- "polls",
-)
-
-MIDDLEWARE = (
- "django.middleware.security.SecurityMiddleware",
- "django.contrib.sessions.middleware.SessionMiddleware",
- "django.middleware.common.CommonMiddleware",
- "django.middleware.csrf.CsrfViewMiddleware",
- "django.contrib.auth.middleware.AuthenticationMiddleware",
- "django.contrib.messages.middleware.MessageMiddleware",
- "django.middleware.clickjacking.XFrameOptionsMiddleware",
-)
-
-ROOT_URLCONF = "mysite.urls"
-
-TEMPLATES = [
- {
- "BACKEND": "django.template.backends.django.DjangoTemplates",
- "DIRS": [],
- "APP_DIRS": True,
- "OPTIONS": {
- "context_processors": [
- "django.template.context_processors.debug",
- "django.template.context_processors.request",
- "django.contrib.auth.context_processors.auth",
- "django.contrib.messages.context_processors.messages",
- ],
- },
- },
-]
-
-WSGI_APPLICATION = "mysite.wsgi.application"
-
-# Database
-
-# [START dbconfig]
-# [START gaeflex_py_django_database_config]
-# Use django-environ to parse the connection string
-DATABASES = {"default": env.db()}
-
-# If the flag as been set, configure to use proxy
-if os.getenv("USE_CLOUD_SQL_AUTH_PROXY", None):
- DATABASES["default"]["HOST"] = "127.0.0.1"
- DATABASES["default"]["PORT"] = 5432
-
-# [END gaeflex_py_django_database_config]
-# [END dbconfig]
-
-# Use a in-memory sqlite3 database when testing in CI systems
-if os.getenv("TRAMPOLINE_CI", None):
- DATABASES = {
- "default": {
- "ENGINE": "django.db.backends.sqlite3",
- "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
- }
- }
-
-
-# Password validation
-
-AUTH_PASSWORD_VALIDATORS = [
- {
- "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", # noqa: 501
- },
- {
- "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", # noqa: 501
- },
- {
- "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", # noqa: 501
- },
- {
- "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", # noqa: 501
- },
-]
-
-# Internationalization
-# https://docs.djangoproject.com/en/3.2/topics/i18n/
-
-LANGUAGE_CODE = "en-us"
-
-TIME_ZONE = "UTC"
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-# Static files (CSS, JavaScript, Images)
-# [START staticurl]
-# [START gaeflex_py_django_static_config]
-# Define static storage via django-storages[google]
-GS_BUCKET_NAME = env("GS_BUCKET_NAME")
-STATIC_URL = "/static/"
-DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
-STATICFILES_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
-GS_DEFAULT_ACL = "publicRead"
-# [END gaeflex_py_django_static_config]
-# [END staticurl]
-
-# Default primary key field type
-# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
-
-DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
diff --git a/appengine/flexible/django_cloudsql/mysite/urls.py b/appengine/flexible/django_cloudsql/mysite/urls.py
deleted file mode 100644
index 62e72564fc2..00000000000
--- a/appengine/flexible/django_cloudsql/mysite/urls.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 gaeflex_py_django_local_static]
-from django.conf import settings
-from django.conf.urls.static import static
-from django.contrib import admin
-from django.urls import include, path
-
-urlpatterns = [
- path("", include("polls.urls")),
- path("admin/", admin.site.urls),
-] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
-# [END gaeflex_py_django_local_static]
diff --git a/appengine/flexible/django_cloudsql/mysite/wsgi.py b/appengine/flexible/django_cloudsql/mysite/wsgi.py
deleted file mode 100644
index 968cf994b60..00000000000
--- a/appengine/flexible/django_cloudsql/mysite/wsgi.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 os
-
-from django.core.wsgi import get_wsgi_application
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
-
-application = get_wsgi_application()
diff --git a/appengine/flexible/django_cloudsql/noxfile_config.py b/appengine/flexible/django_cloudsql/noxfile_config.py
deleted file mode 100644
index 8c838f846b2..00000000000
--- a/appengine/flexible/django_cloudsql/noxfile_config.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2020 Google LLC
-#
-# 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.
-
-# Default TEST_CONFIG_OVERRIDE for python repos.
-
-# You can copy this file into your directory, then it will be imported from
-# the noxfile.py.
-
-# The source of truth:
-# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py
-
-TEST_CONFIG_OVERRIDE = {
- # You can opt out from the test for specific Python versions.
- 'ignored_versions': ["2.7"],
-
- # An envvar key for determining the project id to use. Change it
- # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
- # build specific Cloud project. You can also use your own string
- # to use your own Cloud project.
- 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT',
- # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
-
- # A dictionary you want to inject into your test. Don't put any
- # secrets here. These values will override predefined values.
- 'envs': {
- 'DJANGO_SETTINGS_MODULE': 'mysite.settings'
- },
-}
diff --git a/appengine/flexible/django_cloudsql/polls/__init__.py b/appengine/flexible/django_cloudsql/polls/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/appengine/flexible/django_cloudsql/polls/admin.py b/appengine/flexible/django_cloudsql/polls/admin.py
deleted file mode 100644
index 5fc6d71455b..00000000000
--- a/appengine/flexible/django_cloudsql/polls/admin.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 django.contrib import admin
-
-from .models import Question
-
-admin.site.register(Question)
diff --git a/appengine/flexible/django_cloudsql/polls/apps.py b/appengine/flexible/django_cloudsql/polls/apps.py
deleted file mode 100644
index ae20e178dbe..00000000000
--- a/appengine/flexible/django_cloudsql/polls/apps.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 django.apps import AppConfig
-
-
-class PollsConfig(AppConfig):
- name = 'polls'
diff --git a/appengine/flexible/django_cloudsql/polls/models.py b/appengine/flexible/django_cloudsql/polls/models.py
deleted file mode 100644
index 26cfaa68121..00000000000
--- a/appengine/flexible/django_cloudsql/polls/models.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 django.db import models
-
-
-class Question(models.Model):
- question_text = models.CharField(max_length=200)
- pub_date = models.DateTimeField('date published')
-
-
-class Choice(models.Model):
- question = models.ForeignKey(Question, on_delete=models.CASCADE)
- choice_text = models.CharField(max_length=200)
- votes = models.IntegerField(default=0)
-
-# Create your models here.
diff --git a/appengine/flexible/django_cloudsql/polls/test_polls.py b/appengine/flexible/django_cloudsql/polls/test_polls.py
deleted file mode 100644
index 17bf94fdcdc..00000000000
--- a/appengine/flexible/django_cloudsql/polls/test_polls.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2020 Google LLC.
-#
-# 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 django.test import Client, TestCase # noqa: 401
-
-
-class PollViewTests(TestCase):
- def test_index_view(self):
- response = self.client.get('/')
- assert response.status_code == 200
- assert 'Hello, world' in str(response.content)
diff --git a/appengine/flexible/django_cloudsql/polls/urls.py b/appengine/flexible/django_cloudsql/polls/urls.py
deleted file mode 100644
index 9a0c88fe977..00000000000
--- a/appengine/flexible/django_cloudsql/polls/urls.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 django.urls import re_path
-
-from . import views
-
-urlpatterns = [
- re_path(r'^$', views.index, name='index'),
-]
diff --git a/appengine/flexible/django_cloudsql/polls/views.py b/appengine/flexible/django_cloudsql/polls/views.py
deleted file mode 100644
index 262f571d568..00000000000
--- a/appengine/flexible/django_cloudsql/polls/views.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 django.http import HttpResponse
-
-
-def index(request):
- return HttpResponse("Hello, world. You're at the polls index.")
diff --git a/appengine/flexible/django_cloudsql/requirements-test.txt b/appengine/flexible/django_cloudsql/requirements-test.txt
deleted file mode 100644
index 99bb7d24ca4..00000000000
--- a/appengine/flexible/django_cloudsql/requirements-test.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-pytest==7.0.1
-pytest-django==4.5.0
diff --git a/appengine/flexible/django_cloudsql/requirements.txt b/appengine/flexible/django_cloudsql/requirements.txt
deleted file mode 100644
index e1d759f2818..00000000000
--- a/appengine/flexible/django_cloudsql/requirements.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-Django==4.0.4; python_version >= '3.8'
-Django==3.2.14; python_version < '3.8'
-gunicorn==20.1.0
-psycopg2-binary==2.9.5
-django-environ==0.9.0
-google-cloud-secret-manager==2.12.0
-django-storages[google]==1.13
diff --git a/appengine/flexible/extending_runtime/.dockerignore b/appengine/flexible/extending_runtime/.dockerignore
deleted file mode 100644
index cc6c24ef97f..00000000000
--- a/appengine/flexible/extending_runtime/.dockerignore
+++ /dev/null
@@ -1,8 +0,0 @@
-env
-*.pyc
-__pycache__
-.dockerignore
-Dockerfile
-.git
-.hg
-.svn
diff --git a/appengine/flexible/extending_runtime/Dockerfile b/appengine/flexible/extending_runtime/Dockerfile
deleted file mode 100644
index 71cf0fa8193..00000000000
--- a/appengine/flexible/extending_runtime/Dockerfile
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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 dockerfile]
-FROM gcr.io/google_appengine/python
-
-# Install the fortunes binary from the debian repositories.
-RUN apt-get update && apt-get install -y fortunes
-
-# Change the -p argument to use Python 2.7 if desired.
-RUN virtualenv /env -p python3.4
-
-# Set virtualenv environment variables. This is equivalent to running
-# source /env/bin/activate.
-ENV VIRTUAL_ENV /env
-ENV PATH /env/bin:$PATH
-
-ADD requirements.txt /app/
-RUN pip install -r requirements.txt
-ADD . /app/
-
-CMD gunicorn -b :$PORT main:app
-# [END dockerfile]
diff --git a/appengine/flexible/extending_runtime/app.yaml b/appengine/flexible/extending_runtime/app.yaml
deleted file mode 100644
index 80bd1f30838..00000000000
--- a/appengine/flexible/extending_runtime/app.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-runtime: custom
-env: flex
diff --git a/appengine/flexible/extending_runtime/main.py b/appengine/flexible/extending_runtime/main.py
deleted file mode 100644
index fe0b531b7a7..00000000000
--- a/appengine/flexible/extending_runtime/main.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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
-import subprocess
-
-from flask import Flask
-
-
-app = Flask(__name__)
-
-
-# [START example]
-@app.route('/')
-def fortune():
- output = subprocess.check_output('/usr/games/fortune')
- return output, 200, {'Content-Type': 'text/plain; charset=utf-8'}
-# [END example]
-
-
-@app.errorhandler(500)
-def server_error(e):
- logging.exception('An error occurred during a request.')
- return """
- An internal error occurred: {}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See CMD in Dockerfile.
- app.run(host='127.0.0.1', port=8080, debug=True)
-# [END app]
diff --git a/appengine/flexible/extending_runtime/main_test.py b/appengine/flexible/extending_runtime/main_test.py
deleted file mode 100644
index df10409cfeb..00000000000
--- a/appengine/flexible/extending_runtime/main_test.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 os
-
-import pytest
-
-import main
-
-
-@pytest.mark.skipif(
- not os.path.exists('/usr/games/fortune'),
- reason='Fortune executable is not installed.')
-def test_index():
- main.app.testing = True
- client = main.app.test_client()
-
- r = client.get('/')
- assert r.status_code == 200
- assert len(r.data)
diff --git a/appengine/flexible/extending_runtime/requirements-test.txt b/appengine/flexible/extending_runtime/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/extending_runtime/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/extending_runtime/requirements.txt b/appengine/flexible/extending_runtime/requirements.txt
deleted file mode 100644
index beeed7bed09..00000000000
--- a/appengine/flexible/extending_runtime/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-gunicorn==20.1.0
diff --git a/appengine/flexible/hello_world/app.yaml b/appengine/flexible/hello_world/app.yaml
index 7aa7a47e159..617e5495b28 100644
--- a/appengine/flexible/hello_world/app.yaml
+++ b/appengine/flexible/hello_world/app.yaml
@@ -17,7 +17,10 @@ env: flex
entrypoint: gunicorn -b :$PORT main:app
runtime_config:
- python_version: 3
+ operating_system: ubuntu22
+ # We also support 3.8, 3.9 and 3.11.
+ # See https://cloud.google.com/appengine/docs/flexible/python/runtime#interpreter for more info.
+ runtime_version: "3.10"
# This sample incurs costs to run on the App Engine flexible environment.
# The settings below are to reduce costs during testing and are not appropriate
diff --git a/appengine/flexible/hello_world/main.py b/appengine/flexible/hello_world/main.py
index 8a5a5a9f6fc..d238f1a6f46 100644
--- a/appengine/flexible/hello_world/main.py
+++ b/appengine/flexible/hello_world/main.py
@@ -1,4 +1,4 @@
-# Copyright 2015 Google LLC.
+# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
@app.route('/')
-def hello():
+def hello() -> str:
"""Return a friendly HTTP greeting."""
return 'Hello World!'
diff --git a/appengine/flexible/hello_world/main_test.py b/appengine/flexible/hello_world/main_test.py
index 8bdbf76a920..2a025c095e6 100644
--- a/appengine/flexible/hello_world/main_test.py
+++ b/appengine/flexible/hello_world/main_test.py
@@ -1,4 +1,4 @@
-# Copyright 2015 Google LLC.
+# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
import main
-def test_index():
+def test_index() -> str:
main.app.testing = True
client = main.app.test_client()
diff --git a/appengine/flexible_ubuntu/hello_world/noxfile_config.py b/appengine/flexible/hello_world/noxfile_config.py
similarity index 100%
rename from appengine/flexible_ubuntu/hello_world/noxfile_config.py
rename to appengine/flexible/hello_world/noxfile_config.py
diff --git a/appengine/flexible/hello_world/requirements-test.txt b/appengine/flexible/hello_world/requirements-test.txt
index c2845bffbe8..95ea1e6a02b 100644
--- a/appengine/flexible/hello_world/requirements-test.txt
+++ b/appengine/flexible/hello_world/requirements-test.txt
@@ -1 +1 @@
-pytest==7.0.1
+pytest==6.2.4
diff --git a/appengine/flexible/hello_world/requirements.txt b/appengine/flexible/hello_world/requirements.txt
index beeed7bed09..b690bf61e0a 100644
--- a/appengine/flexible/hello_world/requirements.txt
+++ b/appengine/flexible/hello_world/requirements.txt
@@ -1,3 +1,2 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
+Flask==2.1.1
gunicorn==20.1.0
diff --git a/appengine/flexible/hello_world_django/.gitignore b/appengine/flexible/hello_world_django/.gitignore
deleted file mode 100644
index 49ef2557b16..00000000000
--- a/appengine/flexible/hello_world_django/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-db.sqlite3
diff --git a/appengine/flexible/hello_world_django/README.md b/appengine/flexible/hello_world_django/README.md
deleted file mode 100644
index 592fab654e9..00000000000
--- a/appengine/flexible/hello_world_django/README.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Django sample for Google App Engine Flexible Environment
-
-[![Open in Cloud Shell][shell_img]][shell_link]
-
-[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
-[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/hello_world_django/README.md
-
-This is a basic hello world [Django](https://www.djangoproject.com/) example
-for [Google App Engine Flexible Environment](https://cloud.google.com/appengine).
-
-## Running locally
-
-You can run locally using django's `manage.py`:
-
- $ python manage.py runserver
-
-## Deployment & how the application runs on Google App Engine.
-
-Follow the standard deployment instructions in
-[the top-level README](../README.md). Google App Engine runs the application
-using [gunicorn](http://gunicorn.org/) as defined by `entrypoint` in
-[`app.yaml`](app.yaml). You can use a different WSGI container if you want, as
-long as it listens for web traffic on port `$PORT` and is declared in
-[`requirements.txt`](requirements.txt).
-
-## How this was created
-
-This project was created using standard Django commands:
-
- $ virtualenv env
- $ source env/bin/activate
- $ pip install django gunicorn
- $ pip freeze > requirements.txt
- $ django-admin startproject project_name
- $ python manage.py startapp helloworld
-
-Then, we added a simple view in `hellworld.views`, added the app to
-`project_name.settings.INSTALLED_APPS`, and finally added a URL rule to
-`project_name.urls`.
-
-In order to deploy to Google App Engine, we created a simple
-[`app.yaml`](app.yaml).
-
-## Database notice
-
-This sample project uses Django's default sqlite database. This isn't suitable
-for production as your application can run multiple instances and each will
-have a different sqlite database. Additionally, instance disks are ephemeral,
-so data will not survive restarts.
-
-For production applications running on Google Cloud Platform, you have
-the following options:
-
-* Use [Cloud SQL](https://cloud.google.com/sql), a fully-managed MySQL database.
- There is a [Flask CloudSQL](../cloudsql) sample that should be straightforward
- to adapt to Django.
-* Use any database of your choice hosted on
- [Google Compute Engine](https://cloud.google.com/compute). The
- [Cloud Launcher](https://cloud.google.com/launcher/) can be used to easily
- deploy common databases.
-* Use third-party database services, or services hosted by other providers,
- provided you have configured access.
-
diff --git a/appengine/flexible/hello_world_django/app.yaml b/appengine/flexible/hello_world_django/app.yaml
deleted file mode 100644
index 62b74a9c27e..00000000000
--- a/appengine/flexible/hello_world_django/app.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-runtime: python
-env: flex
-entrypoint: gunicorn -b :$PORT project_name.wsgi
-
-runtime_config:
- python_version: 3
diff --git a/appengine/flexible/hello_world_django/helloworld/__init__.py b/appengine/flexible/hello_world_django/helloworld/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/appengine/flexible/hello_world_django/helloworld/views.py b/appengine/flexible/hello_world_django/helloworld/views.py
deleted file mode 100644
index b1d24cc0af8..00000000000
--- a/appengine/flexible/hello_world_django/helloworld/views.py
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 Google LLC.
-#
-# 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 django.http import HttpResponse
-
-
-def index(request):
- return HttpResponse(
- 'Hello, World. This is Django running on Google App Engine')
diff --git a/appengine/flexible/hello_world_django/manage.py b/appengine/flexible/hello_world_django/manage.py
deleted file mode 100755
index c213c77eca6..00000000000
--- a/appengine/flexible/hello_world_django/manage.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2021 Google LLC
-#
-# 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 os
-import sys
-
-if __name__ == "__main__":
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project_name.settings")
-
- from django.core.management import execute_from_command_line
-
- execute_from_command_line(sys.argv)
diff --git a/appengine/flexible/hello_world_django/project_name/__init__.py b/appengine/flexible/hello_world_django/project_name/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/appengine/flexible/hello_world_django/project_name/settings.py b/appengine/flexible/hello_world_django/project_name/settings.py
deleted file mode 100644
index f77ab7fd9e6..00000000000
--- a/appengine/flexible/hello_world_django/project_name/settings.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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.
-
-"""
-Django settings for project_name project.
-
-Generated by 'django-admin startproject' using Django 1.8.4.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.8/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/1.8/ref/settings/
-"""
-
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-import os
-
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
-
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = 'qgw!j*bpxo7g&o1ux-(2ph818ojfj(3c#-#*_8r^8&hq5jg$3@'
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
-
-ALLOWED_HOSTS = []
-
-
-# Application definition
-
-INSTALLED_APPS = (
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'helloworld'
-)
-
-MIDDLEWARE = (
- 'django.middleware.security.SecurityMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
-)
-
-ROOT_URLCONF = 'project_name.urls'
-
-TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [],
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- ],
- },
- },
-]
-
-WSGI_APPLICATION = 'project_name.wsgi.application'
-
-
-# Database
-# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
- }
-}
-
-
-# Internationalization
-# https://docs.djangoproject.com/en/1.8/topics/i18n/
-
-LANGUAGE_CODE = 'en-us'
-
-TIME_ZONE = 'UTC'
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/1.8/howto/static-files/
-
-STATIC_URL = '/static/'
diff --git a/appengine/flexible/hello_world_django/project_name/urls.py b/appengine/flexible/hello_world_django/project_name/urls.py
deleted file mode 100644
index 334801260a0..00000000000
--- a/appengine/flexible/hello_world_django/project_name/urls.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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.
-
-"""project_name URL Configuration
-
-The `urlpatterns` list routes URLs to views. For more information please see:
- https://docs.djangoproject.com/en/1.8/topics/http/urls/
-Examples:
-Function views
- 1. Add an import: from my_app import views
- 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
-Class-based views
- 1. Add an import: from other_app.views import Home
- 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
-Including another URLconf
- 1. Add an import: from blog import urls as blog_urls
- 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
-"""
-from django.conf.urls import include, url
-from django.contrib import admin
-
-import helloworld.views
-
-
-urlpatterns = [
- url(r'^admin/', include(admin.site.urls)),
- url(r'^$', helloworld.views.index),
-]
diff --git a/appengine/flexible/hello_world_django/project_name/wsgi.py b/appengine/flexible/hello_world_django/project_name/wsgi.py
deleted file mode 100644
index a302b372ec2..00000000000
--- a/appengine/flexible/hello_world_django/project_name/wsgi.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-"""
-WSGI config for project_name project.
-
-It exposes the WSGI callable as a module-level variable named ``application``.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
-"""
-
-import os
-
-from django.core.wsgi import get_wsgi_application
-
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project_name.settings")
-
-application = get_wsgi_application()
diff --git a/appengine/flexible/hello_world_django/requirements-test.txt b/appengine/flexible/hello_world_django/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/hello_world_django/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/hello_world_django/requirements.txt b/appengine/flexible/hello_world_django/requirements.txt
deleted file mode 100644
index 5a3b16e75ed..00000000000
--- a/appengine/flexible/hello_world_django/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Django==4.0.4; python_version >= '3.8'
-Django==3.2.14; python_version < '3.8'
-gunicorn==20.1.0; python_version > '3.0'
-gunicorn==19.10.0; python_version < '3.0'
diff --git a/appengine/flexible/metadata/app.yaml b/appengine/flexible/metadata/app.yaml
deleted file mode 100644
index ca76f83fc3b..00000000000
--- a/appengine/flexible/metadata/app.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-runtime: python
-env: flex
-entrypoint: gunicorn -b :$PORT main:app
-
-runtime_config:
- python_version: 3
diff --git a/appengine/flexible/metadata/main.py b/appengine/flexible/metadata/main.py
deleted file mode 100644
index 3ad872b448d..00000000000
--- a/appengine/flexible/metadata/main.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 logging
-
-from flask import Flask
-import requests
-
-
-logging.basicConfig(level=logging.INFO)
-app = Flask(__name__)
-
-
-# [START gae_flex_metadata]
-METADATA_NETWORK_INTERFACE_URL = \
- ('http://metadata/computeMetadata/v1/instance/network-interfaces/0/'
- 'access-configs/0/external-ip')
-
-
-def get_external_ip():
- """Gets the instance's external IP address from the Compute Engine metadata
- server. If the metadata server is unavailable, it assumes that the
- application is running locally.
- """
- try:
- r = requests.get(
- METADATA_NETWORK_INTERFACE_URL,
- headers={'Metadata-Flavor': 'Google'},
- timeout=2)
- return r.text
- except requests.RequestException:
- logging.info('Metadata server could not be reached, assuming local.')
- return 'localhost'
-# [END gae_flex_metadata]
-
-
-@app.route('/')
-def index():
- # Websocket connections must be made directly to this instance, so the
- # external IP address of this instance is needed.
- external_ip = get_external_ip()
- return 'External IP: {}'.format(external_ip)
-
-
-@app.errorhandler(500)
-def server_error(e):
- logging.exception('An error occurred during a request.')
- return """
- An internal error occurred: {}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/metadata/requirements-test.txt b/appengine/flexible/metadata/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/metadata/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/metadata/requirements.txt b/appengine/flexible/metadata/requirements.txt
deleted file mode 100644
index 9fee7fc1fa3..00000000000
--- a/appengine/flexible/metadata/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-gunicorn==20.1.0
-requests[security]==2.27.1
diff --git a/appengine/flexible/multiple_services/README.md b/appengine/flexible/multiple_services/README.md
deleted file mode 100644
index 16e794c010a..00000000000
--- a/appengine/flexible/multiple_services/README.md
+++ /dev/null
@@ -1,67 +0,0 @@
-# Python Google Cloud Microservices Example - API Gateway
-
-[![Open in Cloud Shell][shell_img]][shell_link]
-
-[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
-[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/multiple_services/README.md
-
-This example demonstrates how to deploy multiple python services to [App Engine flexible environment](https://cloud.google.com/appengine/docs/flexible/)
-
-## To Run Locally
-
-Use [virtualenv](https://virtualenv.pypa.io/en/stable/) to set up each
-service's environment and start the each service in a separate terminal.
-
-Open a terminal and start the first service:
-
-```Bash
-$ cd gateway-service
-$ virtualenv -p python3 env
-$ source env/bin/activate
-$ pip install -r requirements.txt
-$ python main.py
-```
-
-In a separate terminal, start the second service:
-
-```Bash
-$ cd static-service
-$ virtualenv -p python3 env
-$ source env/bin/activate
-$ pip install -r requirements.txt
-$ python main.py
-```
-
-## To Deploy to App Engine
-
-### YAML Files
-
-Each directory contains an `app.yaml` file. These files all describe a
-separate App Engine service within the same project.
-
-For the gateway:
-
-[Gateway service Say hi to:
- - -{}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/numpy/main_test.py b/appengine/flexible/numpy/main_test.py
deleted file mode 100644
index 42c0d594d94..00000000000
--- a/appengine/flexible/numpy/main_test.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2016 Google LLC.
-#
-# 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 main
-
-
-def test_index():
- main.app.testing = True
- client = main.app.test_client()
-
- r = client.get('/')
- assert r.status_code == 200
- assert '[[19 22]\n [43 50]]' in r.data.decode('utf-8')
diff --git a/appengine/flexible/numpy/requirements-test.txt b/appengine/flexible/numpy/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/numpy/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/numpy/requirements.txt b/appengine/flexible/numpy/requirements.txt
deleted file mode 100644
index 277907a21d9..00000000000
--- a/appengine/flexible/numpy/requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-gunicorn==20.1.0
-numpy==1.22.0; python_version > '3.7'
-numpy==1.19.5; python_version <= '3.7'
-
diff --git a/appengine/flexible/pubsub/README.md b/appengine/flexible/pubsub/README.md
deleted file mode 100644
index c4c65500681..00000000000
--- a/appengine/flexible/pubsub/README.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Python Google Cloud Pub/Sub sample for Google App Engine Flexible Environment
-
-[![Open in Cloud Shell][shell_img]][shell_link]
-
-[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
-[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/pubsub/README.md
-
-This demonstrates how to send and receive messages using [Google Cloud Pub/Sub](https://cloud.google.com/pubsub) on [Google App Engine Flexible Environment](https://cloud.google.com/appengine).
-
-## Setup
-
-Before you can run or deploy the sample, you will need to do the following:
-
-1. Enable the Cloud Pub/Sub API in the [Google Developers Console](https://console.developers.google.com/project/_/apiui/apiview/pubsub/overview).
-
-2. Create a topic and subscription.
-
- $ gcloud beta pubsub topics create [your-topic-name]
- $ gcloud beta pubsub subscriptions create [your-subscription-name] \
- --topic [your-topic-name] \
- --push-endpoint \
- https://[your-app-id].appspot.com/pubsub/push?token=[your-token] \
- --ack-deadline 30
-
-3. Update the environment variables in ``app.yaml``.
-
-## Running locally
-
-Refer to the [top-level README](../README.md) for instructions on running and deploying.
-
-When running locally, you can use the [Google Cloud SDK](https://cloud.google.com/sdk) to provide authentication to use Google Cloud APIs:
-
- $ gcloud init
-
-Install dependencies, preferably with a virtualenv:
-
- $ virtualenv env
- $ source env/bin/activate
- $ pip install -r requirements.txt
-
-Then set environment variables before starting your application:
-
- $ export PUBSUB_VERIFICATION_TOKEN=[your-verification-token]
- $ export PUBSUB_TOPIC=[your-topic]
- $ python main.py
-
-### Simulating push notifications
-
-The application can send messages locally, but it is not able to receive push messages locally. You can, however, simulate a push message by making an HTTP request to the local push notification endpoint. There is an included ``sample_message.json``. You can use
-``curl`` or [httpie](https://github.com/jkbrzt/httpie) to POST this:
-
- $ curl -i --data @sample_message.json ":8080/pubsub/push?token=[your-token]"
-
-Or
-
- $ http POST ":8080/pubsub/push?token=[your-token]" < sample_message.json
-
-Response:
-
- HTTP/1.0 200 OK
- Content-Length: 2
- Content-Type: text/html; charset=utf-8
- Date: Mon, 10 Aug 2015 17:52:03 GMT
- Server: Werkzeug/0.10.4 Python/2.7.10
-
- OK
-
-After the request completes, you can refresh ``localhost:8080`` and see the message in the list of received messages.
-
-## Running on App Engine
-
-Deploy using `gcloud`:
-
- gcloud app deploy app.yaml
-
-You can now access the application at `https://your-app-id.appspot.com`. You can use the form to submit messages, but it's non-deterministic which instance of your application will receive the notification. You can send multiple messages and refresh the page to see the received message.
diff --git a/appengine/flexible/pubsub/app.yaml b/appengine/flexible/pubsub/app.yaml
deleted file mode 100644
index 5804ac2b266..00000000000
--- a/appengine/flexible/pubsub/app.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-runtime: python
-env: flex
-entrypoint: gunicorn -b :$PORT main:app
-
-runtime_config:
- python_version: 3
-
-# [START gae_flex_pubsub_env]
-env_variables:
- PUBSUB_TOPIC: your-topic
- # This token is used to verify that requests originate from your
- # application. It can be any sufficiently random string.
- PUBSUB_VERIFICATION_TOKEN: 1234abc
-# [END gae_flex_pubsub_env]
diff --git a/appengine/flexible/pubsub/main.py b/appengine/flexible/pubsub/main.py
deleted file mode 100644
index f146a0788b8..00000000000
--- a/appengine/flexible/pubsub/main.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 base64
-import json
-import logging
-import os
-
-from flask import current_app, Flask, render_template, request
-from google.cloud import pubsub_v1
-
-
-app = Flask(__name__)
-
-# Configure the following environment variables via app.yaml
-# This is used in the push request handler to verify that the request came from
-# pubsub and originated from a trusted source.
-app.config['PUBSUB_VERIFICATION_TOKEN'] = \
- os.environ['PUBSUB_VERIFICATION_TOKEN']
-app.config['PUBSUB_TOPIC'] = os.environ['PUBSUB_TOPIC']
-app.config['PROJECT'] = os.environ['GOOGLE_CLOUD_PROJECT']
-
-
-# Global list to storage messages received by this instance.
-MESSAGES = []
-
-# Initialize the publisher client once to avoid memory leak
-# and reduce publish latency.
-publisher = pubsub_v1.PublisherClient()
-
-
-# [START gae_flex_pubsub_index]
-@app.route('/', methods=['GET', 'POST'])
-def index():
- if request.method == 'GET':
- return render_template('index.html', messages=MESSAGES)
-
- data = request.form.get('payload', 'Example payload').encode('utf-8')
-
- # publisher = pubsub_v1.PublisherClient()
- topic_path = publisher.topic_path(
- current_app.config['PROJECT'],
- current_app.config['PUBSUB_TOPIC'])
-
- publisher.publish(topic_path, data=data)
-
- return 'OK', 200
-# [END gae_flex_pubsub_index]
-
-
-# [START gae_flex_pubsub_push]
-@app.route('/pubsub/push', methods=['POST'])
-def pubsub_push():
- if (request.args.get('token', '') !=
- current_app.config['PUBSUB_VERIFICATION_TOKEN']):
- return 'Invalid request', 400
-
- envelope = json.loads(request.data.decode('utf-8'))
- payload = base64.b64decode(envelope['message']['data'])
-
- MESSAGES.append(payload)
-
- # Returning any 2xx status indicates successful receipt of the message.
- return 'OK', 200
-# [END gae_flex_pubsub_push]
-
-
-@app.errorhandler(500)
-def server_error(e):
- logging.exception('An error occurred during a request.')
- return """
- An internal error occurred: {}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/pubsub/main_test.py b/appengine/flexible/pubsub/main_test.py
deleted file mode 100644
index 67fdb47d784..00000000000
--- a/appengine/flexible/pubsub/main_test.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 base64
-import json
-import os
-
-import pytest
-
-import main
-
-
-@pytest.fixture
-def client():
- main.app.testing = True
- return main.app.test_client()
-
-
-def test_index(client):
- r = client.get('/')
- assert r.status_code == 200
-
-
-def test_post_index(client):
- r = client.post('/', data={'payload': 'Test payload'})
- assert r.status_code == 200
-
-
-def test_push_endpoint(client):
- url = '/pubsub/push?token=' + os.environ['PUBSUB_VERIFICATION_TOKEN']
-
- r = client.post(
- url,
- data=json.dumps({
- "message": {
- "data": base64.b64encode(
- u'Test message'.encode('utf-8')
- ).decode('utf-8')
- }
- })
- )
-
- assert r.status_code == 200
-
- # Make sure the message is visible on the home page.
- r = client.get('/')
- assert r.status_code == 200
- assert 'Test message' in r.data.decode('utf-8')
-
-
-def test_push_endpoint_errors(client):
- # no token
- r = client.post('/pubsub/push')
- assert r.status_code == 400
-
- # invalid token
- r = client.post('/pubsub/push?token=bad')
- assert r.status_code == 400
diff --git a/appengine/flexible/pubsub/requirements-test.txt b/appengine/flexible/pubsub/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/pubsub/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/pubsub/requirements.txt b/appengine/flexible/pubsub/requirements.txt
deleted file mode 100644
index 30e9d9736b5..00000000000
--- a/appengine/flexible/pubsub/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-google-cloud-pubsub==2.9.0
-gunicorn==20.1.0
diff --git a/appengine/flexible/pubsub/sample_message.json b/appengine/flexible/pubsub/sample_message.json
deleted file mode 100644
index 8fe62d23fb9..00000000000
--- a/appengine/flexible/pubsub/sample_message.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "message": {
- "data": "SGVsbG8sIFdvcmxkIQ=="
- }
-}
diff --git a/appengine/flexible/pubsub/templates/index.html b/appengine/flexible/pubsub/templates/index.html
deleted file mode 100644
index 28449216c37..00000000000
--- a/appengine/flexible/pubsub/templates/index.html
+++ /dev/null
@@ -1,36 +0,0 @@
-{#
-# Copyright 2015 Google LLC.
-#
-# 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.
-#}
-
-
-
- Messages received by this instance:
-Note: because your application is likely running multiple instances, each instance will have a different list of messages.
-trdZ}!mP^)0wo494PE9UFZcUz6
z-dVm`0YX7mAy#2QkwVd4@rx3mB%>6ow5Uv_?4;bH0;8g=lB%+)%A)G6+M|Y{W~f%8
zcBw9^9;H67L9OAY(V>Z|si#@2d8H+;6{EGH&7|$4J@6XuwbkoJ9atSrodTT;T?yTI
z-3>hsz4v-Q^{MpV>h~Go8Q2=M8loB+8P>jmexvoK This is a static file serving example. Messages: Status: Messages received by this instance: Note: because your application is likely running multiple instances, each instance will have a different list of messages. This is a static file serving example. Printed task payload: {{ payload }} Say hi to: trdZ}!mP^)0wo494PE9UFZcUz6
z-dVm`0YX7mAy#2QkwVd4@rx3mB%>6ow5Uv_?4;bH0;8g=lB%+)%A)G6+M|Y{W~f%8
zcBw9^9;H67L9OAY(V>Z|si#@2d8H+;6{EGH&7|$4J@6XuwbkoJ9atSrodTT;T?yTI
z-3>hsz4v-Q^{MpV>h~Go8Q2=M8loB+8P>jmexvoK Chat demo Messages: Status:M7Mux2XCB=+j{tg=2oCND-J
zR~I{Mf_`L`kYX^`qX&h^k6d!5_z3>YS@X`4KF-b*oYpDe|EQUMn{Jr}*^+>fYxA|3
zeAG^^9^AV8nMPY4!R&f7C#x|$M#e*RXPyrX>ZiPtX1|)fAm{UnO;{T13M1fOoE)!mVVeN>^r7j|MQ;y5dRIm>m|_7h6h7oml%o)PzWkP13=N
zH=7z62uf^pt5)9Zx5%#Aw0!$&C^LQt^|UGbQHx!ufAhnQ-slrR$LXtSd!NIee@Eu3
z=(MMBU*7Jo$CK*wf$cg4sDcH;B~U$VU}$z6S8z@DcK%QtZFV!E%8i=cl;$Q1B#Y=B
z&;5yVaBf0
zumg5+YCcsy1V)Z1vk$<2fkSP)%A&$`|K}Ij1ibh=O|WizJ&9WSMy*GR)u=%@p1SoY
zOPK`dMkPd-_+LOvG=J!VPQz#k^||`%fw{aDty8*Il{T(#!(QaP@uQSQPfPq41f8+T
zELib7eZC@1nR*hi(wnoCP7kM|*b{L)
z<3zCkvXIm{}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/scipy/main_test.py b/appengine/flexible/scipy/main_test.py
deleted file mode 100644
index 8dfc321ea3d..00000000000
--- a/appengine/flexible/scipy/main_test.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2016 Google LLC.
-#
-# 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 os
-import tempfile
-
-import main
-
-
-def test_index():
- main.app.testing = True
- client = main.app.test_client()
- with tempfile.TemporaryDirectory() as test_dir:
- output_image_path = os.path.join(test_dir, 'resized_google_logo.jpg')
- r = client.get(
- '/', query_string={'output_image_path': output_image_path})
-
- assert os.path.isfile(output_image_path)
- assert r.status_code == 200
diff --git a/appengine/flexible/scipy/noxfile_config.py b/appengine/flexible/scipy/noxfile_config.py
deleted file mode 100644
index 3228fb0bf80..00000000000
--- a/appengine/flexible/scipy/noxfile_config.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2022 Google LLC
-#
-# 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.
-
-# Default TEST_CONFIG_OVERRIDE for python repos.
-
-# You can copy this file into your directory, then it will be imported from
-# the noxfile.py.
-
-# The source of truth:
-# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py
-
-TEST_CONFIG_OVERRIDE = {
- # You can opt out from the test for specific Python versions.
- "ignored_versions": ["2.7", "3.6", "3.11"],
- # Old samples are opted out of enforcing Python type hints
- # All new samples should feature them
- "enforce_type_hints": False,
- # An envvar key for determining the project id to use. Change it
- # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
- # build specific Cloud project. You can also use your own string
- # to use your own Cloud project.
- "gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
- # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
- # A dictionary you want to inject into your test. Don't put any
- # secrets here. These values will override predefined values.
- "envs": {},
-}
diff --git a/appengine/flexible/scipy/requirements-test.txt b/appengine/flexible/scipy/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/scipy/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/scipy/requirements.txt b/appengine/flexible/scipy/requirements.txt
deleted file mode 100644
index aa57c4cd1d0..00000000000
--- a/appengine/flexible/scipy/requirements.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-gunicorn==20.1.0
-imageio==2.14.0
-numpy==1.22.0; python_version > "3.7"
-numpy==1.21.4; python_version <= "3.7"
-pillow==9.2.0
-scipy==1.10.0; python_version > "3.7"
-scipy==1.7.3; python_version <= "3.7"
diff --git a/appengine/flexible/static_files/README.md b/appengine/flexible/static_files/README.md
deleted file mode 100644
index 249a478127e..00000000000
--- a/appengine/flexible/static_files/README.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Python / Flask static files sample for Google App Engine Flexible Environment
-
-[![Open in Cloud Shell][shell_img]][shell_link]
-
-[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
-[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/static_files/README.md
-
-This demonstrates how to use [Flask](http://flask.pocoo.org/) to serve static files in your application.
-
-Flask automatically makes anything in the ``static`` directory available via the ``/static`` URL. If you plan on using a different framework, it may have different conventions for serving static files.
-
-Refer to the [top-level README](../README.md) for instructions on running and deploying.
diff --git a/appengine/flexible/static_files/app.yaml b/appengine/flexible/static_files/app.yaml
deleted file mode 100644
index ca76f83fc3b..00000000000
--- a/appengine/flexible/static_files/app.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2021 Google LLC
-#
-# 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.
-
-runtime: python
-env: flex
-entrypoint: gunicorn -b :$PORT main:app
-
-runtime_config:
- python_version: 3
diff --git a/appengine/flexible/static_files/main.py b/appengine/flexible/static_files/main.py
deleted file mode 100644
index c25c43de6cf..00000000000
--- a/appengine/flexible/static_files/main.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 gae_flex_python_static_files]
-import logging
-
-from flask import Flask, render_template
-
-
-app = Flask(__name__)
-
-
-@app.route('/')
-def hello():
- return render_template('index.html')
-
-
-@app.errorhandler(500)
-def server_error(e):
- logging.exception('An error occurred during a request.')
- return """
- An internal error occurred: {}
- See logs for full stacktrace.
- """.format(e), 500
-
-
-if __name__ == '__main__':
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host='127.0.0.1', port=8080, debug=True)
-# [END gae_flex_python_static_files]
diff --git a/appengine/flexible/static_files/main_test.py b/appengine/flexible/static_files/main_test.py
deleted file mode 100644
index 6fb47d6ff51..00000000000
--- a/appengine/flexible/static_files/main_test.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright 2015 Google LLC.
-#
-# 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 main
-
-
-def test_index():
- main.app.testing = True
- client = main.app.test_client()
-
- r = client.get('/')
- assert r.status_code == 200
-
- r = client.get('/static/main.css')
- assert r.status_code == 200
diff --git a/appengine/flexible/static_files/requirements-test.txt b/appengine/flexible/static_files/requirements-test.txt
deleted file mode 100644
index c2845bffbe8..00000000000
--- a/appengine/flexible/static_files/requirements-test.txt
+++ /dev/null
@@ -1 +0,0 @@
-pytest==7.0.1
diff --git a/appengine/flexible/static_files/requirements.txt b/appengine/flexible/static_files/requirements.txt
deleted file mode 100644
index beeed7bed09..00000000000
--- a/appengine/flexible/static_files/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Flask==2.1.0; python_version > '3.6'
-Flask==2.0.3; python_version < '3.7'
-gunicorn==20.1.0
diff --git a/appengine/flexible/static_files/static/main.css b/appengine/flexible/static_files/static/main.css
deleted file mode 100644
index f906044f4e4..00000000000
--- a/appengine/flexible/static_files/static/main.css
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-Copyright 2015 Google LLC.
-
-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 gae_flex_python_css] */
-body {
- font-family: Verdana, Helvetica, sans-serif;
- background-color: #CCCCFF;
-}
-/* [END gae_flex_python_css] */
diff --git a/appengine/flexible/static_files/templates/index.html b/appengine/flexible/static_files/templates/index.html
deleted file mode 100644
index 13b2ebe61af..00000000000
--- a/appengine/flexible/static_files/templates/index.html
+++ /dev/null
@@ -1,29 +0,0 @@
-{#
-# Copyright 2015 Google LLC.
-#
-# 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.
-#}
-
-
-
-
-
-
{}
- See logs for full stacktrace.
- """.format(
- e
- ),
- 500,
- )
-
-
-if __name__ == "__main__":
- # This is used when running locally. Gunicorn is used to run the
- # application on Google App Engine. See entrypoint in app.yaml.
- app.run(host="127.0.0.1", port=8080, debug=True)
-# [END gae_flex_ubuntu_storage_app]
diff --git a/appengine/flexible_ubuntu/storage/main_test.py b/appengine/flexible_ubuntu/storage/main_test.py
deleted file mode 100644
index 36d02f83354..00000000000
--- a/appengine/flexible_ubuntu/storage/main_test.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright 2023 Google LLC
-#
-# 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 io
-import os
-import uuid
-
-import flask
-import flask.testing
-from google.cloud import storage
-import pytest
-
-import requests
-
-import main
-
-
-@pytest.fixture
-def client() -> flask.testing.FlaskClient:
- main.app.testing = True
- return main.app.test_client()
-
-
-def test_index(client: flask.testing.FlaskClient) -> None:
- r = client.get("/")
- assert r.status_code == 200
-
-
-@pytest.fixture(scope="module")
-def blob_name() -> str:
- name = f"gae-flex-storage-{uuid.uuid4()}"
- yield name
-
- bucket = storage.Client().bucket(os.environ["CLOUD_STORAGE_BUCKET"])
- blob = bucket.blob(name)
- blob.delete()
-
-
-def test_upload(client: flask.testing.FlaskClient, blob_name: str) -> None:
- # Upload a simple file
- file_content = b"This is some test content."
-
- r = client.post("/upload", data={"file": (io.BytesIO(file_content), blob_name)})
-
- assert r.status_code == 200
-
- # The app should return the public cloud storage URL for the uploaded
- # file. Download and verify it.
- cloud_storage_url = r.data.decode("utf-8")
- r = requests.get(cloud_storage_url)
- assert r.text.encode("utf-8") == file_content
diff --git a/appengine/flexible_ubuntu/storage/noxfile_config.py b/appengine/flexible_ubuntu/storage/noxfile_config.py
deleted file mode 100644
index 44097a85005..00000000000
--- a/appengine/flexible_ubuntu/storage/noxfile_config.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright 2023 Google LLC
-#
-# 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.
-
-# Default TEST_CONFIG_OVERRIDE for python repos.
-
-# You can copy this file into your directory, then it will be imported from
-# the noxfile.py.
-
-# The source of truth:
-# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py
-
-TEST_CONFIG_OVERRIDE = {
- # You can opt out from the test for specific Python versions.
- "ignored_versions": ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10"],
- # Old samples are opted out of enforcing Python type hints
- # All new samples should feature them
- "enforce_type_hints": True,
- # An envvar key for determining the project id to use. Change it
- # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
- # build specific Cloud project. You can also use your own string
- # to use your own Cloud project.
- "gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
- # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
- # If you need to use a specific version of pip,
- # change pip_version_override to the string representation
- # of the version number, for example, "20.2.4"
- "pip_version_override": None,
- # A dictionary you want to inject into your test. Don't put any
- # secrets here. These values will override predefined values.
- "envs": {
- "CLOUD_STORAGE_BUCKET": "python-docs-samples-tests-public"
- },
-}
diff --git a/appengine/flexible_ubuntu/storage/requirements-test.txt b/appengine/flexible_ubuntu/storage/requirements-test.txt
deleted file mode 100644
index e6323c66f62..00000000000
--- a/appengine/flexible_ubuntu/storage/requirements-test.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-pytest==7.0.1
-google-cloud-storage==2.1.0;
diff --git a/appengine/flexible_ubuntu/storage/requirements.txt b/appengine/flexible_ubuntu/storage/requirements.txt
deleted file mode 100644
index e254bb503e7..00000000000
--- a/appengine/flexible_ubuntu/storage/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Flask==2.1.0;
-werkzeug==2.1.2;
-google-cloud-storage==2.1.0;
-gunicorn==20.1.0;
From 6d7392091bea9c2e566e49f4149eb3934ea75128 Mon Sep 17 00:00:00 2001
From: Jinglun Dong <1683035+jinglundong@users.noreply.github.com>
Date: Fri, 10 Mar 2023 02:34:29 +0000
Subject: [PATCH 2/9] Remove the runtime_version because we want to promote the
:latest behavior.
---
appengine/flexible/hello_world/app.yaml | 5 +----
appengine/flexible/storage/app.yaml | 3 ---
2 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/appengine/flexible/hello_world/app.yaml b/appengine/flexible/hello_world/app.yaml
index 617e5495b28..ac38af83425 100644
--- a/appengine/flexible/hello_world/app.yaml
+++ b/appengine/flexible/hello_world/app.yaml
@@ -18,11 +18,8 @@ entrypoint: gunicorn -b :$PORT main:app
runtime_config:
operating_system: ubuntu22
- # We also support 3.8, 3.9 and 3.11.
- # See https://cloud.google.com/appengine/docs/flexible/python/runtime#interpreter for more info.
- runtime_version: "3.10"
-# This sample incurs costs to run on the App Engine flexible environment.
+# This sample incurs costs to run on the App Engine flexible environment.
# The settings below are to reduce costs during testing and are not appropriate
# for production use. For more information, see:
# https://cloud.google.com/appengine/docs/flexible/python/configuring-your-app-with-app-yaml
diff --git a/appengine/flexible/storage/app.yaml b/appengine/flexible/storage/app.yaml
index 59577b9ee8c..3a7db763d36 100644
--- a/appengine/flexible/storage/app.yaml
+++ b/appengine/flexible/storage/app.yaml
@@ -17,9 +17,6 @@ env: flex
entrypoint: gunicorn -b :$PORT main:app
runtime_config:
- # We also support 3.8, 3.9 and 3.10.
- # See https://cloud.google.com/appengine/docs/flexible/python/runtime#interpreter for more info.
- runtime_version: "3.11"
operating_system: "ubuntu22"
#[START gae_flex_storage_yaml]
From 4cdf7dd48bebfbac5b03f940fc6eeb765802c0bd Mon Sep 17 00:00:00 2001
From: Jinglun Dong <1683035+jinglundong@users.noreply.github.com>
Date: Fri, 10 Mar 2023 02:38:01 +0000
Subject: [PATCH 3/9] Update the tag to gae_flex_storage_app.
---
appengine/flexible/README.md | 2 +-
appengine/flexible/storage/main.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/appengine/flexible/README.md b/appengine/flexible/README.md
index a21487336b4..db498e5f0bb 100644
--- a/appengine/flexible/README.md
+++ b/appengine/flexible/README.md
@@ -8,7 +8,7 @@
These are samples for using Python on Google App Engine Flexible Environment. These samples are typically referenced from the [docs](https://cloud.google.com/appengine/docs).
For code samples of Python version 3.7 and earlier, please check
-https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine/flexible_python37_and_earlier.
+https://github.com/GoogleCloudPlatform/python-docs-samples/tree/main/appengine/flexible.
See our other [Google Cloud Platform github repos](https://github.com/GoogleCloudPlatform) for sample applications and
scaffolding for other frameworks and use cases.
diff --git a/appengine/flexible/storage/main.py b/appengine/flexible/storage/main.py
index 0664d2aa9ab..8c510651dd2 100644
--- a/appengine/flexible/storage/main.py
+++ b/appengine/flexible/storage/main.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# [START gae_flex_ubuntu_storage_app]
+# [START gae_flex_storage_app]
import logging
import os
from typing import Union
@@ -84,4 +84,4 @@ def server_error(e: Union[Exception, int]) -> str:
# This is used when running locally. Gunicorn is used to run the
# application on Google App Engine. See entrypoint in app.yaml.
app.run(host="127.0.0.1", port=8080, debug=True)
-# [END gae_flex_ubuntu_storage_app]
+# [END gae_flex_storage_app]
From e1bb524b81b25fc94748986e4b267cb775b90904 Mon Sep 17 00:00:00 2001
From: Jinglun Dong <1683035+jinglundong@users.noreply.github.com>
Date: Wed, 15 Mar 2023 22:42:02 +0000
Subject: [PATCH 4/9] Add python 3.11 sample apps for Flex tasks, static files
and pubsub. Also updated copyrights blocks.
---
appengine/flexible/hello_world/app.yaml | 2 +-
.../flexible/hello_world/noxfile_config.py | 2 +-
appengine/flexible/pubsub/README.md | 75 +++++
appengine/flexible/pubsub/app.yaml | 28 ++
appengine/flexible/pubsub/main.py | 91 ++++++
appengine/flexible/pubsub/main_test.py | 69 ++++
.../flexible/pubsub/requirements-test.txt | 1 +
appengine/flexible/pubsub/requirements.txt | 4 +
appengine/flexible/pubsub/sample_message.json | 5 +
.../flexible/pubsub/templates/index.html | 36 +++
appengine/flexible/static_files/README.md | 12 +
appengine/flexible/static_files/app.yaml | 20 ++
appengine/flexible/static_files/main.py | 42 +++
appengine/flexible/static_files/main_test.py | 26 ++
.../static_files/requirements-test.txt | 1 +
.../flexible/static_files/requirements.txt | 3 +
.../flexible/static_files/static/main.css | 21 ++
.../static_files/templates/index.html | 29 ++
appengine/flexible/tasks/Dockerfile | 31 ++
appengine/flexible/tasks/README.md | 115 +++++++
appengine/flexible/tasks/app.flexible.yaml | 20 ++
appengine/flexible/tasks/app.yaml | 20 ++
.../tasks/create_app_engine_queue_task.py | 117 +++++++
.../create_app_engine_queue_task_test.py | 27 ++
appengine/flexible/tasks/main.py | 41 +++
appengine/flexible/tasks/main_test.py | 45 +++
.../flexible/tasks/requirements-test.txt | 1 +
appengine/flexible/tasks/requirements.txt | 4 +
appengine/flexible/tasks/snippets.py | 303 ++++++++++++++++++
appengine/flexible/tasks/snippets_test.py | 127 ++++++++
appengine/flexible/tasks/templates/index.html | 21 ++
.../hello_world/app.yaml | 2 +-
32 files changed, 1338 insertions(+), 3 deletions(-)
create mode 100644 appengine/flexible/pubsub/README.md
create mode 100644 appengine/flexible/pubsub/app.yaml
create mode 100644 appengine/flexible/pubsub/main.py
create mode 100644 appengine/flexible/pubsub/main_test.py
create mode 100644 appengine/flexible/pubsub/requirements-test.txt
create mode 100644 appengine/flexible/pubsub/requirements.txt
create mode 100644 appengine/flexible/pubsub/sample_message.json
create mode 100644 appengine/flexible/pubsub/templates/index.html
create mode 100644 appengine/flexible/static_files/README.md
create mode 100644 appengine/flexible/static_files/app.yaml
create mode 100644 appengine/flexible/static_files/main.py
create mode 100644 appengine/flexible/static_files/main_test.py
create mode 100644 appengine/flexible/static_files/requirements-test.txt
create mode 100644 appengine/flexible/static_files/requirements.txt
create mode 100644 appengine/flexible/static_files/static/main.css
create mode 100644 appengine/flexible/static_files/templates/index.html
create mode 100644 appengine/flexible/tasks/Dockerfile
create mode 100644 appengine/flexible/tasks/README.md
create mode 100644 appengine/flexible/tasks/app.flexible.yaml
create mode 100644 appengine/flexible/tasks/app.yaml
create mode 100644 appengine/flexible/tasks/create_app_engine_queue_task.py
create mode 100644 appengine/flexible/tasks/create_app_engine_queue_task_test.py
create mode 100644 appengine/flexible/tasks/main.py
create mode 100644 appengine/flexible/tasks/main_test.py
create mode 100644 appengine/flexible/tasks/requirements-test.txt
create mode 100644 appengine/flexible/tasks/requirements.txt
create mode 100644 appengine/flexible/tasks/snippets.py
create mode 100644 appengine/flexible/tasks/snippets_test.py
create mode 100644 appengine/flexible/tasks/templates/index.html
diff --git a/appengine/flexible/hello_world/app.yaml b/appengine/flexible/hello_world/app.yaml
index ac38af83425..fb982fc8dd2 100644
--- a/appengine/flexible/hello_world/app.yaml
+++ b/appengine/flexible/hello_world/app.yaml
@@ -1,4 +1,4 @@
-# Copyright 2021 Google LLC
+# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/appengine/flexible/hello_world/noxfile_config.py b/appengine/flexible/hello_world/noxfile_config.py
index 545546d21cb..e5e2be514e2 100644
--- a/appengine/flexible/hello_world/noxfile_config.py
+++ b/appengine/flexible/hello_world/noxfile_config.py
@@ -1,4 +1,4 @@
-# Copyright 2021 Google LLC
+# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/appengine/flexible/pubsub/README.md b/appengine/flexible/pubsub/README.md
new file mode 100644
index 00000000000..2e9b0d71918
--- /dev/null
+++ b/appengine/flexible/pubsub/README.md
@@ -0,0 +1,75 @@
+# Python Google Cloud Pub/Sub sample for Google App Engine Flexible Environment
+
+[![Open in Cloud Shell][shell_img]][shell_link]
+
+[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
+[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible_python37_and_earlier/pubsub/README.md
+
+This demonstrates how to send and receive messages using [Google Cloud Pub/Sub](https://cloud.google.com/pubsub) on [Google App Engine Flexible Environment](https://cloud.google.com/appengine).
+
+## Setup
+
+Before you can run or deploy the sample, you will need to do the following:
+
+1. Enable the Cloud Pub/Sub API in the [Google Developers Console](https://console.developers.google.com/project/_/apiui/apiview/pubsub/overview).
+
+2. Create a topic and subscription.
+
+ $ gcloud beta pubsub topics create [your-topic-name]
+ $ gcloud beta pubsub subscriptions create [your-subscription-name] \
+ --topic [your-topic-name] \
+ --push-endpoint \
+ https://[your-app-id].appspot.com/pubsub/push?token=[your-token] \
+ --ack-deadline 30
+
+3. Update the environment variables in ``app.yaml``.
+
+## Running locally
+
+Refer to the [top-level README](../README.md) for instructions on running and deploying.
+
+When running locally, you can use the [Google Cloud SDK](https://cloud.google.com/sdk) to provide authentication to use Google Cloud APIs:
+
+ $ gcloud init
+
+Install dependencies, please follow https://cloud.google.com/python/docs/setup
+to set up a Python development environment. Then run:
+
+ $ pip install -r requirements.txt
+
+Then set environment variables before starting your application:
+
+ $ export PUBSUB_VERIFICATION_TOKEN=[your-verification-token]
+ $ export PUBSUB_TOPIC=[your-topic]
+ $ python main.py
+
+### Simulating push notifications
+
+The application can send messages locally, but it is not able to receive push messages locally. You can, however, simulate a push message by making an HTTP request to the local push notification endpoint. There is an included ``sample_message.json``. You can use
+``curl`` or [httpie](https://github.com/jkbrzt/httpie) to POST this:
+
+ $ curl -i --data @sample_message.json ":8080/pubsub/push?token=[your-token]"
+
+Or
+
+ $ http POST ":8080/pubsub/push?token=[your-token]" < sample_message.json
+
+Response:
+
+ HTTP/1.0 200 OK
+ Content-Length: 2
+ Content-Type: text/html; charset=utf-8
+ Date: Mon, 10 Aug 2015 17:52:03 GMT
+ Server: Werkzeug/0.10.4 Python/2.7.10
+
+ OK
+
+After the request completes, you can refresh ``localhost:8080`` and see the message in the list of received messages.
+
+## Running on App Engine
+
+Deploy using `gcloud`:
+
+ gcloud app deploy app.yaml
+
+You can now access the application at `https://your-app-id.appspot.com`. You can use the form to submit messages, but it's non-deterministic which instance of your application will receive the notification. You can send multiple messages and refresh the page to see the received message.
diff --git a/appengine/flexible/pubsub/app.yaml b/appengine/flexible/pubsub/app.yaml
new file mode 100644
index 00000000000..327cfd0d638
--- /dev/null
+++ b/appengine/flexible/pubsub/app.yaml
@@ -0,0 +1,28 @@
+# Copyright 2023 Google LLC
+#
+# 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.
+
+runtime: python
+env: flex
+entrypoint: gunicorn -b :$PORT main:app
+
+runtime_config:
+ operating_system: "ubuntu22"
+
+# [START gae_flex_pubsub_env]
+env_variables:
+ PUBSUB_TOPIC: your-topic
+ # This token is used to verify that requests originate from your
+ # application. It can be any sufficiently random string.
+ PUBSUB_VERIFICATION_TOKEN: 1234abc
+# [END gae_flex_pubsub_env]
diff --git a/appengine/flexible/pubsub/main.py b/appengine/flexible/pubsub/main.py
new file mode 100644
index 00000000000..8db0a665370
--- /dev/null
+++ b/appengine/flexible/pubsub/main.py
@@ -0,0 +1,91 @@
+# Copyright 2023 Google LLC.
+#
+# 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 base64
+import json
+import logging
+import os
+
+from flask import current_app, Flask, render_template, request
+from google.cloud import pubsub_v1
+
+
+app = Flask(__name__)
+
+# Configure the following environment variables via app.yaml
+# This is used in the push request handler to verify that the request came from
+# pubsub and originated from a trusted source.
+app.config['PUBSUB_VERIFICATION_TOKEN'] = \
+ os.environ['PUBSUB_VERIFICATION_TOKEN']
+app.config['PUBSUB_TOPIC'] = os.environ['PUBSUB_TOPIC']
+app.config['PROJECT'] = os.environ['GOOGLE_CLOUD_PROJECT']
+
+
+# Global list to storage messages received by this instance.
+MESSAGES = []
+
+# Initialize the publisher client once to avoid memory leak
+# and reduce publish latency.
+publisher = pubsub_v1.PublisherClient()
+
+
+# [START gae_flex_pubsub_index]
+@app.route('/', methods=['GET', 'POST'])
+def index():
+ if request.method == 'GET':
+ return render_template('index.html', messages=MESSAGES)
+
+ data = request.form.get('payload', 'Example payload').encode('utf-8')
+
+ # publisher = pubsub_v1.PublisherClient()
+ topic_path = publisher.topic_path(
+ current_app.config['PROJECT'],
+ current_app.config['PUBSUB_TOPIC'])
+
+ publisher.publish(topic_path, data=data)
+
+ return 'OK', 200
+# [END gae_flex_pubsub_index]
+
+
+# [START gae_flex_pubsub_push]
+@app.route('/pubsub/push', methods=['POST'])
+def pubsub_push():
+ if (request.args.get('token', '') !=
+ current_app.config['PUBSUB_VERIFICATION_TOKEN']):
+ return 'Invalid request', 400
+
+ envelope = json.loads(request.data.decode('utf-8'))
+ payload = base64.b64decode(envelope['message']['data'])
+
+ MESSAGES.append(payload)
+
+ # Returning any 2xx status indicates successful receipt of the message.
+ return 'OK', 200
+# [END gae_flex_pubsub_push]
+
+
+@app.errorhandler(500)
+def server_error(e):
+ logging.exception('An error occurred during a request.')
+ return """
+ An internal error occurred: {}
+ See logs for full stacktrace.
+ """.format(e), 500
+
+
+if __name__ == '__main__':
+ # This is used when running locally. Gunicorn is used to run the
+ # application on Google App Engine. See entrypoint in app.yaml.
+ app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/pubsub/main_test.py b/appengine/flexible/pubsub/main_test.py
new file mode 100644
index 00000000000..086e74cfeea
--- /dev/null
+++ b/appengine/flexible/pubsub/main_test.py
@@ -0,0 +1,69 @@
+# Copyright 2023 Google LLC.
+#
+# 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 base64
+import json
+import os
+
+import pytest
+
+import main
+
+
+@pytest.fixture
+def client():
+ main.app.testing = True
+ return main.app.test_client()
+
+
+def test_index(client):
+ r = client.get('/')
+ assert r.status_code == 200
+
+
+def test_post_index(client):
+ r = client.post('/', data={'payload': 'Test payload'})
+ assert r.status_code == 200
+
+
+def test_push_endpoint(client):
+ url = '/pubsub/push?token=' + os.environ['PUBSUB_VERIFICATION_TOKEN']
+
+ r = client.post(
+ url,
+ data=json.dumps({
+ "message": {
+ "data": base64.b64encode(
+ u'Test message'.encode('utf-8')
+ ).decode('utf-8')
+ }
+ })
+ )
+
+ assert r.status_code == 200
+
+ # Make sure the message is visible on the home page.
+ r = client.get('/')
+ assert r.status_code == 200
+ assert 'Test message' in r.data.decode('utf-8')
+
+
+def test_push_endpoint_errors(client):
+ # no token
+ r = client.post('/pubsub/push')
+ assert r.status_code == 400
+
+ # invalid token
+ r = client.post('/pubsub/push?token=bad')
+ assert r.status_code == 400
diff --git a/appengine/flexible/pubsub/requirements-test.txt b/appengine/flexible/pubsub/requirements-test.txt
new file mode 100644
index 00000000000..c2845bffbe8
--- /dev/null
+++ b/appengine/flexible/pubsub/requirements-test.txt
@@ -0,0 +1 @@
+pytest==7.0.1
diff --git a/appengine/flexible/pubsub/requirements.txt b/appengine/flexible/pubsub/requirements.txt
new file mode 100644
index 00000000000..30e9d9736b5
--- /dev/null
+++ b/appengine/flexible/pubsub/requirements.txt
@@ -0,0 +1,4 @@
+Flask==2.1.0; python_version > '3.6'
+Flask==2.0.3; python_version < '3.7'
+google-cloud-pubsub==2.9.0
+gunicorn==20.1.0
diff --git a/appengine/flexible/pubsub/sample_message.json b/appengine/flexible/pubsub/sample_message.json
new file mode 100644
index 00000000000..8fe62d23fb9
--- /dev/null
+++ b/appengine/flexible/pubsub/sample_message.json
@@ -0,0 +1,5 @@
+{
+ "message": {
+ "data": "SGVsbG8sIFdvcmxkIQ=="
+ }
+}
diff --git a/appengine/flexible/pubsub/templates/index.html b/appengine/flexible/pubsub/templates/index.html
new file mode 100644
index 00000000000..b2e73307c78
--- /dev/null
+++ b/appengine/flexible/pubsub/templates/index.html
@@ -0,0 +1,36 @@
+{#
+# Copyright 2023 Google LLC.
+#
+# 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.
+#}
+
+
+
+
+ {% for message in messages: %}
+
+ {}
+ See logs for full stacktrace.
+ """.format(e), 500
+
+
+if __name__ == '__main__':
+ # This is used when running locally. Gunicorn is used to run the
+ # application on Google App Engine. See entrypoint in app.yaml.
+ app.run(host='127.0.0.1', port=8080, debug=True)
+# [END gae_flex_python_static_files]
diff --git a/appengine/flexible/static_files/main_test.py b/appengine/flexible/static_files/main_test.py
new file mode 100644
index 00000000000..a1d9aab8356
--- /dev/null
+++ b/appengine/flexible/static_files/main_test.py
@@ -0,0 +1,26 @@
+# Copyright 2023 Google LLC.
+#
+# 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 main
+
+
+def test_index():
+ main.app.testing = True
+ client = main.app.test_client()
+
+ r = client.get('/')
+ assert r.status_code == 200
+
+ r = client.get('/static/main.css')
+ assert r.status_code == 200
diff --git a/appengine/flexible/static_files/requirements-test.txt b/appengine/flexible/static_files/requirements-test.txt
new file mode 100644
index 00000000000..c2845bffbe8
--- /dev/null
+++ b/appengine/flexible/static_files/requirements-test.txt
@@ -0,0 +1 @@
+pytest==7.0.1
diff --git a/appengine/flexible/static_files/requirements.txt b/appengine/flexible/static_files/requirements.txt
new file mode 100644
index 00000000000..beeed7bed09
--- /dev/null
+++ b/appengine/flexible/static_files/requirements.txt
@@ -0,0 +1,3 @@
+Flask==2.1.0; python_version > '3.6'
+Flask==2.0.3; python_version < '3.7'
+gunicorn==20.1.0
diff --git a/appengine/flexible/static_files/static/main.css b/appengine/flexible/static_files/static/main.css
new file mode 100644
index 00000000000..6c80163acd3
--- /dev/null
+++ b/appengine/flexible/static_files/static/main.css
@@ -0,0 +1,21 @@
+/*
+Copyright 2023 Google LLC.
+
+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 gae_flex_python_css] */
+body {
+ font-family: Verdana, Helvetica, sans-serif;
+ background-color: #CCCCFF;
+}
+/* [END gae_flex_python_css] */
diff --git a/appengine/flexible/static_files/templates/index.html b/appengine/flexible/static_files/templates/index.html
new file mode 100644
index 00000000000..9792c0a8b29
--- /dev/null
+++ b/appengine/flexible/static_files/templates/index.html
@@ -0,0 +1,29 @@
+{#
+# Copyright 2023 Google LLC.
+#
+# 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.
+#}
+
+
+
+ API GATEWAY DEMO
+
+
+
diff --git a/appengine/flexible/multiple_services/static-service/static/index.js b/appengine/flexible/multiple_services/static-service/static/index.js
new file mode 100644
index 00000000000..021f835b9c1
--- /dev/null
+++ b/appengine/flexible/multiple_services/static-service/static/index.js
@@ -0,0 +1,36 @@
+// Copyright 2016 Google LLC.
+//
+// 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.
+
+function handleResponse(resp){
+ const li = document.createElement('li');
+ li.innerHTML = resp;
+ document.querySelector('.responses').appendChild(li)
+}
+
+function handleClick(event){
+ $.ajax({
+ url: `hello/${event.target.id}`,
+ type: `GET`,
+ success(resp){
+ handleResponse(resp);
+ }
+ });
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const buttons = document.getElementsByTagName('button')
+ for (var i = 0; i < buttons.length; i++) {
+ buttons[i].addEventListener('click', handleClick);
+ }
+});
diff --git a/appengine/flexible/multiple_services/static-service/static/style.css b/appengine/flexible/multiple_services/static-service/static/style.css
new file mode 100644
index 00000000000..65074a9ef4d
--- /dev/null
+++ b/appengine/flexible/multiple_services/static-service/static/style.css
@@ -0,0 +1,19 @@
+/**
+ * Copyright 2021 Google LLC
+ *
+ * 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.
+ */
+
+h1 {
+ color: red;
+}
diff --git a/appengine/flexible/numpy/app.yaml b/appengine/flexible/numpy/app.yaml
new file mode 100644
index 00000000000..ca76f83fc3b
--- /dev/null
+++ b/appengine/flexible/numpy/app.yaml
@@ -0,0 +1,20 @@
+# Copyright 2021 Google LLC
+#
+# 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.
+
+runtime: python
+env: flex
+entrypoint: gunicorn -b :$PORT main:app
+
+runtime_config:
+ python_version: 3
diff --git a/appengine/flexible/numpy/main.py b/appengine/flexible/numpy/main.py
new file mode 100644
index 00000000000..df873c68b91
--- /dev/null
+++ b/appengine/flexible/numpy/main.py
@@ -0,0 +1,48 @@
+# Copyright 2016 Google LLC.
+#
+# 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 logging
+
+from flask import Flask
+import numpy as np
+
+app = Flask(__name__)
+
+
+@app.route('/')
+def calculate():
+ return_str = ''
+ x = np.array([[1, 2], [3, 4]])
+ y = np.array([[5, 6], [7, 8]])
+
+ return_str += 'x: {} , y: {}
'.format(str(x), str(y))
+
+ # Multiply matrices
+ return_str += 'x dot y : {}'.format(str(np.dot(x, y)))
+ return return_str
+
+
+@app.errorhandler(500)
+def server_error(e):
+ logging.exception('An error occurred during a request.')
+ return """
+ An internal error occurred: {}
+ See logs for full stacktrace.
+ """.format(e), 500
+
+
+if __name__ == '__main__':
+ # This is used when running locally. Gunicorn is used to run the
+ # application on Google App Engine. See entrypoint in app.yaml.
+ app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/numpy/main_test.py b/appengine/flexible/numpy/main_test.py
new file mode 100644
index 00000000000..42c0d594d94
--- /dev/null
+++ b/appengine/flexible/numpy/main_test.py
@@ -0,0 +1,24 @@
+# Copyright 2016 Google LLC.
+#
+# 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 main
+
+
+def test_index():
+ main.app.testing = True
+ client = main.app.test_client()
+
+ r = client.get('/')
+ assert r.status_code == 200
+ assert '[[19 22]\n [43 50]]' in r.data.decode('utf-8')
diff --git a/appengine/flexible/numpy/requirements-test.txt b/appengine/flexible/numpy/requirements-test.txt
new file mode 100644
index 00000000000..c2845bffbe8
--- /dev/null
+++ b/appengine/flexible/numpy/requirements-test.txt
@@ -0,0 +1 @@
+pytest==7.0.1
diff --git a/appengine/flexible/numpy/requirements.txt b/appengine/flexible/numpy/requirements.txt
new file mode 100644
index 00000000000..277907a21d9
--- /dev/null
+++ b/appengine/flexible/numpy/requirements.txt
@@ -0,0 +1,6 @@
+Flask==2.1.0; python_version > '3.6'
+Flask==2.0.3; python_version < '3.7'
+gunicorn==20.1.0
+numpy==1.22.0; python_version > '3.7'
+numpy==1.19.5; python_version <= '3.7'
+
diff --git a/appengine/flexible/scipy/.gitignore b/appengine/flexible/scipy/.gitignore
new file mode 100644
index 00000000000..de724cf6213
--- /dev/null
+++ b/appengine/flexible/scipy/.gitignore
@@ -0,0 +1 @@
+assets/resized_google_logo.jpg
diff --git a/appengine/flexible/scipy/README.md b/appengine/flexible/scipy/README.md
new file mode 100644
index 00000000000..3217ab68726
--- /dev/null
+++ b/appengine/flexible/scipy/README.md
@@ -0,0 +1,9 @@
+# SciPy on App Engine Flexible
+
+[![Open in Cloud Shell][shell_img]][shell_link]
+
+[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
+[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/scipy/README.md
+
+This sample demonstrates how to use SciPy to resize an image on App Engine Flexible.
+
diff --git a/appengine/flexible/scipy/app.yaml b/appengine/flexible/scipy/app.yaml
new file mode 100644
index 00000000000..ca76f83fc3b
--- /dev/null
+++ b/appengine/flexible/scipy/app.yaml
@@ -0,0 +1,20 @@
+# Copyright 2021 Google LLC
+#
+# 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.
+
+runtime: python
+env: flex
+entrypoint: gunicorn -b :$PORT main:app
+
+runtime_config:
+ python_version: 3
diff --git a/appengine/flexible/scipy/assets/google_logo.jpg b/appengine/flexible/scipy/assets/google_logo.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5538eaed2bdfb5ccdb0f1082afb97a4d0cf1a465
GIT binary patch
literal 21568
zcmdqIWpo`o(?Y(+ET`HAIs*+SKbwABKtpI4Uk}{G22m}J8!9U<>4M|%@Ow3SORY_7t
zUILr}07%mER`w1MXaHbm@9L~7B}$_GT89L77=Qra0T_S<0E|pr92L|g)d6slkq{$s
z0W&@0|D?;G09XM7Mux2XCB=+j{tg=2oCND-J
zR~I{Mf_`L`kYX^`qX&h^k6d!5_z3>YS@X`4KF-b*oYpDe|EQUMn{Jr}*^+>fYxA|3
zeAG^^9^AV8nMPY4!R&f7C#x|$M#e*RXPyrX>ZiPtX1|)fAm{UnO;{T13M1fOoE)!mVVeN>^r7j|MQ;y5dRIm>m|_7h6h7oml%o)PzWkP13=N
zH=7z62uf^pt5)9Zx5%#Aw0!$&C^LQt^|UGbQHx!ufAhnQ-slrR$LXtSd!NIee@Eu3
z=(MMBU*7Jo$CK*wf$cg4sDcH;B~U$VU}$z6S8z@DcK%QtZFV!E%8i=cl;$Q1B#Y=B
z&;5yVaBf0
zumg5+YCcsy1V)Z1vk$<2fkSP)%A&$`|K}Ij1ibh=O|WizJ&9WSMy*GR)u=%@p1SoY
zOPK`dMkPd-_+LOvG=J!VPQz#k^||`%fw{aDty8*Il{T(#!(QaP@uQSQPfPq41f8+T
zELib7eZC@1nR*hi(wnoCP7kM|*b{L)
z<3zCkvXIm{}
+ See logs for full stacktrace.
+ """.format(e), 500
+
+
+if __name__ == '__main__':
+ # This is used when running locally. Gunicorn is used to run the
+ # application on Google App Engine. See entrypoint in app.yaml.
+ app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/scipy/main_test.py b/appengine/flexible/scipy/main_test.py
new file mode 100644
index 00000000000..8dfc321ea3d
--- /dev/null
+++ b/appengine/flexible/scipy/main_test.py
@@ -0,0 +1,30 @@
+# Copyright 2016 Google LLC.
+#
+# 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 os
+import tempfile
+
+import main
+
+
+def test_index():
+ main.app.testing = True
+ client = main.app.test_client()
+ with tempfile.TemporaryDirectory() as test_dir:
+ output_image_path = os.path.join(test_dir, 'resized_google_logo.jpg')
+ r = client.get(
+ '/', query_string={'output_image_path': output_image_path})
+
+ assert os.path.isfile(output_image_path)
+ assert r.status_code == 200
diff --git a/appengine/flexible/scipy/noxfile_config.py b/appengine/flexible/scipy/noxfile_config.py
new file mode 100644
index 00000000000..3228fb0bf80
--- /dev/null
+++ b/appengine/flexible/scipy/noxfile_config.py
@@ -0,0 +1,38 @@
+# Copyright 2022 Google LLC
+#
+# 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.
+
+# Default TEST_CONFIG_OVERRIDE for python repos.
+
+# You can copy this file into your directory, then it will be imported from
+# the noxfile.py.
+
+# The source of truth:
+# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/noxfile_config.py
+
+TEST_CONFIG_OVERRIDE = {
+ # You can opt out from the test for specific Python versions.
+ "ignored_versions": ["2.7", "3.6", "3.11"],
+ # Old samples are opted out of enforcing Python type hints
+ # All new samples should feature them
+ "enforce_type_hints": False,
+ # An envvar key for determining the project id to use. Change it
+ # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a
+ # build specific Cloud project. You can also use your own string
+ # to use your own Cloud project.
+ "gcloud_project_env": "GOOGLE_CLOUD_PROJECT",
+ # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT',
+ # A dictionary you want to inject into your test. Don't put any
+ # secrets here. These values will override predefined values.
+ "envs": {},
+}
diff --git a/appengine/flexible/scipy/requirements-test.txt b/appengine/flexible/scipy/requirements-test.txt
new file mode 100644
index 00000000000..c2845bffbe8
--- /dev/null
+++ b/appengine/flexible/scipy/requirements-test.txt
@@ -0,0 +1 @@
+pytest==7.0.1
diff --git a/appengine/flexible/scipy/requirements.txt b/appengine/flexible/scipy/requirements.txt
new file mode 100644
index 00000000000..aa57c4cd1d0
--- /dev/null
+++ b/appengine/flexible/scipy/requirements.txt
@@ -0,0 +1,9 @@
+Flask==2.1.0; python_version > '3.6'
+Flask==2.0.3; python_version < '3.7'
+gunicorn==20.1.0
+imageio==2.14.0
+numpy==1.22.0; python_version > "3.7"
+numpy==1.21.4; python_version <= "3.7"
+pillow==9.2.0
+scipy==1.10.0; python_version > "3.7"
+scipy==1.7.3; python_version <= "3.7"
diff --git a/appengine/flexible/twilio/README.md b/appengine/flexible/twilio/README.md
new file mode 100644
index 00000000000..432acef801a
--- /dev/null
+++ b/appengine/flexible/twilio/README.md
@@ -0,0 +1,34 @@
+# Python Twilio voice and SMS sample for Google App Engine Flexible Environment
+
+[![Open in Cloud Shell][shell_img]][shell_link]
+
+[shell_img]: http://gstatic.com/cloudssh/images/open-btn.png
+[shell_link]: https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/GoogleCloudPlatform/python-docs-samples&page=editor&open_in_editor=appengine/flexible/twilio/README.md
+
+This sample demonstrates how to use [Twilio](https://www.twilio.com) on [Google App Engine Flexible Environment](https://cloud.google.com/appengine).
+
+For more information about Twilio, see their [Python quickstart tutorials](https://www.twilio.com/docs/quickstart/python).
+
+## Setup
+
+Before you can run or deploy the sample, you will need to do the following:
+
+1. [Create a Twilio Account](http://ahoy.twilio.com/googlecloudplatform). Google App Engine
+customers receive a complimentary credit for SMS messages and inbound messages.
+
+2. Create a number on twilio, and configure the voice request URL to be ``https://your-app-id.appspot.com/call/receive``
+and the SMS request URL to be ``https://your-app-id.appspot.com/sms/receive``.
+
+3. Configure your Twilio settings in the environment variables section in ``app.yaml``.
+
+## Running locally
+
+Refer to the [top-level README](../README.md) for instructions on running and deploying.
+
+You can run the application locally to test the callbacks and SMS sending. You
+will need to set environment variables before starting your application:
+
+ $ export TWILIO_ACCOUNT_SID=[your-twilio-accoun-sid]
+ $ export TWILIO_AUTH_TOKEN=[your-twilio-auth-token]
+ $ export TWILIO_NUMBER=[your-twilio-number]
+ $ python main.py
diff --git a/appengine/flexible/twilio/app.yaml b/appengine/flexible/twilio/app.yaml
new file mode 100644
index 00000000000..0e7de97eb19
--- /dev/null
+++ b/appengine/flexible/twilio/app.yaml
@@ -0,0 +1,27 @@
+# Copyright 2021 Google LLC
+#
+# 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.
+
+runtime: python
+env: flex
+entrypoint: gunicorn -b :$PORT main:app
+
+runtime_config:
+ python_version: 3
+
+# [START gae_flex_twilio_env]
+env_variables:
+ TWILIO_ACCOUNT_SID: your-account-sid
+ TWILIO_AUTH_TOKEN: your-auth-token
+ TWILIO_NUMBER: your-twilio-number
+# [END gae_flex_twilio_env]
diff --git a/appengine/flexible/twilio/main.py b/appengine/flexible/twilio/main.py
new file mode 100644
index 00000000000..03041370daf
--- /dev/null
+++ b/appengine/flexible/twilio/main.py
@@ -0,0 +1,87 @@
+# Copyright 2015 Google LLC.
+#
+# 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 logging
+import os
+
+from flask import Flask, request
+from twilio import rest
+from twilio.twiml import messaging_response, voice_response
+
+
+TWILIO_ACCOUNT_SID = os.environ['TWILIO_ACCOUNT_SID']
+TWILIO_AUTH_TOKEN = os.environ['TWILIO_AUTH_TOKEN']
+TWILIO_NUMBER = os.environ['TWILIO_NUMBER']
+
+
+app = Flask(__name__)
+
+
+# [START gae_flex_twilio_receive_call]
+@app.route('/call/receive', methods=['POST'])
+def receive_call():
+ """Answers a call and replies with a simple greeting."""
+ response = voice_response.VoiceResponse()
+ response.say('Hello from Twilio!')
+ return str(response), 200, {'Content-Type': 'application/xml'}
+# [END gae_flex_twilio_receive_call]
+
+
+# [START gae_flex_twilio_send_sms]
+@app.route('/sms/send')
+def send_sms():
+ """Sends a simple SMS message."""
+ to = request.args.get('to')
+ if not to:
+ return ('Please provide the number to message in the "to" query string'
+ ' parameter.'), 400
+
+ client = rest.Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
+ rv = client.messages.create(
+ to=to,
+ from_=TWILIO_NUMBER,
+ body='Hello from Twilio!'
+ )
+ return str(rv)
+# [END gae_flex_twilio_send_sms]
+
+
+# [START gae_flex_twilio_receive_sms]
+@app.route('/sms/receive', methods=['POST'])
+def receive_sms():
+ """Receives an SMS message and replies with a simple greeting."""
+ sender = request.values.get('From')
+ body = request.values.get('Body')
+
+ message = 'Hello, {}, you said: {}'.format(sender, body)
+
+ response = messaging_response.MessagingResponse()
+ response.message(message)
+ return str(response), 200, {'Content-Type': 'application/xml'}
+# [END gae_flex_twilio_receive_sms]
+
+
+@app.errorhandler(500)
+def server_error(e):
+ logging.exception('An error occurred during a request.')
+ return """
+ An internal error occurred: {}
+ See logs for full stacktrace.
+ """.format(e), 500
+
+
+if __name__ == '__main__':
+ # This is used when running locally. Gunicorn is used to run the
+ # application on Google App Engine. See entrypoint in app.yaml.
+ app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/appengine/flexible/twilio/main_test.py b/appengine/flexible/twilio/main_test.py
new file mode 100644
index 00000000000..da37c8c3b90
--- /dev/null
+++ b/appengine/flexible/twilio/main_test.py
@@ -0,0 +1,77 @@
+# Copyright 2016 Google LLC.
+#
+# 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 re
+
+import pytest
+import responses
+
+
+@pytest.fixture
+def app(monkeypatch):
+ monkeypatch.setenv('TWILIO_ACCOUNT_SID', 'sid123')
+ monkeypatch.setenv('TWILIO_AUTH_TOKEN', 'auth123')
+ monkeypatch.setenv('TWILIO_NUMBER', '0123456789')
+
+ import main
+
+ main.app.testing = True
+ return main.app.test_client()
+
+
+def test_receive_call(app):
+ r = app.post('/call/receive')
+ assert 'Hello from Twilio!' in r.data.decode('utf-8')
+
+
+@responses.activate
+def test_send_sms(app, monkeypatch):
+ sample_response = {
+ "sid": "sid",
+ "date_created": "Wed, 20 Dec 2017 19:32:14 +0000",
+ "date_updated": "Wed, 20 Dec 2017 19:32:14 +0000",
+ "date_sent": None,
+ "account_sid": "account_sid",
+ "to": "+1234567890",
+ "from": "+9876543210",
+ "messaging_service_sid": None,
+ "body": "Hello from Twilio!",
+ "status": "queued",
+ "num_segments": "1",
+ "num_media": "0",
+ "direction": "outbound-api",
+ "api_version": "2010-04-01",
+ "price": None,
+ "price_unit": "USD",
+ "error_code": None,
+ "error_message": None,
+ "uri": "/2010-04-01/Accounts/sample.json",
+ "subresource_uris": {
+ "media": "/2010-04-01/Accounts/sample/Media.json"
+ }
+ }
+ responses.add(responses.POST, re.compile('.*'),
+ json=sample_response, status=200)
+
+ r = app.get('/sms/send')
+ assert r.status_code == 400
+
+ r = app.get('/sms/send?to=5558675309')
+ assert r.status_code == 200
+
+
+def test_receive_sms(app):
+ r = app.post('/sms/receive', data={
+ 'From': '5558675309', 'Body': 'Jenny, I got your number.'})
+ assert r.status_code == 200
+ assert 'Jenny, I got your number' in r.data.decode('utf-8')
diff --git a/appengine/flexible/twilio/requirements-test.txt b/appengine/flexible/twilio/requirements-test.txt
new file mode 100644
index 00000000000..0dd3a1c6914
--- /dev/null
+++ b/appengine/flexible/twilio/requirements-test.txt
@@ -0,0 +1,3 @@
+pytest==7.0.1
+responses==0.17.0; python_version < '3.7'
+responses==0.20.0; python_version > '3.6'
diff --git a/appengine/flexible/twilio/requirements.txt b/appengine/flexible/twilio/requirements.txt
new file mode 100644
index 00000000000..9eb2dcdf034
--- /dev/null
+++ b/appengine/flexible/twilio/requirements.txt
@@ -0,0 +1,4 @@
+Flask==2.1.0; python_version > '3.6'
+Flask==2.0.3; python_version < '3.7'
+gunicorn==20.1.0
+twilio==7.9.3
diff --git a/appengine/flexible/websockets/README.md b/appengine/flexible/websockets/README.md
new file mode 100644
index 00000000000..fabd0995a40
--- /dev/null
+++ b/appengine/flexible/websockets/README.md
@@ -0,0 +1,11 @@
+# Python websockets sample for Google App Engine Flexible Environment
+
+This sample demonstrates how to use websockets on [Google App Engine Flexible Environment](https://cloud.google.com/appengine).
+
+## Running locally
+
+Refer to the [top-level README](../README.md) for instructions on running and deploying.
+
+To run locally, you need to use gunicorn with the ``flask_socket`` worker:
+
+ $ gunicorn -b 127.0.0.1:8080 -k flask_sockets.worker main:app
diff --git a/appengine/flexible/websockets/app.yaml b/appengine/flexible/websockets/app.yaml
new file mode 100644
index 00000000000..8a323ffe30f
--- /dev/null
+++ b/appengine/flexible/websockets/app.yaml
@@ -0,0 +1,36 @@
+# Copyright 2021 Google LLC
+#
+# 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.
+
+runtime: python
+env: flex
+
+# Use a special gunicorn worker class to support websockets.
+entrypoint: gunicorn -b :$PORT -k flask_sockets.worker main:app
+
+runtime_config:
+ python_version: 3
+
+# Use only a single instance, so that this local-memory-only chat app will work
+# consistently with multiple users. To work across multiple instances, an
+# extra-instance messaging system or data store would be needed.
+manual_scaling:
+ instances: 1
+
+
+# For applications which can take advantage of session affinity
+# (where the load balancer will attempt to route multiple connections from
+# the same user to the same App Engine instance), uncomment the folowing:
+
+# network:
+# session_affinity: true
diff --git a/appengine/flexible/websockets/main.py b/appengine/flexible/websockets/main.py
new file mode 100644
index 00000000000..3fd5da9851d
--- /dev/null
+++ b/appengine/flexible/websockets/main.py
@@ -0,0 +1,53 @@
+# Copyright 2018 Google LLC
+#
+# 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 __future__ import print_function
+
+# [START gae_flex_websockets_app]
+from flask import Flask, render_template
+from flask_sockets import Sockets
+
+
+app = Flask(__name__)
+sockets = Sockets(app)
+
+
+@sockets.route('/chat')
+def chat_socket(ws):
+ while not ws.closed:
+ message = ws.receive()
+ if message is None: # message is "None" if the client has closed.
+ continue
+ # Send the message to all clients connected to this webserver
+ # process. (To support multiple processes or instances, an
+ # extra-instance storage or messaging system would be required.)
+ clients = ws.handler.server.clients.values()
+ for client in clients:
+ client.ws.send(message)
+# [END gae_flex_websockets_app]
+
+
+@app.route('/')
+def index():
+ return render_template('index.html')
+
+
+if __name__ == '__main__':
+ print("""
+This can not be run directly because the Flask development server does not
+support web sockets. Instead, use gunicorn:
+
+gunicorn -b 127.0.0.1:8080 -k flask_sockets.worker main:app
+
+""")
diff --git a/appengine/flexible/websockets/main_test.py b/appengine/flexible/websockets/main_test.py
new file mode 100644
index 00000000000..05f8b816dbd
--- /dev/null
+++ b/appengine/flexible/websockets/main_test.py
@@ -0,0 +1,82 @@
+# Copyright 2018 Google LLC
+#
+# 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 socket
+import subprocess
+
+import pytest
+import requests
+from retrying import retry
+import websocket
+
+
+@pytest.fixture(scope='module')
+def server():
+ """Provides the address of a test HTTP/websocket server.
+ The test server is automatically created before
+ a test and destroyed at the end.
+ """
+ # Ask the OS to allocate a port.
+ sock = socket.socket()
+ sock.bind(('127.0.0.1', 0))
+ port = sock.getsockname()[1]
+
+ # Free the port and pass it to a subprocess.
+ sock.close()
+
+ bind_to = '127.0.0.1:{}'.format(port)
+ server = subprocess.Popen(
+ ['gunicorn', '-b', bind_to, '-k' 'flask_sockets.worker', 'main:app'],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE
+ )
+
+ # With btlr, there can be many processes are spawned and the
+ # server might be in a tight memory situation, so let's wait for 2
+ # mins.
+ # Wait until the server responds before proceeding.
+ @retry(wait_fixed=50, stop_max_delay=120000)
+ def check_server(url):
+ requests.get(url)
+
+ check_server('http://{}/'.format(bind_to))
+
+ yield bind_to
+
+ server.kill()
+
+ # Dump the logs for debugging
+ out, err = server.communicate()
+ print("gunicorn stdout: {}".format(out))
+ print("gunicorn stderr: {}".format(err))
+
+
+def test_http(server):
+ result = requests.get('http://{}/'.format(server))
+ assert 'Python Websockets Chat' in result.text
+
+
+def test_websocket(server):
+ url = 'ws://{}/chat'.format(server)
+ ws_one = websocket.WebSocket()
+ ws_one.connect(url)
+
+ ws_two = websocket.WebSocket()
+ ws_two.connect(url)
+
+ message = 'Hello, World'
+ ws_one.send(message)
+
+ assert ws_one.recv() == message
+ assert ws_two.recv() == message
diff --git a/appengine/flexible/websockets/requirements-test.txt b/appengine/flexible/websockets/requirements-test.txt
new file mode 100644
index 00000000000..7143c9bf0a6
--- /dev/null
+++ b/appengine/flexible/websockets/requirements-test.txt
@@ -0,0 +1,3 @@
+pytest==7.0.1
+retrying==1.3.4
+websocket-client==1.2.2
diff --git a/appengine/flexible/websockets/requirements.txt b/appengine/flexible/websockets/requirements.txt
new file mode 100644
index 00000000000..c9f2a62dea1
--- /dev/null
+++ b/appengine/flexible/websockets/requirements.txt
@@ -0,0 +1,5 @@
+Flask==1.1.4 # it seems like Flask-sockets doesn't play well with 2.0+
+Flask-Sockets==0.2.1
+gunicorn==20.1.0
+requests==2.27.1
+markupsafe===2.0.1
diff --git a/appengine/flexible/websockets/templates/index.html b/appengine/flexible/websockets/templates/index.html
new file mode 100644
index 00000000000..af6d791f148
--- /dev/null
+++ b/appengine/flexible/websockets/templates/index.html
@@ -0,0 +1,96 @@
+{#
+# Copyright 2018 Google LLC
+#
+# 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.
+#}
+
+
+
+
+
+