├── noncloud
└── python
│ ├── sheets
│ ├── Procfile
│ ├── requirements.txt
│ ├── app.yaml
│ ├── templates
│ │ └── index.html
│ ├── .gcloudignore
│ ├── noxfile.py
│ ├── main.py
│ ├── test_sheets.py
│ └── README.md
│ ├── maps
│ ├── requirements.txt
│ ├── Procfile
│ ├── app.yaml
│ ├── .dockerignore
│ ├── settings-tmpl.py
│ ├── app2.yaml
│ ├── templates
│ │ ├── index.html-orig
│ │ └── index.html
│ ├── .gcloudignore
│ ├── noxfile.py
│ ├── main.py
│ ├── test_mapsgeo.py
│ └── README.md
│ └── README.md
├── cloud
├── python
│ ├── Procfile
│ ├── requirements.txt
│ ├── Dockerfile
│ ├── .dockerignore
│ ├── templates
│ │ └── index.html
│ ├── app.yaml
│ ├── appengine_config.py
│ ├── .gcloudignore
│ ├── noxfile.py
│ ├── test_translate.py
│ ├── main.py
│ └── README.md
├── nodejs
│ ├── package.json
│ ├── app.yaml
│ ├── templates
│ │ └── index.html
│ ├── test
│ │ └── test_neb.js
│ ├── .gcloudignore
│ ├── index.js
│ └── README.md
└── README.md
├── .github
└── CODEOWNERS
├── .gitignore
├── CONTRIBUTING.md
├── README.md
└── LICENSE
/noncloud/python/sheets/Procfile:
--------------------------------------------------------------------------------
1 | web: python main.py
2 |
--------------------------------------------------------------------------------
/cloud/python/Procfile:
--------------------------------------------------------------------------------
1 | web: python main.py
2 | #web: gunicorn -b :$PORT -w 2 main:app
3 |
--------------------------------------------------------------------------------
/noncloud/python/maps/requirements.txt:
--------------------------------------------------------------------------------
1 | flask
2 | googlemaps
3 | #requests-toolbelt
4 |
--------------------------------------------------------------------------------
/noncloud/python/maps/Procfile:
--------------------------------------------------------------------------------
1 | web: python main.py
2 | #web: gunicorn -b :$PORT -w 2 main:app
3 |
--------------------------------------------------------------------------------
/noncloud/python/sheets/requirements.txt:
--------------------------------------------------------------------------------
1 | #gunicorn
2 | flask
3 | #google-auth<2.0dev
4 | google-api-python-client #<1.12.0
5 |
--------------------------------------------------------------------------------
/cloud/python/requirements.txt:
--------------------------------------------------------------------------------
1 | #gunicorn>=19.10.0
2 | grpcio<1.40.0; python_version < '3.0'
3 | flask
4 | google-cloud-translate
5 |
--------------------------------------------------------------------------------
/cloud/python/Dockerfile:
--------------------------------------------------------------------------------
1 | #FROM python:3-slim
2 | FROM python:2-slim
3 | WORKDIR /app
4 | COPY requirements.txt .
5 | RUN pip install -r requirements.txt
6 | COPY . .
7 | ENTRYPOINT ["python", "main.py"]
8 | #ENTRYPOINT exec gunicorn -b :$PORT -w 2 main:app
9 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Code owners file.
2 | # This file controls who is tagged for review for any given pull request.
3 | #
4 | # For syntax help see:
5 | # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax
6 |
7 | # The python-samples-owners team is the default owner for anything not
8 | # explicitly taken by someone else.
9 | * @wescpy @GoogleCloudPlatform/python-samples-owners
10 |
--------------------------------------------------------------------------------
/cloud/nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloud-nebulous-serverless-nodejs",
3 | "version": "0.0.1",
4 | "description": "Nebulous Serverless sample app",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node index.js",
8 | "test": "mocha test/test_neb.js"
9 | },
10 | "author": "Google LLC",
11 | "license": "Apache-2.0",
12 | "dependencies": {
13 | "@google-cloud/translate": "^6.3.1",
14 | "express": "^4.17.1",
15 | "nunjucks": "^3.2.3"
16 | },
17 | "devDependencies": {
18 | "mocha": "^9.1.3",
19 | "supertest": "^6.1.6"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/cloud/nodejs/app.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | runtime: nodejs16
16 |
--------------------------------------------------------------------------------
/noncloud/python/maps/app.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | runtime: python39
16 |
--------------------------------------------------------------------------------
/noncloud/python/sheets/app.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | runtime: python39
16 |
--------------------------------------------------------------------------------
/cloud/python/.dockerignore:
--------------------------------------------------------------------------------
1 | .gcloudignore
2 |
3 | # Source code control files
4 | .git/
5 | .gitignore
6 | .hgignore
7 | .hg/
8 |
9 | # Python
10 | *.py[cod]
11 | __pycache__/
12 | /setup.cfg
13 |
14 | # README/text files
15 | LICENSE
16 | *.md
17 |
18 | # Installer logs
19 | pip-log.txt
20 |
21 | # Tests/results
22 | .nox/
23 | .pytest_cache/
24 | noxfile.py
25 | test_translate.py
26 | .coverage
27 | coverage.xml
28 | *sponge_log.xml
29 | system_tests/local_test_setup
30 | pylintrc
31 | pylintrc.test
32 |
33 | # Mac
34 | .DS_Store
35 |
36 | # IDEs/editors
37 | *.sw[op]
38 | *~
39 | .vscode
40 | .idea
41 |
42 | # Built documentation
43 | docs/_build
44 | docs.metadata
45 |
46 | # Virtual environment
47 | env/
48 |
--------------------------------------------------------------------------------
/noncloud/python/README.md:
--------------------------------------------------------------------------------
1 | # Nebulous serverless apps demonstrating use of non-Cloud Google APIs
2 | ### Python (2 and 3) versions
3 |
4 | These apps are Python 2 and 3 compatible, deployable to all Cloud serverless platforms like the other sample apps in this repo. The featured APIs/apps and code are linked below. Also see the [Cloud API Python sample in the other folder](../cloud/python) featuring more complete coverage.
5 |
6 |
7 | ## Sample apps
8 |
9 | Featured API | Codelab link | Description
10 | --- | --- | ---
11 | [Google Sheets API](sheets) | _TBD_ | read display student information a public spreadsheet
12 | [Google Maps Geocoding API](maps) | _TBD_ | use of Maps Geocoding API to get location information
13 |
--------------------------------------------------------------------------------
/noncloud/python/maps/.dockerignore:
--------------------------------------------------------------------------------
1 | .gcloudignore
2 |
3 | # Source code control files
4 | .git/
5 | .gitignore
6 | .hgignore
7 | .hg/
8 |
9 | # Python
10 | *.py[cod]
11 | __pycache__/
12 | /setup.cfg
13 | settings.py
14 |
15 | # README/text files
16 | LICENSE
17 | *.md
18 |
19 | # Installer logs
20 | pip-log.txt
21 |
22 | # Tests/results
23 | .nox/
24 | .pytest_cache/
25 | noxfile.py
26 | test_*.py
27 | .coverage
28 | coverage.xml
29 | *sponge_log.xml
30 | system_tests/local_test_setup
31 | pylintrc
32 | pylintrc.test
33 |
34 | # Mac
35 | .DS_Store
36 |
37 | # IDEs/editors
38 | *.sw[op]
39 | *~
40 | .vscode
41 | .idea
42 |
43 | # Built documentation
44 | docs/_build
45 | docs.metadata
46 |
47 | # Virtual environment
48 | env/
49 |
--------------------------------------------------------------------------------
/cloud/nodejs/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
My Google Translate 1990s
3 |
9 | My Google Translate (1990s edition)
10 |
11 | {% if trans['text'] %}
12 | Previous translation
13 | Original: {{ orig['text'] }} ({{ orig['lc'][0] }})
14 | Translated: {{ trans['text'] }} ({{ trans['lc'][0] }})
15 | {% endif %}
16 |
17 | Enter {{ orig['lc'][1] }} text to translate to {{ trans['lc'][1] }}:
18 |
19 |
20 |
--------------------------------------------------------------------------------
/cloud/python/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 | My Google Translate 1990s
3 |
9 | My Google Translate (1990s edition)
10 |
11 | {% if trans['text'] %}
12 | Previous translation
13 | Original: {{ orig['text'] }} ({{ orig['lc'][0] }})
14 | Translated: {{ trans['text'] }} ({{ trans['lc'][0] }})
15 | {% endif %}
16 |
17 | Enter {{ orig['lc'][1] }} text to translate to {{ trans['lc'][1] }}:
18 |
19 |
20 |
--------------------------------------------------------------------------------
/noncloud/python/maps/settings-tmpl.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the 'License');
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an 'AS IS' BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | API_KEY = 'YOUR_API_KEY' # see developers.google.com/maps/documentation/javascript/get-api-key
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Python
2 | *.py[cod]
3 | __pycache__/
4 | /setup.cfg
5 | settings.py
6 |
7 | # JavaScript/Node.js
8 | node_modules*
9 | package-lock.json
10 |
11 | # C extensions
12 | *.so
13 |
14 | # Packages
15 | *.egg
16 | *.egg-info
17 | dist
18 | build
19 | eggs
20 | .eggs
21 | parts
22 | bin
23 | var
24 | sdist
25 | develop-eggs
26 | .installed.cfg
27 | lib
28 | lib64
29 |
30 | # Installer logs
31 | pip-log.txt
32 |
33 | # Tests/results
34 | .nox/
35 | .pytest_cache/
36 | .cache
37 | .pytype
38 | .coverage
39 | coverage.xml
40 | *sponge_log.xml
41 | system_tests/local_test_setup
42 | credentials.json
43 |
44 | # Mac
45 | .DS_Store
46 |
47 | # IDEs/editors
48 | *.sw[op]
49 | *~
50 | .vscode
51 | .idea
52 |
53 | # Built documentation
54 | docs/_build
55 | docs.metadata
56 |
57 | # Virtual environment
58 | env/
59 |
--------------------------------------------------------------------------------
/noncloud/python/sheets/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 | Student Information
3 |
14 | Student Information
15 |
16 |
17 |
18 | |
19 | #
20 | |
21 | {% for col in headers %}
22 |
23 | {{ col }}
24 | |
25 | {% endfor %}
26 |
27 |
28 | {% for student in students %}
29 |
30 | |
31 | {{ loop.index }}
32 | |
33 | {% for col in student %}
34 |
35 | {{ col }}
36 | |
37 | {% endfor %}
38 |
39 | {% endfor %}
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/noncloud/python/maps/app2.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | runtime: python27
16 | threadsafe: yes
17 | api_version: 1
18 |
19 | handlers:
20 | - url: /.*
21 | script: main.app
22 |
23 | libraries:
24 | - name: setuptools
25 | version: latest
26 |
27 | - name: ssl
28 | version: latest
29 |
--------------------------------------------------------------------------------
/cloud/python/app.yaml:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | #runtime: python310
16 | runtime: python27
17 | threadsafe: yes
18 | api_version: 1
19 |
20 | handlers:
21 | - url: /.*
22 | script: main.app
23 |
24 | libraries:
25 | - name: grpcio
26 | version: latest
27 | - name: setuptools
28 | version: latest
29 |
--------------------------------------------------------------------------------
/cloud/python/appengine_config.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import pkg_resources
16 | from google.appengine.ext import vendor
17 |
18 | # Set PATH to your libraries folder.
19 | PATH = 'lib'
20 | # Add libraries installed in the PATH folder.
21 | vendor.add(PATH)
22 | # Add libraries to pkg_resources working set to find the distribution.
23 | pkg_resources.working_set.add_entry(PATH)
24 |
--------------------------------------------------------------------------------
/noncloud/python/maps/templates/index.html-orig:
--------------------------------------------------------------------------------
1 |
2 | Street address geocoder
3 |
14 | Street address geocoder
15 |
16 | {% if address %}
17 | Previous address information:
18 | Address: {{ address }}
19 | {% if latlong %}
20 | Complete address: {{ full_addr }}
21 | Geocode location: {{ latlong }} (view in Google Maps)
23 | {% endif %}
24 | {% endif %}
25 |
26 | Enter street address for its geocode:
27 |
31 |
32 |
--------------------------------------------------------------------------------
/noncloud/python/maps/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 | Street address geocoder
3 |
14 | Street address geocoder
15 |
16 | {% if results %}
17 | Location information for "{{ address }}":
18 | {% for loc in results %}
19 | {% if loc['latlong'] %}
20 | Complete address: {{ loc['full_addr'] }}
21 | Geocode location: {{ loc['latlong'] }} (view in Google Maps)
23 |
24 | {% endif %}
25 | {% endfor %}
26 | {% else %}
27 | No location found for "{{ address }}"
28 | {% endif %}
29 |
30 | Enter another street address for its geocode:
31 |
35 |
36 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to Contribute
2 |
3 | We'd love to accept your patches and contributions to this project. There are
4 | just a few small guidelines you need to follow.
5 |
6 | ## Contributor License Agreement
7 |
8 | Contributions to this project must be accompanied by a Contributor License
9 | Agreement. You (or your employer) retain the copyright to your contribution;
10 | this simply gives us permission to use and redistribute your contributions as
11 | part of the project. Head over to to see
12 | your current agreements on file or to sign a new one.
13 |
14 | You generally only need to submit a CLA once, so if you've already submitted one
15 | (even if it was for a different project), you probably don't need to do it
16 | again.
17 |
18 | ## Code reviews
19 |
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose. Consult
22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
23 | information on using pull requests.
24 |
25 | ## Community Guidelines
26 |
27 | This project follows [Google's Open Source Community
28 | Guidelines](https://opensource.google/conduct/).
29 |
--------------------------------------------------------------------------------
/cloud/nodejs/test/test_neb.js:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | const request = require('supertest');
16 | const app = require('../index');
17 | const request_app = request(app);
18 |
19 | describe('Unit Tests', () => {
20 |
21 | it('GET / should result in HTML w/"translate" in the body', done => {
22 | request_app
23 | .get('/')
24 | .expect(/translate/)
25 | .expect(200, done)
26 | });
27 |
28 | it('POST / should have translated "hello world" correctly', done => {
29 | const SOURCE = 'hello world';
30 | request_app
31 | .post('/')
32 | .send(`text=${SOURCE}`)
33 | .expect(/Hola Mundo/)
34 | .expect(200, done)
35 | });
36 |
37 | after(() =>
38 | console.log('DONE')
39 | );
40 |
41 | });
42 |
--------------------------------------------------------------------------------
/cloud/nodejs/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 |
11 | # JavaScript/Node.js
12 | node_modules/
13 | test/
14 | #package-lock.json
15 |
16 | # Source code control files
17 | .git/
18 | .gitignore
19 | .hgignore
20 | .hg/
21 |
22 | # README/text files
23 | *.md
24 |
25 | # Python
26 | *.py[cod]
27 | __pycache__/
28 | /setup.cfg
29 |
30 | # C extensions
31 | *.so
32 |
33 | # Packages
34 | *.egg
35 | *.egg-info
36 | dist
37 | build
38 | eggs
39 | .eggs
40 | parts
41 | bin
42 | var
43 | sdist
44 | develop-eggs
45 | .installed.cfg
46 | lib64
47 |
48 | # Installer logs
49 | pip-log.txt
50 |
51 | # Tests/results
52 | .nox/
53 | .pytest_cache/
54 | noxfile.py
55 | test_translate.py
56 | .cache
57 | .pytype
58 | .coverage
59 | coverage.xml
60 | *sponge_log.xml
61 | system_tests/local_test_setup
62 | pylintrc
63 | pylintrc.test
64 | test/
65 | credentials.json
66 |
67 | # Mac
68 | .DS_Store
69 |
70 | # IDEs/editors
71 | *.sw[op]
72 | *~
73 | .vscode
74 | .idea
75 |
76 | # Built documentation
77 | docs/_build
78 | docs.metadata
79 |
80 | # Virtual environment
81 | env/
82 |
--------------------------------------------------------------------------------
/cloud/python/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 | .dockerignore
11 | .gitignore
12 |
13 | # Source code control files
14 | .git/
15 | .gitignore
16 | .hgignore
17 | .hg/
18 |
19 | # README/text files
20 | LICENSE
21 | *.md
22 |
23 | # Tests/results (not in .gitignore)
24 | noxfile.py
25 | test_translate.py
26 | pylintrc
27 | pylintrc.test
28 |
29 | # most of .gitignore (except `lib`)
30 | #
31 | # Python
32 | *.py[cod]
33 | __pycache__/
34 | /setup.cfg
35 |
36 | # C extensions
37 | *.so
38 |
39 | # Packages
40 | *.egg
41 | *.egg-info
42 | dist
43 | build
44 | eggs
45 | .eggs
46 | parts
47 | bin
48 | var
49 | sdist
50 | develop-eggs
51 | .installed.cfg
52 | lib64
53 |
54 | # Installer logs
55 | pip-log.txt
56 |
57 | # Tests/results
58 | .nox/
59 | .pytest_cache/
60 | .cache
61 | .pytype
62 | .coverage
63 | coverage.xml
64 | *sponge_log.xml
65 | system_tests/local_test_setup
66 |
67 | # Mac
68 | .DS_Store
69 |
70 | # IDEs/editors
71 | *.sw[op]
72 | *~
73 | .vscode
74 | .idea
75 |
76 | # Built documentation
77 | docs/_build
78 | docs.metadata
79 |
80 | # Virtual environment
81 | env/
82 |
--------------------------------------------------------------------------------
/noncloud/python/sheets/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 | .dockerignore
11 | .gitignore
12 |
13 | # Source code control files
14 | .git/
15 | .gitignore
16 | .hgignore
17 | .hg/
18 |
19 | # README/text files
20 | LICENSE
21 | *.md
22 |
23 | # Tests/results (not in .gitignore)
24 | noxfile.py
25 | test_translate.py
26 | pylintrc
27 | pylintrc.test
28 |
29 | # most of .gitignore (except `lib`)
30 | #
31 | # Python
32 | *.py[cod]
33 | __pycache__/
34 | /setup.cfg
35 |
36 | # C extensions
37 | *.so
38 |
39 | # Packages
40 | *.egg
41 | *.egg-info
42 | dist
43 | build
44 | eggs
45 | .eggs
46 | parts
47 | bin
48 | var
49 | sdist
50 | develop-eggs
51 | .installed.cfg
52 | lib64
53 |
54 | # Installer logs
55 | pip-log.txt
56 |
57 | # Tests/results
58 | .nox/
59 | .pytest_cache/
60 | .cache
61 | .pytype
62 | .coverage
63 | coverage.xml
64 | *sponge_log.xml
65 | system_tests/local_test_setup
66 |
67 | # Mac
68 | .DS_Store
69 |
70 | # IDEs/editors
71 | *.sw[op]
72 | *~
73 | .vscode
74 | .idea
75 |
76 | # Built documentation
77 | docs/_build
78 | docs.metadata
79 |
80 | # Virtual environment
81 | env/
82 |
--------------------------------------------------------------------------------
/noncloud/python/maps/.gcloudignore:
--------------------------------------------------------------------------------
1 | # This file specifies files that are *not* uploaded to Google Cloud Platform
2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of
3 | # "#!include" directives (which insert the entries of the given .gitignore-style
4 | # file at that point).
5 | #
6 | # For more information, run:
7 | # $ gcloud topic gcloudignore
8 | #
9 | .gcloudignore
10 | .dockerignore
11 | .gitignore
12 |
13 | # Source code control files
14 | .git/
15 | .gitignore
16 | .hgignore
17 | .hg/
18 |
19 | # README/text files
20 | LICENSE
21 | *.md
22 |
23 | # Tests/results (not in .gitignore)
24 | noxfile.py
25 | test_translate.py
26 | pylintrc
27 | pylintrc.test
28 |
29 | # most of .gitignore (except `lib`)
30 | #
31 | # Python
32 | *.py[cod]
33 | __pycache__/
34 | /setup.cfg
35 | #settings.py
36 |
37 | # C extensions
38 | *.so
39 |
40 | # Packages
41 | *.egg
42 | *.egg-info
43 | dist
44 | build
45 | eggs
46 | .eggs
47 | parts
48 | bin
49 | var
50 | sdist
51 | develop-eggs
52 | .installed.cfg
53 | lib64
54 |
55 | # Installer logs
56 | pip-log.txt
57 |
58 | # Tests/results
59 | .nox/
60 | .pytest_cache/
61 | .cache
62 | .pytype
63 | .coverage
64 | coverage.xml
65 | *sponge_log.xml
66 | system_tests/local_test_setup
67 |
68 | # Mac
69 | .DS_Store
70 |
71 | # IDEs/editors
72 | *.sw[op]
73 | *~
74 | .vscode
75 | .idea
76 |
77 | # Built documentation
78 | docs/_build
79 | docs.metadata
80 |
81 | # Virtual environment
82 | env/
83 |
--------------------------------------------------------------------------------
/noncloud/python/maps/noxfile.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the 'License');
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an 'AS IS' BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import nox
16 |
17 | FLAKE8_COMMON_ARGS = [
18 | '--show-source',
19 | '--builtin=gettext',
20 | '--max-complexity=20',
21 | '--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py',
22 | '--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202',
23 | '--max-line-length=88',
24 | '.',
25 | ]
26 |
27 |
28 | @nox.session(python=['2.7', '3.8', '3.9'])
29 | def tests(session):
30 | """
31 | nox test session
32 | """
33 | session.install('pytest', 'blinker', 'flask', 'googlemaps')
34 | session.run('pytest')
35 |
36 |
37 | @nox.session(python=['2.7', '3.8', '3.9'])
38 | def lint(session):
39 | """
40 | nox lint session
41 | """
42 | session.install('flake8')
43 | args = FLAKE8_COMMON_ARGS
44 | session.run('flake8', *args)
45 |
--------------------------------------------------------------------------------
/cloud/python/noxfile.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the 'License');
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an 'AS IS' BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import nox
16 |
17 | FLAKE8_COMMON_ARGS = [
18 | '--show-source',
19 | '--builtin=gettext',
20 | '--max-complexity=20',
21 | '--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py',
22 | '--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202',
23 | '--max-line-length=88',
24 | '.',
25 | ]
26 |
27 |
28 | @nox.session(python=['2.7', '3.6', '3.9'])
29 | def tests(session):
30 | """
31 | nox test session
32 | """
33 | session.install('pytest', 'blinker', 'flask', 'google-cloud-translate')
34 | session.run('pytest')
35 |
36 |
37 | @nox.session(python=['2.7', '3.6', '3.9'])
38 | def lint(session):
39 | """
40 | nox lint session
41 | """
42 | session.install('flake8')
43 | args = FLAKE8_COMMON_ARGS
44 | session.run('flake8', *args)
45 |
--------------------------------------------------------------------------------
/noncloud/python/sheets/noxfile.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the 'License');
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an 'AS IS' BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | import nox
16 |
17 | FLAKE8_COMMON_ARGS = [
18 | '--show-source',
19 | '--builtin=gettext',
20 | '--max-complexity=20',
21 | '--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py',
22 | '--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202',
23 | '--max-line-length=88',
24 | '.',
25 | ]
26 |
27 |
28 | @nox.session(python=['2.7', '3.8', '3.9'])
29 | def tests(session):
30 | """
31 | nox test session
32 | """
33 | session.install('pytest', 'blinker', 'flask', 'google-auth', 'google-api-python-client')
34 | session.run('pytest')
35 |
36 |
37 | @nox.session(python=['2.7', '3.8', '3.9'])
38 | def lint(session):
39 | """
40 | nox lint session
41 | """
42 | session.install('flake8')
43 | args = FLAKE8_COMMON_ARGS
44 | session.run('flake8', *args)
45 |
--------------------------------------------------------------------------------
/noncloud/python/sheets/main.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from flask import Flask, render_template
16 | import google.auth
17 | from googleapiclient import discovery
18 |
19 | app = Flask(__name__)
20 |
21 | # Use service account; can switch to OAuth client ID if desired
22 | CREDS, _PROJECT_ID = google.auth.default()
23 | SHEETS = discovery.build('sheets', 'v4', credentials=CREDS)
24 |
25 | # Quickstart Sheet: developers.google.com/sheets/api/quickstart/python
26 | SHEET_ID = '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms'
27 |
28 |
29 | @app.route('/')
30 | def students(_req=None):
31 | """
32 | read spreadsheet data and render in template
33 | """
34 |
35 | # read data from Google Sheet
36 | rows = SHEETS.spreadsheets().values().get(
37 | spreadsheetId=SHEET_ID,
38 | range='Class Data',
39 | fields='values'
40 | ).execute().get('values', ['(no data)'])
41 |
42 | # create context & render template
43 | context = {'headers': rows[0], 'students': rows[1:]}
44 | return render_template('index.html', **context)
45 |
46 |
47 | if __name__ == '__main__':
48 | import os
49 | app.run(debug=True, threaded=True, host='0.0.0.0',
50 | port=int(os.environ.get('PORT', 8080)))
51 |
--------------------------------------------------------------------------------
/noncloud/python/sheets/test_sheets.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from contextlib import contextmanager
16 |
17 | from flask import template_rendered
18 | import pytest
19 |
20 | from main import app as flask_app
21 |
22 |
23 | @pytest.fixture
24 | def app():
25 | """
26 | fixture connecting Flask app
27 | """
28 | yield flask_app
29 |
30 |
31 | @contextmanager
32 | def captured_templates(app):
33 | """
34 | capture template render requests
35 | """
36 | recorded = []
37 |
38 | def record(sender, template, context, **extra):
39 | recorded.append((template, context))
40 |
41 | template_rendered.connect(record, app)
42 | try:
43 | yield recorded
44 | finally:
45 | template_rendered.disconnect(record, app)
46 |
47 |
48 | def test_sheets_get(app):
49 | """
50 | test GET request to main application
51 | """
52 | with captured_templates(app) as templates:
53 | rv = app.test_client().get('/')
54 | assert rv.status_code == 200
55 | assert len(templates) == 1
56 | template, context = templates[0]
57 | assert template.name == 'index.html'
58 | assert 'headers' in context and 'students' in context
59 | assert context['headers'][0] == 'Student Name'
60 |
--------------------------------------------------------------------------------
/noncloud/python/maps/main.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from flask import Flask, render_template, request
16 | import googlemaps
17 | from settings import API_KEY
18 |
19 | app = Flask(__name__)
20 | GMAPS = googlemaps.Client(key=API_KEY)
21 | ADDRESS = '1600 Amphitheatre Pkwy 94043'
22 |
23 |
24 | @app.route('/', methods=['GET', 'POST'])
25 | def mapsgeo(gcf_request=None):
26 | """
27 | main handler - show form and possibly previous translation
28 | """
29 |
30 | # Flask Request object passed in for Cloud Functions
31 | # (use gcf_request for GCF but flask.request otherwise)
32 | local_request = gcf_request if gcf_request else request
33 |
34 | # reset all variables (GET)
35 | address = ADDRESS
36 | results = []
37 |
38 | # form submission and if there is data to process (POST)
39 | if local_request.method == 'POST':
40 | address = local_request.form['address'].strip()
41 | if not address:
42 | address = ADDRESS
43 | rsp = GMAPS.geocode(address)
44 | if rsp:
45 | for data in rsp:
46 | if 'geometry' in data and 'location' in data['geometry']:
47 | geocode = data['geometry']['location']
48 | results.append({
49 | 'full_addr': data['formatted_address'],
50 | 'latlong': '%s, %s' % (geocode['lat'], geocode['lng']),
51 | })
52 |
53 | # create context & render template
54 | context = {'address': address, 'results': results}
55 | return render_template('index.html', **context)
56 |
57 |
58 | if __name__ == '__main__':
59 | import os
60 | app.run(debug=True, threaded=True, host='0.0.0.0',
61 | port=int(os.environ.get('PORT', 8080)))
62 |
--------------------------------------------------------------------------------
/cloud/nodejs/index.js:
--------------------------------------------------------------------------------
1 | // Copyright 2021 Google LLC
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // https://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | const express = require('express');
16 | const nunjucks = require('nunjucks');
17 | const {TranslationServiceClient} = require('@google-cloud/translate');
18 |
19 | const app = express();
20 | app.use(express.urlencoded({extended: true}));
21 | nunjucks.configure('templates', {autoescape: true, express: app});
22 | const TRANSLATE = new TranslationServiceClient();
23 |
24 | const PORT = process.env.PORT || 8080;
25 | const SOURCE = ['en', 'English'];
26 | const TARGET = ['es', 'Spanish'];
27 | let parent;
28 | TRANSLATE.getProjectId().then(result => {
29 | parent = `projects/${result}`;
30 | });
31 |
32 |
33 | if (!process.env.FUNCTION_TARGET) {
34 | app.listen(PORT, () =>
35 | console.log(`Listening on port ${PORT}`)
36 | );
37 | }
38 |
39 | /**
40 | * main handler - show form and possibly previous translation
41 | */
42 | async function translate(req, rsp) {
43 | // reset all variables (GET/POST)
44 | let text = null;
45 | let translated = null;
46 |
47 | // form submission and if there is data to process (POST)
48 | if (req.method === 'POST') {
49 | text = req.body.text.trim();
50 | if (text) {
51 | const data = {
52 | contents: [text],
53 | parent: parent,
54 | targetLanguageCode: TARGET[0]
55 | };
56 | const [response] = await TRANSLATE.translateText(data);
57 | translated = response.translations[0].translatedText;
58 | }
59 | }
60 |
61 | // create context & render template
62 | const context = {
63 | orig: {text: text, lc: SOURCE},
64 | trans: {text: translated, lc: TARGET}
65 | };
66 | rsp.render('index.html', context);
67 | }
68 |
69 | app.all('/', translate);
70 | module.exports = {
71 | app
72 | };
73 |
--------------------------------------------------------------------------------
/cloud/python/test_translate.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from contextlib import contextmanager
16 |
17 | from flask import template_rendered
18 | import pytest
19 |
20 | from main import app as flask_app
21 |
22 |
23 | @pytest.fixture
24 | def app():
25 | """
26 | fixture connecting Flask app
27 | """
28 | yield flask_app
29 |
30 |
31 | @contextmanager
32 | def captured_templates(app):
33 | """
34 | capture template render requests
35 | """
36 | recorded = []
37 |
38 | def record(sender, template, context, **extra):
39 | recorded.append((template, context))
40 |
41 | template_rendered.connect(record, app)
42 | try:
43 | yield recorded
44 | finally:
45 | template_rendered.disconnect(record, app)
46 |
47 |
48 | def test_translate_get(app):
49 | """
50 | test GET request to main application
51 | """
52 | with captured_templates(app) as templates:
53 | rv = app.test_client().get('/')
54 | assert rv.status_code == 200
55 | assert len(templates) == 1
56 | template, context = templates[0]
57 | assert template.name == 'index.html'
58 | assert 'orig' in context and 'trans' in context
59 | assert len(context['orig']) == len(context['trans']) == 2
60 |
61 |
62 | def test_translate_post(app):
63 | """
64 | test POST request to main application
65 | """
66 | SOURCE, TARGET = 'hello world', 'Hola Mundo'
67 | with captured_templates(app) as templates:
68 | rv = app.test_client().post('/', data={'text': SOURCE})
69 | assert rv.status_code == 200
70 | assert len(templates) == 1
71 | template, context = templates[0]
72 | assert template.name == 'index.html'
73 | assert 'orig' in context and 'trans' in context
74 | assert context['orig']['text'] == SOURCE
75 | assert context['trans']['text'] == TARGET
76 |
--------------------------------------------------------------------------------
/cloud/python/main.py:
--------------------------------------------------------------------------------
1 | # Copyright 2021 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from flask import Flask, render_template, request
16 | import google.auth
17 | from google.cloud import translate
18 |
19 | app = Flask(__name__)
20 | _, PROJECT_ID = google.auth.default()
21 | TRANSLATE = translate.TranslationServiceClient()
22 | PARENT = 'projects/{}'.format(PROJECT_ID)
23 | SOURCE, TARGET = ('en', 'English'), ('es', 'Spanish')
24 |
25 |
26 | @app.route('/', methods=['GET', 'POST'])
27 | def translate(gcf_request=None):
28 | """
29 | main handler - show form and possibly previous translation
30 | """
31 |
32 | # Flask Request object passed in for Cloud Functions
33 | # (use gcf_request for GCF but flask.request otherwise)
34 | local_request = gcf_request if gcf_request else request
35 |
36 | # reset all variables (GET/POST)
37 | text = translated = None
38 |
39 | # form submission and if there is data to process (POST)
40 | if local_request.method == 'POST':
41 | text = local_request.form['text'].strip()
42 | if text:
43 | data = {
44 | 'contents': [text],
45 | 'parent': PARENT,
46 | 'target_language_code': TARGET[0],
47 | }
48 | # handle older call for backwards-compatibility
49 | try:
50 | rsp = TRANSLATE.translate_text(request=data)
51 | except TypeError:
52 | rsp = TRANSLATE.translate_text(**data)
53 | translated = rsp.translations[0].translated_text
54 |
55 | # create context & render template
56 | context = {
57 | 'orig': {'text': text, 'lc': SOURCE},
58 | 'trans': {'text': translated, 'lc': TARGET},
59 | }
60 | return render_template('index.html', **context)
61 |
62 |
63 | if __name__ == '__main__':
64 | import os
65 | app.run(debug=True, threaded=True, host='0.0.0.0',
66 | port=int(os.environ.get('PORT', 8080)))
67 |
--------------------------------------------------------------------------------
/noncloud/python/maps/test_mapsgeo.py:
--------------------------------------------------------------------------------
1 | # Copyright 2022 Google LLC
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | from contextlib import contextmanager
16 |
17 | from flask import template_rendered
18 | import pytest
19 |
20 | from main import ADDRESS, app as flask_app
21 | BAD_ADDR = '1 ave 90000'
22 | MLT_ADDR = 'york' # (1-10), 'springfield' (1-10), 'dakota' (1-2)
23 |
24 |
25 | @pytest.fixture
26 | def app():
27 | """
28 | fixture connecting Flask app
29 | """
30 | yield flask_app
31 |
32 |
33 | @contextmanager
34 | def captured_templates(app):
35 | """
36 | capture template render requests
37 | """
38 | recorded = []
39 |
40 | def record(sender, template, context, **extra):
41 | recorded.append((template, context))
42 |
43 | template_rendered.connect(record, app)
44 | try:
45 | yield recorded
46 | finally:
47 | template_rendered.disconnect(record, app)
48 |
49 |
50 | def test_mapsgeo_get(app):
51 | """
52 | test GET request to main application
53 | """
54 | with captured_templates(app) as templates:
55 | rv = app.test_client().get('/')
56 | assert rv.status_code == 200
57 | assert len(templates) == 1
58 | template, context = templates[0]
59 | assert template.name == 'index.html'
60 | assert len(context['address']) > 1 and len(context['results']) == 0
61 |
62 |
63 | def test_mapsgeo_post(app):
64 | """
65 | test POST request to main application
66 | """
67 | with captured_templates(app) as templates:
68 | rv = app.test_client().post('/', data={'address': ADDRESS})
69 | assert rv.status_code == 200
70 | assert len(templates) == 1
71 | template, context = templates[0]
72 | assert 'address' in context and 'results' in context
73 | assert '37.422388, -122.0841883' == context['results'][0]['latlong']
74 |
75 |
76 | def test_mapsgeo_post_fail(app):
77 | """
78 | test POST request to main application
79 | """
80 | with captured_templates(app) as templates:
81 | rv = app.test_client().post('/', data={'address': BAD_ADDR})
82 | assert rv.status_code == 200
83 | assert len(templates) == 1
84 | template, context = templates[0]
85 | assert template.name == 'index.html'
86 | assert 'address' in context and 'results' in context
87 | assert len(context['results']) == 0
88 |
89 |
90 | def test_mapsgeo_post_sometimes_multi(app):
91 | """
92 | test POST request to main application
93 | """
94 | with captured_templates(app) as templates:
95 | rv = app.test_client().post('/', data={'address': MLT_ADDR})
96 | assert rv.status_code == 200
97 | assert len(templates) == 1
98 | template, context = templates[0]
99 | assert 'address' in context and 'results' in context
100 | assert len(context['results']) >= 1
101 |
--------------------------------------------------------------------------------
/cloud/nodejs/README.md:
--------------------------------------------------------------------------------
1 | # Nebulous serverless Cloud Translation API app
2 |
3 | ## Node.js version
4 |
5 | The Node.js version of this app and its deployments are simpler than the [Python equivalent](../python), primarily due to the differences between Python 2 and 3, and also because Node.js is not an App Engine legacy runtime. As a result, there is a single [Node.js codelab](https://codelabs.developers.google.com/codelabs/cloud-nebulous-serverless-nodejs?utm_source=codelabs&utm_medium=et&utm_campaign=CDR_wes_aap-serverless_nebservnodejs_sms_201130&utm_content=-) for deploying this app while there are seven for Python.
6 |
7 |
8 | ## Deployments and their files
9 |
10 | File | Description
11 | --- | ---
12 | [`index.js`](index.js) | main application file
13 | [`templates/index.html`](templates/index.html) | application HTML template
14 | [`package.json`](package.json) | 3rd-party package requirements file
15 | [`app.yaml`](app.yaml) | App Engine configuration file (only for App Engine deployments)
16 | [`test/test_neb.js`](test/test_neb.js) | unit tests (`mocha` & `supertest`)
17 | [`.gcloudignore`](.gcloudignore) | files to exclude deploying to the cloud (administrative)
18 | `README.md` | this file (administrative)
19 |
20 | Below are the required settings and instructions for all (documented) deployments; administrative files are not discussed. The `app.yaml` file is only used for specific deployments and can be deleted for the others.
21 |
22 | > NOTE: Serverless deployments (as configured here) use [default service accounts](https://cloud.google.com/iam/docs/service-accounts#default) which provide a broad set of permissions to assist you in getting a working prototype. When preparing to launch to production, the Google Cloud team recommends the best practice of "least privileges," and instead use [user-managed service accounts](https://cloud.google.com/iam/docs/service-accounts#user-managed) with the minimal set of permissions allowing your app to function properly.
23 |
24 |
25 | ## **Local Express server (Node 10, 17)**
26 |
27 | **TL;DR:** application files (`index.js` & `package.json`). Instructions:
28 |
29 | 1. **Run** `npm install` (to install packages locally)
30 | 1. **Run** `gcloud auth application-default login` to set your credentials
31 | 1. **Run** `npm start` to run locally
32 |
33 |
34 | ## **App Engine (Node 10, 12, 14, 16)**
35 |
36 | **TL;DR:** application files plus `app.yaml`. You may (first) edit `app.yaml` to specify the desired Node version (default: Node 16). Instruction(s):
37 |
38 | 1. **Run** `gcloud app deploy` to deploy to App Engine
39 | - You'll be prompted for the REGION if deploying to App Engine the first time.
40 | - App Engine apps are tied to one region, so it can't be changed once it's set, meaning you won't be prompted thereafter.
41 |
42 |
43 | ## **Cloud Functions (Node 10, 12, 14, 16)**
44 |
45 | **TL;DR:** Uses only the application files. Instruction(s):
46 |
47 | 1. **Run** `gcloud functions deploy translate --runtime nodejs16 --entry-point app --trigger-http --allow-unauthenticated` to deploy to Cloud Functions (or Node 10, 12, 14)
48 | - You'll be prompted for the REGION if deploying a Cloud Function the first time.
49 | - Cloud Functions can be deployed to different regions within a project, but once the region has been set for a function, it cannot be changed.
50 |
51 | The command creates & deploys a new HTTP-triggered Cloud Function named `translate`. Cloud Functions is directed to call the application object, `app`, via `--entry-point`. During execution `translate()` is called by `app`. In the [Python version](../python), `--entry-point` is unnecessary because `translate()` *is* the application entry point.
52 |
53 |
54 | ## **Cloud Run (Node 10+ via Cloud Buildpacks)**
55 |
56 | **TL;DR:** Uses only the application files. Instruction(s):
57 |
58 | 1. **Run** `gcloud run deploy translate --allow-unauthenticated --platform managed --source .` to deploy to Cloud Run
59 | - You'll be prompted to provide a REGION unless you also add `--region REGION` on the cmd-line which will give you a full non-interactive deploy
60 | - A `Dockerfile` is optional, but if you wish to create one, place it in the top-level folder so the build system can access it. Also see the [Python version's `Dockerfile`](../python/Dockerfile) to get an idea of what a Node equivalent would be similar to.
61 |
62 |
63 | ## References
64 |
65 | These are relevant links only to the app in this folder (for all others, see the [README one level up](../README.md):
66 |
67 | - [Node.js App Engine quickstart](https://cloud.google.com/appengine/docs/standard/nodejs/quickstart)
68 | - [Nodejs App Engine (standard environment) runtime](https://cloud.google.com/appengine/docs/standard/nodejs/runtime)
69 | - [Node.js Cloud Functions quickstart](https://cloud.google.com/functions/docs/quickstart-nodejs)
70 | - [Node.js Cloud Run quickstart](https://cloud.google.com/run/docs/quickstarts/build-and-deploy/nodejs)
71 | - [Express.js](https://expressjs.com)
72 |
73 |
74 | ## Testing
75 |
76 | Testing is driven by [`mocha`](https://mochajs.org) which uses [`supertest`](https://github.com/visionmedia/supertest) for testing and [`eslint`](https://eslint.org) for linting, installing both in virtual environments along with application dependencies, `express`, `nunjucks`, and `@google-cloud/translate`. To run the unit tests (testing `GET` and `POST` requests), run `npm install` followed by `npm test`).
77 |
78 |
79 | ### Expected output
80 |
81 | ```
82 | $ npm test
83 |
84 | > cloud-nebulous-serverless-nodejs@0.0.1 test
85 | > mocha test/test_neb.js
86 |
87 | Listening on port 8080
88 |
89 |
90 | Our application
91 | ✔ GET / should result in HTML w/"translate" in the body
92 | ✔ POST / should have translated "hello world" correctly (140ms)
93 | DONE
94 |
95 |
96 | 2 passing (170ms)
97 | ```
98 |
99 | ### Troubleshooting
100 |
101 | When running the test, there's a situation which resulting in the test hanging like this:
102 |
103 | ```
104 | $ npm test
105 |
106 | > cloud-nebulous-serverless-nodejs@0.0.1 test
107 | > mocha test/test_neb.js
108 |
109 | Listening on port 8080
110 |
111 |
112 | Our application
113 | ✔ GET / should result in HTML w/"translate" in the body
114 | 1) POST / should have translated "hello world" correctly
115 | DONE
116 |
117 |
118 | 1 passing (2s)
119 | 1 failing
120 |
121 | 1) Our application
122 | POST / should have translated "hello world" correctly:
123 | Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/tmp/cloud-nebulous-serverless/cloud/nodejs/test/test_neb.js)
124 | at listOnTimeout (node:internal/timers:557:17)
125 | at processTimers (node:internal/timers:500:7)
126 |
127 | ```
128 | *(hangs here)*
129 |
130 | If this happens to you, **run** `gcloud auth application-default login` to set your credentials and try again.
131 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | | :boom: ALERT!! |
2 | |:---------------------------|
3 | | This repo will soon be relocating to [GoogleCloudPlatform](https://github.com/GoogleCloudPlatform) as we better organize these code samples! Stay tuned as more info is coming soon. |
4 |
5 |
6 | # Nebulous Google Cloud serverless & API sample applications
7 | ### Run the same apps locally, on App Engine, Cloud Functions, or Cloud Run
8 |
9 | ## Description
10 |
11 | This is the repo for a set of sample apps and corresponding codelabs (self-paced, hands-on tutorials) demonstrating how to call Google APIs from [Google Cloud serverless compute platforms](https://cloud.google.com/serverless) (App Engine, Cloud Functions, Cloud Run). More on each platform below. Working wth [Cloud APIs](cloud) differs from [non-Cloud Google APIs](noncloud), so that is how the samples are organized. The common aspect of all of sample apps is that they can be run locally or deployed to any of the 3 platforms without code changes (all done in configuration).
12 |
13 |
14 | ## Hosting options
15 |
16 | - **[App Engine](https://cloud.google.com/appengine)** (standard environment) — source-based application deployments (app-hosting in the cloud; "PaaS")
17 | - _App Engine_ is for users who wish to deploy a traditional (but not containerized) web stack (LAMP, MEAN, etc.) application direct from source code.
18 | - **[Cloud Functions](https://cloud.google.com/functions)** — cloud-hosted functions or microservices ("FaaS"), possibly event-driven
19 | - If your app is relatively simple, is a single function, or perhaps some event-driven microservice, _Cloud Functions_ may be the right platform for you.
20 | - **[Cloud Run](https://cloud.run)** — fully-managed serverless container-hosting in the cloud ("CaaS") service
21 | - If your apps are containerized or you have containerization as part of your software development workflow, use _Cloud Run_. Containers free developers from any language, library, or binary restrictions with App Engine or Cloud Functions.
22 |
23 | A "fourth" product, [App Engine flexible environment](https://cloud.google.com/appengine/docs/flexible), which sits somewhere between App Engine standard environment and Cloud Run, is out-of-scope for these sample apps at this time.
24 |
25 | When running on App Engine or Cloud Functions, the Python runtime supplies a default web server (`gunicorn`), but for Node.js, [Express.js](http://expressjs.com) was selected. No default servers are available at all for Cloud Run, so Python developers can either run the [Flask](https://flask.palletsprojects.com) development server (default) or self-bundle `gunicorn` (per your configuration). All Node.js deployments specify Express.js.
26 |
27 |
28 | ## Inspiration and implementation
29 |
30 | These samples were inspired by a [user's suboptimal experience](https://www.mail-archive.com/google-appengine@googlegroups.com/msg94549.html) trying to create a simple App Engine app using a Cloud API. This was followed-up with the realization that there aren't enough examples showing users how to access non-Cloud Google APIs from serverless, hence *those* samples.
31 |
32 | The table below outlines the development languages, supported versions, deployments tested, and selected web frameworks (whose bundled development servers are used for running locally):
33 |
34 | Language | Versions | Deployment | Framework
35 | --- | --- | --- | ---
36 | Python|2.7|local, cloud|Flask
37 | Python|3.6+|local, cloud|Flask
38 | Node.js|10, 17|local|Express.js
39 | Node.js|10, 12, 14, 16|cloud|Express.js
40 |
41 |
42 | ## Cost
43 |
44 | While many Google APIs can be used without fees, use of GCP products & APIs is _not_ free. Certain products do offer an ["Always Free" tier](https://cloud.google.com/free/docs/gcp-free-tier#free-tier-usage-limits) which you have to exceed in order to be billed. Reference any relevant pricing information linked below before doing so.
45 |
46 | - [App Engine](https://cloud.google.com/appengine/pricing)
47 | - [Cloud Functions](https://cloud.google.com/functions/pricing)
48 | - [Cloud Run](https://cloud.google.com/run/pricing)
49 | - [GCP general pricing](https://cloud.google.com/pricing)
50 | - [GCP pricing calculator](https://cloud.google.com/products/calculator)
51 |
52 | When enabling services, you may be asked for an active billing account which requires a financial instrument such as a credit card. Reference relevant pricing information before doing so. While Cloud Functions and Cloud Run share a similar Always Free tier and pricing model, App Engine is slightly different.
53 |
54 | Furthermore, deploying to GCP serverless platforms incur [minor build and storage costs](https://cloud.google.com/appengine/pricing#pricing-for-related-google-cloud-products). [Cloud Build](https://cloud.google.com/build/pricing) has its own free quota as does [Cloud Storage](https://cloud.google.com/storage/pricing#cloud-storage-always-free). For greater transparency, Cloud Build builds your application image which is then sent to the [Cloud Container Registry](https://cloud.google.com/container-registry/pricing), or [Artifact Registry](https://cloud.google.com/artifact-registry/pricing), its successor; storage of that image uses up some of that (Cloud Storage) quota as does network egress when transferring that image to the service you're deploying to. However you may live in region that does not have such a free tier, so be aware of your storage usage to minimize potential costs. (You may look at what storage you're using and how much, including deleting build artifacts via [your Cloud Storage browser](https://console.cloud.google.com/storage/browser).)
55 |
56 | More specific cost information for each sample is available in their respective README files.
57 |
58 |
59 | ### Academic use
60 |
61 | #### Teaching and research grants
62 |
63 | If you are a faculty member or lecturer at a regionally-accredited, degree-granting, and not-for-profit higher ed institution in one of [75+ supported countries worldwide](https://support.google.com/google-cloud-higher-ed/answer/10723190) teaching a course where students are expected to code or use resources in the cloud, you may be eligible to grant your students (plus yourself and teaching assistants) free usage of Google Cloud. Explore faculty resources at to learn more about our _education (teaching and [initial] research) grants_. **@Students:** send your instructors there so they can get you access to Google Cloud.
64 |
65 |
66 | #### Cloud computing curriculum
67 |
68 | If you are an educator who wishes to add cloud computing to your curriculum or seek to enhance it with Google Cloud teaching materials, take a look at our [free 10-module, 40-hour complete course](https://cloud.google.com/edu/curriculum).
69 |
70 |
71 | #### Hands-on training for self-paced online tutorials
72 |
73 | For a hands-on learning experience on all aspects of Google Cloud, both students and faculty can get their hands on free _training credits_ for [Cloud Skills Boost hands-on labs powered by QwikLabs](https://cloudskillsboost.google). Apply for those credits at as well.
74 |
75 |
76 | ## Testing
77 |
78 | Each app has its own testing battery; refer to each sample's folder to learn about implemented tests.
79 |
--------------------------------------------------------------------------------
/cloud/README.md:
--------------------------------------------------------------------------------
1 | # Nebulous serverless app demonstrating use of Google Cloud APIs
2 | ### Featuring the Cloud Translation API
3 |
4 | ## Description
5 |
6 | This is the code repo for a set of codelab tutorials highlighting a "nebulous" sample app demonstrating how to access Google Cloud APIs from one of our serverless platforms. There are [Python](python) and [Node.js](nodejs) versions of this app available.
7 |
8 | ### Related content
9 |
10 | - [Cloud serverless platforms intro video](https://youtu.be/gle26fT28Bw?list=PL2pQQBHvYcs0PEecTcLD9_VaLvuhK0_VQ?utm_source=youtube&utm_medium=unpaidsoc&utm_campaign=CDR_wes_aap-serverless_nebservconcept_neb_202007&utm_content=info_card)
11 | - [Nebulous serverless app deployments video](https://youtu.be/eTotLOVR7MQ?list=PL2pQQBHvYcs0PEecTcLD9_VaLvuhK0_VQ?utm_source=youtube&utm_medium=unpaidsoc&utm_campaign=CDR_wes_aap-serverless_nebservdeploy_neb_2021xx&utm_content=info_card)
12 | - [Calling Cloud APIs from serverless blog post](https://cloud.google.com/blog/topics/developers-practitioners/calling-google-apis-serverless-part-i-cloud-apis?utm_source=blog&utm_medium=partner&utm_campaign=CDR_wes_aap-serverless_nebservconcept_neb_202007)
13 | - Nebulous serverless app deployments blog post (_coming soon_)
14 | - Calling non-Cloud Google APIs from serverless blog post (_TBD_)
15 |
16 |
17 | ## Inspiration and implementation
18 |
19 | This code sample was inspired by a [user's suboptimal experience](https://www.mail-archive.com/google-appengine@googlegroups.com/msg94549.html) trying to create a simple App Engine app using a Cloud API. It was also inspired by a [colleague's blog post](https://dev.to/googlecloud/portable-code-migrating-across-google-cloud-s-serverless-platforms-2ifk) showing a similar Node.js example "drifting" between GCP serverless platforms.
20 |
21 | This app shows developers how to use the [Cloud Translation API](https://cloud.google.com/translate), the API for [Google Translate](https://translate.google.com), and one of GCP's [AI/ML "building block" APIs](https://web.archive.org/web/20210308144225/https://cloud.google.com/products/ai/building-blocks). Such APIs are backed by pre-trained machine learning models, allowing developers with little or no background in AI/ML to leverage machine learning with only API calls. The application implements a mini Google Translate "MVP" (minimally-viable product) web service.
22 |
23 |
24 | ## Authentication and authorization: service account credentials (local deployments only)
25 |
26 | Google Cloud compute platforms feature [default service account credentials](https://cloud.google.com/iam/docs/service-accounts#default) which are used for these app deployments. However, such credentials are not available when running locally, so users will need to **run** `gcloud auth application-default login` before starting the server.
27 |
28 |
29 | ## Cost
30 |
31 | While the Translation API does not explicitly list a free quota on the ["Always Free" tier page](https://cloud.google.com/free/docs/gcp-free-tier#free-tier-usage-limits), its [pricing page](https://cloud.google.com/translate/pricing#charged-characters) indicates a certain number of [translated characters](https://cloud.google.com/translate/pricing#charged-characters) as a free monthly quota applied as a credit, so long as you stay within that limit, you should not incur any additional charges.
32 |
33 |
34 | ## Enable Google Cloud services used
35 |
36 | Once you have a billing account, you can enable the services/APIs for each product used. Go to the Cloud console pages for each respective Cloud product used and enable the service:
37 |
38 | 1. [App Engine](https://console.cloud.google.com/appengine)
39 | 1. [Cloud Functions](https://console.cloud.google.com/functions)
40 | 1. [Cloud Run](https://console.cloud.google.com/run)
41 | 1. [Cloud Translation](https://console.cloud.google.com/apis/api/translate.googleapis.com)
42 |
43 | Alternatively, you use the [`gcloud` CLI (command-line interface)](https://cloud.google.com/sdk/gcloud) available from the [Cloud SDK](https://cloud.google.com/sdk). Review the [Cloud SDK install instructions](https://cloud.google.com/sdk/docs/quickstart) if needed. New users should also reference the [`gcloud` cheatsheet](https://cloud.google.com/sdk/docs/cheatsheet).
44 |
45 | Enable all 4 services with this one `gcloud` command: `gcloud services enable translate.googleapis.com run.googleapis.com cloudfunctions.googleapis.com appengine.googleapis.com`
46 |
47 |
48 | ## The application itself
49 |
50 | The app consists of a simple web page prompting the user for a phrase to translate from English to Spanish. The translated results along with the original phrase are presented along with an empty form for a follow-up translation if desired.
51 |
52 | This is what the app looks like after completing one translation (Cloud Run version):
53 |
54 | 
55 |
56 |
57 | ## References
58 |
59 | 1. Google Cloud serverless product pages
60 | - App Engine
61 | - [App Engine home page](https://cloud.google.com/appengine)
62 | - [App Engine documentation](https://cloud.google.com/appengine/docs)
63 | - [Default service accounts](https://cloud.google.com/appengine/docs/standard/nodejs/service-account)
64 | - Cloud Functions
65 | - [Cloud Functions home page](https://cloud.google.com/functions)
66 | - [Cloud Functions documentation](https://cloud.google.com/functions/docs)
67 | - [Default service accounts](https://cloud.google.com/functions/docs/concepts/iam#access_control_for_service_accounts)
68 | - Cloud Run
69 | - [Cloud Run home page](https://cloud.run)
70 | - [Cloud Run documentation](https://cloud.google.com/run/docs)
71 | - [Default service accounts](https://cloud.google.com/run/docs/securing/service-identity)
72 |
73 | 1. Cloud SDK and `gcloud` product pages
74 | - [Cloud SDK](https://cloud.google.com/sdk)
75 | - [Cloud SDK installation](https://cloud.google.com/sdk/docs/quickstart)
76 | - [`gcloud` CLI](https://cloud.google.com/sdk/gcloud) (command-line interface)
77 | - [`gcloud` cheatsheet](https://cloud.google.com/sdk/docs/cheatsheet)
78 |
79 | 1. Cloud build-relevant product pages
80 | - [Cloud Buildpacks announcement](https://cloud.google.com/blog/products/containers-kubernetes/google-cloud-now-supports-buildpacks)
81 | - [Cloud Buildpacks repo](https://github.com/GoogleCloudPlatform/buildpacks)
82 | - [Cloud Artifact Registry home page](https://cloud.google.com/artifact-registry)
83 | - [Cloud Artifact Registry documentation](https://cloud.google.com/artifact-registry/docs)
84 |
85 | 1. Google AI/ML API product pages
86 | - [Cloud Translation home page](https://cloud.google.com/translate)
87 | - [Cloud Translation documentation](https://cloud.google.com/translate/docs)
88 | - [Cloud Translation Python client library (v3 for 3.x)](https://cloud.google.com/translate/docs/reference/libraries/v3/python)
89 | - [Cloud Translation Python client library (v2 for 2.x)](https://cloud.google.com/translate/docs/reference/libraries/v2/python)
90 | - [Translation API pricing page](https://cloud.google.com/translate/pricing)
91 | - [All Cloud AI/ML "building block" APIs](https://web.archive.org/web/20210308144225/https://cloud.google.com/products/ai/building-blocks)
92 | - [Google ML Kit (Cloud AI/ML API subset for mobile)](https://developers.google.com/ml-kit)
93 | - [Google ML Kit Translation API](https://developers.google.com/ml-kit/language/translation)
94 |
95 | 1. Other Google Cloud documentation
96 | - [Google Cloud Python support](https://cloud.google.com/python)
97 | - [Google Cloud client libraries](https://cloud.google.com/apis/docs/cloud-client-libraries)
98 | - [Google Cloud "Always Free" tier](https://cloud.google.com/free/docs/gcp-free-tier#free-tier-usage-limits)
99 | - [All Google Cloud documentation](https://cloud.google.com/docs)
100 |
101 | 1. External links
102 | - [Docker](https://docker.com)
103 | - [`Dockerfile` documentation](https://docs.docker.com/engine/reference/builder)
104 | - [`Dockerfile` best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices)
105 | - [`Procfile` documentation](https://devcenter.heroku.com/articles/procfile)
106 | - [CNCF Buildpacks open spec](https://buildpacks.io)
107 |
--------------------------------------------------------------------------------
/noncloud/python/maps/README.md:
--------------------------------------------------------------------------------
1 | # Nebulous serverless Google Maps Geocoding API app
2 | ### Python (2 and 3) version
3 |
4 | This sample is offered in Python 3, but the code itself is Python 2-compatible. Instructions on running it under 2.x will leverage the resources of the [Cloud API Python sample](https:/tmp/github.com/googlecodelabs/cloud-nebulous-serverless/tree/main/cloud/python) which provides a more complete experiencce as it has all configuration available to support 2.x deployments. The app is tested against Python 2.7, 3.8, and 3.9; see [`Testing`](#testing) below for more information.
5 |
6 |
7 | > NOTES:
8 | > - For local or Cloud Run deployments, there are little/no updates to go from Python 2 to 3.
9 | > - Neither Cloud Functions nor Cloud Run with Cloud Buildpacks support Python 2.
10 |
11 |
12 | ## Deployments and their files
13 |
14 | File | Description
15 | --- | ---
16 | [`main.py`](main.py)|main application file
17 | `settings.py`|settings file with API key (copy & modify `settings-tmpl.py` template)
18 | [`templates/index.html`](templates/index.html)|application HTML template
19 | [`requirements.txt`](requirements.txt)|3rd-party package requirements file
20 | [`app.yaml`](app.yaml)|App Engine configuration file (only for App Engine deployments)
21 | [`.gcloudignore`](.gcloudignore)|files to exclude deploying to the cloud (administrative)
22 | [`noxfile.py`](noxfile.py) | unit tests `nox` tool setup file
23 | [`test_mapsgeo.py`](test_mapsgeo.py) | unit tests (`pytest`)
24 | [`Procfile`](Procfile) | "Entrypoint" directive [Procfile](https:/tmp/devcenter.heroku.com/articles/procfile) to start app (only for Cloud Run deployments using Cloud Buildpacks)
25 | `README.md`|this file (administrative)
26 |
27 | Below are the required settings and instructions for all documented deployments. The "**TL:DR;**" section at the top of each configuration summarizes the key files (see above) while the table beneath spells out the details. No administrative files are listed. Create your own `settings.py` file with the API your created in the Cloud console and take precautions to protect it, as outlined in [the Google Maps API key documentation](https://developers.google.com/maps/documentation/javascript/get-api-key).
28 |
29 |
30 | ## **Local [Flask](https://flask.palletsprojects.com) server (Python 2 or 3)**
31 |
32 | **TL;DR:** application files (`main.py`, `templates/`, `requirements.txt`)
33 |
34 | 1. **Run** `pip install -U pip -r requirements.txt` to install/update packages locally (or `pip2` for Python 2 or `pip3` for Python 3 explicitly)
35 | 1. **Run** `python main.py` to run on local Flask server (`python2` or `python3` to be explicit)
36 |
37 |
38 | ## **App Engine (Python 3)**
39 |
40 | **TL;DR:** app files plus `app.yaml`
41 |
42 | 1. **Run** `gcloud app deploy`
43 |
44 |
45 | ## **App Engine (Python 2)**
46 |
47 | **TL;DR:** `app2.yaml` (instead of `app.yaml`), app files plus `appengine_config.py`, and `lib`, and other modifications
48 |
49 | 1. **Copy** the [Cloud API Python 2 `appengine_config.py` file](/blob/main/cloud/python/appengine_config.py)
50 | 1. **Uncomment/enable** `requests-toolbelt` in `requirements.txt`
51 | 1. **Run** `pip install -t lib -r requirements.txt` to populate `lib` folder (or `pip2`)
52 | 1. **Edit** `lib/googlemaps/client.py` by adding `import requests_toolbelt.adapters.appengine; requests_toolbelt.adapters.appengine.monkeypatch()` below `import requests` (as documented [here](https://cloud.google.com/appengine/docs/standard/python/issue-requests#requests))
53 | 1. **Run** `gcloud app deploy app2.yaml`
54 |
55 |
56 | ## **Cloud Functions (Python 3)**
57 |
58 | **TL;DR:** app files
59 |
60 | 1. **Run** `gcloud functions deploy mapsgeo --runtime python39 --trigger-http --allow-unauthenticated` to deploy to Cloud Functions (or Python 3.7 or 3.8)
61 |
62 | - Cloud Functions does not support Python 2.
63 | - The Cloud Function name (here `mapsgeo`) must match the function's name in `main.py` else you need to use [`--entry-point`](https://cloud.google.com/functions/docs/deploying/filesystem).
64 |
65 |
66 | ## **Cloud Run (Python 3 via Cloud Buildpacks)**
67 |
68 | **TL;DR:** app files plus [`Procfile`](https://devcenter.heroku.com/articles/procfile)
69 |
70 | 1. **Run** `gcloud run deploy mapsgeo --allow-unauthenticated --platform managed` to deploy to Cloud Run; optionally add `--source . --region REGION` for non-interactive deploy
71 |
72 | - There is no support for Python 2 with Cloud Buildpacks (2.x developers must use Docker [see below])
73 |
74 | > **NOTE:** This sample uses the Flask development server by default for prototyping; for production, bundle and deploy a production server like `gunicorn`:
75 | > 1. **Uncomment** `gunicorn` from `requirements.txt` (commented out for App Engine & Cloud Functions)
76 | > 1. **Uncomment** `ENTRYPOINT` entry for `gunicorn` in `Dockerfile` replacing default entry
77 | > 1. Re-use the same deploy command above
78 |
79 |
80 | ## **Cloud Run (Python 3 via Docker)**
81 |
82 | **TL;DR:** app files plus `Dockerfile` (nearly identical to Python 2 deployment)
83 |
84 | 1. **Copy** the [Cloud API Python `Dockerfile` file](/blob/main/cloud/python/Dockerfile)
85 | 1. **Edit** `Dockerfile` and switch the `FROM` entry to the `python:3-slim` base image
86 | 1. **Run** `gcloud run deploy mapsgeo --allow-unauthenticated --platform managed` to deploy to Cloud Run; optionally add `--source . --region REGION` for non-interactive deploy
87 |
88 | - The `gunicorn` sidebar above also applies here.
89 |
90 |
91 | ## **Cloud Run (Python 2 via Docker)**
92 |
93 | **TL;DR:** app files plus `Dockerfile`
94 |
95 | 1. **Copy** the [Cloud API Python `Dockerfile` file](/blob/main/cloud/python/Dockerfile)
96 | 1. **Run** `gcloud run deploy mapsgeo --allow-unauthenticated --platform managed` to deploy to Cloud Run; optionally add `--source . --region REGION` for non-interactive deploy
97 |
98 | - The `gunicorn` sidebar above also applies here.
99 |
100 |
101 | ## References
102 |
103 | These are relevant links only to the app in this folder (for all others, see the [README one level up](../README.md):
104 |
105 | - [Google Maps client library for Python](https://github.com/googlemaps/google-maps-services-python)
106 | - [Google Maps API key documentation](https://developers.google.com/maps/documentation/javascript/get-api-key)
107 | - [Python 3 App Engine quickstart](https://cloud.google.com/appengine/docs/standard/python3/quickstart)
108 | - [Python 3 App Engine (standard environment) runtime](https://cloud.google.com/appengine/docs/standard/python3/runtime)
109 | - [Python 2 App Engine (standard environment) runtime](https://cloud.google.com/appengine/docs/standard/python/runtime)
110 | - [Python Cloud Functions quickstart](https://cloud.google.com/functions/docs/quickstart-python)
111 | - [Python Cloud Run quickstart](https://cloud.google.com/run/docs/quickstarts/build-and-deploy/python)
112 | - [Differences between Python 2 & 3 App Engine (standard environment) runtimes](https://cloud.google.com/appengine/docs/standard/runtimes)
113 | - [Python 2 to 3 App Engine (standard environment) migration guide](http://cloud.google.com/appengine/docs/standard/python/migrate-to-python3)
114 | - [App Engine (standard environment) to Cloud Run codelab tutorial](http://g.co/codelabs/pae-migrate-rundocker) (Docker)
115 | - [App Engine (standard environment) to Cloud Run codelab tutorial](http://g.co/codelabs/pae-migrate-runbldpks) (Cloud Buildpacks)
116 |
117 |
118 | ## Testing
119 |
120 | Testing is driven by [`nox`](http://nox.thea.codes) which uses [`pytest`](https://pytest.org) for testing and [`flake8`](https://flake8.pycqa.org) for linting, installing both in virtual environments along with application dependencies, `flask` and [`googlemaps`](https://github.com/googlemaps/google-maps-services-python) and finally, [`blinker`](https://pythonhosted.org/blinker), a signaling framework integrated into Flask. To run the lint and unit tests (testing `GET` and `POST` requests), install `nox` (with the expected `pip install -U nox`) and run it from the command line in the application folder and ensuring `noxfile.py` is present.
121 |
122 | ### Expected output
123 |
124 | ```
125 | $ nox
126 | nox > Running session tests-2.7
127 | nox > Creating virtual environment (virtualenv) using python2.7 in .nox/tests-2-7
128 | nox > python -m pip install pytest blinker flask googlemaps
129 | nox > pytest
130 | =============================================== test session starts ================================================
131 | platform darwin -- Python 2.7.16, pytest-4.6.11, py-1.11.0, pluggy-0.13.1
132 | rootdir: /tmp/noncloud/python/maps
133 | collected 4 items
134 |
135 | test_mapsgeo.py .... [100%]
136 |
137 | ============================================= 4 passed in 2.69 seconds =============================================
138 | nox > Session tests-2.7 was successful.
139 | nox > Running session tests-3.8
140 | nox > Creating virtual environment (virtualenv) using python3.8 in .nox/tests-3-8
141 | nox > python -m pip install pytest blinker flask googlemaps
142 | nox > pytest
143 | =============================================== test session starts ================================================
144 | platform darwin -- Python 3.8.2, pytest-7.0.1, pluggy-1.0.0
145 | rootdir: /tmp/noncloud/python/maps
146 | collected 4 items
147 |
148 | test_mapsgeo.py .... [100%]
149 |
150 | ================================================ 4 passed in 1.26s =================================================
151 | nox > Session tests-3.8 was successful.
152 | nox > Running session tests-3.9
153 | nox > Creating virtual environment (virtualenv) using python3.9 in .nox/tests-3-9
154 | nox > python -m pip install pytest blinker flask googlemaps
155 | nox > pytest
156 | =============================================== test session starts ================================================
157 | platform darwin -- Python 3.9.9, pytest-7.0.1, pluggy-1.0.0
158 | rootdir: /tmp/noncloud/python/maps
159 | collected 4 items
160 |
161 | test_mapsgeo.py .... [100%]
162 |
163 | ================================================ 4 passed in 1.05s =================================================
164 | nox > Session tests-3.9 was successful.
165 | nox > Running session lint-2.7
166 | nox > Creating virtual environment (virtualenv) using python2.7 in .nox/lint-2-7
167 | nox > python -m pip install flake8
168 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
169 | nox > Session lint-2.7 was successful.
170 | nox > Running session lint-3.8
171 | nox > Creating virtual environment (virtualenv) using python3.8 in .nox/lint-3-8
172 | nox > python -m pip install flake8
173 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
174 | nox > Session lint-3.8 was successful.
175 | nox > Running session lint-3.9
176 | nox > Creating virtual environment (virtualenv) using python3.9 in .nox/lint-3-9
177 | nox > python -m pip install flake8
178 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
179 | nox > Session lint-3.9 was successful.
180 | nox > Ran multiple sessions:
181 | nox > * tests-2.7: success
182 | nox > * tests-3.8: success
183 | nox > * tests-3.9: success
184 | nox > * lint-2.7: success
185 | nox > * lint-3.8: success
186 | nox > * lint-3.9: success
187 | ```
188 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/noncloud/python/sheets/README.md:
--------------------------------------------------------------------------------
1 | # Nebulous serverless Google Sheets API app
2 |
3 | ## Python 3 version (Python 2 compatible)
4 |
5 | This sample is offered in Python 3, but the code itself is Python 2-compatible. Instructions on running it under 2.x will leverage the resources of the [Cloud API Python sample](https://github.com/googlecodelabs/cloud-nebulous-serverless/tree/main/cloud/python) which provides a more complete experience as it has all configuration available to support 2.x deployments.
6 |
7 | > NOTES:
8 | > - For local or Cloud Run deployments, there are little/no updates to go from Python 2 to 3.
9 | > - Neither Cloud Functions nor Cloud Run with Cloud Buildpacks support Python 2.
10 |
11 |
12 | ## Deployments and their files
13 |
14 | File | Description
15 | --- | ---
16 | [`main.py`](main.py) | main application file
17 | [`templates/index.html`](templates/index.html) | application HTML template
18 | [`requirements.txt`](requirements.txt) | 3rd-party package requirements file
19 | [`app.yaml`](app.yaml) | App Engine configuration file (only for App Engine deployments)
20 | [`.gcloudignore`](.gcloudignore) | files to exclude deploying to the cloud (administrative)
21 | [`noxfile.py`](noxfile.py) | unit tests `nox` tool setup file
22 | [`test_sheets.py`](test_sheets.py) | unit tests (`pytest`)
23 | [`Procfile`](Procfile) | "Entrypoint" directive [Procfile](https://devcenter.heroku.com/articles/procfile) to start app (only for Cloud Run deployments using Cloud Buildpacks)
24 | `README.md` | this file (administrative)
25 |
26 | Below are the required settings and instructions for all documented deployments. The "**TL:DR;**" section at the top of each configuration summarizes the key files (see above) while the table beneath spells out the details. No administrative files are listed.
27 |
28 |
29 | ## **Local [Flask](https://flask.palletsprojects.com) server (Python 2 or 3)**
30 |
31 | **TL;DR:** application files (`main.py` & `requirements.txt`)
32 |
33 | 1. **Login using [Application Default Credentials](https://cloud.google.com/docs/authentication/production#automatically)**: run the `gcloud auth application-default login` command and ensure you do **not** set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable; also see the [command reference](https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login).
34 | 1. (2.x only) **Uncomment/enable** the line for `google-auth` in `requirements.txt`
35 | 1. **Run** `pip install -U pip -r requirements.txt` to install/update packages locally (or `pip2` for Python 2 or `pip3` for Python 3 explicitly)
36 | 1. **Run** `python main.py` to run on local Flask server (`python2` or `python3` to be explicit)
37 |
38 | **Troubleshooting**: if you're on a VM running `pip install`, you may get an error like this:
39 |
40 | ```
41 | ERROR: Could not install packages due to an OSError: [Errno 13] Permission denied: 'PKG-INFO'
42 | Consider using the `--user` option or check the permissions.
43 | ```
44 |
45 | _Solution_: If this is the case:
46 | - **Update** the line for `flask` in `requirements.txt` to: `flask<2.0dev`
47 |
48 |
49 | ## **App Engine (Python 3)**
50 |
51 | **TL;DR:** app files plus `app.yaml`
52 |
53 | 1. **Run** `gcloud app deploy`
54 |
55 |
56 | ## **App Engine (Python 2)**
57 |
58 | **TL;DR:** app files plus `app.yaml`, `appengine_config.py`, and `lib`
59 |
60 | 1. **Copy** the [Cloud API Python 2 `app.yaml` file](/cloud/python/app.yaml)
61 | 1. **Copy** the [Cloud API Python 2 `appengine_config.py` file](/cloud/python/appengine_config.py)
62 | 1. **Uncomment/enable** the line for `google-auth` in `requirements.txt`
63 | 1. **Uncomment** "<1.12.0" on the line for `google-api-python-client` in `requirements.txt`
64 | 1. **Run** `pip install -t lib -r requirements.txt` to populate `lib` folder (or `pip2`)
65 | 1. **Run** `gcloud app deploy`
66 |
67 |
68 | ## **Cloud Functions (Python 3)**
69 |
70 | **TL;DR:** app files
71 |
72 | 1. **Run** `gcloud functions deploy students --runtime python39 --trigger-http --allow-unauthenticated` to deploy to Cloud Functions (or Python 3.7 or 3.8)
73 |
74 | - Cloud Functions does not support Python 2.
75 | - The Cloud Function name must match the function's name in `main.py` else you need to use [`--entry-point`](https://cloud.google.com/functions/docs/deploying/filesystem#deploy_using_the).
76 |
77 |
78 | ## **Cloud Run (Python 3 via Cloud Buildpacks)**
79 |
80 | **TL;DR:** app files plus [`Procfile`](https://devcenter.heroku.com/articles/procfile)
81 |
82 | 1. **Run** `gcloud run deploy students --allow-unauthenticated --platform managed` to deploy to Cloud Run; optionally add `--source . --region REGION` for non-interactive deploy
83 |
84 | - There is no support for Python 2 with Cloud Buildpacks (2.x developers must use Docker)
85 |
86 | > **NOTE:** This sample uses the Flask development server by default for prototyping; for production, bundle and deploy a production server like `gunicorn`:
87 | > 1. **Uncomment** `gunicorn` from `requirements.txt` (commented out for App Engine & Cloud Functions)
88 | > 1. **Uncomment** `ENTRYPOINT` entry for `gunicorn` in `Dockerfile` replacing default entry
89 | > 1. Re-use the same deploy command above
90 |
91 |
92 | ## **Cloud Run (Python 3 via Docker)**
93 |
94 | **TL;DR:** app files plus `Dockerfile` (nearly identical to Python 2 deployment)
95 |
96 | 1. **Copy** the [Cloud API Python `Dockerfile` file](/cloud/python/Dockerfile)
97 | 1. **Edit** `Dockerfile` and switch the `FROM` entry to the `python:3-slim` base image
98 | 1. **Run** `gcloud run deploy students --allow-unauthenticated --platform managed` to deploy to Cloud Run; optionally add `--source . --region REGION` for non-interactive deploy
99 |
100 | - The `gunicorn` sidebar above also applies here.
101 |
102 |
103 | ## **Cloud Run (Python 2 via Docker)**
104 |
105 | **TL;DR:** app files plus `Dockerfile`
106 |
107 | 1. **Copy** the [Cloud API Python `Dockerfile` file](/cloud/python/Dockerfile)
108 | 1. **Run** `gcloud run deploy students --allow-unauthenticated --platform managed` to deploy to Cloud Run; optionally add `--source . --region REGION` for non-interactive deploy
109 |
110 | - The `gunicorn` sidebar above also applies here.
111 |
112 |
113 | ## Resources
114 |
115 | These are relevant links only to the app in this folder (for all others, see the [README one level up](../README.md):
116 |
117 | ### Google Sheets API and platform client library
118 |
119 | - [Google Sheets API home page](https://developers.google.com/sheets)
120 | - [Google Sheets API Python QuickStart](https://developers.google.com/sheets/api/quickstart/python) (origin of the student spreadsheet)
121 | - [Google Sheets API intro codelab](http://g.co/codelabs/sheets) (Node.js)
122 | - [Google Sheets API videos](https://developers.google.com/sheets/api/videos) (Python or [Apps Script](https://developers.google.com/apps-script) [JavaScript])
123 | - [Google Workspace APIs home page](https://developers.google.com/gsuite)
124 | - [Google APIs client library for Python](https://github.com/googleapis/google-api-python-client)
125 |
126 |
127 | ### Google Cloud serverless platforms
128 |
129 | - [Google Cloud serverless home page](https://cloud.google.com/serverless)
130 | - [Cloud Functions home page](https://cloud.google.com/functions)
131 | - [Cloud Functions Python quickstart](https://cloud.google.com/functions/docs/quickstart-python)
132 | - [Cloud Run home page](https://cloud.run)
133 | - [Cloud Run Python quickstart](https://cloud.google.com/run/docs/quickstarts/build-and-deploy/python)
134 | - [App Engine home page](https://cloud.google.com/appengine)
135 | - [App Engine Python 3 quickstart](https://cloud.google.com/appengine/docs/standard/python3/quickstart)
136 | - [App Engine (standard environment) Python 3 runtime](https://cloud.google.com/appengine/docs/standard/python3/runtime)
137 | - [App Engine (standard environment) Python 2 runtime](https://cloud.google.com/appengine/docs/standard/python/runtime)
138 | - [Differences between Python 2 & 3 App Engine (standard environment) runtimes](https://cloud.google.com/appengine/docs/standard/runtimes)
139 | - [App Engine (standard environment) Python 2 to 3 migration guide](http://cloud.google.com/appengine/docs/standard/python/migrate-to-python3)
140 | - [App Engine (standard environment) to Cloud Run codelab tutorial](http://g.co/codelabs/pae-migrate-rundocker) (via Docker)
141 | - [App Engine (standard environment) to Cloud Run codelab tutorial](http://g.co/codelabs/pae-migrate-runbldpks) (no Docker/`Dockerfile` via Cloud Buildpacks)
142 |
143 |
144 | ## Testing
145 |
146 | Testing is driven by [`nox`](http://nox.thea.codes) which uses [`pytest`](https://pytest.org) for testing and [`flake8`](https://flake8.pycqa.org) for linting, installing both in virtual environments along with application dependencies, `flask` and `google-api-python-client`, and finally, [`blinker`](https://pythonhosted.org/blinker), a signaling framework integrated into Flask. To run the lint and unit tests (testing `GET` and `POST` requests), install `nox` (with the expected `pip install -U nox`) and run it from the command line in the application folder and ensuring `noxfile.py` is present.
147 |
148 |
149 | ### Expected output
150 |
151 | ```
152 | $ nox
153 | nox > Running session tests-2.7
154 | nox > Creating virtual environment (virtualenv) using python2.7 in .nox/tests-2-7
155 | nox > python -m pip install pytest blinker flask google-auth google-api-python-client
156 | nox > pytest
157 | ================================================== test session starts ==================================================
158 | platform darwin -- Python 2.7.16, pytest-4.6.11, py-1.11.0, pluggy-0.13.1
159 | rootdir: /tmp/noncloud/python/sheets
160 | collected 1 item
161 |
162 | test_sheets.py . [100%]
163 |
164 | =============================================== 1 passed in 1.84 seconds ================================================
165 | nox > Session tests-2.7 was successful.
166 | nox > Running session tests-3.8
167 | nox > Creating virtual environment (virtualenv) using python3.8 in .nox/tests-3-8
168 | nox > python -m pip install pytest blinker flask google-auth google-api-python-client
169 | nox > pytest
170 | ================================================== test session starts ==================================================
171 | platform darwin -- Python 3.8.2, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
172 | rootdir: /tmp/noncloud/python/sheets
173 | collected 1 item
174 |
175 | test_sheets.py . [100%]
176 |
177 | =================================================== 1 passed in 1.04s ===================================================
178 | nox > Session tests-3.8 was successful.
179 | nox > Running session tests-3.9
180 | nox > Creating virtual environment (virtualenv) using python3.9 in .nox/tests-3-9
181 | nox > python -m pip install pytest blinker flask google-auth google-api-python-client
182 | nox > pytest
183 | ================================================== test session starts ==================================================
184 | platform darwin -- Python 3.9.1, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
185 | rootdir: /tmp/noncloud/python/sheets
186 | collected 1 item
187 |
188 | test_sheets.py . [100%]
189 |
190 | =================================================== 1 passed in 0.97s ===================================================
191 | nox > Session tests-3.9 was successful.
192 | nox > Running session lint-2.7
193 | nox > Creating virtual environment (virtualenv) using python2.7 in .nox/lint-2-7
194 | nox > python -m pip install flake8
195 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
196 | nox > Session lint-2.7 was successful.
197 | nox > Running session lint-3.8
198 | nox > Creating virtual environment (virtualenv) using python3.8 in .nox/lint-3-8
199 | nox > python -m pip install flake8
200 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
201 | nox > Session lint-3.8 was successful.
202 | nox > Running session lint-3.9
203 | nox > Creating virtual environment (virtualenv) using python3.9 in .nox/lint-3-9
204 | nox > python -m pip install flake8
205 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
206 | nox > Session lint-3.9 was successful.
207 | nox > Ran multiple sessions:
208 | nox > * tests-2.7: success
209 | nox > * tests-3.8: success
210 | nox > * tests-3.9: success
211 | nox > * lint-2.7: success
212 | nox > * lint-3.8: success
213 | nox > * lint-3.9: success
214 | ```
215 |
--------------------------------------------------------------------------------
/cloud/python/README.md:
--------------------------------------------------------------------------------
1 | # Nebulous serverless Cloud Translation API app
2 |
3 | ## Python (2 and 3) version
4 |
5 | While the majority of this app's deployments are in Python 3, there are still users upgrading from Python 2, so our Python 2 code is meant to help with migration & planning. Admittedly, there may _seem_ to be a bit of "cheating" due to the duplicity of Python 2 and 3, especially since the application is compatible across both language versions without modification or use of compatibility libraries. However there are significant differences between Python 2 and 3 deployment requirements irregardless of language differences. Additional notes:
6 |
7 | - For local or Cloud Run deployments, there are little/no updates to go from Python 2 to 3.
8 | - Neither Cloud Functions nor Cloud Run with Cloud Buildpacks support Python 2.
9 | - There is also an [equivalent Node.js version](../nodejs) of this app.
10 |
11 |
12 | ## Codelab links
13 |
14 | Deployment | Python 2 | Python 3
15 | --- | --- | ---
16 | Local/hosted Flask|[codelab](https://codelabs.developers.google.com/codelabs/cloud-nebulous-serverless-python-flask?utm_source=codelabs&utm_medium=et&utm_campaign=CDR_wes_aap-serverless_nebservflask_sms_201020&utm_content=-)|_same as Python 2_
17 | App Engine|[codelab](https://codelabs.developers.google.com/codelabs/cloud-nebulous-serverless-python-gae2?utm_source=codelabs&utm_medium=et&utm_campaign=CDR_wes_aap-serverless_nebservgae2_sms_201020&utm_content=-)|[codelab](https://codelabs.developers.google.com/codelabs/cloud-nebulous-serverless-python-gae3?utm_source=codelabs&utm_medium=et&utm_campaign=CDR_wes_aap-serverless_nebservgae3_sms_201020&utm_content=-)
18 | Cloud Functions| _N/A_ |[codelab](https://codelabs.developers.google.com/codelabs/cloud-nebulous-serverless-python-gcf?utm_source=codelabs&utm_medium=et&utm_campaign=CDR_wes_aap-serverless_nebservgcf_sms_201020&utm_content=-)
19 | Cloud Run (Docker)|[codelab](https://codelabs.developers.google.com/codelabs/cloud-nebulous-serverless-python-gcr2?utm_source=codelabs&utm_medium=et&utm_campaign=CDR_wes_aap-serverless_nebservgcr2_sms_201020&utm_content=-)|[codelab](https://codelabs.developers.google.com/codelabs/cloud-nebulous-serverless-python-gcr3?utm_source=codelabs&utm_medium=et&utm_campaign=CDR_wes_aap-serverless_nebservgcr3_sms_201020&utm_content=-)
20 | Cloud Run (Buildpacks)| _N/A_ |[codelab](https://codelabs.developers.google.com/codelabs/cloud-nebulous-serverless-python-gcrbp?utm_source=codelabs&utm_medium=et&utm_campaign=CDR_wes_aap-serverless_nebservgcrbp_sms_201020&utm_content=-)
21 |
22 |
23 | ## Deployments and their files
24 |
25 | These are the files provided in this repo and the deployments they're applicable to:
26 |
27 | 
28 |
29 | > NOTES:
30 | >- * — `requirements.txt` is used for local and App Engine (2.x) package installations and not required in deployments themselves unlike all others
31 | >- `main.py` and `templates/index.html` comprise the entire application and are always required
32 | >- `noxfile.py` and `test_translate.py` are for testing only; see [Testing section](#testing) below
33 | >- All `.*ignore` and `.git*` files/folders are administrative and not listed in table above or deployments below
34 | >- Files applicable only to a specific language version are annotated above
35 |
36 | Below are the required settings and instructions for all documented deployments. The "**TL:DR;**" section at the top of each configuration summarizes the key files (see above) while the table beneath spells out the details. No administrative files are listed.
37 |
38 | > NOTE: Serverless deployments (as configured here) use [default service accounts](https://cloud.google.com/iam/docs/service-accounts#default) which provide a broad set of permissions to assist you in getting a working prototype. When preparing to launch to production, the Google Cloud team recommends the best practice of "least privileges," and instead use [user-managed service accounts](https://cloud.google.com/iam/docs/service-accounts#user-managed) with the minimal set of permissions allowing your app to function properly.
39 |
40 |
41 | ## **Local Flask server (Python 2)**
42 |
43 | **TL;DR:** application files (`main.py` & `requirements.txt`)
44 |
45 | File | Description
46 | --- | ---
47 | `main.py`|**use as-is** from repo
48 | `app.yaml`|_unused_ (delete or leave as-is)
49 | `appengine_config.py`|_unused_ (delete or leave as-is; only for Python 2 App Engine)
50 | `requirements.txt`|**use as-is** to install packages locally (see below) but _unused_ thereafter
51 | `lib`|_unused_ (delete or leave as-is if it exists)
52 | `Dockerfile`|_unused_ (delete or leave as-is)
53 | `Procfile`|_unused_ (delete or leave as-is)
54 |
55 | Instructions:
56 |
57 | 1. **Run** `pip install -U pip -r requirements.txt` to install/update packages locally (or `pip2`)
58 | 1. **Run** `gcloud auth application-default login` to set your credentials
59 | 1. **Run** `python main.py` to run on local Flask server (or `python2`)
60 |
61 |
62 | ## **Local Flask server (Python 3)**
63 |
64 | **TL;DR:** app files (identical to Python 2 deployment)
65 |
66 | File | Description
67 | --- | ---
68 | `main.py`|**use as-is** from repo
69 | `app.yaml`|_unused_ (delete or leave as-is)
70 | `appengine_config.py`|_unused_ (delete or leave as-is; only for Python 2 App Engine)
71 | `requirements.txt`|**use as-is** to install packages locally (see below) but _unused_ thereafter
72 | `lib`|_unused_ (delete or leave as-is if it exists)
73 | `Dockerfile`|_unused_ (delete or leave as-is)
74 | `Procfile`|_unused_ (delete or leave as-is)
75 |
76 | Instructions:
77 |
78 | 1. **Run** `pip install -U pip -r requirements.txt` to install/update packages locally (or `pip3`)
79 | 1. **Run** `gcloud auth application-default login` to set your credentials
80 | 1. **Run** `python main.py` to run on local Flask server (or `python3`)
81 |
82 |
83 | ## **App Engine (Python 2)**
84 |
85 | **TL;DR:** app files plus `app.yaml`, `appengine_config.py`, and `lib`
86 |
87 | File | Description
88 | --- | ---
89 | `main.py`|**use as-is** from repo
90 | `app.yaml`|**use as-is** from repo (ensure `#runtime:python310` commented out)
91 | `appengine_config.py`|**use as-is** from repo
92 | `requirements.txt`|**use as-is** to install packages locally (see below) but _unused_ thereafter
93 | `lib`|**create folder** per instructions below
94 | `Dockerfile`|_unused_ (delete or leave as-is)
95 | `Procfile`|_unused_ (delete or leave as-is)
96 |
97 | Instructions:
98 |
99 | 1. **Run** `pip install -t lib -r requirements.txt` to populate `lib` folder (or `pip2`)
100 | 1. **Run** `gcloud app deploy` to deploy to Python 2 App Engine
101 | - You'll be prompted for the REGION if deploying to App Engine the first time.
102 | - App Engine apps are tied to one region, so it can't be changed once it's set, meaning you won't be prompted thereafter.
103 |
104 |
105 | ## **App Engine (Python 3)**
106 |
107 | **TL;DR:** app files plus `app.yaml`
108 |
109 | File | Description
110 | --- | ---
111 | `main.py`|**use as-is** from repo
112 | `app.yaml`|**uncomment** `runtime:python310` (or Python 3.7-3.9); **delete** all other lines
113 | `appengine_config.py`|_unused_ (delete or leave as-is; only for Python 2 App Engine)
114 | `requirements.txt`|**use as-is** from repo
115 | `lib`|**delete** (or rename) this folder if it exists (not used with Python 3 App Engine)
116 | `Dockerfile`|_unused_ (delete or leave as-is)
117 | `Procfile`|_unused_ (delete or leave as-is)
118 |
119 | Instructions:
120 |
121 | 1. **Edit** `app.yaml` (see above)
122 | 1. (optional) **Delete** `app.yaml`, `lib` and `appengine_config.py` (unused)
123 | 1. **Run** `gcloud app deploy` to deploy to Python 3 App Engine
124 | - You'll be prompted for the REGION if deploying to App Engine the first time.
125 | - App Engine apps are tied to one region, so it can't be changed once it's set, meaning you won't be prompted thereafter.
126 |
127 |
128 | ## **Cloud Functions (Python 3)**
129 |
130 | **TL;DR:** app files
131 |
132 | File | Description
133 | --- | ---
134 | `main.py`|**use as-is** from repo
135 | `app.yaml`|_unused_ (delete or leave as-is; only for App Engine)
136 | `appengine_config.py`|_unused_ (delete or leave as-is; only for Python 2 App Engine)
137 | `requirements.txt`|**use as-is** from repo
138 | `lib`|**delete** (or rename) this folder if it exists (not used with Cloud Functions)
139 | `Dockerfile`|_unused_ (delete or leave as-is)
140 | `Procfile`|_unused_ (delete or leave as-is)
141 |
142 | Instructions:
143 |
144 | 1. (optional) **Delete** `app.yaml`, `lib` and `appengine_config.py` (unused)
145 | 1. **Run** `gcloud functions deploy translate --runtime python310 --trigger-http --allow-unauthenticated` to deploy to Cloud Functions (or Python 3.7-3.9)
146 | - That command creates & deploys a new HTTP-triggered Cloud Function (name must match what's in `main.py`)
147 | - You'll be prompted for the REGION if deploying a Cloud Function the first time.
148 | - Cloud Functions can be deployed to different regions within a project, but once the region has been set for a function, it cannot be changed.
149 | 1. There is no support for Python 2 with Cloud Functions
150 |
151 |
152 | ## **Cloud Run (Python 2 via Docker)**
153 |
154 | **TL;DR:** app files plus `Dockerfile`
155 |
156 | File | Description
157 | --- | ---
158 | `main.py`|**use as-is** from repo
159 | `app.yaml`|_unused_ (delete or leave as-is; only for App Engine)
160 | `appengine_config.py`|_unused_ (delete or leave as-is; only for Python 2 App Engine)
161 | `requirements.txt`|`grpcio<1.40.0` applies to this deployment
162 | `lib`|**delete** (or rename) this folder if it exists (not used with Cloud Run)
163 | `Dockerfile`|**use as-is** from repo (ensure `#FROM python:3-slim` commented out)
164 | `Procfile`|_unused_ (delete or leave as-is)
165 |
166 | Instructions:
167 |
168 | 1. (optional) **Delete** `app.yaml`, `lib` and `appengine_config.py` (unused)
169 | 1. **Run** `gcloud run deploy translate --allow-unauthenticated --platform managed` to deploy to Cloud Run
170 | - The above command wraps `docker build` and `docker push`, deploying the image to [Cloud Artifact Registry](https://cloud.google.com/artifact-registry) (must be enabled), and finally `docker run` to deploy the service, all in one convenient command.
171 | - You'll be prompted to provide a REGION unless you also add `--region REGION` on the cmd-line
172 | - You'll be prompted to provide a SOURCE folder unless you also add `--source FOLDER`, e.g., `--source .` on the cmd-line
173 | - Supplying both `--region` and `--source` options provide a fully non-interactive deploy (unless you don't have a repository, in which case you'll be prompted to create one)
174 | 1. You can also use this shortcut to deploy to Cloud Run:
175 | [](https://deploy.cloud.run)
176 | 1. By default, App Engine & Cloud Functions launch production servers; with Cloud Run, the Flask development server is used for prototyping. For production, bundle and deploy a production server like `gunicorn`:
177 | 1. **Uncomment** `gunicorn` from `requirements.txt` (commented out for App Engine & Cloud Functions)
178 | 1. **Uncomment** the `ENTRYPOINT` entry for `gunicorn` replacing the default entry in `Dockerfile`
179 | 1. Re-use the same deploy command
180 |
181 |
182 | ## **Cloud Run (Python 3 via Docker)**
183 |
184 | **TL;DR:** app files plus `Dockerfile` (nearly identical to Python 2 deployment)
185 |
186 | File | Description
187 | --- | ---
188 | `main.py`|**use as-is** from repo
189 | `app.yaml`|_unused_ (delete or leave as-is; only for App Engine)
190 | `appengine_config.py`|_unused_ (delete or leave as-is; only for Python 2 App Engine)
191 | `requirements.txt`|**use as-is** from repo
192 | `lib`|**delete** (or rename) this folder if it exists (not used with Cloud Run)
193 | `Dockerfile`|**replace** `FROM python:2-slim` with `FROM python:3-slim` (commented out) but **keep all other lines**
194 | `Procfile`|_unused_ (delete or leave as-is)
195 |
196 | Instructions:
197 |
198 | 1. (optional) **Delete** `app.yaml`, `lib` and `appengine_config.py` (unused)
199 | 1. **Edit** `Dockerfile` (see above)
200 | 1. **Run** `gcloud run deploy translate --allow-unauthenticated --platform managed` to deploy to Cloud Run
201 | - The above command wraps `docker build` and `docker push`, deploying the image to [Cloud Artifact Registry](https://cloud.google.com/artifact-registry) (must be enabled), and finally `docker run` to deploy the service, all in one convenient command.
202 | - You'll be prompted to provide a REGION unless you also add `--region REGION` on the cmd-line
203 | - You'll be prompted to provide a SOURCE folder unless you also add `--source FOLDER`, e.g., `--source .` on the cmd-line
204 | - Supplying both `--region` and `--source` options provide a fully non-interactive deploy (unless you don't have a repository, in which case you'll be prompted to create one)
205 | 1. The shortcut "button" above can be customized for Python 3 if you make the `Dockerfile` update above and commit it to your fork/clone.
206 | 1. By default, App Engine & Cloud Functions launch production servers; with Cloud Run, the Flask development server is used for prototyping. For production, bundle and deploy a production server like `gunicorn`:
207 | 1. **Uncomment** `gunicorn` from `requirements.txt` (commented out for App Engine & Cloud Functions)
208 | 1. **Uncomment** the `ENTRYPOINT` entry for `gunicorn` replacing the default entry in `Dockerfile`
209 | 1. Re-use the same deploy command
210 |
211 |
212 | ## **Cloud Run (Python 3 via Cloud Buildpacks)**
213 |
214 | **TL;DR:** app files plus [`Procfile`](https://devcenter.heroku.com/articles/procfile)
215 |
216 | File | Description
217 | --- | ---
218 | `main.py`|**use as-is** from repo
219 | `app.yaml`|_unused_ (delete or leave as-is; only for App Engine)
220 | `appengine_config.py`|_unused_ (delete or leave as-is; only for Python 2 App Engine)
221 | `requirements.txt`|**use as-is** from repo
222 | `lib`|**delete** (or rename) this folder if it exists (not used with Cloud Run)
223 | `Dockerfile`|**delete** (or rename) this file (_required_)
224 | `Procfile`|**use as-is** from repo
225 |
226 | Instructions:
227 |
228 | 1. (optional) **Delete** `app.yaml`, `lib` and `appengine_config.py` (unused)
229 | 1. **Delete** `Dockerfile` (or rename it)
230 | - There is no support for Python 2 with Cloud Buildpacks (2.x developers must use Docker)
231 | 1. **Run** `gcloud run deploy translate --allow-unauthenticated --platform managed` to deploy to Cloud Run
232 | - The above command wraps `docker build` and `docker push`, deploying the image to [Cloud Artifact Registry](https://cloud.google.com/artifact-registry) (must be enabled), and finally `docker run` to deploy the service, all in one convenient command.
233 | - You'll be prompted to provide a REGION unless you also add `--region REGION` on the cmd-line
234 | - You'll be prompted to provide a SOURCE folder unless you also add `--source FOLDER`, e.g., `--source .` on the cmd-line
235 | - Supplying both `--region` and `--source` options provide a fully non-interactive deploy (unless you don't have a repository, in which case you'll be prompted to create one)
236 | 1. By default, App Engine & Cloud Functions launch production servers; with Cloud Run, the Flask development server is used for prototyping. For production, bundle and deploy a production server like `gunicorn`:
237 | 1. **Uncomment** `gunicorn` from `requirements.txt` (commented out for App Engine & Cloud Functions)
238 | 1. **Uncomment** the `web:` entry for `gunicorn` replacing the default entry in `Procfile`
239 | 1. Re-use the same deploy command
240 |
241 |
242 | ## References
243 |
244 | These are relevant links only to the app in this folder (for all others, see the [README one level up](../README.md):
245 |
246 | - [Python 3 App Engine quickstart](https://cloud.google.com/appengine/docs/standard/python3/quickstart)
247 | - [Python 3 App Engine (standard environment) runtime](https://cloud.google.com/appengine/docs/standard/python3/runtime)
248 | - [Python 2 App Engine (standard environment) runtime](https://cloud.google.com/appengine/docs/standard/python/runtime)
249 | - [Python Cloud Functions quickstart](https://cloud.google.com/functions/docs/quickstart-python)
250 | - [Python Cloud Run quickstart](https://cloud.google.com/run/docs/quickstarts/build-and-deploy/python)
251 | - [Differences between Python 2 & 3 App Engine (standard environment) runtimes](https://cloud.google.com/appengine/docs/standard/runtimes)
252 | - [Python 2 to 3 App Engine (standard environment) migration guide](http://cloud.google.com/appengine/docs/standard/python/migrate-to-python3)
253 | - [App Engine (standard environment) to Cloud Run codelab tutorial](http://g.co/codelabs/pae-migrate-rundocker) (Docker)
254 | - [App Engine (standard environment) to Cloud Run codelab tutorial](http://g.co/codelabs/pae-migrate-runbldpks) (Cloud Buildpacks)
255 | - [Flask](https://flask.palletsprojects.com)
256 |
257 |
258 | ## Testing
259 |
260 | Testing is driven by [`nox`](http://nox.thea.codes) which uses [`pytest`](https://pytest.org) for testing and [`flake8`](https://flake8.pycqa.org) for linting, installing both in virtual environments along with application dependencies, `flask` and `google-cloud-translate`, and finally, `blinker`, a signaling framework integrated into Flask. To run the lint and unit tests (testing `GET` and `POST` requests), install `nox` (with the expected `pip install -U nox`) and run it from the command line in the application folder and ensuring `noxfile.py` is present.
261 |
262 | ### Expected output
263 |
264 | ```
265 | $ nox
266 | nox > Running session tests-2.7
267 | nox > Creating virtual environment (virtualenv) using python2.7 in .nox/tests-2-7
268 | nox > python -m pip install pytest blinker flask google-cloud-translate
269 | nox > pytest
270 | ============================================ test session starts =============================================
271 | platform darwin -- Python 2.7.16, pytest-4.6.11, py-1.10.0, pluggy-0.13.1
272 | rootdir: /private/tmp/cloud-nebulous-serverless-python
273 | collected 2 items
274 |
275 | test_translate.py .. [100%]
276 |
277 | ============================================== warnings summary ==============================================
278 | .nox/tests-2-7/lib/python2.7/site-packages/google/cloud/translate_v3/__init__.py:32
279 | /private/tmp/cloud-nebulous-serverless-python/.nox/tests-2-7/lib/python2.7/site-packages/google/cloud/translate_v3/__init__.py:32: DeprecationWarning: A future version of this library will drop support for Python 2.7. More details about Python 2 support for Google Cloud Client Libraries can be found at https://cloud.google.com/python/docs/python2-sunset/
280 | warnings.warn(message, DeprecationWarning)
281 |
282 | -- Docs: https://docs.pytest.org/en/latest/warnings.html
283 | ==================================== 2 passed, 1 warnings in 1.02 seconds ====================================
284 | nox > Session tests-2.7 was successful.
285 | nox > Running session tests-3.6
286 | nox > Creating virtual environment (virtualenv) using python3.6 in .nox/tests-3-6
287 | nox > python -m pip install pytest blinker flask google-cloud-translate
288 | nox > pytest
289 | ============================================ test session starts =============================================
290 | platform darwin -- Python 3.6.8, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
291 | rootdir: /private/tmp/cloud-nebulous-serverless-python
292 | collected 2 items
293 |
294 | test_translate.py .. [100%]
295 |
296 | ============================================= 2 passed in 1.22s ==============================================
297 | nox > Session tests-3.6 was successful.
298 | nox > Running session tests-3.9
299 | nox > Creating virtual environment (virtualenv) using python3.9 in .nox/tests-3-9
300 | nox > python -m pip install pytest blinker flask google-cloud-translate
301 | nox > pytest
302 | ============================================ test session starts =============================================
303 | platform darwin -- Python 3.9.1, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
304 | rootdir: /private/tmp/cloud-nebulous-serverless-python
305 | collected 2 items
306 |
307 | test_translate.py .. [100%]
308 |
309 | ============================================= 2 passed in 1.04s ==============================================
310 | nox > Session tests-3.9 was successful.
311 | nox > Running session lint-2.7
312 | nox > Creating virtual environment (virtualenv) using python2.7 in .nox/lint-2-7
313 | nox > python -m pip install flake8
314 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
315 | nox > Session lint-2.7 was successful.
316 | nox > Running session lint-3.6
317 | nox > Creating virtual environment (virtualenv) using python3.6 in .nox/lint-3-6
318 | nox > python -m pip install flake8
319 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
320 | nox > Session lint-3.6 was successful.
321 | nox > Running session lint-3.9
322 | nox > Creating virtual environment (virtualenv) using python3.9 in .nox/lint-3-9
323 | nox > python -m pip install flake8
324 | nox > flake8 --show-source --builtin=gettext --max-complexity=20 --exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py --ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202 --max-line-length=88 .
325 | nox > Session lint-3.9 was successful.
326 | nox > Ran multiple sessions:
327 | nox > * tests-2.7: success
328 | nox > * tests-3.6: success
329 | nox > * tests-3.9: success
330 | nox > * lint-2.7: success
331 | nox > * lint-3.6: success
332 | nox > * lint-3.9: success
333 | ```
334 |
--------------------------------------------------------------------------------