Skip to content

feat: modernize packaging with pyproject.toml and uv #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,50 @@ information on using pull requests.

## Setup local environment

Clone the project and run the following commands to setup your environment
Clone the project and install [uv](https://github.com/astral-sh/uv) (our package manager):

```sh
python3.11 -m venv venv
source venv/bin/activate
pip3 install --upgrade pip
python3.11 -m pip install -e ".[dev]"
# Install uv (if not already installed). You can also use 'pip install uv'.
curl -LsSf https://astral.sh/uv/install.sh | sh

# Clone and setup the project
git clone https://github.com/firebase/firebase-functions-python.git
cd firebase-functions-python
uv sync
```

(this also applies to setting up samples environment for each sample)
This will automatically:
- Create a virtual environment
- Install all runtime and development dependencies
- Use the Python version specified in `.python-version` (3.10)

(For samples, you can use the same approach but run `uv sync` in each sample directory)

### Running tests

Without coverage:
```bash
python3.11 -m pytest
uv run pytest
```

With coverage:
```bash
python3.11 -m pytest --cov=src --cov-report term --cov-report html --cov-report xml -vv
uv run pytest --cov=src --cov-report term --cov-report html --cov-report xml -vv
```

### Formatting code

```bash
python3.11 -m ruff format .
uv run ruff format .
```

### Running lints & type checking

```bash
# Type checking
python3.11 -m mypy .
uv run mypy .
# Linting
python3.11 -m ruff check .
uv run ruff check .
```

### Generating Docs
Expand Down
67 changes: 29 additions & 38 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,18 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
python-version: ${{ matrix.python }}
enable-cache: true
- name: Set up Python ${{ matrix.python }}
run: uv python install ${{ matrix.python }}
- name: Install dependencies
run: |
python${{ matrix.python }} -m venv venv
source venv/bin/activate
pip3 install --upgrade pip
python${{ matrix.python }} -m pip install -e ".[dev]"
uv sync --python ${{ matrix.python }}
- name: Test with pytest & coverage
run: |
source venv/bin/activate
python${{ matrix.python }} -m pytest --cov=src --cov-report term --cov-report html --cov-report xml -vv
uv run --python ${{ matrix.python }} pytest --cov=src --cov-report term --cov-report html --cov-report xml -vv
# TODO requires activation for this repository on codecov website first.
# - name: Upload coverage to Codecov
# uses: codecov/codecov-action@v3
Expand All @@ -38,44 +36,39 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
python-version: "3.10"
enable-cache: true
- name: Set up Python
run: uv python install 3.10
- name: Install dependencies
run: |
python3.10 -m venv venv
source venv/bin/activate
pip3 install --upgrade pip
python3.10 -m pip install -e ".[dev]"
uv sync
- name: Lint with ruff
run: |
source venv/bin/activate
python3.10 -m ruff check .
uv run ruff check .
- name: Lint with mypy
run: |
source venv/bin/activate
python3.10 -m mypy .
uv run mypy .

docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
python-version: "3.10"
enable-cache: true
- name: Set up Python
run: uv python install 3.10
- name: Install dependencies
run: |
python3.10 -m venv venv
source venv/bin/activate
pip3 install --upgrade pip
python3.10 -m pip install -e ".[dev]"
uv sync
- name: Generate Reference Docs
run: |
source venv/bin/activate
mkdir ./docs/build
./docs/generate.sh --out=./docs/build/ --pypath=src/
uv run ./docs/generate.sh --out=./docs/build/ --pypath=src/
- uses: actions/upload-artifact@v4
name: Upload Docs Preview
with:
Expand All @@ -86,17 +79,15 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
- name: Install uv
uses: astral-sh/setup-uv@v3
with:
python-version: "3.10"
enable-cache: true
- name: Set up Python
run: uv python install 3.10
- name: Install dependencies
run: |
python3.10 -m venv venv
source venv/bin/activate
pip3 install --upgrade pip
python3.10 -m pip install -e ".[dev]"
uv sync
- name: Check Formatting with ruff
run: |
source venv/bin/activate
python3.10 -m ruff format --check .
uv run ruff format --check .
13 changes: 8 additions & 5 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,23 @@ jobs:
with:
python-version: '3.10'

- name: Install uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true

- name: Install dependencies
run: |
pip install --upgrade pip
python -m pip install -e ".[dev]"
uv sync --dev

- name: Test with pytest & coverage
run: |
python -m pytest --cov=src --cov-report term --cov-report html --cov-report xml -vv
uv run pytest --cov=src --cov-report term --cov-report html --cov-report xml -vv

# Build the Python Wheel and the source distribution.
- name: Package release artifacts
run: |
python -m pip install setuptools wheel
python setup.py bdist_wheel sdist
uv run python -m build

# Attach the packaged artifacts to the workflow output. These can be manually
# downloaded for later inspection if necessary.
Expand Down
5 changes: 0 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,3 @@ doc/dist
.idea
.vscode/*
!.vscode/settings.json

# Local development files
async.md
modernization.md
uv.lock
68 changes: 67 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,73 @@
[build-system]
requires = ["setuptools>=63.4.2", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "firebase_functions"
description = "Firebase Functions Python SDK"
readme = "README.md"
license = {text = "Apache-2.0"}
authors = [
{name = "Firebase Team"}
]
keywords = ["firebase", "functions", "google", "cloud"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
]
requires-python = ">=3.10"
dependencies = [
"flask>=2.1.2",
"functions-framework>=3.0.0",
"firebase-admin>=6.0.0",
"pyyaml>=6.0",
"typing-extensions>=4.4.0",
"cloudevents>=1.2.0,<2.0.0",
"flask-cors>=3.0.10",
"pyjwt[crypto]>=2.5.0",
"google-events==0.5.0",
"google-cloud-firestore>=2.11.0",
]
dynamic = ["version"]

[project.urls]
"Homepage" = "https://github.com/firebase/firebase-functions-python"
"Documentation" = "https://firebase.google.com/docs/functions"
"Repository" = "https://github.com/firebase/firebase-functions-python"
"Bug Tracker" = "https://github.com/firebase/firebase-functions-python/issues"

[dependency-groups]
dev = [
"pytest>=7.1.2,<9",
"setuptools>=63.4.2",
"pytest-cov>=3.0.0",
"mypy>=1.0.0",
"sphinx>=6.1.3",
"sphinxcontrib-napoleon>=0.7",
"toml>=0.10.2",
"google-cloud-tasks>=2.13.1",
"ruff>=0.1.0",
"build>=1.0.0",
]

[tool.setuptools]
package-dir = {"" = "src"}
packages = ["firebase_functions"]

[tool.setuptools.package-data]
firebase_functions = ["py.typed"]

[tool.setuptools.dynamic]
version = {attr = "firebase_functions.__version__"}

[tool.pytest.ini_options]
pythonpath = [
".", "src/",
]

[tool.coverage]
[tool.coverage.run]
omit = [
Expand Down Expand Up @@ -43,4 +109,4 @@ ignore = [
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
line-ending = "auto"
69 changes: 4 additions & 65 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,69 +15,8 @@
Setup for Firebase Functions Python.
"""

from os import path
from setuptools import setup

from setuptools import find_packages, setup

install_requires = [
"flask>=2.1.2",
"functions-framework>=3.0.0",
"firebase-admin>=6.0.0",
"pyyaml>=6.0",
"typing-extensions>=4.4.0",
"cloudevents>=1.2.0,<2.0.0",
"flask-cors>=3.0.10",
"pyjwt[crypto]>=2.5.0",
"google-events==0.5.0",
"google-cloud-firestore>=2.11.0",
]

dev_requires = [
"pytest>=7.1.2",
"setuptools>=63.4.2",
"pytest-cov>=3.0.0",
"mypy>=1.0.0",
"sphinx>=6.1.3",
"sphinxcontrib-napoleon>=0.7",
"toml>=0.10.2",
"google-cloud-tasks>=2.13.1",
"ruff>=0.1.0",
]

# Read in the package metadata per recommendations from:
# https://packaging.python.org/guides/single-sourcing-package-version/
init_path = path.join(
path.dirname(path.abspath(__file__)), "src", "firebase_functions", "__init__.py"
)
version = {}
with open(init_path) as fp:
exec(fp.read(), version) # pylint: disable=exec-used

long_description = (
"The Firebase Functions Python SDK provides an SDK for defining Cloud Functions for Firebase."
)

setup(
name="firebase_functions",
version=version["__version__"],
description="Firebase Functions Python SDK",
long_description=long_description,
url="https://github.com/firebase/firebase-functions-python",
author="Firebase Team",
keywords=["firebase", "functions", "google", "cloud"],
license="Apache License 2.0",
install_requires=install_requires,
extras_require={"dev": dev_requires},
packages=find_packages(where="src"),
package_dir={"": "src"},
include_package_data=True,
package_data={"firebase_functions": ["py.typed"]},
python_requires=">=3.10",
classifiers=[
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Topic :: Software Development :: Build Tools",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
],
)
# All metadata is now defined in pyproject.toml.
# This file is only for compatibility with legacy tools.
setup()
Loading
Loading