functions-framework 3.8.2__tar.gz → 3.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {functions_framework-3.8.2 → functions_framework-3.9.0}/PKG-INFO +21 -18
- {functions_framework-3.8.2 → functions_framework-3.9.0}/README.md +4 -11
- functions_framework-3.9.0/pyproject.toml +69 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/setup.py +4 -1
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/__init__.py +28 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/_cli.py +14 -3
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/_function_registry.py +4 -0
- functions_framework-3.9.0/src/functions_framework/_http/__init__.py +59 -0
- functions_framework-3.9.0/src/functions_framework/_http/asgi.py +43 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/_http/gunicorn.py +25 -0
- functions_framework-3.9.0/src/functions_framework/aio/__init__.py +352 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/execution_id.py +115 -10
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework.egg-info/PKG-INFO +21 -18
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework.egg-info/SOURCES.txt +6 -0
- functions_framework-3.9.0/src/functions_framework.egg-info/requires.txt +14 -0
- functions_framework-3.9.0/tests/test_aio.py +171 -0
- functions_framework-3.9.0/tests/test_asgi.py +117 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_cli.py +60 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_cloud_event_functions.py +45 -26
- functions_framework-3.9.0/tests/test_decorator_functions.py +177 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_execution_id.py +1 -0
- functions_framework-3.9.0/tests/test_execution_id_async.py +365 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_function_registry.py +16 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_functions.py +190 -133
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_http.py +118 -1
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_typing.py +12 -0
- functions_framework-3.8.2/src/functions_framework/_http/__init__.py +0 -42
- functions_framework-3.8.2/src/functions_framework.egg-info/requires.txt +0 -8
- functions_framework-3.8.2/tests/test_decorator_functions.py +0 -69
- {functions_framework-3.8.2 → functions_framework-3.9.0}/LICENSE +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/setup.cfg +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/__main__.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/_http/flask.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/_typed_event.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/background_event.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/event_conversion.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/exceptions.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/py.typed +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/request_timeout.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework.egg-info/dependency_links.txt +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework.egg-info/entry_points.txt +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework.egg-info/namespace_packages.txt +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework.egg-info/top_level.txt +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/google/__init__.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/google/cloud/__init__.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/google/cloud/functions/__init__.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/google/cloud/functions/context.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/google/cloud/functions_v1/__init__.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/google/cloud/functions_v1/context.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/google/cloud/functions_v1beta2/__init__.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/src/google/cloud/functions_v1beta2/context.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_convert.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_main.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_samples.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_timeouts.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_typed_event_functions.py +0 -0
- {functions_framework-3.8.2 → functions_framework-3.9.0}/tests/test_view_functions.py +0 -0
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: functions-framework
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.9.0
|
|
4
4
|
Summary: An open source FaaS (Function as a service) framework for writing portable Python functions -- brought to you by the Google Cloud Functions team.
|
|
5
5
|
Home-page: https://github.com/googlecloudplatform/functions-framework-python
|
|
6
6
|
Author: Google LLC
|
|
7
|
-
Author-email: googleapis-packages@google.com
|
|
7
|
+
Author-email: Google LLC <googleapis-packages@google.com>
|
|
8
|
+
Maintainer-email: Google LLC <googleapis-packages@google.com>
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Project-URL: Homepage, https://github.com/googlecloudplatform/functions-framework-python
|
|
8
11
|
Keywords: functions-framework
|
|
9
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
13
|
Classifier: Intended Audience :: Developers
|
|
11
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
14
|
Classifier: Programming Language :: Python :: 3.7
|
|
13
15
|
Classifier: Programming Language :: Python :: 3.8
|
|
14
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -18,12 +20,20 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
18
20
|
Requires-Python: >=3.5, <4
|
|
19
21
|
Description-Content-Type: text/markdown
|
|
20
22
|
License-File: LICENSE
|
|
21
|
-
Requires-Dist: flask<4.0,>=
|
|
23
|
+
Requires-Dist: flask<4.0,>=2.0
|
|
22
24
|
Requires-Dist: click<9.0,>=7.0
|
|
23
25
|
Requires-Dist: watchdog>=1.0.0
|
|
24
26
|
Requires-Dist: gunicorn>=22.0.0; platform_system != "Windows"
|
|
25
|
-
Requires-Dist: cloudevents
|
|
27
|
+
Requires-Dist: cloudevents<=1.11.0,>=1.2.0
|
|
26
28
|
Requires-Dist: Werkzeug<4.0.0,>=0.14
|
|
29
|
+
Requires-Dist: httpx>=0.24.1
|
|
30
|
+
Requires-Dist: starlette<1.0.0,>=0.37.0; python_version >= "3.8"
|
|
31
|
+
Requires-Dist: uvicorn<1.0.0,>=0.18.0; python_version >= "3.8"
|
|
32
|
+
Requires-Dist: uvicorn-worker<1.0.0,>=0.2.0; python_version >= "3.8"
|
|
33
|
+
Dynamic: author
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
Dynamic: requires-python
|
|
27
37
|
|
|
28
38
|
# Functions Framework for Python
|
|
29
39
|
|
|
@@ -37,9 +47,8 @@ Python functions -- brought to you by the Google Cloud Functions team.
|
|
|
37
47
|
The Functions Framework lets you write lightweight functions that run in many
|
|
38
48
|
different environments, including:
|
|
39
49
|
|
|
40
|
-
* [Google Cloud Functions](https://cloud.google.com/functions/)
|
|
50
|
+
* [Google Cloud Run Functions](https://cloud.google.com/functions/)
|
|
41
51
|
* Your local development machine
|
|
42
|
-
* [Cloud Run and Cloud Run for Anthos](https://cloud.google.com/run/)
|
|
43
52
|
* [Knative](https://github.com/knative/)-based environments
|
|
44
53
|
|
|
45
54
|
The framework allows you to go from:
|
|
@@ -321,7 +330,7 @@ https://cloud.google.com/functions/docs/tutorials/pubsub#functions_helloworld_pu
|
|
|
321
330
|
|
|
322
331
|
## Run your function on serverless platforms
|
|
323
332
|
|
|
324
|
-
### Google Cloud
|
|
333
|
+
### Google Cloud Run functions
|
|
325
334
|
|
|
326
335
|
This Functions Framework is based on the [Python Runtime on Google Cloud Functions](https://cloud.google.com/functions/docs/concepts/python-runtime).
|
|
327
336
|
|
|
@@ -329,12 +338,6 @@ On Cloud Functions, using the Functions Framework is not necessary: you don't ne
|
|
|
329
338
|
|
|
330
339
|
After you've written your function, you can simply deploy it from your local machine using the `gcloud` command-line tool. [Check out the Cloud Functions quickstart](https://cloud.google.com/functions/docs/quickstart).
|
|
331
340
|
|
|
332
|
-
### Cloud Run/Cloud Run on GKE
|
|
333
|
-
|
|
334
|
-
Once you've written your function and added the Functions Framework to your `requirements.txt` file, all that's left is to create a container image. [Check out the Cloud Run quickstart](https://cloud.google.com/run/docs/quickstarts/build-and-deploy) for Python to create a container image and deploy it to Cloud Run. You'll write a `Dockerfile` when you build your container. This `Dockerfile` allows you to specify exactly what goes into your container (including custom binaries, a specific operating system, and more). [Here is an example `Dockerfile` that calls Functions Framework.](https://github.com/GoogleCloudPlatform/functions-framework-python/blob/main/examples/cloud_run_http)
|
|
335
|
-
|
|
336
|
-
If you want even more control over the environment, you can [deploy your container image to Cloud Run on GKE](https://cloud.google.com/run/docs/quickstarts/prebuilt-deploy-gke). With Cloud Run on GKE, you can run your function on a GKE cluster, which gives you additional control over the environment (including use of GPU-based instances, longer timeouts and more).
|
|
337
|
-
|
|
338
341
|
### Container environments based on Knative
|
|
339
342
|
|
|
340
343
|
Cloud Run and Cloud Run on GKE both implement the [Knative Serving API](https://www.knative.dev/docs/). The Functions Framework is designed to be compatible with Knative environments. Just build and deploy your container to a Knative environment.
|
|
@@ -352,10 +355,10 @@ You can configure the Functions Framework using command-line flags or environmen
|
|
|
352
355
|
| `--source` | `FUNCTION_SOURCE` | The path to the file containing your function. Default: `main.py` (in the current working directory) |
|
|
353
356
|
| `--debug` | `DEBUG` | A flag that allows to run functions-framework to run in debug mode, including live reloading. Default: `False` |
|
|
354
357
|
|
|
355
|
-
## Enable Google Cloud
|
|
358
|
+
## Enable Google Cloud Run function Events
|
|
356
359
|
|
|
357
360
|
The Functions Framework can unmarshall incoming
|
|
358
|
-
Google Cloud
|
|
361
|
+
Google Cloud Run functions [event](https://cloud.google.com/functions/docs/concepts/events-triggers#events) payloads to `event` and `context` objects.
|
|
359
362
|
These will be passed as arguments to your function when it receives a request.
|
|
360
363
|
Note that your function must use the `event`-style function signature:
|
|
361
364
|
|
|
@@ -10,9 +10,8 @@ Python functions -- brought to you by the Google Cloud Functions team.
|
|
|
10
10
|
The Functions Framework lets you write lightweight functions that run in many
|
|
11
11
|
different environments, including:
|
|
12
12
|
|
|
13
|
-
* [Google Cloud Functions](https://cloud.google.com/functions/)
|
|
13
|
+
* [Google Cloud Run Functions](https://cloud.google.com/functions/)
|
|
14
14
|
* Your local development machine
|
|
15
|
-
* [Cloud Run and Cloud Run for Anthos](https://cloud.google.com/run/)
|
|
16
15
|
* [Knative](https://github.com/knative/)-based environments
|
|
17
16
|
|
|
18
17
|
The framework allows you to go from:
|
|
@@ -294,7 +293,7 @@ https://cloud.google.com/functions/docs/tutorials/pubsub#functions_helloworld_pu
|
|
|
294
293
|
|
|
295
294
|
## Run your function on serverless platforms
|
|
296
295
|
|
|
297
|
-
### Google Cloud
|
|
296
|
+
### Google Cloud Run functions
|
|
298
297
|
|
|
299
298
|
This Functions Framework is based on the [Python Runtime on Google Cloud Functions](https://cloud.google.com/functions/docs/concepts/python-runtime).
|
|
300
299
|
|
|
@@ -302,12 +301,6 @@ On Cloud Functions, using the Functions Framework is not necessary: you don't ne
|
|
|
302
301
|
|
|
303
302
|
After you've written your function, you can simply deploy it from your local machine using the `gcloud` command-line tool. [Check out the Cloud Functions quickstart](https://cloud.google.com/functions/docs/quickstart).
|
|
304
303
|
|
|
305
|
-
### Cloud Run/Cloud Run on GKE
|
|
306
|
-
|
|
307
|
-
Once you've written your function and added the Functions Framework to your `requirements.txt` file, all that's left is to create a container image. [Check out the Cloud Run quickstart](https://cloud.google.com/run/docs/quickstarts/build-and-deploy) for Python to create a container image and deploy it to Cloud Run. You'll write a `Dockerfile` when you build your container. This `Dockerfile` allows you to specify exactly what goes into your container (including custom binaries, a specific operating system, and more). [Here is an example `Dockerfile` that calls Functions Framework.](https://github.com/GoogleCloudPlatform/functions-framework-python/blob/main/examples/cloud_run_http)
|
|
308
|
-
|
|
309
|
-
If you want even more control over the environment, you can [deploy your container image to Cloud Run on GKE](https://cloud.google.com/run/docs/quickstarts/prebuilt-deploy-gke). With Cloud Run on GKE, you can run your function on a GKE cluster, which gives you additional control over the environment (including use of GPU-based instances, longer timeouts and more).
|
|
310
|
-
|
|
311
304
|
### Container environments based on Knative
|
|
312
305
|
|
|
313
306
|
Cloud Run and Cloud Run on GKE both implement the [Knative Serving API](https://www.knative.dev/docs/). The Functions Framework is designed to be compatible with Knative environments. Just build and deploy your container to a Knative environment.
|
|
@@ -325,10 +318,10 @@ You can configure the Functions Framework using command-line flags or environmen
|
|
|
325
318
|
| `--source` | `FUNCTION_SOURCE` | The path to the file containing your function. Default: `main.py` (in the current working directory) |
|
|
326
319
|
| `--debug` | `DEBUG` | A flag that allows to run functions-framework to run in debug mode, including live reloading. Default: `False` |
|
|
327
320
|
|
|
328
|
-
## Enable Google Cloud
|
|
321
|
+
## Enable Google Cloud Run function Events
|
|
329
322
|
|
|
330
323
|
The Functions Framework can unmarshall incoming
|
|
331
|
-
Google Cloud
|
|
324
|
+
Google Cloud Run functions [event](https://cloud.google.com/functions/docs/concepts/events-triggers#events) payloads to `event` and `context` objects.
|
|
332
325
|
These will be passed as arguments to your function when it receives a request.
|
|
333
326
|
Note that your function must use the `event`-style function signature:
|
|
334
327
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "functions-framework"
|
|
3
|
+
version = "3.9.0"
|
|
4
|
+
description = "An open source FaaS (Function as a service) framework for writing portable Python functions -- brought to you by the Google Cloud Functions team."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.7, <4"
|
|
7
|
+
# Once we drop support for Python 3.7 and 3.8, this can become
|
|
8
|
+
# license = "Apache-2.0"
|
|
9
|
+
license = { text = "Apache-2.0" }
|
|
10
|
+
authors = [{ name = "Google LLC", email = "googleapis-packages@google.com" }]
|
|
11
|
+
maintainers = [
|
|
12
|
+
{ name = "Google LLC", email = "googleapis-packages@google.com" },
|
|
13
|
+
]
|
|
14
|
+
keywords = ["functions-framework"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 5 - Production/Stable",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3.7",
|
|
19
|
+
"Programming Language :: Python :: 3.8",
|
|
20
|
+
"Programming Language :: Python :: 3.9",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"flask>=2.0,<4.0",
|
|
27
|
+
"click>=7.0,<9.0",
|
|
28
|
+
"watchdog>=1.0.0",
|
|
29
|
+
"gunicorn>=22.0.0; platform_system!='Windows'",
|
|
30
|
+
"cloudevents>=1.2.0,<=1.11.0", # Must support python 3.7
|
|
31
|
+
"Werkzeug>=0.14,<4.0.0",
|
|
32
|
+
"httpx>=0.24.1",
|
|
33
|
+
"starlette>=0.37.0,<1.0.0; python_version>='3.8'",
|
|
34
|
+
"uvicorn>=0.18.0,<1.0.0; python_version>='3.8'",
|
|
35
|
+
"uvicorn-worker>=0.2.0,<1.0.0; python_version>='3.8'",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/googlecloudplatform/functions-framework-python"
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
ff = "functions_framework._cli:_cli"
|
|
43
|
+
functions-framework = "functions_framework._cli:_cli"
|
|
44
|
+
functions_framework = "functions_framework._cli:_cli"
|
|
45
|
+
functions-framework-python = "functions_framework._cli:_cli"
|
|
46
|
+
functions_framework_python = "functions_framework._cli:_cli"
|
|
47
|
+
|
|
48
|
+
[build-system]
|
|
49
|
+
requires = ["setuptools>=61.0.0"]
|
|
50
|
+
build-backend = "setuptools.build_meta"
|
|
51
|
+
|
|
52
|
+
[tool.setuptools.packages.find]
|
|
53
|
+
where = ["src"]
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.package-data]
|
|
56
|
+
functions_framework = ["py.typed"]
|
|
57
|
+
|
|
58
|
+
[tool.setuptools.package-dir]
|
|
59
|
+
"" = "src"
|
|
60
|
+
|
|
61
|
+
[dependency-groups]
|
|
62
|
+
dev = [
|
|
63
|
+
"black>=23.3.0",
|
|
64
|
+
"build>=1.1.1",
|
|
65
|
+
"isort>=5.11.5",
|
|
66
|
+
"pretend>=1.0.9",
|
|
67
|
+
"pytest>=7.4.4",
|
|
68
|
+
"pytest-asyncio>=0.21.2",
|
|
69
|
+
]
|
|
@@ -25,7 +25,7 @@ with open(path.join(here, "README.md"), encoding="utf-8") as f:
|
|
|
25
25
|
|
|
26
26
|
setup(
|
|
27
27
|
name="functions-framework",
|
|
28
|
-
version="3.
|
|
28
|
+
version="3.9.0",
|
|
29
29
|
description="An open source FaaS (Function as a service) framework for writing portable Python functions -- brought to you by the Google Cloud Functions team.",
|
|
30
30
|
long_description=long_description,
|
|
31
31
|
long_description_content_type="text/markdown",
|
|
@@ -57,6 +57,9 @@ setup(
|
|
|
57
57
|
"cloudevents>=1.2.0,<2.0.0",
|
|
58
58
|
"Werkzeug>=0.14,<4.0.0",
|
|
59
59
|
],
|
|
60
|
+
extras_require={
|
|
61
|
+
"async": ["starlette>=0.37.0,<1.0.0"],
|
|
62
|
+
},
|
|
60
63
|
entry_points={
|
|
61
64
|
"console_scripts": [
|
|
62
65
|
"ff=functions_framework._cli:_cli",
|
|
@@ -327,6 +327,16 @@ def crash_handler(e):
|
|
|
327
327
|
|
|
328
328
|
|
|
329
329
|
def create_app(target=None, source=None, signature_type=None):
|
|
330
|
+
"""Create an app for the function.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
target: The name of the target function to invoke
|
|
334
|
+
source: The source file containing the function
|
|
335
|
+
signature_type: The signature type of the function
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
A Flask WSGI app or Starlette ASGI app depending on function decorators
|
|
339
|
+
"""
|
|
330
340
|
target = _function_registry.get_function_target(target)
|
|
331
341
|
source = _function_registry.get_function_source(source)
|
|
332
342
|
|
|
@@ -370,6 +380,7 @@ def create_app(target=None, source=None, signature_type=None):
|
|
|
370
380
|
setup_logging()
|
|
371
381
|
|
|
372
382
|
_app.wsgi_app = execution_id.WsgiMiddleware(_app.wsgi_app)
|
|
383
|
+
|
|
373
384
|
# Execute the module, within the application context
|
|
374
385
|
with _app.app_context():
|
|
375
386
|
try:
|
|
@@ -394,6 +405,23 @@ def create_app(target=None, source=None, signature_type=None):
|
|
|
394
405
|
# command fails.
|
|
395
406
|
raise e from None
|
|
396
407
|
|
|
408
|
+
use_asgi = target in _function_registry.ASGI_FUNCTIONS
|
|
409
|
+
if use_asgi:
|
|
410
|
+
# This function needs ASGI, delegate to create_asgi_app
|
|
411
|
+
# Note: @aio decorators only register functions in ASGI_FUNCTIONS when the
|
|
412
|
+
# module is imported. We can't know if a function uses @aio until after
|
|
413
|
+
# we load the module.
|
|
414
|
+
#
|
|
415
|
+
# To avoid loading modules twice, we always create a Flask app first, load the
|
|
416
|
+
# module within its context, then check if ASGI is needed. This results in an
|
|
417
|
+
# unused Flask app for ASGI functions, but we accept this memory overhead as a
|
|
418
|
+
# trade-off.
|
|
419
|
+
from functions_framework.aio import create_asgi_app_from_module
|
|
420
|
+
|
|
421
|
+
return create_asgi_app_from_module(
|
|
422
|
+
target, source, signature_type, source_module, spec
|
|
423
|
+
)
|
|
424
|
+
|
|
397
425
|
# Get the configured function signature type
|
|
398
426
|
signature_type = _function_registry.get_func_signature_type(target, signature_type)
|
|
399
427
|
|
|
@@ -16,7 +16,7 @@ import os
|
|
|
16
16
|
|
|
17
17
|
import click
|
|
18
18
|
|
|
19
|
-
from functions_framework import create_app
|
|
19
|
+
from functions_framework import _function_registry, create_app
|
|
20
20
|
from functions_framework._http import create_server
|
|
21
21
|
|
|
22
22
|
|
|
@@ -32,6 +32,17 @@ from functions_framework._http import create_server
|
|
|
32
32
|
@click.option("--host", envvar="HOST", type=click.STRING, default="0.0.0.0")
|
|
33
33
|
@click.option("--port", envvar="PORT", type=click.INT, default=8080)
|
|
34
34
|
@click.option("--debug", envvar="DEBUG", is_flag=True)
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
@click.option(
|
|
36
|
+
"--asgi",
|
|
37
|
+
envvar="FUNCTION_USE_ASGI",
|
|
38
|
+
is_flag=True,
|
|
39
|
+
help="Use ASGI server for function execution",
|
|
40
|
+
)
|
|
41
|
+
def _cli(target, source, signature_type, host, port, debug, asgi):
|
|
42
|
+
if asgi:
|
|
43
|
+
from functions_framework.aio import create_asgi_app
|
|
44
|
+
|
|
45
|
+
app = create_asgi_app(target, source, signature_type)
|
|
46
|
+
else:
|
|
47
|
+
app = create_app(target, source, signature_type)
|
|
37
48
|
create_server(app, debug).run(host, port)
|
|
@@ -40,6 +40,10 @@ REGISTRY_MAP = {}
|
|
|
40
40
|
# Keys are the user function name, values are the type of the function input
|
|
41
41
|
INPUT_TYPE_MAP = {}
|
|
42
42
|
|
|
43
|
+
# ASGI_FUNCTIONS stores function names that require ASGI mode.
|
|
44
|
+
# Functions decorated with @aio.http or @aio.cloud_event are added here.
|
|
45
|
+
ASGI_FUNCTIONS = set()
|
|
46
|
+
|
|
43
47
|
|
|
44
48
|
def get_user_function(source, source_module, target):
|
|
45
49
|
"""Returns user function, raises exception for invalid function."""
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Copyright 2020 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
|
|
16
|
+
|
|
17
|
+
from functions_framework._http.flask import FlaskApplication
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class HTTPServer:
|
|
21
|
+
def __init__(self, app, debug, **options):
|
|
22
|
+
self.app = app
|
|
23
|
+
self.debug = debug
|
|
24
|
+
self.options = options
|
|
25
|
+
|
|
26
|
+
if isinstance(app, Flask):
|
|
27
|
+
if self.debug:
|
|
28
|
+
self.server_class = FlaskApplication
|
|
29
|
+
else:
|
|
30
|
+
try:
|
|
31
|
+
from functions_framework._http.gunicorn import GunicornApplication
|
|
32
|
+
|
|
33
|
+
self.server_class = GunicornApplication
|
|
34
|
+
except ImportError as e:
|
|
35
|
+
self.server_class = FlaskApplication
|
|
36
|
+
else: # pragma: no cover
|
|
37
|
+
if self.debug:
|
|
38
|
+
from functions_framework._http.asgi import StarletteApplication
|
|
39
|
+
|
|
40
|
+
self.server_class = StarletteApplication
|
|
41
|
+
else:
|
|
42
|
+
try:
|
|
43
|
+
from functions_framework._http.gunicorn import UvicornApplication
|
|
44
|
+
|
|
45
|
+
self.server_class = UvicornApplication
|
|
46
|
+
except ImportError as e:
|
|
47
|
+
from functions_framework._http.asgi import StarletteApplication
|
|
48
|
+
|
|
49
|
+
self.server_class = StarletteApplication
|
|
50
|
+
|
|
51
|
+
def run(self, host, port):
|
|
52
|
+
http_server = self.server_class(
|
|
53
|
+
self.app, host, port, self.debug, **self.options
|
|
54
|
+
)
|
|
55
|
+
http_server.run()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def create_server(app, debug, **options):
|
|
59
|
+
return HTTPServer(app, debug, **options)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Copyright 2025 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 uvicorn
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class StarletteApplication:
|
|
19
|
+
"""A Starlette application that uses Uvicorn for direct serving (development mode)."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, app, host, port, debug, **options):
|
|
22
|
+
"""Initialize the Starlette application.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
app: The ASGI application to serve
|
|
26
|
+
host: The host to bind to
|
|
27
|
+
port: The port to bind to
|
|
28
|
+
debug: Whether to run in debug mode
|
|
29
|
+
**options: Additional options to pass to Uvicorn
|
|
30
|
+
"""
|
|
31
|
+
self.app = app
|
|
32
|
+
self.host = host
|
|
33
|
+
self.port = port
|
|
34
|
+
self.debug = debug
|
|
35
|
+
|
|
36
|
+
self.options = {
|
|
37
|
+
"log_level": "debug" if debug else "error",
|
|
38
|
+
}
|
|
39
|
+
self.options.update(options)
|
|
40
|
+
|
|
41
|
+
def run(self):
|
|
42
|
+
"""Run the Uvicorn server directly."""
|
|
43
|
+
uvicorn.run(self.app, host=self.host, port=int(self.port), **self.options)
|
{functions_framework-3.8.2 → functions_framework-3.9.0}/src/functions_framework/_http/gunicorn.py
RENAMED
|
@@ -70,3 +70,28 @@ class GThreadWorkerWithTimeoutSupport(ThreadWorker): # pragma: no cover
|
|
|
70
70
|
def handle_request(self, req, conn):
|
|
71
71
|
with ThreadingTimeout(TIMEOUT_SECONDS):
|
|
72
72
|
super(GThreadWorkerWithTimeoutSupport, self).handle_request(req, conn)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class UvicornApplication(gunicorn.app.base.BaseApplication):
|
|
76
|
+
"""Gunicorn application for ASGI apps using Uvicorn workers."""
|
|
77
|
+
|
|
78
|
+
def __init__(self, app, host, port, debug, **options):
|
|
79
|
+
self.options = {
|
|
80
|
+
"bind": "%s:%s" % (host, port),
|
|
81
|
+
"workers": int(os.environ.get("WORKERS", 1)),
|
|
82
|
+
"worker_class": "uvicorn_worker.UvicornWorker",
|
|
83
|
+
"timeout": int(os.environ.get("CLOUD_RUN_TIMEOUT_SECONDS", 0)),
|
|
84
|
+
"loglevel": os.environ.get("GUNICORN_LOG_LEVEL", "error"),
|
|
85
|
+
"limit_request_line": 0,
|
|
86
|
+
}
|
|
87
|
+
self.options.update(options)
|
|
88
|
+
self.app = app
|
|
89
|
+
|
|
90
|
+
super().__init__()
|
|
91
|
+
|
|
92
|
+
def load_config(self):
|
|
93
|
+
for key, value in self.options.items():
|
|
94
|
+
self.cfg.set(key, value)
|
|
95
|
+
|
|
96
|
+
def load(self):
|
|
97
|
+
return self.app
|