scenet 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
scenet-0.1.0/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ BSD Zero Clause License (0BSD)
2
+
3
+ Copyright (c) 2026 Scenet contributors
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
10
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
12
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
13
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
14
+ THIS SOFTWARE.
scenet-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,248 @@
1
+ Metadata-Version: 2.4
2
+ Name: scenet
3
+ Version: 0.1.0
4
+ Summary: A semantic DSL for comic panels, compiled to SVG.
5
+ Keywords: comics,dsl,compiler,svg,layout,constraint-solving
6
+ Author: Scenet contributors
7
+ License-Expression: 0BSD
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Classifier: Topic :: Multimedia :: Graphics
15
+ Classifier: Topic :: Software Development :: Compilers
16
+ Classifier: Typing :: Typed
17
+ Requires-Dist: pydantic>=2.9
18
+ Requires-Dist: pyyaml>=6.0
19
+ Requires-Dist: kiwisolver>=1.4
20
+ Requires-Dist: shapely>=2.0
21
+ Requires-Dist: fonttools>=4.55
22
+ Requires-Dist: numpy>=2.1
23
+ Requires-Dist: fonts>=0.1
24
+ Requires-Dist: font-source-sans-pro>=0.0.1
25
+ Requires-Python: >=3.12
26
+ Project-URL: Homepage, https://github.com/azias/scenet
27
+ Project-URL: Documentation, https://azias.github.io/scenet/
28
+ Project-URL: Repository, https://github.com/azias/scenet
29
+ Project-URL: Issues, https://github.com/azias/scenet/issues
30
+ Project-URL: Changelog, https://github.com/azias/scenet/blob/main/CHANGELOG.md
31
+ Project-URL: Playground, https://azias.github.io/scenet/playground/
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Scenet
35
+
36
+ **A semantic DSL for comic panels, compiled to SVG.**
37
+
38
+ ## ⚠️ This project is deliberately AI-generated
39
+
40
+ This project is, by design, almost entirely generated by AI. It exists as a personal training
41
+ ground for learning to work with AI coding tools. The architecture, code, tests and documentation
42
+ are overwhelmingly AI-authored, under human direction and review.
43
+
44
+ Treat it accordingly: an experiment first, a usable tool second.
45
+
46
+ ---
47
+
48
+ [![CI](https://github.com/azias/scenet/actions/workflows/ci.yml/badge.svg)](https://github.com/azias/scenet/actions/workflows/ci.yml)
49
+ [![PyPI](https://img.shields.io/pypi/v/scenet.svg)](https://pypi.org/project/scenet/)
50
+ [![Python](https://img.shields.io/pypi/pyversions/scenet.svg)](https://pypi.org/project/scenet/)
51
+ [![License: 0BSD](https://img.shields.io/badge/License-0BSD-brightgreen.svg)](LICENSE)
52
+ ![Status: alpha](https://img.shields.io/badge/status-alpha-orange.svg)
53
+
54
+ **[Documentation](https://azias.github.io/scenet/)** ·
55
+ **[Playground](https://azias.github.io/scenet/playground/)** ·
56
+ **[Tutorial](https://azias.github.io/scenet/tutorial/first_panel.html)** ·
57
+ **[Changelog](CHANGELOG.md)**
58
+
59
+ ## What this is
60
+
61
+ Music has notation. A score describes the *semantics* of a piece — pitch, duration, dynamics —
62
+ without describing the waveform that eventually reaches your ear. Rendering is left to an
63
+ interpreter, human or machine.
64
+
65
+ Images have no such thing. SVG describes *how to draw*, not *what is depicted*: it is closer to a
66
+ WAV file than to a score. Scenet is an attempt at the missing layer, narrowed to one tractable
67
+ domain — the comic panel.
68
+
69
+ You write what is in the panel:
70
+
71
+ ```yaml
72
+ panel:
73
+ size: [1000, 1000]
74
+ camera:
75
+ shot: medium_shot
76
+ angle: eye_level
77
+ cast:
78
+ alice: {reference: alice, pose: pointing, at: left_third, facing: right}
79
+ bob: {reference: bob, pose: arms_crossed, at: right_third, facing: left}
80
+ staging:
81
+ - alice left_of bob
82
+ - alice looking_at bob
83
+ script:
84
+ - say: {by: alice, text: "You forgot your umbrella!", prefer: top_left}
85
+ - say: {by: bob, text: "I know."}
86
+ ```
87
+
88
+ You can also write a sequence, where each panel states only what changed from the one
89
+ before — borrowed from OpenUSD's sparse override, because consecutive panels in a scene
90
+ share nearly all their staging:
91
+
92
+ ```yaml
93
+ panels:
94
+ establishing:
95
+ camera: {shot: full_shot}
96
+ cast: {alice: {reference: alice}, bob: {reference: bob}}
97
+ reaction:
98
+ over: establishing # same cast, same staging
99
+ camera: {shot: close_up} # move in
100
+ ```
101
+
102
+ Or in comic script, the format writers already use:
103
+
104
+ ```
105
+ PANEL 1
106
+ @shot: full_shot
107
+ Alice and Bob face each other on a rainy street corner.
108
+
109
+ ALICE
110
+ You forgot your umbrella!
111
+
112
+ BOB (whisper)
113
+ I know.
114
+ ```
115
+
116
+ From any of these, the compiler works out the rest: how large each figure must be for a medium shot, where they
117
+ stand, which way they face, how big each balloon needs to be for its text, where a balloon can sit
118
+ without covering a face, and how its tail reaches the speaker's mouth — all while preserving
119
+ reading order.
120
+
121
+ **No generative image model is involved.** This is a deterministic compiler: constraint solving and
122
+ computational geometry. The same input always produces byte-identical output.
123
+
124
+ ## Status
125
+
126
+ **Alpha — panels and sequences compile end to end, from the command line, the
127
+ browser, or an editor.** Framing, actor placement, balloon
128
+ placement, reading order, tail routing and SVG emission all work, from either of two
129
+ frontends. Not yet built: page composition (tiers, panels of varying size) and the
130
+ interpretation layer that would give a panel a *style*. See
131
+ [the phase plan](docs/explanation/status.md) for detail.
132
+
133
+ ```bash
134
+ uv run scenet build examples/duel.panel.yaml --core --debug
135
+ uv run scenet build examples/sequence.scene.yaml --strip
136
+ uv run scenet build examples/umbrella.script --strip
137
+ ```
138
+
139
+ `--core` writes the resolved intermediate tier as JSON; `--debug` writes an overlay showing
140
+ the geometry the solver was working against — silhouette hulls, face exclusion zones, anchors,
141
+ gaze vectors and tail routes.
142
+
143
+ ## How it works
144
+
145
+ ```
146
+ duel.panel.yaml → Panel Core (.core.json) → panel.svg
147
+ authored, resolved, fully numeric, rendered
148
+ no coordinates still named & inspectable
149
+ ```
150
+
151
+ The intermediate tier is a real, writable format rather than a hidden data structure — so layouts
152
+ can be inspected, hand-adjusted, and diffed independently of how they are drawn. The approach is
153
+ borrowed from Vega-Lite, which compiles a high-level grammar into a lower-level one before emitting
154
+ SVG.
155
+
156
+ ## Try it in the browser
157
+
158
+ The **[playground](https://azias.github.io/scenet/playground/)** runs this compiler — the
159
+ same Python, unmodified — in your browser under WebAssembly via
160
+ [Pyodide](https://pyodide.org/). It is not a reimplementation: the page installs the exact
161
+ wheel `uv build` produces, so there is no second copy of the geometry to drift out of step.
162
+
163
+ Fifteen worked examples, covering every shot type, every balloon kind, both frontends and
164
+ the constraint priorities. Each one is a real file under
165
+ [`examples/gallery/`](examples/gallery/) that the test suite compiles, so the playground
166
+ cannot offer an example that does not work.
167
+
168
+ The editor is Monaco, fed the *same* JSON Schema the VS Code extension uses — generated
169
+ from the compiler's own models, so completion and hover documentation cannot drift from
170
+ what compiles. Everything is served from one origin: no CDN, no analytics, nothing
171
+ fetched from anywhere else.
172
+
173
+ ## Editor support
174
+
175
+ The [VS Code extension](editor/) gives completion and inline validation for panel
176
+ documents, plus a side-by-side preview. Its JSON Schema is *generated from the
177
+ compiler's own models* by `scenet schema`, so what the editor offers is what actually
178
+ compiles. A test fails if the shipped schema goes stale.
179
+
180
+ ## Install
181
+
182
+ ```bash
183
+ pip install scenet
184
+ ```
185
+
186
+ Python 3.12 or newer. No system libraries, no fonts to install, nothing to configure. Ships
187
+ a `py.typed` marker, so mypy, pyright, ty and basedpyright read the annotations straight
188
+ from the package.
189
+
190
+ ```python
191
+ from scenet import compile_source, render
192
+
193
+ result = compile_source("cast: {alice: {reference: alice}}")
194
+ svg = render(result.core)
195
+ ```
196
+
197
+ ## Development
198
+
199
+ Requires [uv](https://docs.astral.sh/uv/). It manages the Python version too, so this is the whole
200
+ setup:
201
+
202
+ ```bash
203
+ uv sync --all-groups
204
+ uv run pytest
205
+ ```
206
+
207
+ Checks, all of which run in CI:
208
+
209
+ ```bash
210
+ uv run ruff check . && uv run ruff format --check .
211
+ uv run ty check
212
+ uv run pytest
213
+ ```
214
+
215
+ ## Documentation
216
+
217
+ **[azias.github.io/scenet](https://azias.github.io/scenet/)** — or read the Markdown
218
+ source under [`docs/`](docs/), which GitHub renders without a build step.
219
+
220
+ | | |
221
+ |---|---|
222
+ | [Tutorial](docs/tutorial/first_panel.md) | Build a panel from nothing, in fifteen minutes |
223
+ | [How-to guides](docs/howto/index.md) | Sequences, comic scripts, your own characters, using it as a library |
224
+ | [Language specification](docs/reference/language.md) | Every construct, with examples |
225
+ | [Shot types](docs/reference/shot_types.md) | Normative camera framing table |
226
+ | [Panel Core](docs/reference/panel_core.md) | The resolved intermediate format |
227
+ | [Asset contract](docs/reference/asset_contract.md) | What a character puppet must declare |
228
+ | [API reference](docs/reference/api/index.md) | Every public name |
229
+ | [Design decisions](docs/explanation/design_decisions.md) | Why it is shaped this way |
230
+ | [Prior art](docs/explanation/prior_art.md) | What already exists, and what was taken from it |
231
+
232
+ Every Python example in the documentation is executed by the test suite. An example that
233
+ omits an import, or that has drifted out of step with the code, fails the build.
234
+
235
+ ## License
236
+
237
+ **0BSD** — see [LICENSE](LICENSE). This is deliberately one step more permissive than
238
+ MIT: you may use, copy, modify and distribute this software for any purpose, with no
239
+ obligation to preserve a copyright notice or reproduce the license. No attribution is
240
+ required, though it is always welcome.
241
+
242
+ Third-party components are listed in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). The
243
+ lettering font arrives as an ordinary dependency under the SIL Open Font License, which does
244
+ require its own notice be kept with it.
245
+
246
+ **The language specification is free to implement.** Anyone may build their own compiler, editor,
247
+ renderer or tooling for this language, in any project, commercial or otherwise, without restriction
248
+ or attribution. A notation is only worth having if it is not owned.
scenet-0.1.0/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # Scenet
2
+
3
+ **A semantic DSL for comic panels, compiled to SVG.**
4
+
5
+ ## ⚠️ This project is deliberately AI-generated
6
+
7
+ This project is, by design, almost entirely generated by AI. It exists as a personal training
8
+ ground for learning to work with AI coding tools. The architecture, code, tests and documentation
9
+ are overwhelmingly AI-authored, under human direction and review.
10
+
11
+ Treat it accordingly: an experiment first, a usable tool second.
12
+
13
+ ---
14
+
15
+ [![CI](https://github.com/azias/scenet/actions/workflows/ci.yml/badge.svg)](https://github.com/azias/scenet/actions/workflows/ci.yml)
16
+ [![PyPI](https://img.shields.io/pypi/v/scenet.svg)](https://pypi.org/project/scenet/)
17
+ [![Python](https://img.shields.io/pypi/pyversions/scenet.svg)](https://pypi.org/project/scenet/)
18
+ [![License: 0BSD](https://img.shields.io/badge/License-0BSD-brightgreen.svg)](LICENSE)
19
+ ![Status: alpha](https://img.shields.io/badge/status-alpha-orange.svg)
20
+
21
+ **[Documentation](https://azias.github.io/scenet/)** ·
22
+ **[Playground](https://azias.github.io/scenet/playground/)** ·
23
+ **[Tutorial](https://azias.github.io/scenet/tutorial/first_panel.html)** ·
24
+ **[Changelog](CHANGELOG.md)**
25
+
26
+ ## What this is
27
+
28
+ Music has notation. A score describes the *semantics* of a piece — pitch, duration, dynamics —
29
+ without describing the waveform that eventually reaches your ear. Rendering is left to an
30
+ interpreter, human or machine.
31
+
32
+ Images have no such thing. SVG describes *how to draw*, not *what is depicted*: it is closer to a
33
+ WAV file than to a score. Scenet is an attempt at the missing layer, narrowed to one tractable
34
+ domain — the comic panel.
35
+
36
+ You write what is in the panel:
37
+
38
+ ```yaml
39
+ panel:
40
+ size: [1000, 1000]
41
+ camera:
42
+ shot: medium_shot
43
+ angle: eye_level
44
+ cast:
45
+ alice: {reference: alice, pose: pointing, at: left_third, facing: right}
46
+ bob: {reference: bob, pose: arms_crossed, at: right_third, facing: left}
47
+ staging:
48
+ - alice left_of bob
49
+ - alice looking_at bob
50
+ script:
51
+ - say: {by: alice, text: "You forgot your umbrella!", prefer: top_left}
52
+ - say: {by: bob, text: "I know."}
53
+ ```
54
+
55
+ You can also write a sequence, where each panel states only what changed from the one
56
+ before — borrowed from OpenUSD's sparse override, because consecutive panels in a scene
57
+ share nearly all their staging:
58
+
59
+ ```yaml
60
+ panels:
61
+ establishing:
62
+ camera: {shot: full_shot}
63
+ cast: {alice: {reference: alice}, bob: {reference: bob}}
64
+ reaction:
65
+ over: establishing # same cast, same staging
66
+ camera: {shot: close_up} # move in
67
+ ```
68
+
69
+ Or in comic script, the format writers already use:
70
+
71
+ ```
72
+ PANEL 1
73
+ @shot: full_shot
74
+ Alice and Bob face each other on a rainy street corner.
75
+
76
+ ALICE
77
+ You forgot your umbrella!
78
+
79
+ BOB (whisper)
80
+ I know.
81
+ ```
82
+
83
+ From any of these, the compiler works out the rest: how large each figure must be for a medium shot, where they
84
+ stand, which way they face, how big each balloon needs to be for its text, where a balloon can sit
85
+ without covering a face, and how its tail reaches the speaker's mouth — all while preserving
86
+ reading order.
87
+
88
+ **No generative image model is involved.** This is a deterministic compiler: constraint solving and
89
+ computational geometry. The same input always produces byte-identical output.
90
+
91
+ ## Status
92
+
93
+ **Alpha — panels and sequences compile end to end, from the command line, the
94
+ browser, or an editor.** Framing, actor placement, balloon
95
+ placement, reading order, tail routing and SVG emission all work, from either of two
96
+ frontends. Not yet built: page composition (tiers, panels of varying size) and the
97
+ interpretation layer that would give a panel a *style*. See
98
+ [the phase plan](docs/explanation/status.md) for detail.
99
+
100
+ ```bash
101
+ uv run scenet build examples/duel.panel.yaml --core --debug
102
+ uv run scenet build examples/sequence.scene.yaml --strip
103
+ uv run scenet build examples/umbrella.script --strip
104
+ ```
105
+
106
+ `--core` writes the resolved intermediate tier as JSON; `--debug` writes an overlay showing
107
+ the geometry the solver was working against — silhouette hulls, face exclusion zones, anchors,
108
+ gaze vectors and tail routes.
109
+
110
+ ## How it works
111
+
112
+ ```
113
+ duel.panel.yaml → Panel Core (.core.json) → panel.svg
114
+ authored, resolved, fully numeric, rendered
115
+ no coordinates still named & inspectable
116
+ ```
117
+
118
+ The intermediate tier is a real, writable format rather than a hidden data structure — so layouts
119
+ can be inspected, hand-adjusted, and diffed independently of how they are drawn. The approach is
120
+ borrowed from Vega-Lite, which compiles a high-level grammar into a lower-level one before emitting
121
+ SVG.
122
+
123
+ ## Try it in the browser
124
+
125
+ The **[playground](https://azias.github.io/scenet/playground/)** runs this compiler — the
126
+ same Python, unmodified — in your browser under WebAssembly via
127
+ [Pyodide](https://pyodide.org/). It is not a reimplementation: the page installs the exact
128
+ wheel `uv build` produces, so there is no second copy of the geometry to drift out of step.
129
+
130
+ Fifteen worked examples, covering every shot type, every balloon kind, both frontends and
131
+ the constraint priorities. Each one is a real file under
132
+ [`examples/gallery/`](examples/gallery/) that the test suite compiles, so the playground
133
+ cannot offer an example that does not work.
134
+
135
+ The editor is Monaco, fed the *same* JSON Schema the VS Code extension uses — generated
136
+ from the compiler's own models, so completion and hover documentation cannot drift from
137
+ what compiles. Everything is served from one origin: no CDN, no analytics, nothing
138
+ fetched from anywhere else.
139
+
140
+ ## Editor support
141
+
142
+ The [VS Code extension](editor/) gives completion and inline validation for panel
143
+ documents, plus a side-by-side preview. Its JSON Schema is *generated from the
144
+ compiler's own models* by `scenet schema`, so what the editor offers is what actually
145
+ compiles. A test fails if the shipped schema goes stale.
146
+
147
+ ## Install
148
+
149
+ ```bash
150
+ pip install scenet
151
+ ```
152
+
153
+ Python 3.12 or newer. No system libraries, no fonts to install, nothing to configure. Ships
154
+ a `py.typed` marker, so mypy, pyright, ty and basedpyright read the annotations straight
155
+ from the package.
156
+
157
+ ```python
158
+ from scenet import compile_source, render
159
+
160
+ result = compile_source("cast: {alice: {reference: alice}}")
161
+ svg = render(result.core)
162
+ ```
163
+
164
+ ## Development
165
+
166
+ Requires [uv](https://docs.astral.sh/uv/). It manages the Python version too, so this is the whole
167
+ setup:
168
+
169
+ ```bash
170
+ uv sync --all-groups
171
+ uv run pytest
172
+ ```
173
+
174
+ Checks, all of which run in CI:
175
+
176
+ ```bash
177
+ uv run ruff check . && uv run ruff format --check .
178
+ uv run ty check
179
+ uv run pytest
180
+ ```
181
+
182
+ ## Documentation
183
+
184
+ **[azias.github.io/scenet](https://azias.github.io/scenet/)** — or read the Markdown
185
+ source under [`docs/`](docs/), which GitHub renders without a build step.
186
+
187
+ | | |
188
+ |---|---|
189
+ | [Tutorial](docs/tutorial/first_panel.md) | Build a panel from nothing, in fifteen minutes |
190
+ | [How-to guides](docs/howto/index.md) | Sequences, comic scripts, your own characters, using it as a library |
191
+ | [Language specification](docs/reference/language.md) | Every construct, with examples |
192
+ | [Shot types](docs/reference/shot_types.md) | Normative camera framing table |
193
+ | [Panel Core](docs/reference/panel_core.md) | The resolved intermediate format |
194
+ | [Asset contract](docs/reference/asset_contract.md) | What a character puppet must declare |
195
+ | [API reference](docs/reference/api/index.md) | Every public name |
196
+ | [Design decisions](docs/explanation/design_decisions.md) | Why it is shaped this way |
197
+ | [Prior art](docs/explanation/prior_art.md) | What already exists, and what was taken from it |
198
+
199
+ Every Python example in the documentation is executed by the test suite. An example that
200
+ omits an import, or that has drifted out of step with the code, fails the build.
201
+
202
+ ## License
203
+
204
+ **0BSD** — see [LICENSE](LICENSE). This is deliberately one step more permissive than
205
+ MIT: you may use, copy, modify and distribute this software for any purpose, with no
206
+ obligation to preserve a copyright notice or reproduce the license. No attribution is
207
+ required, though it is always welcome.
208
+
209
+ Third-party components are listed in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). The
210
+ lettering font arrives as an ordinary dependency under the SIL Open Font License, which does
211
+ require its own notice be kept with it.
212
+
213
+ **The language specification is free to implement.** Anyone may build their own compiler, editor,
214
+ renderer or tooling for this language, in any project, commercial or otherwise, without restriction
215
+ or attribution. A notation is only worth having if it is not owned.
@@ -0,0 +1,183 @@
1
+ [project]
2
+ name = "scenet"
3
+ version = "0.1.0"
4
+ description = "A semantic DSL for comic panels, compiled to SVG."
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ license = "0BSD"
8
+ license-files = ["LICENSE"]
9
+ keywords = [
10
+ "comics",
11
+ "dsl",
12
+ "compiler",
13
+ "svg",
14
+ "layout",
15
+ "constraint-solving",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 3 - Alpha",
19
+ "Intended Audience :: Developers",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Programming Language :: Python :: 3.14",
23
+ "Topic :: Multimedia :: Graphics",
24
+ "Topic :: Software Development :: Compilers",
25
+ "Typing :: Typed",
26
+ ]
27
+ dependencies = [
28
+ "pydantic>=2.9",
29
+ "pyyaml>=6.0",
30
+ "kiwisolver>=1.4",
31
+ "shapely>=2.0",
32
+ "fonttools>=4.55",
33
+ "numpy>=2.1",
34
+ "fonts>=0.1",
35
+ "font-source-sans-pro>=0.0.1",
36
+ ]
37
+
38
+ [[project.authors]]
39
+ name = "Scenet contributors"
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/azias/scenet"
43
+ Documentation = "https://azias.github.io/scenet/"
44
+ Repository = "https://github.com/azias/scenet"
45
+ Issues = "https://github.com/azias/scenet/issues"
46
+ Changelog = "https://github.com/azias/scenet/blob/main/CHANGELOG.md"
47
+ Playground = "https://azias.github.io/scenet/playground/"
48
+
49
+ [project.scripts]
50
+ scenet = "scenet.cli:main"
51
+
52
+ [dependency-groups]
53
+ dev = [
54
+ "pytest>=8.3",
55
+ "pytest-cov>=6.0",
56
+ "sybil>=10.1",
57
+ "ruff>=0.14",
58
+ "ty>=0.0.73",
59
+ "basedpyright>=1.31",
60
+ "pip-licenses>=5.0",
61
+ "types-pyyaml>=6.0",
62
+ ]
63
+ docs = [
64
+ "sphinx>=9.1",
65
+ "myst-parser>=5.1",
66
+ "pydata-sphinx-theme>=0.20",
67
+ "sphinx-design>=0.7",
68
+ "sphinx-copybutton>=0.5.2",
69
+ "sphinx-autodoc-typehints>=3.13",
70
+ "sphinx-autobuild>=2025.8.25",
71
+ "linkify-it-py>=2.0",
72
+ ]
73
+
74
+ [build-system]
75
+ requires = ["uv_build>=0.12.5,<0.13.0"]
76
+ build-backend = "uv_build"
77
+
78
+ [tool.ruff]
79
+ line-length = 100
80
+ target-version = "py312"
81
+ src = [
82
+ "src",
83
+ "tests",
84
+ ]
85
+
86
+ [tool.ruff.lint]
87
+ select = [
88
+ "E",
89
+ "W",
90
+ "F",
91
+ "I",
92
+ "N",
93
+ "UP",
94
+ "ANN",
95
+ "B",
96
+ "C4",
97
+ "SIM",
98
+ "TC",
99
+ "PGH",
100
+ "PT",
101
+ "PL",
102
+ "RUF",
103
+ "D",
104
+ "S",
105
+ "A",
106
+ "RET",
107
+ "PTH",
108
+ "TRY",
109
+ ]
110
+ ignore = [
111
+ "PLR0913",
112
+ "PLR2004",
113
+ "TRY003",
114
+ "TRY004",
115
+ "TC001",
116
+ "TC002",
117
+ "TC003",
118
+ ]
119
+
120
+ [tool.ruff.lint.flake8-type-checking]
121
+ quote-annotations = false
122
+
123
+ [tool.ruff.lint.pydocstyle]
124
+ convention = "google"
125
+
126
+ [tool.ruff.lint.per-file-ignores]
127
+ "tests/**" = [
128
+ "ANN",
129
+ "PLR2004",
130
+ "S101",
131
+ "S314",
132
+ "D",
133
+ "RUF012",
134
+ "SLF001",
135
+ ]
136
+ "src/scenet/__init__.py" = ["RUF022"]
137
+ "docs/conf.py" = [
138
+ "D",
139
+ "A",
140
+ "INP",
141
+ ]
142
+
143
+ [tool.ruff.format]
144
+ docstring-code-format = true
145
+
146
+ [tool.ty.src]
147
+ include = [
148
+ "src",
149
+ "tests",
150
+ ]
151
+
152
+ [tool.ty.rules]
153
+ possibly-unresolved-reference = "error"
154
+
155
+ [tool.basedpyright]
156
+ include = [
157
+ "src",
158
+ "tests",
159
+ ]
160
+ typeCheckingMode = "strict"
161
+ pythonVersion = "3.12"
162
+ reportMissingTypeStubs = false
163
+
164
+ [tool.pytest.ini_options]
165
+ testpaths = [
166
+ "tests",
167
+ "src",
168
+ "docs",
169
+ "README.md",
170
+ ]
171
+ addopts = " -q --strict-markers --strict-config --doctest-modules --cov=scenet --cov-report=term-missing --cov-fail-under=90"
172
+ xfail_strict = true
173
+
174
+ [tool.coverage.run]
175
+ branch = true
176
+ source = ["src/scenet"]
177
+
178
+ [tool.coverage.report]
179
+ exclude_also = [
180
+ "if TYPE_CHECKING:",
181
+ "raise NotImplementedError",
182
+ "if __name__ == .__main__.:",
183
+ ]