-
Notifications
You must be signed in to change notification settings - Fork 83
Expand file tree
/
Copy pathpyproject.toml
More file actions
99 lines (92 loc) · 5.31 KB
/
Copy pathpyproject.toml
File metadata and controls
99 lines (92 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# SPDX-License-Identifier: Apache-2.0
[build-system]
# 77, not 68: `license = "Apache-2.0"` below is the PEP 639 string form, which older
# setuptools rejects outright — measured, backend called directly, this very tree:
# 76.1.0 dies with "`project.license` must be valid exactly by one definition", 77.0.1
# builds. Nobody hit it because pip's build isolation always fetches the newest setuptools,
# but the floor was a claim about a build that could not happen.
requires = ["setuptools>=77"]
build-backend = "setuptools.build_meta"
[project]
name = "sprite-gen"
# Release discipline: keep this package metadata version synchronized with
# SKILL.md's `version:` field in the same release commit.
version = "2.0.3"
description = "Component-row pipeline for clean 2D game sprites and animation atlases"
readme = "README.md"
license = "Apache-2.0"
requires-python = ">=3.10"
dependencies = [
"pillow>=12.0,<13",
# NumPy is a direct dependency, never a transitive ride-along: the chroma
# extraction path imports it directly and must not depend on some other
# package happening to pull it in.
# Floor 2.2.6 is the newest release with CPython 3.10 wheels, so it is the
# highest floor that keeps `requires-python = ">=3.10"` honest (2.3.x
# requires >=3.11, 2.5.x requires >=3.12 — either would break the 3.10 CI
# job outright). It is also >= 2.0, which matters: the byte-identity
# contract for the extraction path depends on NEP 50 promotion rules, which
# only became the default in NumPy 2.0. The `<3` ceiling is there for the
# same reason — a major bump is free to change promotion again.
"numpy>=2.2.6,<3",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
# The packaging guard builds a wheel and reads what is inside it, because the declarations
# below are a claim and only the build is the fact. That needs the declared build backend
# importable in the test environment — build isolation puts it somewhere the tests cannot
# see, and a modern `python -m venv` no longer provides it. Same floor as build-system.
"setuptools>=77",
# Many tests shell out to a pipeline step as a subprocess; a wrong path or a
# server that never returns would otherwise hang the whole suite silently.
# A per-test timeout turns that into a named failure. `signal` method (below)
# is required — the default `thread` method cannot interrupt a blocked
# subprocess.wait(), which is exactly the case that hangs here.
"pytest-timeout>=2.3",
]
# The console script is what removes the "which python?" question: pip writes it
# with a shebang naming the interpreter of the environment it was installed
# into, so `sprite-gen <tool>` runs on that environment's dependencies without
# anyone naming an interpreter. It fronts the same parser as
# `python -m sprite_gen.cli`, so the two forms cannot drift.
[project.scripts]
sprite-gen = "sprite_gen.cli:main"
[project.urls]
Repository = "https://github.com/aldegad/sprite-gen"
[tool.pytest.ini_options]
testpaths = ["tests"]
# Tests are grouped into per-domain folders (tests/<domain>/) so a domain can be
# run alone (`pytest tests/effects`). conftest.py stays at the tests/ root and is
# imported by name (`from conftest import run_script`) from every subfolder, so the
# tests/ dir must be on sys.path.
pythonpath = ["tests"]
# A hung subprocess test must become a named failure, not a silent stall. signal
# method (SIGALRM) is required — thread method cannot interrupt a blocked
# subprocess.wait(). 120s is generous for the extract/compose subprocess tests.
timeout = 120
timeout_method = "signal"
# The pipeline ships an importable sprite_gen package. The canonical invocation is the
# console script declared above (`sprite-gen <tool>`); `scripts/<tool>.py` survives as a
# backwards-compatible wrapper for callers that already name the file, and it is a wrapper
# only — never the form docs teach, because a bare `python3` in a shell that never activated
# the venv is a different interpreter than the one holding this file's dependencies
# (`tests/test_entrypoint_interpreter.py` locks that rule for SKILL.md and docs/).
#
# Discovered, not hand-listed: a literal `packages = ["sprite_gen"]` silently dropped the
# `sprite_gen.gen` subpackage from every built wheel, so `sprite-gen --help` (cli.py imports
# `gen` at module scope) died on a non-editable install. The filesystem is the truth about
# which packages exist; this derives from it so a new subpackage cannot go missing again.
[tool.setuptools.packages.find]
include = ["sprite_gen*"]
# The curation SPA is package data, not a repo-side script asset: the server resolves it
# relative to its own module (serve_curation.CURATOR_DIR), so it has to travel inside the
# wheel or the installed console script serves a 404 shell. One location, no fallback.
#
# Whole subtree, not an extension list: setuptools expands these with glob(recursive=True),
# where a single `*` stops at a directory boundary. A hand-listed `curator/src/*.js` therefore
# drops `curator/src/<anything>/*.js` from the wheel the day someone nests a folder — measured,
# not feared: adding curator/src/deep/new.js under the old patterns built a wheel without it.
# `curator/**/*` derives the answer from the filesystem, the same fix as packages.find above.
[tool.setuptools.package-data]
sprite_gen = ["serve/curator/**/*", "serve/composer/**/*"]