pyproject.toml
Rama main · réplica de lectura del repositorio original.
[project]
name = "foilstack"
dynamic = ["version"]
description = "Open-source card scanning, inventory and listing export. Self-hostable."
readme = "README.md"
requires-python = ">=3.11"
license = { text = "AGPL-3.0-or-later" }
keywords = ["tcg", "trading-cards", "inventory", "mtg", "pokemon", "self-hosted"]
authors = [{ name = "foilstack contributors" }]
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Web Environment",
"Framework :: FastAPI",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Games/Entertainment",
"Topic :: Office/Business",
]
dependencies = [
"fastapi>=0.115",
"uvicorn[standard]>=0.30",
"sqlalchemy>=2.0",
"psycopg[binary]>=3.2",
"pgvector>=0.3.6",
# Runtime, not development. `foilstack migrate` is how an installed copy
# creates its schema, and without this it fails on an ImportError at the
# one moment a new user has nothing else to try.
"alembic>=1.13",
"argon2-cffi>=23.1",
"itsdangerous>=2.2",
"jinja2>=3.1",
"python-multipart>=0.0.9",
"httpx>=0.27",
"numpy>=1.26",
"pillow>=10.0",
"pydantic>=2.7",
# Runtime, not development, and declared rather than leaned on: it arrives
# transitively with uvicorn[standard], and a settings read that silently
# stops finding `.env` because a transitive dependency moved is the kind of
# break that points at the wrong thing.
"python-dotenv>=1.0",
]
[project.urls]
Homepage = "https://foilstack.ai"
Source = "https://github.com/foilstack/foilstack"
Issues = "https://github.com/foilstack/foilstack/issues"
[project.optional-dependencies]
embedder = ["torch>=2.2", "transformers>=4.44"]
# `foilstack enrich` streams a 1.1 GB JSON file. An extra rather than a
# dependency: it is needed by one Magic-only command that most installs will
# run once or never, and the enricher says so by name when it is missing.
mtgjson = ["ijson>=3.2"]
# `ijson` is in here as well as in `mtgjson` because the suite covers the
# enricher, and a test that skips when an extra is absent is a test that
# reports green for code nobody ran.
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.23",
"playwright>=1.48",
"ruff>=0.14",
"mypy>=1.13",
"ijson>=3.2",
]
# Installs a `foilstack` command. Without it the CLI is only reachable as
# `python -m foilstack.cli`, which is not what the README says and not what
# anybody types.
[project.scripts]
foilstack = "foilstack.cli:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
# The version lives in `src/foilstack/__init__.py` and is read from there.
# It is rendered in the page footer and sent as the TCGCSV User-Agent, so a
# second copy here is a copy that goes stale and then misreports both.
[tool.hatch.version]
path = "src/foilstack/__init__.py"
[tool.hatch.build.targets.wheel]
packages = ["src/foilstack"]
[tool.pytest.ini_options]
pythonpath = ["src"]
asyncio_mode = "auto"
[dependency-groups]
dev = [
"pre-commit>=4.6.2",
]
[tool.ruff]
# Wider than the default 88. The prose comments in this codebase are wrapped
# to about 79 and the code sits comfortably under 100; at 88 the formatter
# explodes several readable tables — the pricing rules, the queue row builder —
# into one item per line for the sake of a few characters.
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = [
"E", "W", # pycodestyle
"F", # pyflakes
"I", # import sorting
"UP", # pyupgrade
"B", # bugbear
"C4", # comprehensions
"SIM", # simplify
"BLE", # blind except
"RUF",
]
ignore = [
# `assert` in tests is the point of tests.
"S101",
]
[tool.ruff.lint.flake8-bugbear]
# FastAPI's whole dependency system is function calls in argument defaults —
# `Depends()`, `Query()`, `Form()`, `File()`. B008 exists to catch a mutable
# default evaluated once by accident; these are evaluated once on purpose and
# are the documented way to use the framework. Exempting them by name rather
# than switching B008 off keeps the rule working everywhere else.
extend-immutable-calls = [
"fastapi.Depends", "fastapi.Query", "fastapi.Form",
"fastapi.File", "fastapi.Body", "fastapi.Header",
]
[tool.ruff.lint.per-file-ignores]
# Migrations are generated, then annotated by hand. Import order and line
# length in them are alembic's business, not ours.
"src/foilstack/migrations/versions/*" = ["E501", "I001"]
# Sixteen quoted columns is 120 characters. Those fixtures are rows copied
# verbatim out of a real TCGplayer export, and a row reflowed to fit is no
# longer the thing the test claims to be testing against.
"tests/test_tcgplayer_match.py" = ["E501"]
[tool.ruff.format]
docstring-code-format = true
[tool.mypy]
python_version = "3.11"
files = ["src/foilstack"]
# Third-party stubs are patchy across sqlalchemy plugins, transformers and
# torch; chasing them adds noise without finding bugs.
ignore_missing_imports = true
# Deliberately not `strict`. Strict reports 142 errors on this codebase, almost
# all of them "add an annotation here" rather than "this is wrong" — a number
# that large gets a blanket ignore rather than a fix, and then the check is
# decoration. At this setting it found four real things: a mutable class
# attribute shared between plugin instances, a deprecated Pillow constant, a
# dict lookup on a possibly-None key, and a plugin protocol that did not
# describe half of what the application calls on it. Tighten a module at a
# time as annotations arrive.
warn_unused_ignores = true
warn_redundant_casts = true
# numpy ships stubs written with 3.12+ `type` statements, which mypy refuses to
# parse while `python_version` says 3.11 — and 3.11 is what `requires-python`
# promises, so lowering the check to suit a dependency's stubs would be the
# wrong way round. Skip following into it instead; nothing here relies on
# numpy's types beyond "an array of floats goes to the encoder".
[[tool.mypy.overrides]]
module = ["numpy.*"]
follow_imports = "skip"
follow_imports_for_stubs = true