cgshop2027-pyutils 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.
Files changed (37) hide show
  1. cgshop2027_pyutils-0.1.0/LICENSE +21 -0
  2. cgshop2027_pyutils-0.1.0/MANIFEST.in +4 -0
  3. cgshop2027_pyutils-0.1.0/PKG-INFO +232 -0
  4. cgshop2027_pyutils-0.1.0/README.md +205 -0
  5. cgshop2027_pyutils-0.1.0/pyproject.toml +90 -0
  6. cgshop2027_pyutils-0.1.0/setup.cfg +4 -0
  7. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/__init__.py +3 -0
  8. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/grid.py +252 -0
  9. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/instance_database/__init__.py +7 -0
  10. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/instance_database/instance_base_database.py +86 -0
  11. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/instance_database/instance_database.py +73 -0
  12. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/instance_database/instance_file_database.py +81 -0
  13. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/instance_database/instance_zip_database.py +77 -0
  14. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/io/__init__.py +54 -0
  15. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/schemas/__init__.py +9 -0
  16. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/schemas/instance.py +199 -0
  17. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/schemas/solution.py +171 -0
  18. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/verify.py +153 -0
  19. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/visualize.py +504 -0
  20. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/zip/__init__.py +9 -0
  21. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/zip/zip_processor.py +121 -0
  22. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/zip/zip_reader_errors.py +96 -0
  23. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils/zip/zip_writer.py +52 -0
  24. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils.egg-info/PKG-INFO +232 -0
  25. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils.egg-info/SOURCES.txt +35 -0
  26. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils.egg-info/dependency_links.txt +1 -0
  27. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils.egg-info/requires.txt +12 -0
  28. cgshop2027_pyutils-0.1.0/src/cgshop2027_pyutils.egg-info/top_level.txt +1 -0
  29. cgshop2027_pyutils-0.1.0/tests/conftest.py +79 -0
  30. cgshop2027_pyutils-0.1.0/tests/test_grid.py +150 -0
  31. cgshop2027_pyutils-0.1.0/tests/test_imports.py +64 -0
  32. cgshop2027_pyutils-0.1.0/tests/test_instance_database.py +159 -0
  33. cgshop2027_pyutils-0.1.0/tests/test_io.py +32 -0
  34. cgshop2027_pyutils-0.1.0/tests/test_schemas.py +655 -0
  35. cgshop2027_pyutils-0.1.0/tests/test_verify.py +341 -0
  36. cgshop2027_pyutils-0.1.0/tests/test_visualize.py +389 -0
  37. cgshop2027_pyutils-0.1.0/tests/test_zip.py +218 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Technische Universität Braunschweig, Algorithms Group, Phillip Keldenich
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ # The test suite is shipped in the sdist; setuptools' defaults pick up the
2
+ # test modules but not conftest.py, which two of them import from.
3
+ graft tests
4
+ global-exclude __pycache__ *.py[cod]
@@ -0,0 +1,232 @@
1
+ Metadata-Version: 2.4
2
+ Name: cgshop2027-pyutils
3
+ Version: 0.1.0
4
+ Summary: Utilities for verifying solutions of the CG:SHOP 2027 Competition.
5
+ Author: Phillip Keldenich
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/CG-SHOP/pyutils27
8
+ Project-URL: Issues, https://github.com/CG-SHOP/pyutils27/issues
9
+ Keywords: cgshop,computational geometry,optimization challenge
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: matplotlib>=3.6
18
+ Requires-Dist: numpy>=1.24
19
+ Requires-Dist: pydantic>=2.0.0
20
+ Requires-Dist: shapely>=2.1.2
21
+ Requires-Dist: typing_extensions>=4.0.0; python_version < "3.12"
22
+ Provides-Extra: dev
23
+ Requires-Dist: pre-commit; extra == "dev"
24
+ Requires-Dist: pytest; extra == "dev"
25
+ Requires-Dist: ruff; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ # pyutils27 (cgshop2027-pyutils)
29
+
30
+ Utilities for working with CG:SHOP 2027 instances & solutions. This is a pure
31
+ Python package containing a parser/verifier for our instance format, solution
32
+ format and a verifier for solutions.
33
+
34
+ ---
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install cgshop2027-pyutils
40
+ ```
41
+
42
+ The current state of `main`, ahead of the latest release:
43
+
44
+ ```bash
45
+ pip install git+https://github.com/CG-SHOP/pyutils27
46
+ ```
47
+
48
+ From a local clone (editable, for development):
49
+
50
+ ```bash
51
+ git clone https://github.com/CG-SHOP/pyutils27
52
+ cd pyutils27
53
+ pip install -e ".[dev]"
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Layout
59
+
60
+ ```
61
+ src/cgshop2027_pyutils/
62
+ ├── schemas/ # Pydantic models for instances & solutions
63
+ ├── io/ # reading instances & solutions from paths or file objects
64
+ ├── zip/ # safe reading/writing of instance & solution archives
65
+ ├── instance_database/ # query instances from a folder or a zip
66
+ ├── grid.py # cell-set algebra on the integer grid
67
+ ├── verify.py # checking a solution against its instance
68
+ └── visualize.py # matplotlib plots and animations
69
+ tests/ # pytest test suite
70
+ ```
71
+
72
+ ---
73
+
74
+ ## Usage
75
+
76
+ Verifying a solution against its instance:
77
+
78
+ ```python
79
+ from cgshop2027_pyutils.io import read_instance, read_solution
80
+ from cgshop2027_pyutils.verify import check_for_errors
81
+
82
+ errors = check_for_errors(
83
+ read_instance("demo.instance.json"),
84
+ read_solution("demo.solution.json"),
85
+ )
86
+ ```
87
+
88
+ `check_for_errors` returns a list of human-readable messages; an empty list
89
+ means the solution is feasible. When checking many solutions for the same
90
+ instance, use `SolutionValidator(instance)` directly so that the
91
+ instance-derived precomputation is only paid once.
92
+
93
+ A solution consists of exactly `number_of_cutters` tours, one per cutter:
94
+
95
+ ```python
96
+ solution = CGSHOP2027Solution(
97
+ instance_uid="demo",
98
+ tours=[{"x": [0, 3, 3, 0], "y": [0, 0, 1, 1]}, {"x": [7], "y": [7]}],
99
+ )
100
+ ```
101
+
102
+ Each tour lists the points the cutter's _center_ passes through and is closed
103
+ implicitly, so the cutter travels from the last point back to the first one.
104
+ Consecutive points must be axis-parallel; a point may be visited again later,
105
+ but not immediately again. A tour of a single point is a cutter that stays where
106
+ it is. Cutters do not interfere with each other and may leave the region; all
107
+ that is required is that together they sweep the whole region.
108
+
109
+ The objective is `solution.max_tour_length`, the length of the longest tour, and
110
+ it is to be minimized.
111
+
112
+ Bundling instances or solutions into an archive:
113
+
114
+ ```python
115
+ from cgshop2027_pyutils.zip import ZipWriter
116
+
117
+ with ZipWriter("solutions.zip") as writer:
118
+ for solution in solutions:
119
+ writer.add_solution(solution)
120
+ ```
121
+
122
+ Reading a submitted archive, with size, CRC and path-traversal checks:
123
+
124
+ ```python
125
+ from cgshop2027_pyutils.zip import BadSolutionFile, ZipSolutionIterator, ZipReaderError
126
+
127
+ try:
128
+ for solution in ZipSolutionIterator("solutions.zip"):
129
+ print(solution.instance_uid)
130
+ except (ZipReaderError, BadSolutionFile) as e:
131
+ print(f"Rejected: {e}")
132
+ ```
133
+
134
+ `example_zip.ipynb` walks the whole submission path end to end: reading the
135
+ instances, checking solutions against them, packing an archive, and what a
136
+ rejection looks like. It runs on the two archives next to it:
137
+ `example_instances.zip`, a copy of the published example instances, and
138
+ `example_solutions.zip`, one feasible solution for each of them to check against
139
+ and to beat.
140
+
141
+ Looking instances up by name, from either a folder or a zip:
142
+
143
+ ```python
144
+ from cgshop2027_pyutils.instance_database import InstanceDatabase
145
+
146
+ db = InstanceDatabase("instances.zip")
147
+ instance = db["demo"]
148
+ for instance in db:
149
+ ...
150
+ ```
151
+
152
+ Plotting an instance, a solution, or an animation of the cutters at work:
153
+
154
+ ```python
155
+ from cgshop2027_pyutils.visualize import (
156
+ create_instance_plot,
157
+ create_solution_animation,
158
+ create_solution_plot,
159
+ )
160
+
161
+ create_instance_plot(instance).savefig("instance.png")
162
+ create_solution_plot(instance, solution).savefig("solution.png")
163
+
164
+ animation = create_solution_animation(instance, solution)
165
+ animation.save("solution.gif", writer="pillow")
166
+ ```
167
+
168
+ The solution plot shades the swept area, marks any cells left uncovered in red
169
+ and draws one tour per cutter. The animation strides through the tours to fit
170
+ `max_frames` (300 by default), filling in coverage as the cutters move; pass
171
+ `step` to control the stride yourself.
172
+
173
+ All three take `bare=True`, which drops the axes, the grid and every title and
174
+ trims the figure to the drawing, for a picture meant for a paper or a slide
175
+ rather than for debugging:
176
+
177
+ ```python
178
+ create_solution_plot(instance, solution, bare=True).savefig("solution.pdf")
179
+ ```
180
+
181
+ Instance files must be named `NAME.instance.json`. A lookup key may be the bare
182
+ name, the file name, or a path to it: `db["demo"]`, `db["demo.instance.json"]`
183
+ and `db["batch1/demo.instance.json"]` all resolve to the same instance. Note
184
+ that every `.json` file in the folder or archive is treated as an instance, so
185
+ keep solutions in a separate location.
186
+
187
+ ---
188
+
189
+ ## Development
190
+
191
+ Set up the tooling (linting & formatting run through pre-commit):
192
+
193
+ ```bash
194
+ pip install -e ".[dev]"
195
+ pre-commit install
196
+ ```
197
+
198
+ Run the checks manually:
199
+
200
+ ```bash
201
+ ruff check .
202
+ ruff format .
203
+ pytest
204
+ ```
205
+
206
+ Linting, formatting and import sorting are all handled by
207
+ [ruff](https://docs.astral.sh/ruff/); its configuration lives in
208
+ `pyproject.toml`.
209
+
210
+ ---
211
+
212
+ ## Contributing
213
+
214
+ Issues & PRs welcome. Please:
215
+
216
+ 1. Add/adjust unit tests for new behavior
217
+ 2. Keep the public API documented here
218
+ 3. Run the test suite before submitting
219
+
220
+ ---
221
+
222
+ ## Changelog
223
+
224
+ - **0.1.0** (2026-08-25): First release. Instance and solution schemas, the
225
+ solution verifier, archive reading and writing, the instance database, and
226
+ plotting and animation.
227
+
228
+ ---
229
+
230
+ ## License
231
+
232
+ MIT, see `LICENSE`.
@@ -0,0 +1,205 @@
1
+ # pyutils27 (cgshop2027-pyutils)
2
+
3
+ Utilities for working with CG:SHOP 2027 instances & solutions. This is a pure
4
+ Python package containing a parser/verifier for our instance format, solution
5
+ format and a verifier for solutions.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install cgshop2027-pyutils
13
+ ```
14
+
15
+ The current state of `main`, ahead of the latest release:
16
+
17
+ ```bash
18
+ pip install git+https://github.com/CG-SHOP/pyutils27
19
+ ```
20
+
21
+ From a local clone (editable, for development):
22
+
23
+ ```bash
24
+ git clone https://github.com/CG-SHOP/pyutils27
25
+ cd pyutils27
26
+ pip install -e ".[dev]"
27
+ ```
28
+
29
+ ---
30
+
31
+ ## Layout
32
+
33
+ ```
34
+ src/cgshop2027_pyutils/
35
+ ├── schemas/ # Pydantic models for instances & solutions
36
+ ├── io/ # reading instances & solutions from paths or file objects
37
+ ├── zip/ # safe reading/writing of instance & solution archives
38
+ ├── instance_database/ # query instances from a folder or a zip
39
+ ├── grid.py # cell-set algebra on the integer grid
40
+ ├── verify.py # checking a solution against its instance
41
+ └── visualize.py # matplotlib plots and animations
42
+ tests/ # pytest test suite
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Usage
48
+
49
+ Verifying a solution against its instance:
50
+
51
+ ```python
52
+ from cgshop2027_pyutils.io import read_instance, read_solution
53
+ from cgshop2027_pyutils.verify import check_for_errors
54
+
55
+ errors = check_for_errors(
56
+ read_instance("demo.instance.json"),
57
+ read_solution("demo.solution.json"),
58
+ )
59
+ ```
60
+
61
+ `check_for_errors` returns a list of human-readable messages; an empty list
62
+ means the solution is feasible. When checking many solutions for the same
63
+ instance, use `SolutionValidator(instance)` directly so that the
64
+ instance-derived precomputation is only paid once.
65
+
66
+ A solution consists of exactly `number_of_cutters` tours, one per cutter:
67
+
68
+ ```python
69
+ solution = CGSHOP2027Solution(
70
+ instance_uid="demo",
71
+ tours=[{"x": [0, 3, 3, 0], "y": [0, 0, 1, 1]}, {"x": [7], "y": [7]}],
72
+ )
73
+ ```
74
+
75
+ Each tour lists the points the cutter's _center_ passes through and is closed
76
+ implicitly, so the cutter travels from the last point back to the first one.
77
+ Consecutive points must be axis-parallel; a point may be visited again later,
78
+ but not immediately again. A tour of a single point is a cutter that stays where
79
+ it is. Cutters do not interfere with each other and may leave the region; all
80
+ that is required is that together they sweep the whole region.
81
+
82
+ The objective is `solution.max_tour_length`, the length of the longest tour, and
83
+ it is to be minimized.
84
+
85
+ Bundling instances or solutions into an archive:
86
+
87
+ ```python
88
+ from cgshop2027_pyutils.zip import ZipWriter
89
+
90
+ with ZipWriter("solutions.zip") as writer:
91
+ for solution in solutions:
92
+ writer.add_solution(solution)
93
+ ```
94
+
95
+ Reading a submitted archive, with size, CRC and path-traversal checks:
96
+
97
+ ```python
98
+ from cgshop2027_pyutils.zip import BadSolutionFile, ZipSolutionIterator, ZipReaderError
99
+
100
+ try:
101
+ for solution in ZipSolutionIterator("solutions.zip"):
102
+ print(solution.instance_uid)
103
+ except (ZipReaderError, BadSolutionFile) as e:
104
+ print(f"Rejected: {e}")
105
+ ```
106
+
107
+ `example_zip.ipynb` walks the whole submission path end to end: reading the
108
+ instances, checking solutions against them, packing an archive, and what a
109
+ rejection looks like. It runs on the two archives next to it:
110
+ `example_instances.zip`, a copy of the published example instances, and
111
+ `example_solutions.zip`, one feasible solution for each of them to check against
112
+ and to beat.
113
+
114
+ Looking instances up by name, from either a folder or a zip:
115
+
116
+ ```python
117
+ from cgshop2027_pyutils.instance_database import InstanceDatabase
118
+
119
+ db = InstanceDatabase("instances.zip")
120
+ instance = db["demo"]
121
+ for instance in db:
122
+ ...
123
+ ```
124
+
125
+ Plotting an instance, a solution, or an animation of the cutters at work:
126
+
127
+ ```python
128
+ from cgshop2027_pyutils.visualize import (
129
+ create_instance_plot,
130
+ create_solution_animation,
131
+ create_solution_plot,
132
+ )
133
+
134
+ create_instance_plot(instance).savefig("instance.png")
135
+ create_solution_plot(instance, solution).savefig("solution.png")
136
+
137
+ animation = create_solution_animation(instance, solution)
138
+ animation.save("solution.gif", writer="pillow")
139
+ ```
140
+
141
+ The solution plot shades the swept area, marks any cells left uncovered in red
142
+ and draws one tour per cutter. The animation strides through the tours to fit
143
+ `max_frames` (300 by default), filling in coverage as the cutters move; pass
144
+ `step` to control the stride yourself.
145
+
146
+ All three take `bare=True`, which drops the axes, the grid and every title and
147
+ trims the figure to the drawing, for a picture meant for a paper or a slide
148
+ rather than for debugging:
149
+
150
+ ```python
151
+ create_solution_plot(instance, solution, bare=True).savefig("solution.pdf")
152
+ ```
153
+
154
+ Instance files must be named `NAME.instance.json`. A lookup key may be the bare
155
+ name, the file name, or a path to it: `db["demo"]`, `db["demo.instance.json"]`
156
+ and `db["batch1/demo.instance.json"]` all resolve to the same instance. Note
157
+ that every `.json` file in the folder or archive is treated as an instance, so
158
+ keep solutions in a separate location.
159
+
160
+ ---
161
+
162
+ ## Development
163
+
164
+ Set up the tooling (linting & formatting run through pre-commit):
165
+
166
+ ```bash
167
+ pip install -e ".[dev]"
168
+ pre-commit install
169
+ ```
170
+
171
+ Run the checks manually:
172
+
173
+ ```bash
174
+ ruff check .
175
+ ruff format .
176
+ pytest
177
+ ```
178
+
179
+ Linting, formatting and import sorting are all handled by
180
+ [ruff](https://docs.astral.sh/ruff/); its configuration lives in
181
+ `pyproject.toml`.
182
+
183
+ ---
184
+
185
+ ## Contributing
186
+
187
+ Issues & PRs welcome. Please:
188
+
189
+ 1. Add/adjust unit tests for new behavior
190
+ 2. Keep the public API documented here
191
+ 3. Run the test suite before submitting
192
+
193
+ ---
194
+
195
+ ## Changelog
196
+
197
+ - **0.1.0** (2026-08-25): First release. Instance and solution schemas, the
198
+ solution verifier, archive reading and writing, the instance database, and
199
+ plotting and animation.
200
+
201
+ ---
202
+
203
+ ## License
204
+
205
+ MIT, see `LICENSE`.
@@ -0,0 +1,90 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cgshop2027-pyutils"
7
+ version = "0.1.0"
8
+ description = "Utilities for verifying solutions of the CG:SHOP 2027 Competition."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Phillip Keldenich" }]
14
+ keywords = ["cgshop", "computational geometry", "optimization challenge"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Science/Research",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Scientific/Engineering :: Mathematics",
20
+ ]
21
+ dependencies = [
22
+ "matplotlib>=3.6", # `width_ratios` on `plt.subplots`
23
+ "numpy>=1.24",
24
+ "pydantic>=2.0.0",
25
+ "shapely>=2.1.2",
26
+ # For `override` (3.12+) and `Self` (3.11+).
27
+ "typing_extensions>=4.0.0; python_version<'3.12'",
28
+ ]
29
+
30
+ [project.optional-dependencies]
31
+ dev = ["pre-commit", "pytest", "ruff"]
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/CG-SHOP/pyutils27"
35
+ Issues = "https://github.com/CG-SHOP/pyutils27/issues"
36
+
37
+ [tool.setuptools.packages.find]
38
+ where = ["src"]
39
+
40
+ [tool.pytest.ini_options]
41
+ testpaths = ["tests"]
42
+ filterwarnings = [
43
+ # The animation tests inspect frames without ever rendering the animation.
44
+ "ignore:Animation was deleted without rendering anything:UserWarning",
45
+ ]
46
+
47
+ [tool.ruff]
48
+ target-version = "py310"
49
+
50
+ [tool.ruff.lint]
51
+ select = [
52
+ "A", # builtin shadowing
53
+ "ARG", # unused arguments
54
+ "B", # bugbear
55
+ "C4", # comprehensions
56
+ "E", # pycodestyle
57
+ "EM", # error messages (no string literals in raise)
58
+ "F", # pyflakes
59
+ "FA", # future annotations
60
+ "I", # import sorting
61
+ "N", # naming
62
+ "PERF", # performance
63
+ "PIE",
64
+ "PL", # pylint
65
+ "PT", # pytest style
66
+ "PTH", # use pathlib
67
+ "RET",
68
+ "RSE",
69
+ "RUF",
70
+ "SIM",
71
+ "UP", # pyupgrade
72
+ "W",
73
+ ]
74
+ ignore = [
75
+ "E501", # line length is handled by the formatter
76
+ "PLR0913", # too many arguments
77
+ "PLR2004", # magic value comparison
78
+ ]
79
+
80
+ [tool.ruff.lint.per-file-ignores]
81
+ # The import tests import inside the test functions on purpose.
82
+ "tests/*" = ["ARG", "PLC0415", "PLR2004"]
83
+ # These exception names are part of the public API carried over from previous
84
+ # years; renaming them to an `Error` suffix would break existing consumers.
85
+ "src/cgshop2027_pyutils/zip/*" = ["N818"]
86
+
87
+ [tool.pyright]
88
+ reportUnusedCallResult = false
89
+ reportPrivateUsage = false
90
+ reportImplicitStringConcatenation = false
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """Utilities for the CG:SHOP 2027 competition."""
2
+
3
+ __version__ = "0.1.0"