pythonscad-stl-generator 0.1.1__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 (25) hide show
  1. pythonscad_stl_generator-0.1.1/LICENSE +21 -0
  2. pythonscad_stl_generator-0.1.1/MANIFEST.in +2 -0
  3. pythonscad_stl_generator-0.1.1/PKG-INFO +159 -0
  4. pythonscad_stl_generator-0.1.1/README.md +125 -0
  5. pythonscad_stl_generator-0.1.1/VERSION.txt +1 -0
  6. pythonscad_stl_generator-0.1.1/docs/generate-pythonscad-stls.1 +100 -0
  7. pythonscad_stl_generator-0.1.1/docs/generate-pythonscad-stls.1.md +99 -0
  8. pythonscad_stl_generator-0.1.1/pyproject.toml +76 -0
  9. pythonscad_stl_generator-0.1.1/setup.cfg +4 -0
  10. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator/__init__.py +10 -0
  11. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator/cli.py +92 -0
  12. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator/discovery.py +42 -0
  13. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator/presets.py +47 -0
  14. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator/py.typed +0 -0
  15. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator/render.py +215 -0
  16. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator.egg-info/PKG-INFO +159 -0
  17. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator.egg-info/SOURCES.txt +23 -0
  18. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator.egg-info/dependency_links.txt +1 -0
  19. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator.egg-info/entry_points.txt +2 -0
  20. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator.egg-info/requires.txt +7 -0
  21. pythonscad_stl_generator-0.1.1/src/pythonscad_stl_generator.egg-info/top_level.txt +1 -0
  22. pythonscad_stl_generator-0.1.1/tests/test_cli.py +42 -0
  23. pythonscad_stl_generator-0.1.1/tests/test_discovery.py +45 -0
  24. pythonscad_stl_generator-0.1.1/tests/test_presets.py +39 -0
  25. pythonscad_stl_generator-0.1.1/tests/test_render.py +183 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nomike
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,2 @@
1
+ include docs/generate-pythonscad-stls.1
2
+ include docs/generate-pythonscad-stls.1.md
@@ -0,0 +1,159 @@
1
+ Metadata-Version: 2.4
2
+ Name: pythonscad-stl-generator
3
+ Version: 0.1.1
4
+ Summary: Render PythonSCAD design scripts to STL files, including customizer presets.
5
+ Author: Nomike
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/nomike/pythonscad-stl-generator
8
+ Project-URL: Repository, https://github.com/nomike/pythonscad-stl-generator
9
+ Project-URL: Issues, https://github.com/nomike/pythonscad-stl-generator/issues
10
+ Project-URL: Changelog, https://github.com/nomike/pythonscad-stl-generator/blob/main/CHANGELOG.md
11
+ Keywords: 3d,cad,openscad,pythonscad,stl,3d-printing
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Manufacturing
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 :: Utilities
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: docopt-ng<1,>=0.9
28
+ Provides-Extra: dev
29
+ Requires-Dist: build>=1.5; extra == "dev"
30
+ Requires-Dist: pytest>=8; extra == "dev"
31
+ Requires-Dist: pytest-cov>=7; extra == "dev"
32
+ Requires-Dist: ruff>=0.15; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # PythonSCAD STL Generator
36
+
37
+ PythonSCAD STL Generator is a small command line tool for batch-rendering
38
+ PythonSCAD design files. It scans a directory for Python files that import
39
+ `pythonscad`, renders each design with the `pythonscad` executable from
40
+ `PATH`, and optionally renders once per customizer preset from a sibling JSON
41
+ file.
42
+
43
+ ## Installation
44
+
45
+ Install the published package with `pipx`:
46
+
47
+ ```sh
48
+ pipx install pythonscad-stl-generator
49
+ ```
50
+
51
+ Or install it into an existing environment with `pip`:
52
+
53
+ ```sh
54
+ python -m pip install pythonscad-stl-generator
55
+ ```
56
+
57
+ For development:
58
+
59
+ ```sh
60
+ git clone https://github.com/nomike/pythonscad-stl-generator.git
61
+ cd pythonscad-stl-generator
62
+ python -m pip install -e ".[dev]"
63
+ ```
64
+
65
+ PythonSCAD itself is not bundled. The tool expects a `pythonscad` executable to
66
+ be available on `PATH`, or you can point to it explicitly with
67
+ `--pythonscad=/path/to/pythonscad`.
68
+
69
+ ## Usage
70
+
71
+ From a directory containing PythonSCAD designs:
72
+
73
+ ```sh
74
+ generate-pythonscad-stls
75
+ ```
76
+
77
+ The command writes STL files to `output/` by default. A Python file is treated
78
+ as a design when it imports `pythonscad`, for example:
79
+
80
+ ```python
81
+ from pythonscad import *
82
+
83
+ width = add_parameter("width", 20)
84
+ cube([width, width, width]).show()
85
+ ```
86
+
87
+ Useful options:
88
+
89
+ ```sh
90
+ generate-pythonscad-stls --output-dir stls
91
+ generate-pythonscad-stls --pythonscad ~/bin/pythonscad
92
+ generate-pythonscad-stls --format 3mf
93
+ generate-pythonscad-stls --dry-run --verbose
94
+ generate-pythonscad-stls --recursive
95
+ ```
96
+
97
+ The generated PythonSCAD command includes `--trust-python`, because PythonSCAD
98
+ requires that flag for command-line execution of Python input files.
99
+
100
+ ## Customizer Presets
101
+
102
+ If `box.py` has a sibling `box.json`, the tool reads its top-level
103
+ `parameterSets` object and renders once per preset:
104
+
105
+ ```json
106
+ {
107
+ "parameterSets": {
108
+ "small": {
109
+ "width": "10"
110
+ },
111
+ "large": {
112
+ "width": "50"
113
+ }
114
+ },
115
+ "fileFormatVersion": "1"
116
+ }
117
+ ```
118
+
119
+ This produces files like:
120
+
121
+ ```text
122
+ output/box-small.stl
123
+ output/box-large.stl
124
+ ```
125
+
126
+ Without a sibling preset file, the design renders once to `output/box.stl`.
127
+
128
+ ## Up-To-Date Checks
129
+
130
+ Existing output files are skipped when they are newer than their inputs. For a
131
+ plain design, the input is the `.py` file. For preset renders, both the `.py`
132
+ file and the sibling `.json` preset file must be older than the output.
133
+
134
+ Use `--force` to render everything regardless of timestamps.
135
+
136
+ ## Development
137
+
138
+ Run tests:
139
+
140
+ ```sh
141
+ python -m pytest
142
+ ```
143
+
144
+ Run linting and formatting:
145
+
146
+ ```sh
147
+ ruff check .
148
+ ruff format .
149
+ ```
150
+
151
+ Run all pre-commit hooks:
152
+
153
+ ```sh
154
+ pre-commit run --all-files
155
+ ```
156
+
157
+ ## License
158
+
159
+ This project is licensed under the MIT License. See `LICENSE`.
@@ -0,0 +1,125 @@
1
+ # PythonSCAD STL Generator
2
+
3
+ PythonSCAD STL Generator is a small command line tool for batch-rendering
4
+ PythonSCAD design files. It scans a directory for Python files that import
5
+ `pythonscad`, renders each design with the `pythonscad` executable from
6
+ `PATH`, and optionally renders once per customizer preset from a sibling JSON
7
+ file.
8
+
9
+ ## Installation
10
+
11
+ Install the published package with `pipx`:
12
+
13
+ ```sh
14
+ pipx install pythonscad-stl-generator
15
+ ```
16
+
17
+ Or install it into an existing environment with `pip`:
18
+
19
+ ```sh
20
+ python -m pip install pythonscad-stl-generator
21
+ ```
22
+
23
+ For development:
24
+
25
+ ```sh
26
+ git clone https://github.com/nomike/pythonscad-stl-generator.git
27
+ cd pythonscad-stl-generator
28
+ python -m pip install -e ".[dev]"
29
+ ```
30
+
31
+ PythonSCAD itself is not bundled. The tool expects a `pythonscad` executable to
32
+ be available on `PATH`, or you can point to it explicitly with
33
+ `--pythonscad=/path/to/pythonscad`.
34
+
35
+ ## Usage
36
+
37
+ From a directory containing PythonSCAD designs:
38
+
39
+ ```sh
40
+ generate-pythonscad-stls
41
+ ```
42
+
43
+ The command writes STL files to `output/` by default. A Python file is treated
44
+ as a design when it imports `pythonscad`, for example:
45
+
46
+ ```python
47
+ from pythonscad import *
48
+
49
+ width = add_parameter("width", 20)
50
+ cube([width, width, width]).show()
51
+ ```
52
+
53
+ Useful options:
54
+
55
+ ```sh
56
+ generate-pythonscad-stls --output-dir stls
57
+ generate-pythonscad-stls --pythonscad ~/bin/pythonscad
58
+ generate-pythonscad-stls --format 3mf
59
+ generate-pythonscad-stls --dry-run --verbose
60
+ generate-pythonscad-stls --recursive
61
+ ```
62
+
63
+ The generated PythonSCAD command includes `--trust-python`, because PythonSCAD
64
+ requires that flag for command-line execution of Python input files.
65
+
66
+ ## Customizer Presets
67
+
68
+ If `box.py` has a sibling `box.json`, the tool reads its top-level
69
+ `parameterSets` object and renders once per preset:
70
+
71
+ ```json
72
+ {
73
+ "parameterSets": {
74
+ "small": {
75
+ "width": "10"
76
+ },
77
+ "large": {
78
+ "width": "50"
79
+ }
80
+ },
81
+ "fileFormatVersion": "1"
82
+ }
83
+ ```
84
+
85
+ This produces files like:
86
+
87
+ ```text
88
+ output/box-small.stl
89
+ output/box-large.stl
90
+ ```
91
+
92
+ Without a sibling preset file, the design renders once to `output/box.stl`.
93
+
94
+ ## Up-To-Date Checks
95
+
96
+ Existing output files are skipped when they are newer than their inputs. For a
97
+ plain design, the input is the `.py` file. For preset renders, both the `.py`
98
+ file and the sibling `.json` preset file must be older than the output.
99
+
100
+ Use `--force` to render everything regardless of timestamps.
101
+
102
+ ## Development
103
+
104
+ Run tests:
105
+
106
+ ```sh
107
+ python -m pytest
108
+ ```
109
+
110
+ Run linting and formatting:
111
+
112
+ ```sh
113
+ ruff check .
114
+ ruff format .
115
+ ```
116
+
117
+ Run all pre-commit hooks:
118
+
119
+ ```sh
120
+ pre-commit run --all-files
121
+ ```
122
+
123
+ ## License
124
+
125
+ This project is licensed under the MIT License. See `LICENSE`.
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,100 @@
1
+ .TH GENERATE-PYTHONSCAD-STLS 1 "July 2026" "pythonscad-stl-generator" "User Commands"
2
+ .SH NAME
3
+ generate-pythonscad-stls \- render PythonSCAD designs and customizer presets
4
+ .SH SYNOPSIS
5
+ .B generate-pythonscad-stls
6
+ [\fB--directory=\fR\fIDIR\fR] [\fB--output-dir=\fR\fIDIR\fR]
7
+ [\fB--pythonscad=\fR\fIPATH\fR] [\fB--format=\fR\fIEXT\fR]
8
+ [\fB--force\fR] [\fB--dry-run\fR] [\fB--recursive\fR]
9
+ [\fB-v\fR|\fB--verbose\fR]
10
+ .br
11
+ .B generate-pythonscad-stls
12
+ \fB-h\fR|\fB--help\fR
13
+ .br
14
+ .B generate-pythonscad-stls
15
+ \fB--version\fR
16
+ .SH DESCRIPTION
17
+ .B generate-pythonscad-stls
18
+ scans a directory for Python files that import
19
+ .B pythonscad
20
+ and renders each detected design by invoking the PythonSCAD command line
21
+ application. It passes
22
+ .B --trust-python
23
+ automatically.
24
+ .PP
25
+ When a design has a sibling JSON file with a top-level
26
+ .B parameterSets
27
+ object, the design is rendered once for each named preset using PythonSCAD's
28
+ .B -p
29
+ and
30
+ .B -P
31
+ customizer options.
32
+ .SH OPTIONS
33
+ .TP
34
+ .B -h, --help
35
+ Show help text.
36
+ .TP
37
+ .B --version
38
+ Show the program version.
39
+ .TP
40
+ .BI --directory= DIR
41
+ Directory to scan for PythonSCAD designs. Defaults to the current directory.
42
+ .TP
43
+ .BI --output-dir= DIR
44
+ Directory for generated output files. Relative paths are resolved below the
45
+ scan directory. Defaults to
46
+ .BR output .
47
+ .TP
48
+ .BI --pythonscad= PATH
49
+ PythonSCAD executable to run. Defaults to
50
+ .B pythonscad
51
+ from
52
+ .BR PATH .
53
+ .TP
54
+ .BI --format= EXT
55
+ Output file extension and PythonSCAD export format. Defaults to
56
+ .BR stl .
57
+ .TP
58
+ .B --force
59
+ Render even when output files are newer than their inputs.
60
+ .TP
61
+ .B --dry-run
62
+ Print render commands without executing them.
63
+ .TP
64
+ .B --recursive
65
+ Search for designs recursively below the scan directory.
66
+ .TP
67
+ .B -v, --verbose
68
+ Enable debug logging.
69
+ .SH FILES
70
+ .TP
71
+ .I design.py
72
+ PythonSCAD design script. The file is detected as a design when it imports
73
+ .BR pythonscad .
74
+ .TP
75
+ .I design.json
76
+ Optional customizer preset file with a top-level
77
+ .B parameterSets
78
+ object.
79
+ .SH EXAMPLES
80
+ .EX
81
+ generate-pythonscad-stls
82
+ .EE
83
+ .PP
84
+ .EX
85
+ generate-pythonscad-stls --dry-run --verbose
86
+ .EE
87
+ .PP
88
+ .EX
89
+ generate-pythonscad-stls --pythonscad ~/bin/pythonscad --output-dir stls
90
+ .EE
91
+ .SH EXIT STATUS
92
+ .TP
93
+ .B 0
94
+ All requested renders completed successfully, or no designs were found.
95
+ .TP
96
+ .B 2
97
+ Command line input, scan directory, or preset JSON was invalid.
98
+ .TP
99
+ .B other non-zero status from pythonscad
100
+ At least one render command failed; the PythonSCAD exit code is returned.
@@ -0,0 +1,99 @@
1
+ # generate-pythonscad-stls(1)
2
+
3
+ ## Name
4
+
5
+ generate-pythonscad-stls - render PythonSCAD designs and customizer presets
6
+
7
+ ## Synopsis
8
+
9
+ ```text
10
+ generate-pythonscad-stls [--directory=<dir>] [--output-dir=<dir>]
11
+ [--pythonscad=<path>] [--format=<ext>]
12
+ [--force] [--dry-run] [--recursive]
13
+ [-v | --verbose]
14
+ generate-pythonscad-stls -h | --help
15
+ generate-pythonscad-stls --version
16
+ ```
17
+
18
+ ## Description
19
+
20
+ `generate-pythonscad-stls` scans a directory for Python files that import
21
+ `pythonscad` and renders each detected design by invoking the PythonSCAD
22
+ command line application. It passes `--trust-python` automatically.
23
+
24
+ When a design has a sibling JSON file with a top-level `parameterSets` object,
25
+ the design is rendered once for each named preset using PythonSCAD's `-p` and
26
+ `-P` customizer options.
27
+
28
+ ## Options
29
+
30
+ `-h`, `--help`
31
+ : Show help text.
32
+
33
+ `--version`
34
+ : Show the program version.
35
+
36
+ `--directory=<dir>`
37
+ : Directory to scan for PythonSCAD designs. Defaults to the current directory.
38
+
39
+ `--output-dir=<dir>`
40
+ : Directory for generated output files. Relative paths are resolved below the
41
+ scan directory. Defaults to `output`.
42
+
43
+ `--pythonscad=<path>`
44
+ : PythonSCAD executable to run. Defaults to `pythonscad` from `PATH`.
45
+
46
+ `--format=<ext>`
47
+ : Output file extension and PythonSCAD export format. Defaults to `stl`.
48
+
49
+ `--force`
50
+ : Render even when output files are newer than their inputs.
51
+
52
+ `--dry-run`
53
+ : Print render commands without executing them.
54
+
55
+ `--recursive`
56
+ : Search for designs recursively below the scan directory.
57
+
58
+ `-v`, `--verbose`
59
+ : Enable debug logging.
60
+
61
+ ## Files
62
+
63
+ `<design>.py`
64
+ : PythonSCAD design script. The file is detected as a design when it imports
65
+ `pythonscad`.
66
+
67
+ `<design>.json`
68
+ : Optional customizer preset file with a top-level `parameterSets` object.
69
+
70
+ ## Examples
71
+
72
+ Render designs in the current directory:
73
+
74
+ ```sh
75
+ generate-pythonscad-stls
76
+ ```
77
+
78
+ Preview the commands that would be run:
79
+
80
+ ```sh
81
+ generate-pythonscad-stls --dry-run --verbose
82
+ ```
83
+
84
+ Use a specific PythonSCAD binary and output directory:
85
+
86
+ ```sh
87
+ generate-pythonscad-stls --pythonscad ~/bin/pythonscad --output-dir stls
88
+ ```
89
+
90
+ ## Exit Status
91
+
92
+ `0`
93
+ : All requested renders completed successfully, or no designs were found.
94
+
95
+ `2`
96
+ : Command line input, scan directory, or preset JSON was invalid.
97
+
98
+ Any other non-zero status from `pythonscad`
99
+ : At least one render command failed; the PythonSCAD exit code is returned.
@@ -0,0 +1,76 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pythonscad-stl-generator"
7
+ dynamic = ["version"]
8
+ description = "Render PythonSCAD design scripts to STL files, including customizer presets."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [
13
+ { name = "Nomike" },
14
+ ]
15
+ keywords = ["3d", "cad", "openscad", "pythonscad", "stl", "3d-printing"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Manufacturing",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: 3.14",
27
+ "Topic :: Multimedia :: Graphics :: 3D Modeling",
28
+ "Topic :: Utilities",
29
+ ]
30
+ dependencies = [
31
+ "docopt-ng>=0.9,<1",
32
+ ]
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "build>=1.5",
37
+ "pytest>=8",
38
+ "pytest-cov>=7",
39
+ "ruff>=0.15",
40
+ ]
41
+
42
+ [project.scripts]
43
+ generate-pythonscad-stls = "pythonscad_stl_generator.cli:main"
44
+
45
+ [project.urls]
46
+ Homepage = "https://github.com/nomike/pythonscad-stl-generator"
47
+ Repository = "https://github.com/nomike/pythonscad-stl-generator"
48
+ Issues = "https://github.com/nomike/pythonscad-stl-generator/issues"
49
+ Changelog = "https://github.com/nomike/pythonscad-stl-generator/blob/main/CHANGELOG.md"
50
+
51
+ [tool.setuptools]
52
+ package-dir = { "" = "src" }
53
+ include-package-data = true
54
+
55
+ [tool.setuptools.dynamic]
56
+ version = { file = "VERSION.txt" }
57
+
58
+ [tool.setuptools.packages.find]
59
+ where = ["src"]
60
+
61
+ [tool.setuptools.package-data]
62
+ pythonscad_stl_generator = ["py.typed"]
63
+
64
+ [tool.pytest.ini_options]
65
+ addopts = "-ra"
66
+ testpaths = ["tests"]
67
+
68
+ [tool.ruff]
69
+ line-length = 100
70
+ target-version = "py310"
71
+
72
+ [tool.ruff.lint]
73
+ select = ["E", "F", "I", "UP", "B", "SIM"]
74
+
75
+ [tool.ruff.format]
76
+ quote-style = "double"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,10 @@
1
+ """Tools for batch-rendering PythonSCAD designs."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("pythonscad-stl-generator")
7
+ except PackageNotFoundError:
8
+ __version__ = "0.0.0"
9
+
10
+ __all__ = ["__version__"]
@@ -0,0 +1,92 @@
1
+ """Command line interface for PythonSCAD STL generation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import sys
7
+ from pathlib import Path
8
+ from typing import NoReturn
9
+
10
+ from docopt import docopt
11
+
12
+ from . import __version__
13
+ from .discovery import discover_designs
14
+ from .presets import PresetError
15
+ from .render import plan_jobs, run_jobs
16
+
17
+ USAGE = """PythonSCAD STL Generator.
18
+
19
+ Usage:
20
+ generate-pythonscad-stls [--directory=<dir>] [--output-dir=<dir>]
21
+ [--pythonscad=<path>] [--format=<ext>]
22
+ [--force] [--dry-run] [--recursive]
23
+ [-v | --verbose]
24
+ generate-pythonscad-stls -h | --help
25
+ generate-pythonscad-stls --version
26
+
27
+ Options:
28
+ -h --help Show this screen.
29
+ --version Show the version.
30
+ --directory=<dir> Directory to scan for PythonSCAD designs [default: .].
31
+ --output-dir=<dir> Directory to save generated files to [default: output].
32
+ --pythonscad=<path> PythonSCAD executable to run [default: pythonscad].
33
+ --format=<ext> Output file extension/export format [default: stl].
34
+ --force Render even when output files are up to date.
35
+ --dry-run Print commands without executing them.
36
+ --recursive Search for designs recursively below the scan directory.
37
+ -v --verbose Show debug messages.
38
+ """
39
+
40
+
41
+ def main(argv: list[str] | None = None) -> int:
42
+ """Run the CLI and return a process-style exit code."""
43
+ arguments = docopt(USAGE, argv=argv, version=f"generate-pythonscad-stls {__version__}")
44
+ _configure_logging(verbose=bool(arguments["--verbose"]))
45
+
46
+ directory = Path(str(arguments["--directory"])).resolve()
47
+ output_dir = Path(str(arguments["--output-dir"]))
48
+ if not output_dir.is_absolute():
49
+ output_dir = directory / output_dir
50
+
51
+ if not directory.is_dir():
52
+ logging.error("%s is not a directory", directory)
53
+ return 2
54
+
55
+ try:
56
+ designs = discover_designs(directory, recursive=bool(arguments["--recursive"]))
57
+ if not designs:
58
+ logging.info("No PythonSCAD designs found in %s", directory)
59
+ return 0
60
+
61
+ jobs = plan_jobs(
62
+ designs,
63
+ output_dir=output_dir,
64
+ output_format=str(arguments["--format"]),
65
+ pythonscad=str(arguments["--pythonscad"]),
66
+ base_dir=directory,
67
+ )
68
+ except PresetError as error:
69
+ logging.error("%s", error)
70
+ return 2
71
+
72
+ logging.info("Planned %d render job(s) from %d design(s)", len(jobs), len(designs))
73
+ return run_jobs(
74
+ jobs,
75
+ force=bool(arguments["--force"]),
76
+ dry_run=bool(arguments["--dry-run"]),
77
+ )
78
+
79
+
80
+ def _configure_logging(*, verbose: bool) -> None:
81
+ logging.basicConfig(
82
+ level=logging.DEBUG if verbose else logging.INFO,
83
+ format="%(levelname)s: %(message)s",
84
+ )
85
+
86
+
87
+ def _entrypoint() -> NoReturn:
88
+ raise SystemExit(main())
89
+
90
+
91
+ if __name__ == "__main__":
92
+ sys.exit(main())