Files
responder/pyproject.toml
T
kennethreitz 09325515f9 CI: install orjson and fakeredis[lua] only where wheels exist
The orjson and lupa (fakeredis[lua]) test dependencies have no wheels for
free-threaded CPython (3.14t), so uv tried to build orjson from Rust source
on that matrix cell and failed, reddening the 8.1.0 Tests run. PEP 508
markers can't distinguish 3.14t from 3.14, so the previous
"CPython and python_version < '3.15'" marker over-matched.

Move both compiled optionals out of the [test] extra and install them in a
version-scoped CI step (CPython 3.11-3.14). The JSON and atomic rate-limit
tests that use them already skip gracefully wherever they are absent, so
3.14t, 3.15, and PyPy exercise the stdlib/fallback paths instead. No runtime
change: the shipped package and its [orjson] feature extra are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 12:49:49 -04:00

242 lines
6.4 KiB
TOML

[build-system]
build-backend = "setuptools.build_meta"
requires = [
# PEP 639 SPDX `license = "Apache-2.0"` requires setuptools>=77.
"setuptools>=77",
]
[project]
name = "responder"
description = "A familiar HTTP Service Framework for Python."
readme = "README.md"
license = "Apache-2.0"
authors = [
{ name = "Kenneth Reitz", email = "me@kennethreitz.org" },
]
requires-python = ">=3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python :: Free Threading",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Internet :: WWW/HTTP",
]
dynamic = [ "version" ]
dependencies = [
"a2wsgi",
"apispec>=6.6",
"chardet",
"docopt-ng",
"itsdangerous",
"jinja2>=3.1",
"marshmallow>=3.20",
"msgpack",
"pydantic>=2",
"python-multipart>=0.0.12",
"pyyaml>=6",
"starlette[full]>=1",
"uvicorn[standard]",
]
optional-dependencies.cli = [
"pueblo[sfa-full]>=0.0.11",
]
optional-dependencies.develop = [
"pyproject-fmt",
"ruff",
"validate-pyproject",
]
optional-dependencies.docs = [
"alabaster<1.1",
"myst-parser",
"sphinx>=5,<9",
"sphinx-autobuild",
"sphinx-copybutton",
"sphinx-design-elements",
]
optional-dependencies.graphql = [
"graphene>=3",
"graphql-core>=3.1",
]
optional-dependencies.jwt = [
"pyjwt>=2.8",
]
optional-dependencies.orjson = [
"orjson>=3.9",
]
optional-dependencies.release = [ "build", "twine" ]
optional-dependencies.server = [
"granian",
]
optional-dependencies.test = [
# Exercises the JWTAuth RS256/ES256 and algorithm-confusion security tests.
"cryptography",
"fakeredis",
"flask",
"graphene>=3",
"mypy",
"openapi-spec-validator",
"pueblo[sfa-full]>=0.0.11",
"pyjwt>=2.8",
"pytest",
"pytest-cov",
"pytest-mock",
"pytest-rerunfailures",
"types-pyyaml",
# NOTE: the compiled optional backends that only exercise fallback-guarded
# paths — orjson (JSON) and fakeredis[lua] (atomic rate-limit script) — are
# NOT listed here. They lack wheels on free-threaded CPython and PyPy, where
# building from source fails; PEP 508 markers can't distinguish 3.14t from
# 3.14, so CI installs them in a separate version-scoped step and the tests
# skip gracefully wherever they are absent.
]
urls.Documentation = "https://responder.kennethreitz.org"
urls.Homepage = "https://responder.kennethreitz.org"
urls.Issues = "https://github.com/kennethreitz/responder/issues"
urls.Repository = "https://github.com/kennethreitz/responder"
scripts.responder = "responder.ext.cli:cli"
[tool.setuptools]
dynamic.version = { attr = "responder.__version__.__version__" }
package-data.responder = [ "py.typed", "ext/openapi/docs/*.html" ]
[tool.setuptools.packages.find]
include = [ "responder*" ]
exclude = [ "tests*", "docs*", "examples*" ]
[tool.ruff]
line-length = 90
extend-exclude = [
"docs/source/conf.py",
]
lint.select = [
# Builtins
"A",
# Bugbear
"B",
# comprehensions
"C4",
# Pycodestyle
"E",
# eradicate
"ERA",
# Pyflakes
"F",
# isort
"I",
# pandas-vet
"PD",
# return
"RET",
# Bandit
"S",
# print
"T20",
"W",
# flake8-2020
"YTT",
]
lint.extend-ignore = [
"S101", # Allow use of `assert`.
]
# The Query/Header/Cookie/Path markers are designed to be called in parameter
# defaults (FastAPI-style), so they are safe there.
lint.flake8-bugbear.extend-immutable-calls = [
"responder.Query",
"responder.Header",
"responder.Cookie",
"responder.Path",
"responder.Form",
"responder.File",
"responder.Depends",
"responder.params.Query",
"responder.params.Header",
"responder.params.Cookie",
"responder.params.Path",
"responder.params.Form",
"responder.params.File",
"responder.params.Depends",
]
lint.per-file-ignores."examples/*" = [ "T201" ] # Allow `print` in examples
lint.per-file-ignores."responder/util/cmd.py" = [ "A005" ] # Module shadows a Python standard-library module
lint.per-file-ignores."scripts/release_check.py" = [
"S603", # Release guard intentionally shells out to git/uv/twine.
"S607", # Use PATH-resolved project tools in the developer environment.
"T201", # Progress output is useful for release runs.
]
lint.per-file-ignores."scripts/release.py" = [
"S603", # Release orchestration intentionally shells out to git/gh/uv/twine.
"S607", # Use PATH-resolved project tools in the developer environment.
"T201", # Progress output is useful for release runs.
]
lint.per-file-ignores."tests/*" = [
"A002", # Allow shadowing builtins (e.g. `id`) in view signatures.
"E501", # Allow long lines.
"ERA001", # Found commented-out code.
"S101", # Allow use of `assert`, and `print`.
"S105", # Allow dummy secret-key literals in fixtures.
"S106", # Allow dummy secret-key literals in fixtures.
]
[tool.mypy]
packages = [
"responder",
]
exclude = []
check_untyped_defs = true
disallow_incomplete_defs = true
explicit_package_bases = true
ignore_missing_imports = true
install_types = true
namespace_packages = true
no_implicit_optional = true
non_interactive = true
warn_redundant_casts = true
warn_unused_ignores = true
[tool.pytest]
ini_options.addopts = """
-rfEXs -p pytester --strict-markers --verbosity=3
--cov --cov-report=term-missing --cov-report=xml
"""
ini_options.filterwarnings = [
"error::UserWarning",
]
ini_options.log_level = "DEBUG"
ini_options.log_cli_level = "DEBUG"
ini_options.log_format = "%(asctime)-15s [%(name)-36s] %(levelname)-8s: %(message)s"
ini_options.minversion = "2.0"
ini_options.testpaths = [
"responder",
"tests",
]
ini_options.markers = []
ini_options.xfail_strict = true
[tool.coverage]
run.branch = false
# Only measure the package itself — without this, generated artifacts (e.g.
# clientgen output written to pytest tmp dirs) and examples/*.py pollute the
# report and drag the total down.
run.source = [ "responder" ]
run.omit = [
"*.html",
"examples/*",
"tests/*",
]
report.exclude_lines = [
"# pragma: no cover",
"raise NotImplemented",
]
report.fail_under = 80
report.show_missing = true