Skip to content

chore: modernize Python tooling setup (Phase 1) #244

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

Closed
wants to merge 1 commit into from
Closed
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
6 changes: 6 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# .git-blame-ignore-revs
# Use this file to ignore commits in git blame that are just formatting changes
# Configure with: git config blame.ignoreRevsFile .git-blame-ignore-revs

# Switch from yapf to ruff formatting (one-time reformatting)
# TODO: Add commit hash here after formatting commit
57 changes: 28 additions & 29 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Install uv
uses: astral-sh/setup-uv@v2
with:
version: "latest"
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v4
with:
python-version: ${{ 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 --extra dev
- 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 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 +38,43 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install uv
uses: astral-sh/setup-uv@v2
with:
version: "latest"
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "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]"
- name: Lint with pylint
uv sync --extra dev
- name: Lint with ruff
run: |
source venv/bin/activate
python3.10 -m pylint $(git ls-files '*.py')
- name: Lint with mypy
uv run ruff check .
- name: Type check 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: Install uv
uses: astral-sh/setup-uv@v2
with:
version: "latest"
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "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 --extra dev
- 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 +85,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install uv
uses: astral-sh/setup-uv@v2
with:
version: "latest"
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "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]"
- name: Check Formatting
uv sync --extra dev
- name: Check Formatting with ruff
run: |
source venv/bin/activate
yapf -d -r -p .
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 @@ -36,25 +36,28 @@ jobs:
- name: Checkout source for staging
uses: actions/checkout@v3

- name: Install uv
uses: astral-sh/setup-uv@v2
with:
version: "latest"

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'

- name: Install dependencies
run: |
pip install --upgrade pip
python -m pip install -e ".[dev]"
uv sync --extra 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: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ profile_default/
ipython_config.py

# pyenv
.python-version
# .python-version # We're now tracking this for uv

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
Expand Down Expand Up @@ -139,3 +139,6 @@ doc/dist
.idea
.vscode/*
!.vscode/settings.json

# uv
uv.lock
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.10
194 changes: 180 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,23 +1,189 @@
[tool.pytest.ini_options]
pythonpath = [
".", "src/",
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "firebase_functions"
description = "Firebase Functions Python SDK"
readme = "README.md"
license = "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",
"Programming Language :: Python :: 3.12",
]
requires-python = ">=3.10"
dynamic = ["version"]
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",
]

[project.optional-dependencies]
dev = [
"pytest>=7.1.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",
"pre-commit>=3.0.0",
"tox>=4.0.0",
"build>=1.0.0",
]
test = [
"pytest>=7.1.2",
"pytest-cov>=3.0.0",
"google-cloud-tasks>=2.13.1",
]
docs = [
"sphinx>=6.1.3",
"sphinxcontrib-napoleon>=0.7",
]

[project.urls]
Homepage = "https://github.com/firebase/firebase-functions-python"
Repository = "https://github.com/firebase/firebase-functions-python"
Issues = "https://github.com/firebase/firebase-functions-python/issues"

[tool.setuptools]
packages = ["firebase_functions", "firebase_functions.private"]
package-dir = {"" = "src"}
include-package-data = true

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

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

[tool.pytest.ini_options]
pythonpath = [".", "src/"]
testpaths = ["tests"]
addopts = "-v --cov=firebase_functions --cov-report=term-missing"

[tool.coverage]
[tool.coverage.run]
source = ["src/firebase_functions"]
omit = [
'__init__.py',
'tests/*',
'*/tests/*',
"__init__.py",
"tests/*",
"*/tests/*",
]

[tool.coverage.report]
skip_empty = true
[tool.yapf]
based_on_style = "google"
indent_width = 4
[tool.yapfignore]
ignore_patterns = [
"venv",
"build",
"dist",
show_missing = true
precision = 2

[tool.mypy]
python_version = "3.10"
exclude = ["build", "dist", "venv", "docs"]
ignore_missing_imports = true
enable_incomplete_feature = ["Unpack"]
strict = true
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true

[[tool.mypy.overrides]]
module = "yaml.*"
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = "cloudevents.*"
ignore_missing_imports = true

[tool.ruff]
target-version = "py310"
line-length = 100
indent-width = 4

[tool.ruff.lint]
# Enable Pyflakes `E` and `F` codes by default, plus additional rules
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"UP", # pyupgrade
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"PL", # pylint
"PIE", # flake8-pie
"RET", # flake8-return
"SIM", # flake8-simplify
"TCH", # flake8-type-checking
"PTH", # flake8-use-pathlib
"ERA", # eradicate
"TRY", # tryceratops
"RUF", # Ruff-specific rules
]

# Disable specific rules to match existing pylint configuration
ignore = [
"PLR0913", # Too many arguments
"PLR0912", # Too many branches
"PLR0915", # Too many statements
"PLR2004", # Magic value used in comparison
"PLW0603", # Using the global statement
"PLC0415", # Import outside toplevel
"E501", # Line too long (handled by formatter)
"TRY003", # Avoid specifying long messages outside the exception class
"TRY400", # Use logging.exception instead of logging.error
"B008", # Do not perform function calls in argument defaults
"SIM108", # Use ternary operator
"SIM114", # Combine if branches using logical or
"RET504", # Unnecessary variable assignment before return
"RET505", # Unnecessary else after return
"RET506", # Unnecessary else after raise
# Removed UP007 to allow modern Union type syntax
]

# Enable Python 3.10+ specific rules
pyupgrade.keep-runtime-typing = false

[tool.ruff.lint.pylint]
max-args = 10
max-branches = 20
max-returns = 10
max-statements = 100

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["PLR2004", "PLR0913"]
"setup.py" = ["ALL"]

[tool.ruff.lint.isort]
known-first-party = ["firebase_functions"]
combine-as-imports = true
split-on-trailing-comma = false

[tool.ruff.format]
quote-style = "double" # Consistent double quotes (Black-style)
indent-style = "space"
skip-magic-trailing-comma = false # Always add trailing commas for cleaner diffs
line-ending = "auto"
docstring-code-format = true # Format code examples in docstrings
Loading