draftwright 0.6.0a1__cp39-abi3-win_amd64.whl
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.
- draftwright/__init__.py +18 -0
- draftwright/_cli.py +23 -0
- draftwright/_drawing.py +105 -0
- draftwright/_legacy.py +90 -0
- draftwright/_native.pyd +4 -0
- draftwright/builder.py +13 -0
- draftwright-0.6.0a1.dist-info/METADATA +207 -0
- draftwright-0.6.0a1.dist-info/RECORD +14 -0
- draftwright-0.6.0a1.dist-info/WHEEL +4 -0
- draftwright-0.6.0a1.dist-info/entry_points.txt +3 -0
- draftwright-0.6.0a1.dist-info/licenses/LICENSE +661 -0
- draftwright-0.6.0a1.dist-info/licenses/fonts/LICENSE-IBMPlexMono-OFL.txt +93 -0
- draftwright-0.6.0a1.dist-info/licenses/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt +93 -0
- draftwright-0.6.0a1.dist-info/sboms/draftwright-py.cyclonedx.json +4540 -0
draftwright/__init__.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Engineering drawings from STEP, using the Rust engine.
|
|
2
|
+
|
|
3
|
+
``make_drawing`` returns **(svg_path, pdf_path)** in 0.6, replacing 0.4's
|
|
4
|
+
(svg_path, dxf_path). DXF export and the other 0.4 Python classes are unavailable.
|
|
5
|
+
"""
|
|
6
|
+
from ._native import DraftwrightError, __version__
|
|
7
|
+
from ._drawing import make_drawing
|
|
8
|
+
from ._legacy import install as _install, removed as _removed
|
|
9
|
+
|
|
10
|
+
__all__ = ["make_drawing", "DraftwrightError", "__version__"]
|
|
11
|
+
_install()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def __getattr__(name):
|
|
15
|
+
if _removed(name):
|
|
16
|
+
from ._legacy import AttributeMigrationError, message
|
|
17
|
+
raise AttributeMigrationError(message(name))
|
|
18
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
draftwright/_cli.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Console adapters for the Rust implementations."""
|
|
2
|
+
import signal
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
from . import _native
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _run(entry):
|
|
9
|
+
# Python normally defers SIGINT until native code returns. Console commands need
|
|
10
|
+
# the OS default instead: terminate even inside a render or a blocking stdin read.
|
|
11
|
+
previous = signal.signal(signal.SIGINT, signal.SIG_DFL)
|
|
12
|
+
try:
|
|
13
|
+
return entry(sys.argv)
|
|
14
|
+
finally:
|
|
15
|
+
signal.signal(signal.SIGINT, previous)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main():
|
|
19
|
+
return _run(_native.cli)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def mcp():
|
|
23
|
+
return _run(_native.mcp)
|
draftwright/_drawing.py
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""The supported part of the archived make_drawing interface."""
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from tempfile import TemporaryDirectory
|
|
6
|
+
|
|
7
|
+
from . import _native
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _unsupported(name):
|
|
11
|
+
raise TypeError(f"make_drawing keyword {name!r} is not supported in 0.6")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def make_drawing(
|
|
15
|
+
step_file, out=None, title=None, number="DWG-001", tolerance=None,
|
|
16
|
+
drawn_by="", scale=None, page=None, auto_dims=True, detail_view=True,
|
|
17
|
+
pmi=None, assembly=None, material=None, date="", revision="A", company="",
|
|
18
|
+
frame=False, projection=None, zones=False, scale_policy="fallback",
|
|
19
|
+
reproducible=True, framed_recognition=False, text_position="inline",
|
|
20
|
+
text_orientation="aligned", *, projection_symbol=True, source=None,
|
|
21
|
+
approved_by="", document_type="", sheet="", margin_left=None,
|
|
22
|
+
margin_right=None, margin_top=None, margin_bottom=None, title_block_width=None,
|
|
23
|
+
leader_region="auto", annotation_layout="demand-guided",
|
|
24
|
+
):
|
|
25
|
+
"""Draw a STEP path (str/PathLike) or build123d Shape using the Rust CLI engine.
|
|
26
|
+
|
|
27
|
+
Returns **(svg_path, pdf_path)** as strings. In 0.4 the second path was DXF;
|
|
28
|
+
**0.6 writes PDF instead and does not export DXF**. Additional sheets use the
|
|
29
|
+
CLI's usual suffixes. ``out`` is a stem, defaulting to the STEP path without
|
|
30
|
+
its extension, or ``drawing`` in the working directory for a shape.
|
|
31
|
+
|
|
32
|
+
Title fields, numeric scale, ISO page (A4..A0), first/third projection,
|
|
33
|
+
zones, auto_dims and pmi map to the Rust Spec. The renderer always draws a
|
|
34
|
+
frame and projection symbol. PMI defaults to off: None, "off" and "report"
|
|
35
|
+
select inventory without annotations; "annotate" opts in. ISO page names
|
|
36
|
+
accept surrounding whitespace and either case. Other old options accept
|
|
37
|
+
their defaults only; a non-default value raises TypeError naming the
|
|
38
|
+
unsupported keyword. Custom page dimensions
|
|
39
|
+
are likewise unsupported. Rust failures raise DraftwrightError.
|
|
40
|
+
|
|
41
|
+
build123d is imported only for a Shape, exported via its own STEP exporter
|
|
42
|
+
into a temporary directory. It is not a wheel dependency. For a shape,
|
|
43
|
+
``source`` names the original STEP document for PMI; geometry still comes
|
|
44
|
+
from step_file. It also supplies PMI when step_file is a STEP path. An
|
|
45
|
+
unreadable source raises DraftwrightError.
|
|
46
|
+
|
|
47
|
+
The Rust defaults for automatic dimensions, views, scale and layout apply;
|
|
48
|
+
accepting an old option's default does not select the old Python solver.
|
|
49
|
+
Spec documentation: https://github.com/pzfreo/draftwright/blob/main/docs/model.md
|
|
50
|
+
"""
|
|
51
|
+
values = locals()
|
|
52
|
+
for name, default in {
|
|
53
|
+
"detail_view": True, "assembly": None,
|
|
54
|
+
"scale_policy": "fallback", "reproducible": True, "framed_recognition": False,
|
|
55
|
+
"text_position": "inline", "text_orientation": "aligned",
|
|
56
|
+
"projection_symbol": True, "margin_left": None, "margin_right": None,
|
|
57
|
+
"margin_top": None, "margin_bottom": None, "title_block_width": None,
|
|
58
|
+
"leader_region": "auto", "annotation_layout": "demand-guided",
|
|
59
|
+
}.items():
|
|
60
|
+
if values[name] != default:
|
|
61
|
+
_unsupported(name)
|
|
62
|
+
if pmi not in (None, "off", "report", "annotate"):
|
|
63
|
+
_unsupported("pmi")
|
|
64
|
+
if page is not None:
|
|
65
|
+
original_page = page
|
|
66
|
+
page = page.strip().upper() if isinstance(page, str) else page
|
|
67
|
+
if page not in ("A4", "A3", "A2", "A1", "A0"):
|
|
68
|
+
raise TypeError(
|
|
69
|
+
f"make_drawing page value {original_page!r} is not supported in 0.6; "
|
|
70
|
+
"expected an ISO name A4..A0 (case-insensitive) or None"
|
|
71
|
+
)
|
|
72
|
+
fields = {
|
|
73
|
+
name: values[name] for name in (
|
|
74
|
+
"title", "number", "tolerance", "drawn_by", "material", "date", "revision",
|
|
75
|
+
"company", "approved_by", "document_type", "sheet",
|
|
76
|
+
) if values[name] is not None
|
|
77
|
+
}
|
|
78
|
+
spec = {"sheet": {"title": fields, "zones": zones}}
|
|
79
|
+
if not auto_dims:
|
|
80
|
+
spec["dimension_source"] = "authored"
|
|
81
|
+
spec["sheet"].update(centre_lines=False, centre_marks=False)
|
|
82
|
+
# The archived Python API defaults to off, unlike the native CLI's First.
|
|
83
|
+
spec["pmi"] = "first" if pmi == "annotate" else "ignore"
|
|
84
|
+
if page is not None:
|
|
85
|
+
spec["sheet"]["size"] = page
|
|
86
|
+
if projection is not None:
|
|
87
|
+
spec["sheet"]["projection"] = projection
|
|
88
|
+
spec_json = json.dumps(spec)
|
|
89
|
+
output = os.fsdecode(os.fspath(out)) if out is not None else None
|
|
90
|
+
source_path = os.fsdecode(os.fspath(source)) if source is not None else None
|
|
91
|
+
if isinstance(step_file, (str, bytes, os.PathLike)):
|
|
92
|
+
return _native.render(os.fsdecode(os.fspath(step_file)), output, spec_json, scale, source_path)
|
|
93
|
+
|
|
94
|
+
# No CAD-kernel import is paid by path users, importers or console commands.
|
|
95
|
+
from build123d import Shape, export_step
|
|
96
|
+
if not isinstance(step_file, Shape):
|
|
97
|
+
raise TypeError("step_file must be a STEP path or a build123d Shape")
|
|
98
|
+
with TemporaryDirectory(prefix="draftwright-") as temporary:
|
|
99
|
+
step = Path(temporary) / "drawing.step"
|
|
100
|
+
if not export_step(step_file, step):
|
|
101
|
+
raise _native.DraftwrightError("build123d could not export the shape to STEP")
|
|
102
|
+
return _native.render(
|
|
103
|
+
str(step), output if output is not None else "drawing", spec_json, scale,
|
|
104
|
+
source_path,
|
|
105
|
+
)
|
draftwright/_legacy.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Explicit migration errors for the archived Python package's public surface."""
|
|
2
|
+
import importlib.abc
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
# draftwright-python main, src/draftwright/__init__.py::__all__.
|
|
6
|
+
OLD_ALL = frozenset([
|
|
7
|
+
"BuildEvent", "BuildCancelled", "observe_build", "INSPECTION_SCHEMA",
|
|
8
|
+
"INSPECTION_SCHEMA_VERSION", "Drawing", "Document", "DocumentResult",
|
|
9
|
+
"DocumentBuildError", "SoftDeprecationWarning", "FeatureInfo", "FixedInkMeshCache",
|
|
10
|
+
"InspectionUnavailableError", "LeaderRegionPolicy", "PmiExtractionReport", "PmiRecord",
|
|
11
|
+
"PmiSourceEntity", "ReportUnavailableError", "Sheet", "ScaleIncompatibilityError",
|
|
12
|
+
"ScaleCompletenessWarning", "ProjectionGeometryWarning", "ViewPlanIncomplete",
|
|
13
|
+
"ViewConstraints", "ViewSpec", "build_drawing", "choose_scale", "extract_pmi",
|
|
14
|
+
"extract_pmi_report", "inspect_step", "lint_feature_coverage", "make_drawing",
|
|
15
|
+
])
|
|
16
|
+
# Generated once from every .py module and directory in draftwright-python
|
|
17
|
+
# src/draftwright at 6f6a27fea57fb19a9adcdc20257dc0e60a1be309; exclude __init__.py / py.typed.
|
|
18
|
+
OLD_MODULES = frozenset([
|
|
19
|
+
'_build_profile', '_core', '_geometry', '_pmi_datum_geometry',
|
|
20
|
+
'_pmi_linear_geometry', '_pmi_part21', '_pmi_schema', '_pmi_support_blockers',
|
|
21
|
+
'_pmi_topology', '_warnings', 'analysis', 'angular_geometry',
|
|
22
|
+
'annotate', 'annotation_layout_profile', 'annotations', 'audit',
|
|
23
|
+
'auxiliary_layout', 'blend_contract', 'build_once', 'build_options',
|
|
24
|
+
'build_policy', 'builder', 'cli', 'compose',
|
|
25
|
+
'contract_values', 'document', 'document_evidence', 'document_input',
|
|
26
|
+
'drawing', 'drawing_diagnostics', 'drawing_evidence', 'drawing_export',
|
|
27
|
+
'drawing_state', 'drawing_tables', 'evaluation', 'explicit_scale',
|
|
28
|
+
'export', 'family_table', 'feature_identity', 'fits',
|
|
29
|
+
'fixed_ink_cache', 'fonts', 'inspection', 'inspection_contract',
|
|
30
|
+
'intent_drain', 'intent_routing', 'intents', 'layout',
|
|
31
|
+
'layout_safety', 'layout_scheme', 'layout_selection', 'leader_policy',
|
|
32
|
+
'linting', 'location_contract', 'make_drawing', 'measurement_support',
|
|
33
|
+
'model', 'obligations', 'oriented_slot_contract', 'pdf_text',
|
|
34
|
+
'plate_correspondence', 'pmi', 'profile_angles', 'progress',
|
|
35
|
+
'projection', 'recogniser_contract', 'recogniser_policy', 'recogniser_schema',
|
|
36
|
+
'recognition', 'recognition_cache', 'recognition_frame', 'recognition_ownership',
|
|
37
|
+
'registry', 'repair', 'replay_assessment', 'reporting',
|
|
38
|
+
'score', 'section_recess_contract', 'section_scale_recovery', 'sheet',
|
|
39
|
+
'sheet_emit', 'sheet_feature_lines', 'sheet_features', 'sheet_layout_controls',
|
|
40
|
+
'sheet_metadata', 'sheet_object_source', 'sheet_views', 'view_plan',
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def removed(name):
|
|
45
|
+
return name in OLD_ALL and name != "make_drawing"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def message(name):
|
|
49
|
+
return (
|
|
50
|
+
f"{name} was part of the Python draftwright 0.4 API, which 0.6 does not include; "
|
|
51
|
+
"pin draftwright<0.6 to keep using it. The Rust engine is driven by a Spec: "
|
|
52
|
+
"https://github.com/pzfreo/draftwright/blob/main/docs/model.md. "
|
|
53
|
+
"For the supported one-liner use from draftwright import make_drawing."
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# AttributeError gained extra C instance fields in CPython 3.10; its layout
|
|
58
|
+
# conflicts with ImportError's on newer CPython. Use the dual type where legal,
|
|
59
|
+
# otherwise preserve both behaviours with errors selected at the API boundary.
|
|
60
|
+
try:
|
|
61
|
+
class MigrationError(ImportError, AttributeError):
|
|
62
|
+
"""A removed Python 0.4 API on interpreters supporting both bases."""
|
|
63
|
+
except TypeError:
|
|
64
|
+
class MigrationError(Exception):
|
|
65
|
+
"""Common base for migration errors across attribute and import access."""
|
|
66
|
+
|
|
67
|
+
class AttributeMigrationError(MigrationError, AttributeError):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
class ImportMigrationError(MigrationError, ImportError):
|
|
71
|
+
pass
|
|
72
|
+
else:
|
|
73
|
+
AttributeMigrationError = ImportMigrationError = MigrationError
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class _LegacyFinder(importlib.abc.MetaPathFinder):
|
|
77
|
+
def find_spec(self, fullname, path=None, target=None):
|
|
78
|
+
if fullname.startswith("draftwright."):
|
|
79
|
+
relative = fullname[len("draftwright."):]
|
|
80
|
+
if relative.split(".")[0] in OLD_MODULES or removed(relative):
|
|
81
|
+
# Match the message from getattr(package, name) exactly for old
|
|
82
|
+
# public names imported with `from draftwright import name`.
|
|
83
|
+
name = relative if removed(relative) else fullname
|
|
84
|
+
raise ImportMigrationError(message(name))
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def install():
|
|
89
|
+
if not any(isinstance(finder, _LegacyFinder) for finder in sys.meta_path):
|
|
90
|
+
sys.meta_path.append(_LegacyFinder())
|
draftwright/_native.pyd
ADDED
draftwright/builder.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Compatibility import for the supported make_drawing one-liner."""
|
|
2
|
+
from ._drawing import make_drawing
|
|
3
|
+
from ._legacy import AttributeMigrationError, message, removed
|
|
4
|
+
|
|
5
|
+
__all__ = ["make_drawing"]
|
|
6
|
+
# Let importlib resolve removed from-import names through our migration finder.
|
|
7
|
+
__path__ = []
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def __getattr__(name):
|
|
11
|
+
if removed(name):
|
|
12
|
+
raise AttributeMigrationError(message(f"{__name__}.{name}"))
|
|
13
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: draftwright
|
|
3
|
+
Version: 0.6.0a1
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: Environment :: Console
|
|
6
|
+
Classifier: Programming Language :: Rust
|
|
7
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
License-File: fonts/LICENSE-IBMPlexMono-OFL.txt
|
|
10
|
+
License-File: fonts/LICENSE-IBMPlexSansCondensed-OFL.txt
|
|
11
|
+
Summary: Engineering drawings from STEP: Rust CLI and a small Python API.
|
|
12
|
+
License-Expression: AGPL-3.0-only
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
15
|
+
Project-URL: Homepage, https://draftwright.io
|
|
16
|
+
Project-URL: Issues, https://github.com/pzfreo/draftwright/issues
|
|
17
|
+
Project-URL: Releases, https://github.com/pzfreo/draftwright/releases
|
|
18
|
+
Project-URL: Repository, https://github.com/pzfreo/draftwright
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
<img src="docs/images/draftwright-logo.png" alt="draftwright: technical drawings, generated" width="460">
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<a href="https://crates.io/crates/draftwright"><img src="https://img.shields.io/crates/v/draftwright.svg" alt="crates.io"></a>
|
|
26
|
+
<a href="https://github.com/pzfreo/draftwright/actions/workflows/ci.yml"><img src="https://github.com/pzfreo/draftwright/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
27
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/licence-AGPL--3.0-blue.svg" alt="Licence: AGPL-3.0"></a>
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
**Draftwright turns a 3D STEP file into a complete, dimensioned engineering drawing.** It
|
|
31
|
+
recognises the part's features (holes, patterns, slots, pockets, turned steps, threads),
|
|
32
|
+
decides what to dimension and where, reads tolerances and GD&T from AP242 files, lays out the
|
|
33
|
+
views on a standard sheet, and tells you anything it could not state. One Rust binary, one
|
|
34
|
+
command, one repeatable drawing.
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<img src="docs/images/hero-nist-ctc-03.png" alt="An A3 drawing of NIST test part CTC-03, a sheet-metal bracket, with plan and elevation views, an isometric view, a hole table, datums and GD&T frames" width="100%">
|
|
38
|
+
<br>
|
|
39
|
+
<sub>NIST CTC-03, drawn from its AP242 STEP file with only the title set. Every view, dimension,
|
|
40
|
+
hole-table entry, datum and GD&T frame is placed automatically.</sub>
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## Python
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
pip install draftwright
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from draftwright import make_drawing
|
|
52
|
+
svg_path, pdf_path = make_drawing("part.step", out="drawing", title="Bracket")
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
STEP paths and build123d shapes are supported (install build123d separately for
|
|
56
|
+
shapes). The wheel also installs `draftwright` and `draftwright-mcp` on PATH.
|
|
57
|
+
|
|
58
|
+
**Changed from 0.4:** `make_drawing` returns `(svg_path, pdf_path)` as strings;
|
|
59
|
+
the second file is now **PDF, not DXF**. DXF export and the other old Python
|
|
60
|
+
classes/functions are unavailable. Unsupported options with non-default values
|
|
61
|
+
raise `TypeError`; old names/imports give migration guidance. Pin
|
|
62
|
+
`draftwright<0.6` to keep the old API. The Rust engine uses a [Spec](docs/model.md).
|
|
63
|
+
See the [Python API, keyword mapping and interrupt behaviour](docs/python.md).
|
|
64
|
+
|
|
65
|
+
## Ways to use it
|
|
66
|
+
|
|
67
|
+
- **In the browser:** [draftwright.io](https://draftwright.io). Open a STEP file, see the drawing,
|
|
68
|
+
move and edit dimensions, add requirements, and export PDF or STEP. The whole engine runs in
|
|
69
|
+
the browser as WebAssembly.
|
|
70
|
+
- **With an AI agent:** the hosted MCP server at `mcp.draftwright.io` lets Claude, ChatGPT and
|
|
71
|
+
other MCP clients open parts, read drawings and make changes. See [docs/mcp.md](docs/mcp.md).
|
|
72
|
+
- **On the command line:** `draftwright render part.step -o part` (below).
|
|
73
|
+
- **From Rust:** the `draftwright` crate's five stateless operations (`analyse`, `plan`, `edit`,
|
|
74
|
+
`render`, `review`). See [docs/model.md](docs/model.md).
|
|
75
|
+
|
|
76
|
+
## Install
|
|
77
|
+
|
|
78
|
+
With a recent stable Rust toolchain:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
cargo install draftwright # installs draftwright and draftwright-mcp
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Without Rust, download a ready-built archive for macOS (Apple silicon), Linux x86_64 or
|
|
85
|
+
Windows x86_64 from the [latest release](https://github.com/pzfreo/draftwright/releases/latest).
|
|
86
|
+
|
|
87
|
+
From 0.6.0, the same two commands install from PyPI without Rust:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
uv tool install draftwright # or: pipx install draftwright
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
PyPI releases before 0.6 use the archived
|
|
94
|
+
[Python implementation](https://github.com/pzfreo/draftwright-python). Starting with
|
|
95
|
+
0.6, this Rust project provides both commands and the small
|
|
96
|
+
[Python API](docs/python.md). Pin `draftwright<0.6` to keep the full old API.
|
|
97
|
+
The old command form `draftwright part.step [options]` still renders a drawing;
|
|
98
|
+
see [CLI migration](docs/cli-migration.md) for the options it keeps.
|
|
99
|
+
|
|
100
|
+
Shell completion: `draftwright completions zsh` (or `bash`, `fish`, `powershell`, `elvish`)
|
|
101
|
+
prints a completion script; see [docs/engine.md](docs/engine.md#using-it) for where to put it.
|
|
102
|
+
|
|
103
|
+
## Quick start
|
|
104
|
+
|
|
105
|
+
```sh
|
|
106
|
+
draftwright render part.step -o part # part.svg and part.pdf
|
|
107
|
+
draftwright render part.step -o part --shaded --below # shaded views from above and below
|
|
108
|
+
draftwright render part.step -o part --formats pdf,png # choose formats
|
|
109
|
+
draftwright review part.step # the drawing as text, with what it could not state
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
A drawing is adjusted with a **Spec**: a small JSON file naming only what you want different
|
|
113
|
+
from the automatic drawing. For example, to fill in the title block:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{ "sheet": { "title": { "title": "Mounting plate", "number": "MP-001" } } }
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
draftwright render part.step --spec part.drawing.json -o part
|
|
121
|
+
draftwright spec part.pdf # every drawing carries its Spec; this reads it back
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
More:
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
draftwright diff old.step new.step --spec part.drawing.json -o changes # carry a drawing to a new revision
|
|
128
|
+
draftwright pack assembly.step -o pack # drawings and parts list for an assembly
|
|
129
|
+
draftwright --help
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## What it does
|
|
133
|
+
|
|
134
|
+
- **Recognises features** from the B-rep with [quiddity](https://github.com/pzfreo/quiddity):
|
|
135
|
+
holes and counterbores, hole patterns, slots, pockets and recesses, turned steps, grooves,
|
|
136
|
+
chamfers and fillets, threads. Anything it cannot read is reported, not guessed.
|
|
137
|
+
- **Dimensions completely.** Each feature family has its own rules. Dimensions are placed
|
|
138
|
+
without collisions, and every omission is reported with a reason.
|
|
139
|
+
- **Reads PMI.** Tolerances, fits, datums, GD&T frames, threads and surface finish come from
|
|
140
|
+
AP242 semantic PMI. [Specify](https://github.com/pzfreo/specify-core) writes requirements back
|
|
141
|
+
into STEP.
|
|
142
|
+
- **Lays out sheets.** Views, sections, detail views and hole tables go on ISO 5457 sheets with
|
|
143
|
+
an ISO 7200 title block. Sheet size and scale are chosen automatically, using more sheets when
|
|
144
|
+
needed.
|
|
145
|
+
- **Is deterministic.** The same inputs give the same bytes. SVG and PDF carry real, searchable
|
|
146
|
+
text and embed the Spec that made them.
|
|
147
|
+
- **Handles assemblies.** `pack` draws each made part once and writes an ISO 7573 parts list,
|
|
148
|
+
item numbers and a CSV/JSON bill of materials.
|
|
149
|
+
- **Tracks revisions.** `diff` carries a drawing's edits to a new revision of the part and marks
|
|
150
|
+
up what changed.
|
|
151
|
+
|
|
152
|
+
## Examples
|
|
153
|
+
|
|
154
|
+
Drawings of NIST test parts, FreeCAD and build123d parts, and assemblies, rebuilt by CI on every
|
|
155
|
+
release, are in **[pzfreo/dw-examples](https://github.com/pzfreo/dw-examples)**.
|
|
156
|
+
|
|
157
|
+
<table>
|
|
158
|
+
<tr>
|
|
159
|
+
<td><a href="https://github.com/pzfreo/dw-examples/tree/main/drawings/t2c-circular-flange"><img src="docs/images/example-t2c-circular-flange.png" alt="Circular flange drawing"></a></td>
|
|
160
|
+
<td><a href="https://github.com/pzfreo/dw-examples/tree/main/drawings/nema17-mount-bracket"><img src="docs/images/example-nema17-mount-bracket.png" alt="NEMA 17 mount bracket drawing"></a></td>
|
|
161
|
+
<td><a href="https://github.com/pzfreo/dw-examples/tree/main/drawings/nist-ftc-06"><img src="docs/images/example-nist-ftc-06.png" alt="NIST FTC-06 drawing with hole tables and a section"></a></td>
|
|
162
|
+
</tr>
|
|
163
|
+
<tr>
|
|
164
|
+
<td align="center"><sub>Flange: bolt circle callout</sub></td>
|
|
165
|
+
<td align="center"><sub>Bracket: slots, chamfers, fillets</sub></td>
|
|
166
|
+
<td align="center"><sub>NIST FTC-06: hole tables, GD&T, section</sub></td>
|
|
167
|
+
</tr>
|
|
168
|
+
</table>
|
|
169
|
+
|
|
170
|
+
## Documentation
|
|
171
|
+
|
|
172
|
+
- [Engine guide](docs/engine.md): building, the full command line, what is and isn't supported,
|
|
173
|
+
known limitations, checking a change
|
|
174
|
+
- [Model and Spec reference](docs/model.md): the Analysis, Spec and Plan, and every setting
|
|
175
|
+
- [Python API and migration](docs/python.md)
|
|
176
|
+
- [MCP and agents](docs/mcp.md)
|
|
177
|
+
- [Browser / WASM package](docs/wasm.md)
|
|
178
|
+
- [Thread callouts](docs/thread-callouts.md) · [Bills of materials](docs/bom.md) ·
|
|
179
|
+
[Finding impact](docs/finding-impact.md)
|
|
180
|
+
- [Changelog](CHANGELOG.md)
|
|
181
|
+
|
|
182
|
+
## Status
|
|
183
|
+
|
|
184
|
+
Draftwright is young and moving quickly: 0.2.x releases come every few days. Drawings report what
|
|
185
|
+
they do not state, but dense parts can still be less tidy than a hand-made drawing; see
|
|
186
|
+
[Known limitations](docs/engine.md#known-limitations). Issues and example parts are welcome.
|
|
187
|
+
|
|
188
|
+
## Related projects
|
|
189
|
+
|
|
190
|
+
- [quiddity](https://github.com/pzfreo/quiddity): feature recognition from STEP B-rep, and the
|
|
191
|
+
haecceity geometry kernel Draftwright is built on.
|
|
192
|
+
- [Specify](https://github.com/pzfreo/specify-core): writes requirements (tolerances, fits, GD&T,
|
|
193
|
+
BOM data) into STEP as AP242 PMI. It is the Specify view at
|
|
194
|
+
[draftwright.io/specify](https://draftwright.io/specify).
|
|
195
|
+
- [dw-examples](https://github.com/pzfreo/dw-examples): the example drawings.
|
|
196
|
+
- [draftwright-python](https://github.com/pzfreo/draftwright-python): the original Python
|
|
197
|
+
implementation, no longer developed.
|
|
198
|
+
|
|
199
|
+
## Licence and contributing
|
|
200
|
+
|
|
201
|
+
Draftwright is licensed under the [GNU AGPL v3.0](LICENSE), and is also available under
|
|
202
|
+
separate commercial terms; contact paul@draftwright.io. quiddity and haecceity are Apache-2.0.
|
|
203
|
+
The bundled IBM Plex fonts are under the SIL Open Font License 1.1.
|
|
204
|
+
|
|
205
|
+
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md); pull requests need the
|
|
206
|
+
[Contributor License Agreement](CLA.md).
|
|
207
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
draftwright/__init__.py,sha256=Ajr6jqiXppSm_bUX03Mj8o5iz67WR00y1JkclIHnVcA,698
|
|
2
|
+
draftwright/_cli.py,sha256=E3lH3eYc5zYGNNXY7uz1_bXV-oa6UnUofN3N6AQCpxE,560
|
|
3
|
+
draftwright/_drawing.py,sha256=lRmBMd2Vaoku2DVhDmMkyvbXbaMaXgPilcAkeVs5oTk,5386
|
|
4
|
+
draftwright/_legacy.py,sha256=O1YRWUdln2ba8oRDypO_6rhMLS4ZXvPTvN7Bl2p-j-w,4636
|
|
5
|
+
draftwright/_native.pyd,sha256=yHX03j1VALYHVUoo1nwUVB43ip0o8FAB1ybADn9KJ6k,45012992
|
|
6
|
+
draftwright/builder.py,sha256=nL8sRxopGuW-w7UP7UsX3Hilq4MG0kI5McwLS2VGzB0,493
|
|
7
|
+
draftwright-0.6.0a1.dist-info/METADATA,sha256=ljHdLV--pOHwYmvpysXpf1nrlBrBUigVfpNCWnBmhJY,10097
|
|
8
|
+
draftwright-0.6.0a1.dist-info/WHEEL,sha256=xw8F9xBWUOgm5ym2S9tihj_bLJOb723bjhA0kdANo2I,95
|
|
9
|
+
draftwright-0.6.0a1.dist-info/entry_points.txt,sha256=dzqc5DyIfdNhS_Vom-s-iutjhNs5IbiL1y6J_svAMV8,89
|
|
10
|
+
draftwright-0.6.0a1.dist-info/licenses/LICENSE,sha256=4O7bphXVzRuYavtsWzpLGuM3E-fp3HTRna7F4yIfnS4,35184
|
|
11
|
+
draftwright-0.6.0a1.dist-info/licenses/fonts/LICENSE-IBMPlexMono-OFL.txt,sha256=fmsoGO29j2oBroBkHMjxalEIDQj7TlMr46C290rbB9o,4456
|
|
12
|
+
draftwright-0.6.0a1.dist-info/licenses/fonts/LICENSE-IBMPlexSansCondensed-OFL.txt,sha256=fmsoGO29j2oBroBkHMjxalEIDQj7TlMr46C290rbB9o,4456
|
|
13
|
+
draftwright-0.6.0a1.dist-info/sboms/draftwright-py.cyclonedx.json,sha256=cNcboJ4KvfeQSBJNpviIyiDmVOz9OFqlV5sGYYcRggk,141032
|
|
14
|
+
draftwright-0.6.0a1.dist-info/RECORD,,
|