diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index e913bef1..8b137891 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -1,9 +1 @@ -assign_prs: - - HKwinterhalter - - nifflets - - liuyunnnn -assign_issues: - - HKwinterhalter - - nifflets - - liuyunnnn diff --git a/.github/workflows/buildpack-integration-test.yml b/.github/workflows/buildpack-integration-test.yml index 0c9e6eff..234c24ef 100644 --- a/.github/workflows/buildpack-integration-test.yml +++ b/.github/workflows/buildpack-integration-test.yml @@ -58,3 +58,29 @@ jobs: builder-runtime: 'python310' builder-runtime-version: '3.10' start-delay: 5 + python311: + uses: GoogleCloudPlatform/functions-framework-conformance/.github/workflows/buildpack-integration-test.yml@main + with: + http-builder-source: 'tests/conformance' + http-builder-target: 'write_http_declarative' + cloudevent-builder-source: 'tests/conformance' + cloudevent-builder-target: 'write_cloud_event_declarative' + prerun: 'tests/conformance/prerun.sh ${{ github.sha }}' + builder-runtime: 'python311' + builder-runtime-version: '3.11' + start-delay: 5 +# Python 3.12 conformance tests are disabled due to the buildpack defaulting to +# Ubuntu 18.04, which has no Python 3.12 version, and being unable to specify +# the OS/stack via the conformance test configuration +# +# python312: +# uses: GoogleCloudPlatform/functions-framework-conformance/.github/workflows/buildpack-integration-test.yml@main +# with: +# http-builder-source: 'tests/conformance' +# http-builder-target: 'write_http_declarative' +# cloudevent-builder-source: 'tests/conformance' +# cloudevent-builder-target: 'write_cloud_event_declarative' +# prerun: 'tests/conformance/prerun.sh ${{ github.sha }}' +# builder-runtime: 'python312' +# builder-runtime-version: '3.12' +# start-delay: 5 diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index 0d86d788..4e066990 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -10,10 +10,16 @@ permissions: read-all jobs: build: - runs-on: ubuntu-latest strategy: matrix: - python: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12'] + python: ['3.9', '3.10', '3.11', '3.12'] + platform: [ubuntu-latest] + 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@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9b5609a5..815c6308 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,7 +28,7 @@ jobs: - name: Build distributions run: python -m build - name: Publish - uses: pypa/gh-action-pypi-publish@1f5d4ec244f65dce93685ee3e98e77123f090866 # main + uses: pypa/gh-action-pypi-publish@916e57631f04a497e4bec0e29e80684e45b4305e # main with: user: __token__ password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 463340a5..404b5159 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -1,5 +1,5 @@ name: Python Unit CI -on: +on: push: branches: - main @@ -13,8 +13,9 @@ jobs: matrix: python: ['3.7', '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-14 + # Python <= 3.9 is not available on macos-latest # Workaround for https://github.com/actions/setup-python/issues/696 + # Python <= 3.8 is not available on ubuntu-latest exclude: - platform: macos-latest python: '3.9' @@ -22,6 +23,10 @@ jobs: 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' @@ -29,6 +34,10 @@ jobs: 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 @@ -39,7 +48,9 @@ jobs: allowed-endpoints: > auth.docker.io:443 files.pythonhosted.org:443 + api.github.com:443 github.com:443 + objects.githubusercontent.com:443 production.cloudflare.docker.com:443 pypi.org:443 registry-1.docker.io:443 diff --git a/CHANGELOG.md b/CHANGELOG.md index e2438f81..8231717d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,20 @@ 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.8.3](https://github.com/GoogleCloudPlatform/functions-framework-python/compare/v3.8.2...v3.8.3) (2025-05-14) + + +### Bug Fixes + +* Switch to `pyproject.toml` based builds ([#365](https://github.com/GoogleCloudPlatform/functions-framework-python/issues/365)) ([4c44d08](https://github.com/GoogleCloudPlatform/functions-framework-python/commit/4c44d08c5ebb304e80a3adc3f8e6d150987b29bb)) +* Update minimum required version of Flask to 2.0 ([#356](https://github.com/GoogleCloudPlatform/functions-framework-python/issues/356)) ([c6eab2f](https://github.com/GoogleCloudPlatform/functions-framework-python/commit/c6eab2fecb913d5bab1d5dbd6ba2e34b7d6cf9b9)) +* Update test suite for EOL Python versions ([#360](https://github.com/GoogleCloudPlatform/functions-framework-python/issues/360)) ([c0fa420](https://github.com/GoogleCloudPlatform/functions-framework-python/commit/c0fa420970d36d57adceaf70bbaea784e427e594)) + + +### Documentation + +* Add a development guide ([#359](https://github.com/GoogleCloudPlatform/functions-framework-python/issues/359)) ([9348c87](https://github.com/GoogleCloudPlatform/functions-framework-python/commit/9348c87cf05eae3726d041f26e43db586951cebb)) + ## [3.8.2](https://github.com/GoogleCloudPlatform/functions-framework-python/compare/v3.8.1...v3.8.2) (2024-11-13) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 00000000..f6966656 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,55 @@ +# Development + +Quickstart for functions-framework maintainers. + +## Environment setup + +Install [tox](https://pypi.org/p/tox), the test runner: + +``` +$ python -m pip install -U tox +``` + +## Running linting + +Linting can be run with: + +``` +$ python -m tox -e lint +``` + +## Running tests + +All tests can be run with: + +``` +$ python -m tox +``` + +Tests for the current Python version can be run with: + +``` +$ python -m tox -e py +``` + +Tests for a specific Python version can be run with: + +``` +$ python -m tox -e py3.12 +``` + +A specific test file (e.g. `tests/test_cli.py`) can be run with: + +``` +$ python -m tox -e py -- tests/test_cli.py +``` + +A specific test in the file (e.g. `test_cli_no_arguements` in `tests/test_cli.py`) can be run with: + +``` +$ python -m tox -e py -- tests/test_cli.py::test_cli_no_arguments +``` + +## Releasing + +Releases are triggered via the [Release Please](https://github.com/apps/release-please) app, which in turn kicks off the [Release to PyPI](https://github.com/GoogleCloudPlatform/functions-framework-python/blob/main/.github/workflows/release.yml) workflow. diff --git a/README.md b/README.md index a234586c..d564ad92 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,8 @@ Python functions -- brought to you by the Google Cloud Functions team. The Functions Framework lets you write lightweight functions that run in many different environments, including: -* [Google Cloud Functions](https://cloud.google.com/functions/) +* [Google Cloud Run Functions](https://cloud.google.com/functions/) * Your local development machine -* [Cloud Run and Cloud Run for Anthos](https://cloud.google.com/run/) * [Knative](https://github.com/knative/)-based environments The framework allows you to go from: @@ -294,7 +293,7 @@ https://cloud.google.com/functions/docs/tutorials/pubsub#functions_helloworld_pu ## Run your function on serverless platforms -### Google Cloud Functions +### Google Cloud Run functions This Functions Framework is based on the [Python Runtime on Google Cloud Functions](https://cloud.google.com/functions/docs/concepts/python-runtime). @@ -302,12 +301,6 @@ On Cloud Functions, using the Functions Framework is not necessary: you don't ne 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). -### Cloud Run/Cloud Run on GKE - -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) - -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). - ### Container environments based on Knative 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 | `--source` | `FUNCTION_SOURCE` | The path to the file containing your function. Default: `main.py` (in the current working directory) | | `--debug` | `DEBUG` | A flag that allows to run functions-framework to run in debug mode, including live reloading. Default: `False` | -## Enable Google Cloud Function Events +## Enable Google Cloud Run function Events The Functions Framework can unmarshall incoming -Google Cloud Functions [event](https://cloud.google.com/functions/docs/concepts/events-triggers#events) payloads to `event` and `context` objects. +Google Cloud Run functions [event](https://cloud.google.com/functions/docs/concepts/events-triggers#events) payloads to `event` and `context` objects. These will be passed as arguments to your function when it receives a request. Note that your function must use the `event`-style function signature: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..c160562f --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,57 @@ +[project] +name = "functions-framework" +version = "3.8.3" +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.5, <4" +# Once we drop support for Python 3.7 and 3.8, this can become +# license = "Apache-2.0" +license = {text = "Apache-2.0"} +authors = [ + { name = "Google LLC", email = "googleapis-packages@google.com" } +] +maintainers = [ + { name = "Google LLC", email = "googleapis-packages@google.com" } +] +keywords = ["functions-framework"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] +dependencies = [ + "flask>=2.0,<4.0", + "click>=7.0,<9.0", + "watchdog>=1.0.0", + "gunicorn>=22.0.0; platform_system!='Windows'", + "cloudevents>=1.2.0,<2.0.0", + "Werkzeug>=0.14,<4.0.0", +] + +[project.urls] +Homepage = "https://github.com/googlecloudplatform/functions-framework-python" + +[project.scripts] +ff = "functions_framework._cli:_cli" +functions-framework = "functions_framework._cli:_cli" +functions_framework = "functions_framework._cli:_cli" +functions-framework-python = "functions_framework._cli:_cli" +functions_framework_python = "functions_framework._cli:_cli" + +[build-system] +requires = ["setuptools>=61.0.0"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +functions_framework = ["py.typed"] + +[tool.setuptools.package-dir] +"" = "src" diff --git a/setup.py b/setup.py deleted file mode 100644 index 14f0b106..00000000 --- a/setup.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from io import open -from os import path - -from setuptools import find_packages, setup - -here = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(here, "README.md"), encoding="utf-8") as f: - long_description = f.read() - -setup( - name="functions-framework", - version="3.8.2", - 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", - url="https://github.com/googlecloudplatform/functions-framework-python", - author="Google LLC", - author_email="googleapis-packages@google.com", - classifiers=[ - "Development Status :: 5 - Production/Stable ", - "Intended Audience :: Developers", - "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - ], - keywords="functions-framework", - packages=find_packages(where="src"), - package_data={"functions_framework": ["py.typed"]}, - namespace_packages=["google", "google.cloud"], - package_dir={"": "src"}, - python_requires=">=3.5, <4", - install_requires=[ - "flask>=1.0,<4.0", - "click>=7.0,<9.0", - "watchdog>=1.0.0", - "gunicorn>=22.0.0; platform_system!='Windows'", - "cloudevents>=1.2.0,<2.0.0", - "Werkzeug>=0.14,<4.0.0", - ], - entry_points={ - "console_scripts": [ - "ff=functions_framework._cli:_cli", - "functions-framework=functions_framework._cli:_cli", - "functions_framework=functions_framework._cli:_cli", - "functions-framework-python=functions_framework._cli:_cli", - "functions_framework_python=functions_framework._cli:_cli", - ] - }, -) diff --git a/tox.ini b/tox.ini index 6ba6d3b4..1599608c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,24 @@ [tox] -envlist = py{35,36,37,38,39,310}-{ubuntu-latest,macos-latest,windows-latest},lint +envlist = + lint + py312-ubuntu-latest + py312-macos-latest + py312-windows-latest + py311-ubuntu-latest + py311-macos-latest + py311-windows-latest + py310-ubuntu-latest + py310-macos-latest + py310-windows-latest + py39-ubuntu-latest + py39-macos-13 + py39-windows-latest + py38-ubuntu-22.04 + py38-macos-13 + py38-windows-latest + py37-ubuntu-22.04 + py37-macos-13 + py37-windows-latest [testenv] usedevelop = true @@ -21,9 +40,10 @@ deps = twine isort mypy + build commands = - black --check src tests setup.py conftest.py --exclude tests/test_functions/background_load_error/main.py - isort -c src tests setup.py conftest.py + black --check src tests conftest.py --exclude tests/test_functions/background_load_error/main.py + isort -c src tests conftest.py mypy tests/test_typing.py - python setup.py --quiet sdist bdist_wheel + python -m build twine check dist/*