From 8656bd62d39284d73e5ca7ba1b59da4efd11f2c7 Mon Sep 17 00:00:00 2001 From: David del Real Sifuentes Date: Mon, 16 Feb 2026 19:04:05 +0000 Subject: [PATCH 1/2] Remove deprecated samples Removal of appengine/flexible_python37_and_earlier path for deprecation. As per my search on Code Search, there are no samples using these deprecated code snippets anymore. b/475332253 --- .../flexible_python37_and_earlier/README.md | 70 ----------- .../analytics/README.md | 25 ---- .../analytics/app.yaml | 25 ---- .../analytics/main.py | 77 ------------ .../analytics/main_test.py | 45 ------- .../analytics/noxfile_config.py | 39 ------ .../analytics/requirements-test.txt | 3 - .../analytics/requirements.txt | 5 - .../hello_world/app.yaml | 31 ----- .../hello_world/main.py | 35 ------ .../hello_world/main_test.py | 24 ---- .../hello_world/noxfile_config.py | 39 ------ .../hello_world/requirements-test.txt | 1 - .../hello_world/requirements.txt | 4 - .../hello_world_django/.gitignore | 1 - .../hello_world_django/README.md | 66 ---------- .../hello_world_django/app.yaml | 20 --- .../hello_world_django/helloworld/__init__.py | 0 .../hello_world_django/helloworld/views.py | 21 ---- .../hello_world_django/manage.py | 24 ---- .../hello_world_django/noxfile_config.py | 39 ------ .../project_name/__init__.py | 0 .../project_name/settings.py | 116 ------------------ .../hello_world_django/project_name/urls.py | 24 ---- .../hello_world_django/project_name/wsgi.py | 30 ----- .../hello_world_django/requirements-test.txt | 1 - .../hello_world_django/requirements.txt | 2 - .../metadata/app.yaml | 20 --- .../metadata/main.py | 87 ------------- .../metadata/main_test.py | 26 ---- .../metadata/noxfile_config.py | 39 ------ .../metadata/requirements-test.txt | 1 - .../metadata/requirements.txt | 5 - .../multiple_services/README.md | 63 ---------- .../gateway-service/app.yaml | 24 ---- .../multiple_services/gateway-service/main.py | 58 --------- .../gateway-service/requirements-test.txt | 1 - .../gateway-service/requirements.txt | 5 - .../gateway-service/services_config.py | 53 -------- .../multiple_services/noxfile_config.py | 39 ------ .../multiple_services/static-service/app.yaml | 24 ---- .../multiple_services/static-service/main.py | 46 ------- .../static-service/requirements-test.txt | 1 - .../static-service/requirements.txt | 5 - .../static-service/static/index.html | 32 ----- .../static-service/static/index.js | 36 ------ .../static-service/static/style.css | 19 --- .../numpy/app.yaml | 20 --- .../numpy/main.py | 59 --------- .../numpy/main_test.py | 24 ---- .../numpy/noxfile_config.py | 39 ------ .../numpy/requirements-test.txt | 1 - .../numpy/requirements.txt | 8 -- .../pubsub/README.md | 75 ----------- .../pubsub/app.yaml | 28 ----- .../pubsub/main.py | 98 --------------- .../pubsub/main_test.py | 65 ---------- .../pubsub/noxfile_config.py | 39 ------ .../pubsub/requirements-test.txt | 1 - .../pubsub/requirements.txt | 5 - .../pubsub/sample_message.json | 5 - .../pubsub/templates/index.html | 36 ------ .../scipy/.gitignore | 1 - .../scipy/README.md | 9 -- .../scipy/app.yaml | 20 --- .../scipy/assets/google_logo.jpg | Bin 21568 -> 0 bytes .../scipy/main.py | 63 ---------- .../scipy/main_test.py | 29 ----- .../scipy/noxfile_config.py | 39 ------ .../scipy/requirements-test.txt | 1 - .../scipy/requirements.txt | 11 -- .../static_files/README.md | 12 -- .../static_files/app.yaml | 20 --- .../static_files/main.py | 52 -------- .../static_files/main_test.py | 26 ---- .../static_files/noxfile_config.py | 39 ------ .../static_files/requirements-test.txt | 1 - .../static_files/requirements.txt | 4 - .../static_files/static/main.css | 21 ---- .../static_files/templates/index.html | 29 ----- .../twilio/README.md | 34 ----- .../twilio/app.yaml | 27 ---- .../twilio/main.py | 96 --------------- .../twilio/main_test.py | 75 ----------- .../twilio/noxfile_config.py | 39 ------ .../twilio/requirements-test.txt | 3 - .../twilio/requirements.txt | 6 - 87 files changed, 2511 deletions(-) delete mode 100644 appengine/flexible_python37_and_earlier/README.md delete mode 100644 appengine/flexible_python37_and_earlier/analytics/README.md delete mode 100644 appengine/flexible_python37_and_earlier/analytics/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/analytics/main.py delete mode 100644 appengine/flexible_python37_and_earlier/analytics/main_test.py delete mode 100644 appengine/flexible_python37_and_earlier/analytics/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/analytics/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/analytics/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/hello_world/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/hello_world/main.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world/main_test.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/hello_world/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/.gitignore delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/README.md delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/helloworld/__init__.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/helloworld/views.py delete mode 100755 appengine/flexible_python37_and_earlier/hello_world_django/manage.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/project_name/__init__.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/project_name/settings.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/project_name/urls.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/project_name/wsgi.py delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/hello_world_django/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/metadata/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/metadata/main.py delete mode 100644 appengine/flexible_python37_and_earlier/metadata/main_test.py delete mode 100644 appengine/flexible_python37_and_earlier/metadata/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/metadata/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/metadata/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/README.md delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/gateway-service/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/gateway-service/main.py delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/gateway-service/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/gateway-service/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/gateway-service/services_config.py delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/static-service/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/static-service/main.py delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/static-service/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/static-service/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/static-service/static/index.html delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/static-service/static/index.js delete mode 100644 appengine/flexible_python37_and_earlier/multiple_services/static-service/static/style.css delete mode 100644 appengine/flexible_python37_and_earlier/numpy/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/numpy/main.py delete mode 100644 appengine/flexible_python37_and_earlier/numpy/main_test.py delete mode 100644 appengine/flexible_python37_and_earlier/numpy/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/numpy/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/numpy/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/README.md delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/main.py delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/main_test.py delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/sample_message.json delete mode 100644 appengine/flexible_python37_and_earlier/pubsub/templates/index.html delete mode 100644 appengine/flexible_python37_and_earlier/scipy/.gitignore delete mode 100644 appengine/flexible_python37_and_earlier/scipy/README.md delete mode 100644 appengine/flexible_python37_and_earlier/scipy/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/scipy/assets/google_logo.jpg delete mode 100644 appengine/flexible_python37_and_earlier/scipy/main.py delete mode 100644 appengine/flexible_python37_and_earlier/scipy/main_test.py delete mode 100644 appengine/flexible_python37_and_earlier/scipy/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/scipy/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/scipy/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/static_files/README.md delete mode 100644 appengine/flexible_python37_and_earlier/static_files/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/static_files/main.py delete mode 100644 appengine/flexible_python37_and_earlier/static_files/main_test.py delete mode 100644 appengine/flexible_python37_and_earlier/static_files/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/static_files/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/static_files/requirements.txt delete mode 100644 appengine/flexible_python37_and_earlier/static_files/static/main.css delete mode 100644 appengine/flexible_python37_and_earlier/static_files/templates/index.html delete mode 100644 appengine/flexible_python37_and_earlier/twilio/README.md delete mode 100644 appengine/flexible_python37_and_earlier/twilio/app.yaml delete mode 100644 appengine/flexible_python37_and_earlier/twilio/main.py delete mode 100644 appengine/flexible_python37_and_earlier/twilio/main_test.py delete mode 100644 appengine/flexible_python37_and_earlier/twilio/noxfile_config.py delete mode 100644 appengine/flexible_python37_and_earlier/twilio/requirements-test.txt delete mode 100644 appengine/flexible_python37_and_earlier/twilio/requirements.txt diff --git a/appengine/flexible_python37_and_earlier/README.md b/appengine/flexible_python37_and_earlier/README.md deleted file mode 100644 index 41927a35c3d..00000000000 --- a/appengine/flexible_python37_and_earlier/README.md +++ /dev/null @@ -1,70 +0,0 @@ -## Google App Engine Flexible Environment Python Samples - -[![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/README.md - -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). - -See our other [Google Cloud Platform github repos](https://github.com/GoogleCloudPlatform) for sample applications and -scaffolding for other frameworks and use cases. - -## Run Locally - -Some samples have specific instructions. If there is a README in the sample folder, please refer to it for any additional steps required to run the sample. - -In general, the samples typically require: - -1. Install the [Google Cloud SDK](https://cloud.google.com/sdk/), including the [gcloud tool](https://cloud.google.com/sdk/gcloud/), and [gcloud app component](https://cloud.google.com/sdk/gcloud-app). - -2. Setup the gcloud tool. This provides authentication to Google Cloud APIs and services. - - ``` - gcloud init - ``` - -3. Clone this repo. - - ``` - git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git - cd python-docs-samples/appengine/flexible_python37_and_earlier - ``` - -4. Follow https://cloud.google.com/python/docs/setup to set up a Python development environment. Then run: - - ``` - pip install -r requirements.txt - python main.py - ``` - -5. Visit the application at [http://localhost:8080](http://localhost:8080). - - -## Deploying - -Some samples in this repositories may have special deployment instructions. Refer to the readme in the sample directory. - -1. Use the [Google Developers Console](https://console.developer.google.com) to create a project/app id. (App id and project id are identical) - -2. Setup the gcloud tool, if you haven't already. - - ``` - gcloud init - ``` - -3. Use gcloud to deploy your app. - - ``` - gcloud app deploy - ``` - -4. Congratulations! Your application is now live at `your-app-id.appspot.com` - -## Contributing changes - -* See [CONTRIBUTING.md](../../CONTRIBUTING.md) - -## Licensing - -* See [LICENSE](../../LICENSE) diff --git a/appengine/flexible_python37_and_earlier/analytics/README.md b/appengine/flexible_python37_and_earlier/analytics/README.md deleted file mode 100644 index d4fa88bef8b..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/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_python37_and_earlier/analytics/app.yaml b/appengine/flexible_python37_and_earlier/analytics/app.yaml deleted file mode 100644 index 0f5590d7058..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/analytics/main.py b/appengine/flexible_python37_and_earlier/analytics/main.py deleted file mode 100644 index c07ab9b4703..00000000000 --- a/appengine/flexible_python37_and_earlier/analytics/main.py +++ /dev/null @@ -1,77 +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_python37_and_earlier/analytics/main_test.py b/appengine/flexible_python37_and_earlier/analytics/main_test.py deleted file mode 100644 index 02914bda79d..00000000000 --- a/appengine/flexible_python37_and_earlier/analytics/main_test.py +++ /dev/null @@ -1,45 +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_python37_and_earlier/analytics/noxfile_config.py b/appengine/flexible_python37_and_earlier/analytics/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/analytics/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/analytics/requirements-test.txt b/appengine/flexible_python37_and_earlier/analytics/requirements-test.txt deleted file mode 100644 index e89f6031ad7..00000000000 --- a/appengine/flexible_python37_and_earlier/analytics/requirements-test.txt +++ /dev/null @@ -1,3 +0,0 @@ -pytest==8.2.0 -responses==0.17.0; python_version < '3.7' -responses==0.23.1; python_version > '3.6' diff --git a/appengine/flexible_python37_and_earlier/analytics/requirements.txt b/appengine/flexible_python37_and_earlier/analytics/requirements.txt deleted file mode 100644 index 9bfb6dcc546..00000000000 --- a/appengine/flexible_python37_and_earlier/analytics/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.3.3; python_version < '3.7' -gunicorn==23.0.0 -requests[security]==2.31.0 -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/hello_world/app.yaml b/appengine/flexible_python37_and_earlier/hello_world/app.yaml deleted file mode 100644 index 7aa7a47e159..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world/app.yaml +++ /dev/null @@ -1,31 +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 - -# 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 -manual_scaling: - instances: 1 -resources: - cpu: 1 - memory_gb: 0.5 - disk_size_gb: 10 diff --git a/appengine/flexible_python37_and_earlier/hello_world/main.py b/appengine/flexible_python37_and_earlier/hello_world/main.py deleted file mode 100644 index eba195ed4fd..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world/main.py +++ /dev/null @@ -1,35 +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_quickstart] -from flask import Flask - -app = Flask(__name__) - - -@app.route("/") -def hello(): - """Return a friendly HTTP greeting. - - Returns: - A string with the words 'Hello World!'. - """ - return "Hello World!" - - -if __name__ == "__main__": - # This is used when running locally only. When deploying to Google App - # Engine, a webserver process such as Gunicorn will serve the app. - app.run(host="127.0.0.1", port=8080, debug=True) -# [END gae_flex_quickstart] diff --git a/appengine/flexible_python37_and_earlier/hello_world/main_test.py b/appengine/flexible_python37_and_earlier/hello_world/main_test.py deleted file mode 100644 index a6049b094f9..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world/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("/") - assert r.status_code == 200 - assert "Hello World" in r.data.decode("utf-8") diff --git a/appengine/flexible_python37_and_earlier/hello_world/noxfile_config.py b/appengine/flexible_python37_and_earlier/hello_world/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/hello_world/requirements-test.txt b/appengine/flexible_python37_and_earlier/hello_world/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/hello_world/requirements.txt b/appengine/flexible_python37_and_earlier/hello_world/requirements.txt deleted file mode 100644 index 055e4c6a13d..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==3.0.3; python_version < '3.7' -gunicorn==23.0.0 -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/hello_world_django/.gitignore b/appengine/flexible_python37_and_earlier/hello_world_django/.gitignore deleted file mode 100644 index 49ef2557b16..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world_django/.gitignore +++ /dev/null @@ -1 +0,0 @@ -db.sqlite3 diff --git a/appengine/flexible_python37_and_earlier/hello_world_django/README.md b/appengine/flexible_python37_and_earlier/hello_world_django/README.md deleted file mode 100644 index d6705b131a3..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world_django/README.md +++ /dev/null @@ -1,66 +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_python37_and_earlier/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 - -To set up Python development environment, please follow -https://cloud.google.com/python/docs/setup. - -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_python37_and_earlier/hello_world_django/app.yaml b/appengine/flexible_python37_and_earlier/hello_world_django/app.yaml deleted file mode 100644 index 62b74a9c27e..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/hello_world_django/helloworld/__init__.py b/appengine/flexible_python37_and_earlier/hello_world_django/helloworld/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/appengine/flexible_python37_and_earlier/hello_world_django/helloworld/views.py b/appengine/flexible_python37_and_earlier/hello_world_django/helloworld/views.py deleted file mode 100644 index 71c0106bda1..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world_django/helloworld/views.py +++ /dev/null @@ -1,21 +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_python37_and_earlier/hello_world_django/manage.py b/appengine/flexible_python37_and_earlier/hello_world_django/manage.py deleted file mode 100755 index c213c77eca6..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/hello_world_django/noxfile_config.py b/appengine/flexible_python37_and_earlier/hello_world_django/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world_django/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/hello_world_django/project_name/__init__.py b/appengine/flexible_python37_and_earlier/hello_world_django/project_name/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/appengine/flexible_python37_and_earlier/hello_world_django/project_name/settings.py b/appengine/flexible_python37_and_earlier/hello_world_django/project_name/settings.py deleted file mode 100644 index f8b93099d56..00000000000 --- a/appengine/flexible_python37_and_earlier/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/stable/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/stable/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/stable/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/stable/ref/settings/#databases - -DATABASES = { - "default": { - "ENGINE": "django.db.backends.sqlite3", - "NAME": os.path.join(BASE_DIR, "db.sqlite3"), - } -} - - -# Internationalization -# https://docs.djangoproject.com/en/stable/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/stable/howto/static-files/ - -STATIC_URL = "/static/" diff --git a/appengine/flexible_python37_and_earlier/hello_world_django/project_name/urls.py b/appengine/flexible_python37_and_earlier/hello_world_django/project_name/urls.py deleted file mode 100644 index 9a393bb42d2..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world_django/project_name/urls.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. - -from django.contrib import admin -from django.urls import include, path - -import helloworld.views - - -urlpatterns = [ - path("admin/", include(admin.site.urls)), - path("", helloworld.views.index), -] diff --git a/appengine/flexible_python37_and_earlier/hello_world_django/project_name/wsgi.py b/appengine/flexible_python37_and_earlier/hello_world_django/project_name/wsgi.py deleted file mode 100644 index c069a496999..00000000000 --- a/appengine/flexible_python37_and_earlier/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/stable/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_python37_and_earlier/hello_world_django/requirements-test.txt b/appengine/flexible_python37_and_earlier/hello_world_django/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world_django/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/hello_world_django/requirements.txt b/appengine/flexible_python37_and_earlier/hello_world_django/requirements.txt deleted file mode 100644 index 435ef2cb8ee..00000000000 --- a/appengine/flexible_python37_and_earlier/hello_world_django/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -Django==5.2.9 -gunicorn==23.0.0 diff --git a/appengine/flexible_python37_and_earlier/metadata/app.yaml b/appengine/flexible_python37_and_earlier/metadata/app.yaml deleted file mode 100644 index ca76f83fc3b..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/metadata/main.py b/appengine/flexible_python37_and_earlier/metadata/main.py deleted file mode 100644 index 9d1e320865a..00000000000 --- a/appengine/flexible_python37_and_earlier/metadata/main.py +++ /dev/null @@ -1,87 +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. - - Returns: - The instance's external IP address, or the string 'localhost' if the IP address - is not available. - """ - 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(): - """Serves a string with the instance's external IP address. - - Websocket connections must be made directly to this instance. - - Returns: - A formatted string containing the instance's external IP address. - """ - external_ip = get_external_ip() - return f"External IP: {external_ip}" - - -@app.errorhandler(500) -def server_error(e): - """Serves a formatted message on-error. - - Returns: - The error message and a code 500 status. - """ - logging.exception("An error occurred during a request.") - return ( - f"An internal error occurred:
{e}

See logs for full stacktrace.", - 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_python37_and_earlier/metadata/main_test.py b/appengine/flexible_python37_and_earlier/metadata/main_test.py deleted file mode 100644 index 55d345d170d..00000000000 --- a/appengine/flexible_python37_and_earlier/metadata/main_test.py +++ /dev/null @@ -1,26 +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 main - - -def test_index(): - main.app.testing = True - client = main.app.test_client() - - external_ip = main.get_external_ip() - - r = client.get("/") - assert r.status_code == 200 - assert f"External IP: {external_ip}" in r.data.decode("utf-8") diff --git a/appengine/flexible_python37_and_earlier/metadata/noxfile_config.py b/appengine/flexible_python37_and_earlier/metadata/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/metadata/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/metadata/requirements-test.txt b/appengine/flexible_python37_and_earlier/metadata/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/metadata/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/metadata/requirements.txt b/appengine/flexible_python37_and_earlier/metadata/requirements.txt deleted file mode 100644 index 9bfb6dcc546..00000000000 --- a/appengine/flexible_python37_and_earlier/metadata/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.3.3; python_version < '3.7' -gunicorn==23.0.0 -requests[security]==2.31.0 -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/multiple_services/README.md b/appengine/flexible_python37_and_earlier/multiple_services/README.md deleted file mode 100644 index 1e300dd8e00..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/README.md +++ /dev/null @@ -1,63 +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_python37_and_earlier/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 - -Open a terminal and start the first service: - -```Bash -$ cd gateway-service -$ # follow https://cloud.google.com/python/docs/setup to set up a Python -development environment -$ pip install -r requirements.txt -$ python main.py -``` - -In a separate terminal, start the second service: - -```Bash -$ cd static-service -$ # follow https://cloud.google.com/python/docs/setup to set up a Python -$ 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 ](gateway/app.yaml) - -This is the `default` service. There must be one (and not more). The deployed -url will be `https://.appspot.com` - -For the static file server: - -[Static file service ](static/app.yaml) - -The deployed url will be `https://-dot-.appspot.com` - -### Deployment - -To deploy a service cd into its directory and run: -```Bash -$ gcloud app deploy app.yaml -``` -and enter `Y` when prompted. Or to skip the check add `-q`. - -To deploy multiple services simultaneously just add the path to each `app.yaml` -file as an argument to `gcloud app deploy `: -```Bash -$ gcloud app deploy gateway-service/app.yaml static-service/app.yaml -``` diff --git a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/app.yaml b/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/app.yaml deleted file mode 100644 index fde45fada1c..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/app.yaml +++ /dev/null @@ -1,24 +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. - -service: default -runtime: python -env: flex -entrypoint: gunicorn -b :$PORT main:app - -runtime_config: - python_version: 3 - -manual_scaling: - instances: 1 diff --git a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/main.py b/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/main.py deleted file mode 100644 index f963995ae0b..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/main.py +++ /dev/null @@ -1,58 +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. - -from flask import Flask -import requests - -import services_config - -app = Flask(__name__) -services_config.init_app(app) - - -@app.route("/") -def root(): - """Gets index.html from the static file server""" - res = requests.get(app.config["SERVICE_MAP"]["static"]) - return res.content - - -@app.route("/hello/") -def say_hello(service): - """Recieves requests from buttons on the front end and resopnds - or sends request to the static file server""" - # If 'gateway' is specified return immediate - if service == "gateway": - return "Gateway says hello" - - # Otherwise send request to service indicated by URL param - responses = [] - url = app.config["SERVICE_MAP"][service] - res = requests.get(url + "/hello") - responses.append(res.content) - return b"\n".join(responses) - - -@app.route("/") -def static_file(path): - """Gets static files required by index.html to static file server""" - url = app.config["SERVICE_MAP"]["static"] - res = requests.get(url + "/" + path) - return res.content, 200, {"Content-Type": res.headers["Content-Type"]} - - -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=8000, debug=True) diff --git a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/requirements-test.txt b/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/requirements.txt b/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/requirements.txt deleted file mode 100644 index 052021ed812..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.3.3; python_version < '3.7' -gunicorn==23.0.0 -requests==2.31.0 -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/services_config.py b/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/services_config.py deleted file mode 100644 index 429ed402e03..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/gateway-service/services_config.py +++ /dev/null @@ -1,53 +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 - -# To add services insert key value pair of the name of the service and -# the port you want it to run on when running locally -SERVICES = {"default": 8000, "static": 8001} - - -def init_app(app): - # The GAE_INSTANCE environment variable will be set when deployed to GAE. - gae_instance = os.environ.get("GAE_INSTANCE", os.environ.get("GAE_MODULE_INSTANCE")) - environment = "production" if gae_instance is not None else "development" - app.config["SERVICE_MAP"] = map_services(environment) - - -def map_services(environment): - """Generates a map of services to correct urls for running locally - or when deployed.""" - url_map = {} - for service, local_port in SERVICES.items(): - if environment == "production": - url_map[service] = production_url(service) - if environment == "development": - url_map[service] = local_url(local_port) - return url_map - - -def production_url(service_name): - """Generates url for a service when deployed to App Engine.""" - project_id = os.getenv("GOOGLE_CLOUD_PROJECT") - project_url = f"{project_id}.appspot.com" - if service_name == "default": - return f"https://{project_url}" - else: - return f"https://{service_name}-dot-{project_url}" - - -def local_url(port): - """Generates url for a service when running locally""" - return f"http://localhost:{str(port)}" diff --git a/appengine/flexible_python37_and_earlier/multiple_services/noxfile_config.py b/appengine/flexible_python37_and_earlier/multiple_services/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/multiple_services/static-service/app.yaml b/appengine/flexible_python37_and_earlier/multiple_services/static-service/app.yaml deleted file mode 100644 index 0583df96c7e..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/static-service/app.yaml +++ /dev/null @@ -1,24 +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. - -service: static -runtime: python -env: flex -entrypoint: gunicorn -b :$PORT main:app - -runtime_config: - python_version: 3 - -manual_scaling: - instances: 1 diff --git a/appengine/flexible_python37_and_earlier/multiple_services/static-service/main.py b/appengine/flexible_python37_and_earlier/multiple_services/static-service/main.py deleted file mode 100644 index c4b3a8d4799..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/static-service/main.py +++ /dev/null @@ -1,46 +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. - -from flask import Flask - -app = Flask(__name__) - - -@app.route("/hello") -def say_hello(): - """responds to request from frontend via gateway""" - return "Static File Server says hello!" - - -@app.route("/") -def root(): - """serves index.html""" - return app.send_static_file("index.html") - - -@app.route("/") -def static_file(path): - """serves static files required by index.html""" - mimetype = "" - if "." in path and path.split(".")[1] == "css": - mimetype = "text/css" - if "." in path and path.split(".")[1] == "js": - mimetype = "application/javascript" - return app.send_static_file(path), 200, {"Content-Type": mimetype} - - -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=8001, debug=True) diff --git a/appengine/flexible_python37_and_earlier/multiple_services/static-service/requirements-test.txt b/appengine/flexible_python37_and_earlier/multiple_services/static-service/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/static-service/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/multiple_services/static-service/requirements.txt b/appengine/flexible_python37_and_earlier/multiple_services/static-service/requirements.txt deleted file mode 100644 index 052021ed812..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/static-service/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.3.3; python_version < '3.7' -gunicorn==23.0.0 -requests==2.31.0 -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/multiple_services/static-service/static/index.html b/appengine/flexible_python37_and_earlier/multiple_services/static-service/static/index.html deleted file mode 100644 index 9310b700113..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/static-service/static/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - API Gateway on App Engine Flexible Environment - - -

API GATEWAY DEMO

-

Say hi to:

- - -
    - - diff --git a/appengine/flexible_python37_and_earlier/multiple_services/static-service/static/index.js b/appengine/flexible_python37_and_earlier/multiple_services/static-service/static/index.js deleted file mode 100644 index 021f835b9c1..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/static-service/static/index.js +++ /dev/null @@ -1,36 +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. - -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_python37_and_earlier/multiple_services/static-service/static/style.css b/appengine/flexible_python37_and_earlier/multiple_services/static-service/static/style.css deleted file mode 100644 index 65074a9ef4d..00000000000 --- a/appengine/flexible_python37_and_earlier/multiple_services/static-service/static/style.css +++ /dev/null @@ -1,19 +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. - */ - -h1 { - color: red; -} diff --git a/appengine/flexible_python37_and_earlier/numpy/app.yaml b/appengine/flexible_python37_and_earlier/numpy/app.yaml deleted file mode 100644 index ca76f83fc3b..00000000000 --- a/appengine/flexible_python37_and_earlier/numpy/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_python37_and_earlier/numpy/main.py b/appengine/flexible_python37_and_earlier/numpy/main.py deleted file mode 100644 index cb14c931d62..00000000000 --- a/appengine/flexible_python37_and_earlier/numpy/main.py +++ /dev/null @@ -1,59 +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 logging - -from flask import Flask -import numpy as np - -app = Flask(__name__) - - -@app.route("/") -def calculate(): - """Performs a dot product on predefined arrays. - - Returns: - Returns a formatted message containing the dot product result of - two predefined arrays. - """ - return_str = "" - x = np.array([[1, 2], [3, 4]]) - y = np.array([[5, 6], [7, 8]]) - - return_str += f"x: {str(x)} , y: {str(y)}
    " - - # Multiply matrices - return_str += f"x dot y : {str(np.dot(x, y))}" - return return_str - - -@app.errorhandler(500) -def server_error(e): - """Serves a formatted message on-error. - - Returns: - The error message and a code 500 status. - """ - logging.exception("An error occurred during a request.") - return ( - f"An internal error occurred:
    {e}

    See logs for full stacktrace.", - 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_python37_and_earlier/numpy/main_test.py b/appengine/flexible_python37_and_earlier/numpy/main_test.py deleted file mode 100644 index e25c4dfcac3..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/numpy/noxfile_config.py b/appengine/flexible_python37_and_earlier/numpy/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/numpy/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/numpy/requirements-test.txt b/appengine/flexible_python37_and_earlier/numpy/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/numpy/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/numpy/requirements.txt b/appengine/flexible_python37_and_earlier/numpy/requirements.txt deleted file mode 100644 index ccd96a3d6d1..00000000000 --- a/appengine/flexible_python37_and_earlier/numpy/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.0.3; python_version < '3.7' -gunicorn==23.0.0 -numpy==2.2.4; python_version > '3.9' -numpy==2.2.4; python_version == '3.9' -numpy==2.2.4; python_version == '3.8' -numpy==2.2.4; python_version == '3.7' -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/pubsub/README.md b/appengine/flexible_python37_and_earlier/pubsub/README.md deleted file mode 100644 index 2e9b0d71918..00000000000 --- a/appengine/flexible_python37_and_earlier/pubsub/README.md +++ /dev/null @@ -1,75 +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_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_python37_and_earlier/pubsub/app.yaml b/appengine/flexible_python37_and_earlier/pubsub/app.yaml deleted file mode 100644 index 5804ac2b266..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/pubsub/main.py b/appengine/flexible_python37_and_earlier/pubsub/main.py deleted file mode 100644 index 5ffc960841c..00000000000 --- a/appengine/flexible_python37_and_earlier/pubsub/main.py +++ /dev/null @@ -1,98 +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_python37_and_earlier/pubsub/main_test.py b/appengine/flexible_python37_and_earlier/pubsub/main_test.py deleted file mode 100644 index 37abb0d6240..00000000000 --- a/appengine/flexible_python37_and_earlier/pubsub/main_test.py +++ /dev/null @@ -1,65 +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(b"Test message").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_python37_and_earlier/pubsub/noxfile_config.py b/appengine/flexible_python37_and_earlier/pubsub/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/pubsub/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/pubsub/requirements-test.txt b/appengine/flexible_python37_and_earlier/pubsub/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/pubsub/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/pubsub/requirements.txt b/appengine/flexible_python37_and_earlier/pubsub/requirements.txt deleted file mode 100644 index d5b7ce68695..00000000000 --- a/appengine/flexible_python37_and_earlier/pubsub/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.3.3; python_version < '3.7' -google-cloud-pubsub==2.28.0 -gunicorn==23.0.0 -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/pubsub/sample_message.json b/appengine/flexible_python37_and_earlier/pubsub/sample_message.json deleted file mode 100644 index 8fe62d23fb9..00000000000 --- a/appengine/flexible_python37_and_earlier/pubsub/sample_message.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "message": { - "data": "SGVsbG8sIFdvcmxkIQ==" - } -} diff --git a/appengine/flexible_python37_and_earlier/pubsub/templates/index.html b/appengine/flexible_python37_and_earlier/pubsub/templates/index.html deleted file mode 100644 index 28449216c37..00000000000 --- a/appengine/flexible_python37_and_earlier/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. -#} - - - - Pub/Sub Python on Google App Engine Flexible Environment - - -
    -

    Messages received by this instance:

    -
      - {% for message in messages: %} -
    • {{message}}
    • - {% endfor %} -
    -

    Note: because your application is likely running multiple instances, each instance will have a different list of messages.

    -
    -
    - - -
    - - diff --git a/appengine/flexible_python37_and_earlier/scipy/.gitignore b/appengine/flexible_python37_and_earlier/scipy/.gitignore deleted file mode 100644 index de724cf6213..00000000000 --- a/appengine/flexible_python37_and_earlier/scipy/.gitignore +++ /dev/null @@ -1 +0,0 @@ -assets/resized_google_logo.jpg diff --git a/appengine/flexible_python37_and_earlier/scipy/README.md b/appengine/flexible_python37_and_earlier/scipy/README.md deleted file mode 100644 index f1fe346a338..00000000000 --- a/appengine/flexible_python37_and_earlier/scipy/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# 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_python37_and_earlier/scipy/README.md - -This sample demonstrates how to use SciPy to resize an image on App Engine Flexible. - diff --git a/appengine/flexible_python37_and_earlier/scipy/app.yaml b/appengine/flexible_python37_and_earlier/scipy/app.yaml deleted file mode 100644 index ca76f83fc3b..00000000000 --- a/appengine/flexible_python37_and_earlier/scipy/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_python37_and_earlier/scipy/assets/google_logo.jpg b/appengine/flexible_python37_and_earlier/scipy/assets/google_logo.jpg deleted file mode 100644 index 5538eaed2bdfb5ccdb0f1082afb97a4d0cf1a465..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21568 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
    See logs for full stacktrace.", - 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_python37_and_earlier/scipy/main_test.py b/appengine/flexible_python37_and_earlier/scipy/main_test.py deleted file mode 100644 index d3124ffbb0a..00000000000 --- a/appengine/flexible_python37_and_earlier/scipy/main_test.py +++ /dev/null @@ -1,29 +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_python37_and_earlier/scipy/noxfile_config.py b/appengine/flexible_python37_and_earlier/scipy/noxfile_config.py deleted file mode 100644 index 887244766fd..00000000000 --- a/appengine/flexible_python37_and_earlier/scipy/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/scipy/requirements-test.txt b/appengine/flexible_python37_and_earlier/scipy/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/scipy/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/scipy/requirements.txt b/appengine/flexible_python37_and_earlier/scipy/requirements.txt deleted file mode 100644 index a67d9f49c61..00000000000 --- a/appengine/flexible_python37_and_earlier/scipy/requirements.txt +++ /dev/null @@ -1,11 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.0.3; python_version < '3.7' -gunicorn==23.0.0 -imageio==2.36.1 -numpy==2.2.4; python_version > '3.9' -numpy==2.2.4; python_version == '3.9' -numpy==2.2.4; python_version == '3.8' -numpy==2.2.4; python_version == '3.7' -pillow==10.4.0 -scipy==1.14.1 -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/static_files/README.md b/appengine/flexible_python37_and_earlier/static_files/README.md deleted file mode 100644 index 024a0abfbd9..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/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_python37_and_earlier/static_files/app.yaml b/appengine/flexible_python37_and_earlier/static_files/app.yaml deleted file mode 100644 index ca76f83fc3b..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/static_files/main.py b/appengine/flexible_python37_and_earlier/static_files/main.py deleted file mode 100644 index d77eca69f44..00000000000 --- a/appengine/flexible_python37_and_earlier/static_files/main.py +++ /dev/null @@ -1,52 +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(): - """Renders and serves a static HTML template page. - - Returns: - A string containing the rendered HTML page. - """ - return render_template("index.html") - - -@app.errorhandler(500) -def server_error(e): - """Serves a formatted message on-error. - - Returns: - The error message and a code 500 status. - """ - logging.exception("An error occurred during a request.") - return ( - f"An internal error occurred:
    {e}

    See logs for full stacktrace.", - 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_python37_and_earlier/static_files/main_test.py b/appengine/flexible_python37_and_earlier/static_files/main_test.py deleted file mode 100644 index 2662db44201..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/static_files/noxfile_config.py b/appengine/flexible_python37_and_earlier/static_files/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/static_files/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/static_files/requirements-test.txt b/appengine/flexible_python37_and_earlier/static_files/requirements-test.txt deleted file mode 100644 index 15d066af319..00000000000 --- a/appengine/flexible_python37_and_earlier/static_files/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.2.0 diff --git a/appengine/flexible_python37_and_earlier/static_files/requirements.txt b/appengine/flexible_python37_and_earlier/static_files/requirements.txt deleted file mode 100644 index 70ecce34b5b..00000000000 --- a/appengine/flexible_python37_and_earlier/static_files/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.0.3; python_version < '3.7' -gunicorn==23.0.0 -Werkzeug==3.0.3 diff --git a/appengine/flexible_python37_and_earlier/static_files/static/main.css b/appengine/flexible_python37_and_earlier/static_files/static/main.css deleted file mode 100644 index f906044f4e4..00000000000 --- a/appengine/flexible_python37_and_earlier/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_python37_and_earlier/static_files/templates/index.html b/appengine/flexible_python37_and_earlier/static_files/templates/index.html deleted file mode 100644 index 13b2ebe61af..00000000000 --- a/appengine/flexible_python37_and_earlier/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. -#} - - - - Static Files - - - - -

    This is a static file serving example.

    - - diff --git a/appengine/flexible_python37_and_earlier/twilio/README.md b/appengine/flexible_python37_and_earlier/twilio/README.md deleted file mode 100644 index 9a62b8400b5..00000000000 --- a/appengine/flexible_python37_and_earlier/twilio/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# 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_python37_and_earlier/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-account-sid] - $ export TWILIO_AUTH_TOKEN=[your-twilio-auth-token] - $ export TWILIO_NUMBER=[your-twilio-number] - $ python main.py diff --git a/appengine/flexible_python37_and_earlier/twilio/app.yaml b/appengine/flexible_python37_and_earlier/twilio/app.yaml deleted file mode 100644 index 0e7de97eb19..00000000000 --- a/appengine/flexible_python37_and_earlier/twilio/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. - -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_python37_and_earlier/twilio/main.py b/appengine/flexible_python37_and_earlier/twilio/main.py deleted file mode 100644 index 6f2a3a6830f..00000000000 --- a/appengine/flexible_python37_and_earlier/twilio/main.py +++ /dev/null @@ -1,96 +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 - -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 = f"Hello, {sender}, you said: {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_python37_and_earlier/twilio/main_test.py b/appengine/flexible_python37_and_earlier/twilio/main_test.py deleted file mode 100644 index 4878384f65a..00000000000 --- a/appengine/flexible_python37_and_earlier/twilio/main_test.py +++ /dev/null @@ -1,75 +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("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_python37_and_earlier/twilio/noxfile_config.py b/appengine/flexible_python37_and_earlier/twilio/noxfile_config.py deleted file mode 100644 index 1665dd736f8..00000000000 --- a/appengine/flexible_python37_and_earlier/twilio/noxfile_config.py +++ /dev/null @@ -1,39 +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. - # Skipping for Python 3.9 due to pyarrow compilation failure. - "ignored_versions": ["2.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"], - # 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_python37_and_earlier/twilio/requirements-test.txt b/appengine/flexible_python37_and_earlier/twilio/requirements-test.txt deleted file mode 100644 index e89f6031ad7..00000000000 --- a/appengine/flexible_python37_and_earlier/twilio/requirements-test.txt +++ /dev/null @@ -1,3 +0,0 @@ -pytest==8.2.0 -responses==0.17.0; python_version < '3.7' -responses==0.23.1; python_version > '3.6' diff --git a/appengine/flexible_python37_and_earlier/twilio/requirements.txt b/appengine/flexible_python37_and_earlier/twilio/requirements.txt deleted file mode 100644 index cfa80d12edf..00000000000 --- a/appengine/flexible_python37_and_earlier/twilio/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -Flask==3.0.3; python_version > '3.6' -Flask==2.0.3; python_version < '3.7' -gunicorn==23.0.0 -twilio==9.0.3 -Werkzeug==3.0.3; python_version >= '3.7' -Werkzeug==2.3.8; python_version < '3.7' From 48525437cc52d6fffc783122bbac724da6abbf90 Mon Sep 17 00:00:00 2001 From: David del Real Sifuentes Date: Wed, 18 Feb 2026 23:22:45 +0000 Subject: [PATCH 2/2] Remove reference to python 3.7 earlier samples from README.md file --- appengine/flexible/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/appengine/flexible/README.md b/appengine/flexible/README.md index 0cc851a437e..8f6a03a894f 100644 --- a/appengine/flexible/README.md +++ b/appengine/flexible/README.md @@ -7,8 +7,6 @@ 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.