stlbench 0.2.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 (33) hide show
  1. stlbench-0.2.0/LICENSE +21 -0
  2. stlbench-0.2.0/PKG-INFO +204 -0
  3. stlbench-0.2.0/README.md +166 -0
  4. stlbench-0.2.0/pyproject.toml +94 -0
  5. stlbench-0.2.0/stlbench/__init__.py +3 -0
  6. stlbench-0.2.0/stlbench/__main__.py +4 -0
  7. stlbench-0.2.0/stlbench/cli.py +275 -0
  8. stlbench-0.2.0/stlbench/config/__init__.py +4 -0
  9. stlbench-0.2.0/stlbench/config/loader.py +83 -0
  10. stlbench-0.2.0/stlbench/config/schema.py +62 -0
  11. stlbench-0.2.0/stlbench/core/__init__.py +31 -0
  12. stlbench-0.2.0/stlbench/core/fit.py +148 -0
  13. stlbench-0.2.0/stlbench/core/orientation.py +159 -0
  14. stlbench-0.2.0/stlbench/export/__init__.py +3 -0
  15. stlbench-0.2.0/stlbench/export/plate.py +64 -0
  16. stlbench-0.2.0/stlbench/hollow/__init__.py +3 -0
  17. stlbench-0.2.0/stlbench/hollow/meshlib_note.md +5 -0
  18. stlbench-0.2.0/stlbench/hollow/voxel_shell.py +45 -0
  19. stlbench-0.2.0/stlbench/packing/__init__.py +14 -0
  20. stlbench-0.2.0/stlbench/packing/layout_orientation.py +103 -0
  21. stlbench-0.2.0/stlbench/packing/rectpack_plate.py +125 -0
  22. stlbench-0.2.0/stlbench/packing/shelf.py +105 -0
  23. stlbench-0.2.0/stlbench/pipeline/__init__.py +18 -0
  24. stlbench-0.2.0/stlbench/pipeline/common.py +79 -0
  25. stlbench-0.2.0/stlbench/pipeline/mesh_io.py +25 -0
  26. stlbench-0.2.0/stlbench/pipeline/run_autopack.py +207 -0
  27. stlbench-0.2.0/stlbench/pipeline/run_fill.py +206 -0
  28. stlbench-0.2.0/stlbench/pipeline/run_info.py +98 -0
  29. stlbench-0.2.0/stlbench/pipeline/run_layout.py +132 -0
  30. stlbench-0.2.0/stlbench/pipeline/run_scale.py +273 -0
  31. stlbench-0.2.0/stlbench/py.typed +0 -0
  32. stlbench-0.2.0/stlbench/supports/__init__.py +5 -0
  33. stlbench-0.2.0/stlbench/supports/external.py +15 -0
stlbench-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nikita Dmitryuk
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,204 @@
1
+ Metadata-Version: 2.4
2
+ Name: stlbench
3
+ Version: 0.2.0
4
+ Summary: STL preparation toolkit for resin 3D printing: uniform scaling, bed packing, fill, autopack.
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: stl,3d-printing,resin,scaling,packing,sla,dlp
8
+ Author: NikitaDmitryuk
9
+ Author-email: dmitryuk.nikita@gmail.com
10
+ Requires-Python: >=3.10
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Intended Audience :: Manufacturing
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
22
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Modeling
23
+ Classifier: Topic :: Scientific/Engineering
24
+ Provides-Extra: hollow
25
+ Requires-Dist: numpy (>=1.23)
26
+ Requires-Dist: pydantic (>=2.0,<3)
27
+ Requires-Dist: rectpack (>=0.2.2)
28
+ Requires-Dist: rich (>=13.0)
29
+ Requires-Dist: scipy (>=1.9) ; extra == "hollow"
30
+ Requires-Dist: tomli (>=1.1) ; python_version < "3.11"
31
+ Requires-Dist: trimesh (>=3.21)
32
+ Requires-Dist: typer (>=0.9)
33
+ Project-URL: Bug Tracker, https://github.com/NikitaDmitryuk/stlbench/issues
34
+ Project-URL: Homepage, https://github.com/NikitaDmitryuk/stlbench
35
+ Project-URL: Repository, https://github.com/NikitaDmitryuk/stlbench
36
+ Description-Content-Type: text/markdown
37
+
38
+ # stlbench
39
+
40
+ [![PyPI version](https://img.shields.io/pypi/v/stlbench.svg)](https://pypi.org/project/stlbench/)
41
+ [![Python versions](https://img.shields.io/pypi/pyversions/stlbench.svg)](https://pypi.org/project/stlbench/)
42
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
43
+
44
+ **STL preparation toolkit for resin 3D printing.**
45
+
46
+ stlbench takes STL files and prepares them for SLA/DLP printers: uniform scaling to
47
+ fit the build volume, packing parts onto rectangular print plates, filling the bed with
48
+ copies, and combined scale-and-pack in one step. Supports are **not** generated --
49
+ use your slicer (Lychee, Chitubox, PrusaSlicer, etc.) after export.
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ pip install stlbench
55
+ ```
56
+
57
+ For hollow shell support (optional, requires `scipy`):
58
+
59
+ ```bash
60
+ pip install "stlbench[hollow]"
61
+ ```
62
+
63
+ ### Development install
64
+
65
+ ```bash
66
+ git clone https://github.com/NikitaDmitryuk/stlbench.git
67
+ cd stlbench
68
+ poetry install --with dev
69
+ ```
70
+
71
+ ## Quick Start
72
+
73
+ ```bash
74
+ # Inspect model parts
75
+ stlbench info -i ./parts -c configs/mars5_ultra.toml
76
+
77
+ # Scale all parts to fit the printer
78
+ stlbench scale -i ./parts -o ./scaled -c configs/mars5_ultra.toml
79
+
80
+ # Pack scaled parts onto plates
81
+ stlbench layout -i ./scaled -o ./plates -c configs/mars5_ultra.toml
82
+
83
+ # Scale + pack all on one plate in one step
84
+ stlbench autopack -i ./parts -o ./packed -c configs/mars5_ultra.toml
85
+
86
+ # Fill the bed with copies of a single part
87
+ stlbench fill -i ./part.stl -o ./filled -c configs/mars5_ultra.toml
88
+ ```
89
+
90
+ Or specify the printer inline without a config file:
91
+
92
+ ```bash
93
+ stlbench scale -i ./parts -o ./scaled -p "153.36,77.76,165"
94
+ ```
95
+
96
+ ## Commands
97
+
98
+ ### `info` -- Analyze models (read-only)
99
+
100
+ ```bash
101
+ stlbench info -i ./parts -c configs/mars5_ultra.toml
102
+ ```
103
+
104
+ Displays a table with AABB dimensions, volume, vertex/face counts, whether each
105
+ part fits the bed, maximum scale factor, and how many copies would fit (`fill`).
106
+ No files are written.
107
+
108
+ ### `scale` -- Uniform scaling
109
+
110
+ ```bash
111
+ stlbench scale -i ./parts -o ./out -c configs/mars5_ultra.toml
112
+ ```
113
+
114
+ Computes a single scale factor so that **every** part fits inside the printer
115
+ build volume. The largest part determines the factor; all parts share the same
116
+ scale. Supports two methods: `sorted` (default) and `conservative`.
117
+
118
+ Key options: `--dry-run`, `--no-upscale`, `--method`, `--orientation free`,
119
+ `--hollow`, `--supports-scale`.
120
+
121
+ ### `layout` -- Pack parts onto plates
122
+
123
+ ```bash
124
+ stlbench layout -i ./scaled -o ./plates -c configs/mars5_ultra.toml
125
+ ```
126
+
127
+ Arranges already-scaled STL files onto rectangular print plates using `rectpack`.
128
+ Exports `plate_01.stl` + `plate_01.json` with positions. Multiple plates are
129
+ created if parts do not fit on one.
130
+
131
+ Key options: `--dry-run`, `--gap-mm`, `--algorithm shelf|rectpack`.
132
+
133
+ ### `autopack` -- Scale + layout on one plate
134
+
135
+ ```bash
136
+ stlbench autopack -i ./parts -o ./packed -c configs/mars5_ultra.toml
137
+ ```
138
+
139
+ Binary-searches for the maximum scale factor at which **all** parts fit onto a
140
+ single plate simultaneously. Combines `scale` and `layout` into one step with a
141
+ different goal: all parts on one plate, not each part fitting individually.
142
+
143
+ Key options: `--dry-run`, `--gap-mm`, `--margin`, `--supports-scale`.
144
+
145
+ ### `fill` -- Maximum copies of one part
146
+
147
+ ```bash
148
+ stlbench fill -i ./part.stl -o ./filled -c configs/mars5_ultra.toml
149
+ ```
150
+
151
+ Packs as many copies of a single STL file as possible onto one plate. Useful for
152
+ batch printing identical parts.
153
+
154
+ Key options: `--scale` (scale the part to fit before filling), `--dry-run`, `--gap-mm`.
155
+
156
+ ### `hollow` / `supports`
157
+
158
+ - `stlbench hollow` -- reminder to configure `[hollow]` in the TOML config and use `--hollow` with `scale`.
159
+ - `stlbench supports` -- reminder that supports are added in the slicer.
160
+
161
+ ## Configuration
162
+
163
+ Printer profiles are TOML files. See [`configs/mars5_ultra.toml`](configs/mars5_ultra.toml)
164
+ for a complete example (ELEGOO Mars 5 Ultra).
165
+
166
+ Key sections:
167
+
168
+ | Section | Purpose |
169
+ |-----------------|--------------------------------------------------|
170
+ | `[printer]` | Build volume: `width_mm`, `depth_mm`, `height_mm`|
171
+ | `[scaling]` | `bed_margin`, `supports_scale` |
172
+ | `[orientation]` | `mode` (axis/free), `samples`, `seed` |
173
+ | `[packing]` | `algorithm` (rectpack/shelf), `gap_mm`, `report` |
174
+ | `[hollow]` | `enabled`, `wall_thickness_mm`, `voxel_mm` |
175
+
176
+ ## Examples
177
+
178
+ See [`examples/README.md`](examples/README.md) for a full walkthrough using the
179
+ included Gendalf model (3 parts tracked via Git LFS).
180
+
181
+ ## Package Structure
182
+
183
+ | Module | Purpose |
184
+ |--------------------|--------------------------------------------|
185
+ | `stlbench.cli` | Typer CLI application |
186
+ | `stlbench.core` | Scale factor computation and orientation |
187
+ | `stlbench.config` | Pydantic schema + TOML loader |
188
+ | `stlbench.packing` | Shelf and rectpack algorithms |
189
+ | `stlbench.export` | Plate STL assembly and JSON manifest |
190
+ | `stlbench.hollow` | Voxel shell hollowing (optional, scipy) |
191
+ | `stlbench.pipeline`| Command runners (scale, layout, fill, etc.)|
192
+
193
+ ## Limitations
194
+
195
+ - Boolean and voxel operations are sensitive to non-manifold STL. For complex
196
+ models use a mesh repair tool first.
197
+ - Hollow shells in this package are a simplified voxel approach; for production
198
+ use your slicer's built-in hollowing.
199
+ - Supports are **not** generated -- always add them in your slicer.
200
+
201
+ ## License
202
+
203
+ [MIT](LICENSE)
204
+
@@ -0,0 +1,166 @@
1
+ # stlbench
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/stlbench.svg)](https://pypi.org/project/stlbench/)
4
+ [![Python versions](https://img.shields.io/pypi/pyversions/stlbench.svg)](https://pypi.org/project/stlbench/)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ **STL preparation toolkit for resin 3D printing.**
8
+
9
+ stlbench takes STL files and prepares them for SLA/DLP printers: uniform scaling to
10
+ fit the build volume, packing parts onto rectangular print plates, filling the bed with
11
+ copies, and combined scale-and-pack in one step. Supports are **not** generated --
12
+ use your slicer (Lychee, Chitubox, PrusaSlicer, etc.) after export.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ pip install stlbench
18
+ ```
19
+
20
+ For hollow shell support (optional, requires `scipy`):
21
+
22
+ ```bash
23
+ pip install "stlbench[hollow]"
24
+ ```
25
+
26
+ ### Development install
27
+
28
+ ```bash
29
+ git clone https://github.com/NikitaDmitryuk/stlbench.git
30
+ cd stlbench
31
+ poetry install --with dev
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ```bash
37
+ # Inspect model parts
38
+ stlbench info -i ./parts -c configs/mars5_ultra.toml
39
+
40
+ # Scale all parts to fit the printer
41
+ stlbench scale -i ./parts -o ./scaled -c configs/mars5_ultra.toml
42
+
43
+ # Pack scaled parts onto plates
44
+ stlbench layout -i ./scaled -o ./plates -c configs/mars5_ultra.toml
45
+
46
+ # Scale + pack all on one plate in one step
47
+ stlbench autopack -i ./parts -o ./packed -c configs/mars5_ultra.toml
48
+
49
+ # Fill the bed with copies of a single part
50
+ stlbench fill -i ./part.stl -o ./filled -c configs/mars5_ultra.toml
51
+ ```
52
+
53
+ Or specify the printer inline without a config file:
54
+
55
+ ```bash
56
+ stlbench scale -i ./parts -o ./scaled -p "153.36,77.76,165"
57
+ ```
58
+
59
+ ## Commands
60
+
61
+ ### `info` -- Analyze models (read-only)
62
+
63
+ ```bash
64
+ stlbench info -i ./parts -c configs/mars5_ultra.toml
65
+ ```
66
+
67
+ Displays a table with AABB dimensions, volume, vertex/face counts, whether each
68
+ part fits the bed, maximum scale factor, and how many copies would fit (`fill`).
69
+ No files are written.
70
+
71
+ ### `scale` -- Uniform scaling
72
+
73
+ ```bash
74
+ stlbench scale -i ./parts -o ./out -c configs/mars5_ultra.toml
75
+ ```
76
+
77
+ Computes a single scale factor so that **every** part fits inside the printer
78
+ build volume. The largest part determines the factor; all parts share the same
79
+ scale. Supports two methods: `sorted` (default) and `conservative`.
80
+
81
+ Key options: `--dry-run`, `--no-upscale`, `--method`, `--orientation free`,
82
+ `--hollow`, `--supports-scale`.
83
+
84
+ ### `layout` -- Pack parts onto plates
85
+
86
+ ```bash
87
+ stlbench layout -i ./scaled -o ./plates -c configs/mars5_ultra.toml
88
+ ```
89
+
90
+ Arranges already-scaled STL files onto rectangular print plates using `rectpack`.
91
+ Exports `plate_01.stl` + `plate_01.json` with positions. Multiple plates are
92
+ created if parts do not fit on one.
93
+
94
+ Key options: `--dry-run`, `--gap-mm`, `--algorithm shelf|rectpack`.
95
+
96
+ ### `autopack` -- Scale + layout on one plate
97
+
98
+ ```bash
99
+ stlbench autopack -i ./parts -o ./packed -c configs/mars5_ultra.toml
100
+ ```
101
+
102
+ Binary-searches for the maximum scale factor at which **all** parts fit onto a
103
+ single plate simultaneously. Combines `scale` and `layout` into one step with a
104
+ different goal: all parts on one plate, not each part fitting individually.
105
+
106
+ Key options: `--dry-run`, `--gap-mm`, `--margin`, `--supports-scale`.
107
+
108
+ ### `fill` -- Maximum copies of one part
109
+
110
+ ```bash
111
+ stlbench fill -i ./part.stl -o ./filled -c configs/mars5_ultra.toml
112
+ ```
113
+
114
+ Packs as many copies of a single STL file as possible onto one plate. Useful for
115
+ batch printing identical parts.
116
+
117
+ Key options: `--scale` (scale the part to fit before filling), `--dry-run`, `--gap-mm`.
118
+
119
+ ### `hollow` / `supports`
120
+
121
+ - `stlbench hollow` -- reminder to configure `[hollow]` in the TOML config and use `--hollow` with `scale`.
122
+ - `stlbench supports` -- reminder that supports are added in the slicer.
123
+
124
+ ## Configuration
125
+
126
+ Printer profiles are TOML files. See [`configs/mars5_ultra.toml`](configs/mars5_ultra.toml)
127
+ for a complete example (ELEGOO Mars 5 Ultra).
128
+
129
+ Key sections:
130
+
131
+ | Section | Purpose |
132
+ |-----------------|--------------------------------------------------|
133
+ | `[printer]` | Build volume: `width_mm`, `depth_mm`, `height_mm`|
134
+ | `[scaling]` | `bed_margin`, `supports_scale` |
135
+ | `[orientation]` | `mode` (axis/free), `samples`, `seed` |
136
+ | `[packing]` | `algorithm` (rectpack/shelf), `gap_mm`, `report` |
137
+ | `[hollow]` | `enabled`, `wall_thickness_mm`, `voxel_mm` |
138
+
139
+ ## Examples
140
+
141
+ See [`examples/README.md`](examples/README.md) for a full walkthrough using the
142
+ included Gendalf model (3 parts tracked via Git LFS).
143
+
144
+ ## Package Structure
145
+
146
+ | Module | Purpose |
147
+ |--------------------|--------------------------------------------|
148
+ | `stlbench.cli` | Typer CLI application |
149
+ | `stlbench.core` | Scale factor computation and orientation |
150
+ | `stlbench.config` | Pydantic schema + TOML loader |
151
+ | `stlbench.packing` | Shelf and rectpack algorithms |
152
+ | `stlbench.export` | Plate STL assembly and JSON manifest |
153
+ | `stlbench.hollow` | Voxel shell hollowing (optional, scipy) |
154
+ | `stlbench.pipeline`| Command runners (scale, layout, fill, etc.)|
155
+
156
+ ## Limitations
157
+
158
+ - Boolean and voxel operations are sensitive to non-manifold STL. For complex
159
+ models use a mesh repair tool first.
160
+ - Hollow shells in this package are a simplified voxel approach; for production
161
+ use your slicer's built-in hollowing.
162
+ - Supports are **not** generated -- always add them in your slicer.
163
+
164
+ ## License
165
+
166
+ [MIT](LICENSE)
@@ -0,0 +1,94 @@
1
+ [project]
2
+ name = "stlbench"
3
+ version = "0.2.0"
4
+ description = "STL preparation toolkit for resin 3D printing: uniform scaling, bed packing, fill, autopack."
5
+ authors = [
6
+ {name = "NikitaDmitryuk", email = "dmitryuk.nikita@gmail.com"}
7
+ ]
8
+ license = {text = "MIT"}
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ keywords = ["stl", "3d-printing", "resin", "scaling", "packing", "sla", "dlp"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Intended Audience :: End Users/Desktop",
15
+ "Intended Audience :: Manufacturing",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Programming Language :: Python :: 3.14",
24
+ "Topic :: Multimedia :: Graphics :: 3D Modeling",
25
+ "Topic :: Scientific/Engineering",
26
+ ]
27
+ dependencies = [
28
+ "numpy>=1.23",
29
+ "pydantic>=2.0,<3",
30
+ "rectpack>=0.2.2",
31
+ "rich>=13.0",
32
+ "tomli>=1.1; python_version < '3.11'",
33
+ "trimesh>=3.21",
34
+ "typer>=0.9",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ hollow = ["scipy>=1.9"]
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/NikitaDmitryuk/stlbench"
42
+ Repository = "https://github.com/NikitaDmitryuk/stlbench"
43
+ "Bug Tracker" = "https://github.com/NikitaDmitryuk/stlbench/issues"
44
+
45
+ [project.scripts]
46
+ stlbench = "stlbench.cli:main"
47
+
48
+ [tool.poetry]
49
+ packages = [{ include = "stlbench" }]
50
+
51
+ [dependency-groups]
52
+ dev = [
53
+ "pytest>=8.0",
54
+ "isort>=5.12",
55
+ "mypy>=1.5",
56
+ "ruff>=0.1",
57
+ "black>=23.0",
58
+ "twine>=5.0",
59
+ "build>=1.0",
60
+ ]
61
+
62
+ [build-system]
63
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
64
+ build-backend = "poetry.core.masonry.api"
65
+
66
+ [tool.pytest.ini_options]
67
+ testpaths = ["tests"]
68
+
69
+ [tool.black]
70
+ line-length = 100
71
+ target-version = ["py310"]
72
+
73
+ [tool.isort]
74
+ profile = "black"
75
+ line_length = 100
76
+ src_paths = ["stlbench", "tests"]
77
+ known_first_party = ["stlbench"]
78
+
79
+ [tool.ruff]
80
+ line-length = 100
81
+ target-version = "py310"
82
+ src = ["stlbench", "tests"]
83
+
84
+ [tool.ruff.lint]
85
+ select = ["E", "F", "W", "UP", "B", "SIM"]
86
+ ignore = ["E501"]
87
+
88
+ [tool.mypy]
89
+ python_version = "3.10"
90
+ packages = ["stlbench"]
91
+ warn_return_any = true
92
+ warn_unused_ignores = true
93
+ ignore_missing_imports = true
94
+ disallow_untyped_defs = false
@@ -0,0 +1,3 @@
1
+ """STL preparation toolkit for resin 3D printing: scale, layout, fill, autopack, info."""
2
+
3
+ __version__ = "0.2.0"
@@ -0,0 +1,4 @@
1
+ from stlbench.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())