mirror of
https://github.com/kennethreitz/responder.git
synced 2026-06-05 06:46:14 +00:00
0cbcaf9c4f
## Summary
Comprehensive post-v3.0.0 modernization: new features, bug fixes,
dependency cleanup, docs, and test coverage.
**New features:**
- **HTTP method filtering** — `@api.route("/data", methods=["GET"])`
- **Lifespan context manager** — modern async startup/shutdown
- **`api.exception_handler()`** — custom error handling per exception
type
- **`api.graphql()`** — one-liner GraphQL setup
- **`resp.file()`** — serve files from disk with auto content-type
- **before_request short-circuit** — set status code to skip route
handler
- **`req.path_params`** / **`req.client`** / **`req.is_json`** — new
request properties
- **`uuid`** and **`path`** route convertors
- **PEP 561 `py.typed`** marker
**Bug fixes:**
- Fix multipart parser losing headers
- Fix `url_for()` with typed params (`{id:int}`)
- Fix `resp.body` encoding crash on bytes content
- Fix Python 3.9 type syntax (`from __future__ import annotations`)
- Fix broken session test and no-op file upload test
- Fix helloworld example 404 on root path
**Dependencies:**
- Flattened — `pip install responder` gets everything
- Core: just starlette + uvicorn (down from 10 deps)
**Docs & README:**
- All new features documented in tour
- Modernized README features list
- Deployment guide: Docker, cloud, uvicorn
- Removed Pipenv, extras, stale references throughout
**Tests & quality:**
- 117 tests (up from 92), 91% coverage, 0 warnings
- CaseInsensitiveDict, GraphQL edge cases, staticfiles tests
- Ruff clean, all `tmpdir` → `tmp_path`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
231 lines
4.7 KiB
TOML
231 lines
4.7 KiB
TOML
[build-system]
|
|
build-backend = "setuptools.build_meta"
|
|
requires = [
|
|
"setuptools>=42",
|
|
]
|
|
|
|
[project]
|
|
name = "responder"
|
|
description = "A familiar HTTP Service Framework for Python."
|
|
readme = "README.md"
|
|
license = {text = "Apache 2.0"}
|
|
authors = [
|
|
{ name = "Kenneth Reitz", email = "me@kennethreitz.org" },
|
|
]
|
|
requires-python = ">=3.9"
|
|
classifiers = [
|
|
"Development Status :: 5 - Production/Stable",
|
|
"Environment :: Web Environment",
|
|
"Intended Audience :: Developers",
|
|
"License :: OSI Approved :: Apache Software License",
|
|
"Operating System :: OS Independent",
|
|
"Programming Language :: Python",
|
|
"Programming Language :: Python :: 3",
|
|
"Programming Language :: Python :: 3.9",
|
|
"Programming Language :: Python :: 3.10",
|
|
"Programming Language :: Python :: 3.11",
|
|
"Programming Language :: Python :: 3.12",
|
|
"Programming Language :: Python :: 3.13",
|
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
"Topic :: Internet :: WWW/HTTP",
|
|
]
|
|
dynamic = ["version"]
|
|
dependencies = [
|
|
"a2wsgi",
|
|
"apispec>=1.0.0",
|
|
"chardet",
|
|
"docopt-ng",
|
|
"graphene>=3",
|
|
"graphql-core>=3.1",
|
|
"marshmallow",
|
|
"pueblo[sfa-full]>=0.0.11",
|
|
"python-multipart",
|
|
"starlette[full]>=0.40",
|
|
"uvicorn[standard]",
|
|
]
|
|
|
|
[project.optional-dependencies]
|
|
develop = [
|
|
"poethepoet",
|
|
"pyproject-fmt",
|
|
"ruff",
|
|
"validate-pyproject",
|
|
]
|
|
docs = [
|
|
"alabaster<1.1",
|
|
"myst-parser[linkify]",
|
|
"sphinx>=5,<9",
|
|
"sphinx-autobuild",
|
|
"sphinx-copybutton",
|
|
"sphinx-design-elements",
|
|
"sphinxext.opengraph",
|
|
]
|
|
release = ["build", "twine"]
|
|
test = [
|
|
"flask",
|
|
"mypy",
|
|
"pytest",
|
|
"pytest-cov",
|
|
"pytest-mock",
|
|
"pytest-rerunfailures",
|
|
]
|
|
|
|
[project.scripts]
|
|
responder = "responder.ext.cli:cli"
|
|
|
|
[project.urls]
|
|
Homepage = "https://github.com/kennethreitz/responder"
|
|
Documentation = "https://responder.kennethreitz.org"
|
|
Repository = "https://github.com/kennethreitz/responder"
|
|
Issues = "https://github.com/kennethreitz/responder/issues"
|
|
|
|
[tool.setuptools.dynamic]
|
|
version = {attr = "responder.__version__.__version__"}
|
|
|
|
[tool.setuptools.package-data]
|
|
responder = ["py.typed"]
|
|
|
|
[tool.setuptools.packages.find]
|
|
exclude = ["tests"]
|
|
|
|
[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`.
|
|
]
|
|
|
|
lint.per-file-ignores."responder/util/cmd.py" = [ "A005" ] # Module shadows a Python standard-library module
|
|
|
|
lint.per-file-ignores."tests/*" = [
|
|
"ERA001", # Found commented-out code.
|
|
"S101", # Allow use of `assert`, and `print`.
|
|
]
|
|
|
|
[tool.pytest.ini_options]
|
|
addopts = """
|
|
-rfEXs -p pytester --strict-markers --verbosity=3
|
|
--cov --cov-report=term-missing --cov-report=xml
|
|
"""
|
|
filterwarnings = [
|
|
"error::UserWarning",
|
|
]
|
|
log_level = "DEBUG"
|
|
log_cli_level = "DEBUG"
|
|
log_format = "%(asctime)-15s [%(name)-36s] %(levelname)-8s: %(message)s"
|
|
minversion = "2.0"
|
|
testpaths = [
|
|
"responder",
|
|
"tests",
|
|
]
|
|
markers = [
|
|
]
|
|
xfail_strict = true
|
|
|
|
[tool.coverage.run]
|
|
branch = false
|
|
omit = [
|
|
"*.html",
|
|
"tests/*",
|
|
]
|
|
|
|
[tool.coverage.report]
|
|
fail_under = 0
|
|
show_missing = true
|
|
exclude_lines = [
|
|
"# pragma: no cover",
|
|
"raise NotImplemented",
|
|
]
|
|
|
|
[tool.mypy]
|
|
packages = [
|
|
"responder",
|
|
]
|
|
exclude = [
|
|
]
|
|
check_untyped_defs = true
|
|
explicit_package_bases = true
|
|
ignore_missing_imports = true
|
|
implicit_optional = true
|
|
install_types = true
|
|
namespace_packages = true
|
|
non_interactive = true
|
|
|
|
[tool.poe.tasks]
|
|
|
|
check = [
|
|
"test",
|
|
]
|
|
|
|
docs-autobuild = [
|
|
{ cmd = "sphinx-autobuild --open-browser --watch docs/source docs/source docs/build" },
|
|
]
|
|
docs-html = [
|
|
{ cmd = "sphinx-build -W --keep-going docs/source docs/build" },
|
|
]
|
|
docs-linkcheck = [
|
|
{ cmd = "sphinx-build -W --keep-going -b linkcheck docs/source docs/build" },
|
|
]
|
|
|
|
format = [
|
|
{ cmd = "ruff format ." },
|
|
# Configure Ruff not to auto-fix (remove!):
|
|
# unused imports (F401), unused variables (F841), `print` statements (T201), and commented-out code (ERA001).
|
|
{ cmd = "ruff check --fix --ignore=ERA --ignore=F401 --ignore=F841 --ignore=T20 --ignore=ERA001 ." },
|
|
{ cmd = "pyproject-fmt --keep-full-version pyproject.toml" },
|
|
]
|
|
|
|
lint = [
|
|
{ cmd = "ruff format --check ." },
|
|
{ cmd = "ruff check ." },
|
|
{ cmd = "validate-pyproject pyproject.toml" },
|
|
{ cmd = "mypy" },
|
|
]
|
|
|
|
release = [
|
|
{ cmd = "python -m build" },
|
|
{ cmd = "twine upload --skip-existing dist/*" },
|
|
]
|
|
|
|
[tool.poe.tasks.test]
|
|
cmd = "pytest"
|
|
help = "Invoke software tests"
|
|
|
|
[tool.poe.tasks.test.args.expression]
|
|
options = [ "-k" ]
|
|
|
|
[tool.poe.tasks.test.args.marker]
|
|
options = [ "-m" ]
|