diff --git a/.coveragerc-py37 b/.coveragerc-py37 deleted file mode 100644 index efb63fec..00000000 --- a/.coveragerc-py37 +++ /dev/null @@ -1,22 +0,0 @@ -[run] -# Coverage configuration specifically for Python 3.7 environments -# Excludes the aio module which requires Python 3.8+ (Starlette dependency) -# This file is only used by py37-* tox environments -omit = - */functions_framework/aio/* - */functions_framework/_http/asgi.py - */.tox/* - */tests/* - */venv/* - */.venv/* - -[report] -exclude_lines = - pragma: no cover - from functions_framework.aio import - from functions_framework._http.asgi import - from functions_framework._http.gunicorn import UvicornApplication - class AsgiMiddleware: - def set_execution_context_async - return create_asgi_app_from_module - app = create_asgi_app\(target, source, signature_type\) \ No newline at end of file diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 270f890c..e5e575fb 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: disable-sudo: true egress-policy: block @@ -51,13 +51,14 @@ jobs: github.com:443 pypi.org:443 objects.githubusercontent.com:443 + release-assets.githubusercontent.com:443 - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4 + uses: github/codeql-action/init@5d5cd550d3e189c569da8f16ea8de2d821c9bf7a # v3.31.2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -67,7 +68,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4 + uses: github/codeql-action/autobuild@5d5cd550d3e189c569da8f16ea8de2d821c9bf7a # v3.31.2 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -80,6 +81,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4 + uses: github/codeql-action/analyze@5d5cd550d3e189c569da8f16ea8de2d821c9bf7a # v3.31.2 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/conformance-asgi.yml b/.github/workflows/conformance-asgi.yml index 69f2b215..ee568faa 100644 --- a/.github/workflows/conformance-asgi.yml +++ b/.github/workflows/conformance-asgi.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.platform }} steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: disable-sudo: true egress-policy: block @@ -32,7 +32,7 @@ jobs: release-assets.githubusercontent.com:443 - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Setup Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -45,7 +45,7 @@ jobs: - name: Setup Go uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: - go-version: '1.24' + go-version: '1.25' - name: Run HTTP conformance tests uses: GoogleCloudPlatform/functions-framework-conformance/action@c7b9c8798fb35e454f76da185a40547ee55c784e # v1.8.7 diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 9eedb0a2..6c14136e 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -17,12 +17,10 @@ jobs: include: - platform: ubuntu-22.04 python: '3.8' - - platform: ubuntu-22.04 - python: '3.7' runs-on: ${{ matrix.platform }} steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: disable-sudo: true egress-policy: block @@ -37,7 +35,7 @@ jobs: release-assets.githubusercontent.com:443 - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Setup Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 @@ -50,7 +48,7 @@ jobs: - name: Setup Go uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: - go-version: '1.24' + go-version: '1.25' - name: Run HTTP conformance tests uses: GoogleCloudPlatform/functions-framework-conformance/action@c7b9c8798fb35e454f76da185a40547ee55c784e # v1.8.7 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 02009c72..efa405f8 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: disable-sudo: true egress-policy: block @@ -25,6 +25,6 @@ jobs: api.github.com:443 github.com:443 - name: 'Checkout Repository' - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: 'Dependency Review' - uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1 + uses: actions/dependency-review-action@40c09b7dc99638e5ddb0bfd91c1673effc064d8a # v4.8.1 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1c99b0f7..e9088c6a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: disable-sudo: true egress-policy: block @@ -21,7 +21,7 @@ jobs: github.com:443 pypi.org:443 - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Setup Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 - name: Install tox diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6bb76655..c209a7ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,12 +13,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: ref: ${{ github.event.release.tag_name }} - name: Install Python diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 23b0c7c0..6fdac794 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: disable-sudo: true egress-policy: block @@ -47,12 +47,12 @@ jobs: - name: "Checkout code" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif @@ -64,6 +64,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4e828ff8d448a8a6e532957b1811f387a63867e8 # v3.29.4 + uses: github/codeql-action/upload-sarif@5d5cd550d3e189c569da8f16ea8de2d821c9bf7a # v3.31.2 with: sarif_file: results.sarif diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 90e9e915..96a880d2 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -11,7 +11,7 @@ jobs: test: strategy: matrix: - python: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12'] + python: ['3.8', '3.9', '3.10', '3.11', '3.12'] platform: [ubuntu-latest, macos-latest, windows-latest] # Python <= 3.9 is not available on macos-latest # Workaround for https://github.com/actions/setup-python/issues/696 @@ -21,27 +21,19 @@ jobs: python: '3.9' - platform: macos-latest python: '3.8' - - platform: macos-latest - python: '3.7' - platform: ubuntu-latest python: '3.8' - - platform: ubuntu-latest - python: '3.7' include: - platform: macos-latest python: '3.9' - platform: macos-13 python: '3.8' - - platform: macos-13 - python: '3.7' - platform: ubuntu-22.04 python: '3.8' - - platform: ubuntu-22.04 - python: '3.7' runs-on: ${{ matrix.platform }} steps: - name: Harden Runner - uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 + uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2 with: disable-sudo: true egress-policy: block @@ -57,7 +49,7 @@ jobs: release-assets.githubusercontent.com:443 - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 - name: Use Python ${{ matrix.python }} uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 73ed6d36..b817ff60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.10.0](https://github.com/GoogleCloudPlatform/functions-framework-python/compare/v3.9.2...v3.10.0) (2025-11-10) + + +### Features + +* Add async and streaming examples ([#393](https://github.com/GoogleCloudPlatform/functions-framework-python/issues/393)) ([a07b1e4](https://github.com/GoogleCloudPlatform/functions-framework-python/commit/a07b1e4f81d84424189488022e5f3d59c06014cc)) + + +### Bug Fixes + +* **ci:** Add release-assets.githubusercontent.com to allowed endpoints ([#394](https://github.com/GoogleCloudPlatform/functions-framework-python/issues/394)) ([9b37f85](https://github.com/GoogleCloudPlatform/functions-framework-python/commit/9b37f85f6c37078119c2ea3cc91e6b3c00954a8c)) +* remove Python 3.7 test execution ([#402](https://github.com/GoogleCloudPlatform/functions-framework-python/issues/402)) ([ef45fae](https://github.com/GoogleCloudPlatform/functions-framework-python/commit/ef45fae46896b50a7a3e0e5c3cb4813519e3cb76)) + ## [3.9.2](https://github.com/GoogleCloudPlatform/functions-framework-python/compare/v3.9.1...v3.9.2) (2025-07-24) diff --git a/examples/README.md b/examples/README.md index 7960a743..47b7c398 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,6 +5,8 @@ * [`cloud_run_http`](./cloud_run_http/) - Deploying an HTTP function to [Cloud Run](http://cloud.google.com/run) with the Functions Framework * [`cloud_run_event`](./cloud_run_event/) - Deploying a CloudEvent function to [Cloud Run](http://cloud.google.com/run) with the Functions Framework * [`cloud_run_cloud_events`](cloud_run_cloud_events/) - Deploying a [CloudEvent](https://github.com/cloudevents/sdk-python) function to [Cloud Run](http://cloud.google.com/run) with the Functions Framework +* [`cloud_run_async`](./cloud_run_async/) - Deploying asynchronous HTTP and CloudEvent functions to [Cloud Run](http://cloud.google.com/run) with the Functions Framework +* [`cloud_run_streaming_http`](./cloud_run_streaming_http/) - Deploying streaming HTTP functions to [Cloud Run](http://cloud.google.com/run) with the Functions Framework ## Development Tools * [`docker-compose`](./docker-compose) - diff --git a/examples/cloud_run_async/README.md b/examples/cloud_run_async/README.md new file mode 100644 index 00000000..81de2747 --- /dev/null +++ b/examples/cloud_run_async/README.md @@ -0,0 +1,68 @@ +# Deploying async functions to Cloud Run + +This sample shows how to deploy asynchronous functions to [Cloud Run functions](https://cloud.google.com/functions) with the Functions Framework. It includes examples for both HTTP and CloudEvent functions, which can be found in the `main.py` file. + +## Dependencies + +Install the dependencies for this example: + +```sh +pip install -r requirements.txt +``` + +## Running locally + +### HTTP Function + +To run the HTTP function locally, use the `functions-framework` command: + +```sh +functions-framework --target=hello_async_http +``` + +Then, send a request to it from another terminal: + +```sh +curl localhost:8080 +# Output: Hello, async world! +``` + +### CloudEvent Function + +To run the CloudEvent function, specify the target and set the signature type: + +```sh +functions-framework --target=hello_async_cloudevent --signature-type=cloudevent +``` + +Then, in another terminal, send a sample CloudEvent using the provided script: + +```sh +python send_cloud_event.py +``` + +## Deploying to Cloud Run + +You can deploy these functions to Cloud Run using the `gcloud` CLI. + +### HTTP Function + +```sh +gcloud run deploy async-http-function \ + --source . \ + --function hello_async_http \ + --base-image python312 \ + --region +``` + +### CloudEvent Function + +```sh +gcloud run deploy async-cloudevent-function \ + --source . \ + --function hello_async_cloudevent \ + --base-image python312 \ + --region +``` + +After deploying, you can invoke the CloudEvent function by sending an HTTP POST request with a CloudEvent payload to its URL. diff --git a/examples/cloud_run_async/main.py b/examples/cloud_run_async/main.py new file mode 100644 index 00000000..40062a95 --- /dev/null +++ b/examples/cloud_run_async/main.py @@ -0,0 +1,36 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import functions_framework.aio + +@functions_framework.aio.http +async def hello_async_http(request): + """ + An async HTTP function. + Args: + request (starlette.requests.Request): The request object. + Returns: + The response text, or an instance of any Starlette response class + (e.g. `starlette.responses.Response`). + """ + return "Hello, async world!" + +@functions_framework.aio.cloud_event +async def hello_async_cloudevent(cloud_event): + """ + An async CloudEvent function. + Args: + cloud_event (cloudevents.http.CloudEvent): The CloudEvent object. + """ + print(f"Received event with ID: {cloud_event['id']} and data {cloud_event.data}") diff --git a/examples/cloud_run_async/requirements.txt b/examples/cloud_run_async/requirements.txt new file mode 100644 index 00000000..b862cce2 --- /dev/null +++ b/examples/cloud_run_async/requirements.txt @@ -0,0 +1,4 @@ +functions-framework>=3.9.2,<4.0.0 + +# For testing +httpx<=0.28.1 diff --git a/examples/cloud_run_async/send_cloud_event.py b/examples/cloud_run_async/send_cloud_event.py new file mode 100644 index 00000000..714bc719 --- /dev/null +++ b/examples/cloud_run_async/send_cloud_event.py @@ -0,0 +1,38 @@ +#!/usr/local/bin/python + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import asyncio +import httpx + +from cloudevents.http import CloudEvent, to_structured + + +async def main(): + attributes = { + "Content-Type": "application/json", + "source": "from-galaxy-far-far-away", + "type": "cloudevent.greet.you", + } + data = {"name": "john"} + + event = CloudEvent(attributes, data) + + headers, data = to_structured(event) + + async with httpx.AsyncClient() as client: + await client.post("http://localhost:8080/", headers=headers, data=data) + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/cloud_run_streaming_http/README.md b/examples/cloud_run_streaming_http/README.md new file mode 100644 index 00000000..839b09c7 --- /dev/null +++ b/examples/cloud_run_streaming_http/README.md @@ -0,0 +1,65 @@ +# Deploying streaming functions to Cloud Run + +This sample shows how to deploy streaming functions to [Cloud Run](http://cloud.google.com/run) with the Functions Framework. The `main.py` file contains examples for both synchronous and asynchronous streaming. + +## Dependencies + +Install the dependencies for this example: + +```sh +pip install -r requirements.txt +``` + +## Running locally + +### Synchronous Streaming + +To run the synchronous streaming function locally: + +```sh +functions-framework --target=hello_stream +``` + +Then, send a request to it from another terminal: + +```sh +curl localhost:8080 +``` + +### Asynchronous Streaming + +To run the asynchronous streaming function locally: + +```sh +functions-framework --target=hello_stream_async +``` + +Then, send a request to it from another terminal: + +```sh +curl localhost:8080 +``` + +## Deploying to Cloud Run + +You can deploy these functions to Cloud Run using the `gcloud` CLI. + +### Synchronous Streaming + +```sh +gcloud run deploy streaming-function \ + --source . \ + --function hello_stream \ + --base-image python312 \ + --region +``` + +### Asynchronous Streaming + +```sh +gcloud run deploy streaming-async-function \ + --source . \ + --function hello_stream_async \ + --base-image python312 \ + --region +``` diff --git a/examples/cloud_run_streaming_http/main.py b/examples/cloud_run_streaming_http/main.py new file mode 100644 index 00000000..5010b1a3 --- /dev/null +++ b/examples/cloud_run_streaming_http/main.py @@ -0,0 +1,59 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import time +import asyncio +import functions_framework +import functions_framework.aio +from starlette.responses import StreamingResponse + +# Helper function for the synchronous streaming example. +def slow_numbers(minimum, maximum): + yield '
    ' + for number in range(minimum, maximum + 1): + yield '
  • %d
  • ' % number + time.sleep(0.5) + yield '
' + +@functions_framework.http +def hello_stream(request): + """ + A synchronous HTTP function that streams a response. + Args: + request (flask.Request): The request object. + Returns: + A generator, which will be streamed as the response. + """ + generator = slow_numbers(1, 10) + return generator, {'Content-Type': 'text/html'} + +# Helper function for the asynchronous streaming example. +async def slow_numbers_async(minimum, maximum): + yield '
    ' + for number in range(minimum, maximum + 1): + yield '
  • %d
  • ' % number + await asyncio.sleep(0.5) + yield '
' + +@functions_framework.aio.http +async def hello_stream_async(request): + """ + An asynchronous HTTP function that streams a response. + Args: + request (starlette.requests.Request): The request object. + Returns: + A starlette.responses.StreamingResponse. + """ + generator = slow_numbers_async(1, 10) + return StreamingResponse(generator, media_type='text/html') diff --git a/examples/cloud_run_streaming_http/requirements.txt b/examples/cloud_run_streaming_http/requirements.txt new file mode 100644 index 00000000..83e77d02 --- /dev/null +++ b/examples/cloud_run_streaming_http/requirements.txt @@ -0,0 +1 @@ +functions-framework>=3.9.2,<4.0.0 diff --git a/pyproject.toml b/pyproject.toml index 19912786..b187260f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "functions-framework" -version = "3.9.2" +version = "3.10.0" description = "An open source FaaS (Function as a service) framework for writing portable Python functions -- brought to you by the Google Cloud Functions team." readme = "README.md" requires-python = ">=3.7, <4" @@ -27,7 +27,7 @@ dependencies = [ "click>=7.0,<9.0", "watchdog>=1.0.0", "gunicorn>=22.0.0; platform_system!='Windows'", - "cloudevents>=1.2.0,<=1.11.0", # Must support python 3.7 + "cloudevents>=1.12.0,<=1.12.0", # Must support python 3.7 "Werkzeug>=0.14,<4.0.0", "starlette>=0.37.0,<1.0.0; python_version>='3.8'", "uvicorn>=0.18.0,<1.0.0; python_version>='3.8'", diff --git a/setup.py b/setup.py index 3ba48c93..28d0ea11 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ setup( name="functions-framework", - version="3.9.2", + version="3.10.0", description="An open source FaaS (Function as a service) framework for writing portable Python functions -- brought to you by the Google Cloud Functions team.", long_description=long_description, long_description_content_type="text/markdown", diff --git a/tox.ini b/tox.ini index cb0873b6..2e36e689 100644 --- a/tox.ini +++ b/tox.ini @@ -16,9 +16,6 @@ envlist = py38-ubuntu-22.04 py38-macos-13 py38-windows-latest - py37-ubuntu-22.04 - py37-macos-13 - py37-windows-latest [testenv] usedevelop = true @@ -31,10 +28,6 @@ deps = pretend setenv = PYTESTARGS = --cov=functions_framework --cov-branch --cov-report term-missing --cov-fail-under=100 - # Python 3.7: Use .coveragerc-py37 to exclude aio module from coverage since it requires Python 3.8+ (Starlette dependency) - py37-ubuntu-22.04: PYTESTARGS = --cov=functions_framework --cov-config=.coveragerc-py37 --cov-branch --cov-report term-missing --cov-fail-under=100 - py37-macos-13: PYTESTARGS = --cov=functions_framework --cov-config=.coveragerc-py37 --cov-branch --cov-report term-missing --cov-fail-under=100 - py37-windows-latest: PYTESTARGS = windows-latest: PYTESTARGS = commands = pytest {env:PYTESTARGS} {posargs}