swdesigntables 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.
- swdesigntables-0.1.0/.github/workflows/release.yml +61 -0
- swdesigntables-0.1.0/.github/workflows/test.yml +35 -0
- swdesigntables-0.1.0/.gitignore +18 -0
- swdesigntables-0.1.0/CHANGELOG.md +52 -0
- swdesigntables-0.1.0/LICENSE +21 -0
- swdesigntables-0.1.0/PKG-INFO +334 -0
- swdesigntables-0.1.0/README.md +303 -0
- swdesigntables-0.1.0/pyproject.toml +66 -0
- swdesigntables-0.1.0/src/swdesigntables/__init__.py +172 -0
- swdesigntables-0.1.0/src/swdesigntables/columns.py +272 -0
- swdesigntables-0.1.0/src/swdesigntables/errors.py +67 -0
- swdesigntables-0.1.0/src/swdesigntables/parameters.py +401 -0
- swdesigntables-0.1.0/src/swdesigntables/py.typed +0 -0
- swdesigntables-0.1.0/src/swdesigntables/table.py +368 -0
- swdesigntables-0.1.0/src/swdesigntables/template.py +122 -0
- swdesigntables-0.1.0/src/swdesigntables/validation.py +515 -0
- swdesigntables-0.1.0/src/swdesigntables/values.py +160 -0
- swdesigntables-0.1.0/src/swdesigntables/vocabulary.py +51 -0
- swdesigntables-0.1.0/src/swdesigntables/writer.py +130 -0
- swdesigntables-0.1.0/tests/conftest.py +65 -0
- swdesigntables-0.1.0/tests/test_columns.py +139 -0
- swdesigntables-0.1.0/tests/test_determinism.py +35 -0
- swdesigntables-0.1.0/tests/test_examples.py +177 -0
- swdesigntables-0.1.0/tests/test_sheets.py +52 -0
- swdesigntables-0.1.0/tests/test_table_model.py +90 -0
- swdesigntables-0.1.0/tests/test_template.py +97 -0
- swdesigntables-0.1.0/tests/test_validation.py +259 -0
- swdesigntables-0.1.0/tests/test_values.py +70 -0
- swdesigntables-0.1.0/tests/test_writer.py +182 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI when a v* tag is pushed, using Trusted Publishing.
|
|
4
|
+
# No API token is stored anywhere: PyPI verifies the workflow's OIDC identity.
|
|
5
|
+
#
|
|
6
|
+
# One-time setup on PyPI (Publishing -> Add a new pending publisher):
|
|
7
|
+
# owner/repository: ivanperezdesigner/swdesigntables
|
|
8
|
+
# workflow: release.yml
|
|
9
|
+
# environment: pypi
|
|
10
|
+
# and create the `pypi` environment under Settings -> Environments here.
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
tags: ["v*"]
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.12"
|
|
26
|
+
|
|
27
|
+
- name: Install build tooling
|
|
28
|
+
run: python -m pip install --upgrade pip build twine
|
|
29
|
+
|
|
30
|
+
- name: Check the tag matches __version__
|
|
31
|
+
# Publishing v0.2.0 from a 0.1.0 source is the classic own goal.
|
|
32
|
+
run: |
|
|
33
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
34
|
+
VERSION=$(python -c "import re,pathlib; print(re.search(r'__version__ = \"([^\"]+)\"', pathlib.Path('src/swdesigntables/__init__.py').read_text()).group(1))")
|
|
35
|
+
echo "tag=$TAG source=$VERSION"
|
|
36
|
+
test "$TAG" = "$VERSION"
|
|
37
|
+
|
|
38
|
+
- name: Build
|
|
39
|
+
run: python -m build
|
|
40
|
+
|
|
41
|
+
- name: Check metadata
|
|
42
|
+
run: python -m twine check dist/*
|
|
43
|
+
|
|
44
|
+
- uses: actions/upload-artifact@v4
|
|
45
|
+
with:
|
|
46
|
+
name: dist
|
|
47
|
+
path: dist/
|
|
48
|
+
|
|
49
|
+
publish:
|
|
50
|
+
needs: build
|
|
51
|
+
runs-on: ubuntu-latest
|
|
52
|
+
environment: pypi
|
|
53
|
+
permissions:
|
|
54
|
+
id-token: write
|
|
55
|
+
steps:
|
|
56
|
+
- uses: actions/download-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: dist
|
|
59
|
+
path: dist/
|
|
60
|
+
|
|
61
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ${{ matrix.os }}
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
os: [ubuntu-latest, windows-latest]
|
|
16
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
|
|
25
|
+
- name: Install
|
|
26
|
+
run: python -m pip install --upgrade pip && python -m pip install -e ".[dev]"
|
|
27
|
+
|
|
28
|
+
- name: Lint
|
|
29
|
+
run: python -m ruff check .
|
|
30
|
+
|
|
31
|
+
- name: Type check
|
|
32
|
+
run: python -m mypy
|
|
33
|
+
|
|
34
|
+
- name: Test
|
|
35
|
+
run: python -m pytest -q
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-09-11
|
|
11
|
+
|
|
12
|
+
First release.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- `DesignTable`: title cell, headers from B2, the `Family` defined name, and
|
|
17
|
+
configuration rows addressed by column identity rather than column number.
|
|
18
|
+
- A parameter catalogue with typed factories for `dimension`, `global_variable`,
|
|
19
|
+
`state`, `prop`, `description`, `parent`, `display_state`, `component_config`,
|
|
20
|
+
`component_state`, `component_visibility`, `component_fixed`,
|
|
21
|
+
`component_display_state`, `comment`, `color`, `part_number`, `user_notes`,
|
|
22
|
+
`never_expand_in_bom`, `suppress_new_features`, `suppress_new_components`,
|
|
23
|
+
`sw_property` and `tolerance`.
|
|
24
|
+
- A verification `Status` on every parameter, and an `unverified-parameter`
|
|
25
|
+
warning for anything not confirmed against a real model.
|
|
26
|
+
- `register_parameter()` and `raw()` so no header is out of reach.
|
|
27
|
+
- `parse_header()`, which turns an existing header string into its typed column,
|
|
28
|
+
for migrating scripts that already hold a list of header strings.
|
|
29
|
+
- `TableTemplate` and `blank_table()` for reusable bases and empty skeletons.
|
|
30
|
+
- Value types `State`, `ComponentState`, `YesNo` and `Expression`, with
|
|
31
|
+
`StateFormat.NUMERIC` for tables that spell suppression `1`/`0`.
|
|
32
|
+
- Validation with stable issue codes, three levels of strictness, and per-code
|
|
33
|
+
suppression.
|
|
34
|
+
- Extra sheets, optionally hidden, plus extra workbook defined names. `_SWX`,
|
|
35
|
+
`Family` and `_SWX_0` are reserved.
|
|
36
|
+
- Deterministic output: fixed document timestamps, so a regenerated table only
|
|
37
|
+
differs in git when it actually changed.
|
|
38
|
+
|
|
39
|
+
### Known limitations
|
|
40
|
+
|
|
41
|
+
- Roughly half the catalogue is marked `DOCUMENTED` rather than `VERIFIED`: the
|
|
42
|
+
syntax comes from documentation but has not been watched working in
|
|
43
|
+
SOLIDWORKS. See the README for the Auto-create recipe that confirms one.
|
|
44
|
+
- Sheet metal parameters (`$SM-…`) are not shipped, because no reliable source
|
|
45
|
+
confirmed their syntax. Use `raw()` or `register_parameter()`.
|
|
46
|
+
- The spelling of `$USER_NOTES` and `$NEVER_EXPAND_IN_BOM` is uncertain; sources
|
|
47
|
+
disagree on hyphens versus underscores. Both are single constants in
|
|
48
|
+
`Vocabulary`.
|
|
49
|
+
- Write only. No reading of existing tables, no COM integration, no CLI.
|
|
50
|
+
|
|
51
|
+
[Unreleased]: https://github.com/ivanperezdesigner/swdesigntables/compare/v0.1.0...HEAD
|
|
52
|
+
[0.1.0]: https://github.com/ivanperezdesigner/swdesigntables/releases/tag/v0.1.0
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ivan Perez
|
|
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,334 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: swdesigntables
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Build SOLIDWORKS design tables from Python, with typed headers and validation.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ivanperezdesigner/swdesigntables
|
|
6
|
+
Project-URL: Issues, https://github.com/ivanperezdesigner/swdesigntables/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/ivanperezdesigner/swdesigntables/blob/main/CHANGELOG.md
|
|
8
|
+
Author: Ivan Perez
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: cad,configurations,design table,openpyxl,solidworks,xlsx
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Manufacturing
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: openpyxl<4,>=3.1
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
25
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
28
|
+
Requires-Dist: twine>=5; extra == 'dev'
|
|
29
|
+
Requires-Dist: types-openpyxl; extra == 'dev'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# swdesigntables
|
|
33
|
+
|
|
34
|
+
Build SOLIDWORKS design tables from Python, with typed headers instead of
|
|
35
|
+
hand-typed strings.
|
|
36
|
+
|
|
37
|
+
A design table is an Excel sheet embedded in a SOLIDWORKS model: each row makes
|
|
38
|
+
a configuration, each column drives a parameter. The format has a handful of
|
|
39
|
+
load-bearing details that are easy to get wrong and that fail *silently* — the
|
|
40
|
+
table inserts, nothing changes, and you go looking at the model. This package
|
|
41
|
+
writes those details for you and warns about the rest.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install swdesigntables
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Only dependency: `openpyxl`. Pure Python, no SOLIDWORKS install needed to
|
|
48
|
+
generate a file.
|
|
49
|
+
|
|
50
|
+
## Quickstart
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import swdesigntables as sw
|
|
54
|
+
|
|
55
|
+
length = sw.dimension("Length", "Boss-Extrude1")
|
|
56
|
+
holes = sw.state("HolePattern")
|
|
57
|
+
material = sw.prop("Material")
|
|
58
|
+
|
|
59
|
+
table = sw.DesignTable("BRK-MASTER", [length, holes, material])
|
|
60
|
+
table.add_configuration(
|
|
61
|
+
"BRK-025",
|
|
62
|
+
{length: 25.0, holes: sw.SUPPRESSED, material: "6061-T6"},
|
|
63
|
+
description="Short bracket",
|
|
64
|
+
)
|
|
65
|
+
table.add_configuration(
|
|
66
|
+
"BRK-040",
|
|
67
|
+
{length: 40.0, holes: sw.UNSUPPRESSED, material: "6061-T6"},
|
|
68
|
+
description="Long bracket",
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
table.save("brk_master_dt.xlsx")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Insert the result with **Insert → Tables → Design Table → From file**.
|
|
75
|
+
|
|
76
|
+
## What it gets right so you do not have to
|
|
77
|
+
|
|
78
|
+
| Detail | Why it matters |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `Design Table for: <model>` in A1 | The title cell SOLIDWORKS expects |
|
|
81
|
+
| Headers start in **B2**, A2 stays empty | Writing from A2 shifts every value one column left |
|
|
82
|
+
| Workbook-level defined name `Family` → `Sheet1!$A$2` | Without it SOLIDWORKS cannot find the table at all |
|
|
83
|
+
| Equation values written as literal text | `cell = "=W/2"` becomes an Excel *formula* with no cached result, and SOLIDWORKS reads an empty parameter |
|
|
84
|
+
| Fixed document timestamps | Two identical runs produce identical bytes, so git shows a change only when the table really changed |
|
|
85
|
+
| Numeric-looking strings stay strings | A part number of `0012` does not come back as `12` |
|
|
86
|
+
|
|
87
|
+
## Values are addressed by identity, never by column number
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
length = table.add_column(sw.dimension("Length", "Boss-Extrude1"))
|
|
91
|
+
table.add_configuration("A", {length: 25.0})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
You cannot pass a positional row. That is deliberate: mixing a
|
|
95
|
+
header-to-index map with literal column numbers is how a table silently starts
|
|
96
|
+
writing the wrong values after someone inserts a column in the middle.
|
|
97
|
+
|
|
98
|
+
Supplying a value for a column that was never declared is always an error, so
|
|
99
|
+
a typo loses nothing quietly.
|
|
100
|
+
|
|
101
|
+
## The parameter catalogue
|
|
102
|
+
|
|
103
|
+
Every parameter carries a **verification status**, readable at runtime via
|
|
104
|
+
`column.status` and listed by `sw.list_parameters()`.
|
|
105
|
+
|
|
106
|
+
- **`VERIFIED`** — confirmed against real design table files.
|
|
107
|
+
- **`DOCUMENTED`** — described by SOLIDWORKS documentation, not confirmed here
|
|
108
|
+
against a live model. Using one emits an `unverified-parameter` warning.
|
|
109
|
+
- **`UNVERIFIED`** — registered at runtime by you, or otherwise unconfirmed.
|
|
110
|
+
|
|
111
|
+
This distinction is not decoration. Half of the catalogue below has not been
|
|
112
|
+
watched working in SOLIDWORKS by the author, and saying so is more useful than
|
|
113
|
+
implying a certainty that is not there.
|
|
114
|
+
|
|
115
|
+
### Verified
|
|
116
|
+
|
|
117
|
+
| Factory | Header | Values |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| `dimension("Length", "Boss-Extrude1")` | `Length@Boss-Extrude1` | number |
|
|
120
|
+
| `global_variable("width")` | `$VALUE@width@Equations` | number or `Expression` |
|
|
121
|
+
| `state("Draft2")` | `$STATE@Draft2` | `State.SUPPRESSED` / `State.UNSUPPRESSED` |
|
|
122
|
+
| `prop("Material")` | `$PRP@Material` | text or number |
|
|
123
|
+
| `component_config("Arm", 1)` | `$CONFIGURATION@Arm<1>` | configuration name |
|
|
124
|
+
| `description()` | `$DESCRIPTION` | text |
|
|
125
|
+
| `parent()` | `$PARENT` | configuration name |
|
|
126
|
+
| `display_state()` | `$DISPLAYSTATE` | name |
|
|
127
|
+
|
|
128
|
+
### Documented, not verified here
|
|
129
|
+
|
|
130
|
+
| Factory | Header | Values |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `comment()` | `$COMMENT` | text; SOLIDWORKS ignores it |
|
|
133
|
+
| `color()` | `$COLOR` | 32-bit RGB integer |
|
|
134
|
+
| `part_number()` | `$PARTNUMBER` | text |
|
|
135
|
+
| `user_notes()` | `$USER_NOTES` | text |
|
|
136
|
+
| `never_expand_in_bom()` | `$NEVER_EXPAND_IN_BOM` | `YesNo` |
|
|
137
|
+
| `tolerance("D1", "Sketch1")` | `$TOLERANCE@D1@Sketch1` | tolerance spec |
|
|
138
|
+
| `component_state("Screw", 2)` | `$STATE@Screw<2>` | `ComponentState` (`S`/`R`) |
|
|
139
|
+
| `component_visibility("Screw", 2)` | `$SHOW@Screw<2>` | `YesNo` |
|
|
140
|
+
| `component_fixed("Screw", 2)` | `$FIXED@Screw<2>` | `YesNo` |
|
|
141
|
+
| `component_display_state("Screw", 2)` | `$DISPLAYSTATE@Screw<2>` | name |
|
|
142
|
+
| `suppress_new_features()` | `$SUPPRESS NEW FEATURES` | `YesNo` |
|
|
143
|
+
| `suppress_new_components()` | `$SUPPRESS NEW COMPONENTS` | `YesNo` |
|
|
144
|
+
| `sw_property("Mass")` | `$SW-Mass` | read-only |
|
|
145
|
+
|
|
146
|
+
Two spellings are genuinely uncertain because sources disagree on punctuation:
|
|
147
|
+
`$USER_NOTES` vs `$USERNOTES`, and `$NEVER_EXPAND_IN_BOM` vs
|
|
148
|
+
`$NEVER-EXPAND-IN-BOM`. Header syntax is case insensitive in SOLIDWORKS, but
|
|
149
|
+
that does not extend to hyphens and underscores. Both live as single constants
|
|
150
|
+
in `Vocabulary`, so correcting one is a one-line change.
|
|
151
|
+
|
|
152
|
+
**Sheet metal (`$SM-…`) is deliberately absent.** No reliable source confirmed
|
|
153
|
+
its syntax, and shipping an invented factory is worse than shipping none. Use
|
|
154
|
+
`raw()` or `register_parameter()`.
|
|
155
|
+
|
|
156
|
+
### Confirming a parameter yourself
|
|
157
|
+
|
|
158
|
+
The syntax is not worth guessing at. On a **copy** of the model:
|
|
159
|
+
|
|
160
|
+
1. **Insert → Tables → Design Table → Auto-create**
|
|
161
|
+
2. SOLIDWORKS opens an embedded sheet with the header row it proposes
|
|
162
|
+
3. Copy that row, close without saving, delete the copy
|
|
163
|
+
|
|
164
|
+
A minute of checking beats an afternoon of columns the model ignores.
|
|
165
|
+
|
|
166
|
+
### Nothing is out of reach
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
sw.raw("$WHATEVER@Thing<3>") # any header at all, unchecked
|
|
170
|
+
|
|
171
|
+
sw.register_parameter( # a new typed factory, at runtime
|
|
172
|
+
"sheet_metal_thickness",
|
|
173
|
+
template="$SM-THICKNESS",
|
|
174
|
+
summary="Sheet metal thickness.",
|
|
175
|
+
value_kind=sw.ValueKind.NUMBER,
|
|
176
|
+
)
|
|
177
|
+
sw.column("sheet_metal_thickness")
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Reusable bases
|
|
181
|
+
|
|
182
|
+
`TableTemplate` holds everything that does not change row to row — model, output
|
|
183
|
+
directory, file name, columns, naming rule — so every script in a project starts
|
|
184
|
+
from the same base.
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from pathlib import Path
|
|
188
|
+
import swdesigntables as sw
|
|
189
|
+
|
|
190
|
+
BRACKET = sw.TableTemplate(
|
|
191
|
+
model_name="BRK-MASTER",
|
|
192
|
+
output_dir=Path("tables"),
|
|
193
|
+
file_name="brk_master_dt.xlsx",
|
|
194
|
+
columns=(length, width, sw.description()),
|
|
195
|
+
config_name=lambda width, length: f"BRK-{width:03d}-{length:03d}",
|
|
196
|
+
round_floats=3,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
table = BRACKET.new_table()
|
|
200
|
+
table.add_configuration(BRACKET.name_for(width=25, length=40), {...})
|
|
201
|
+
table.save() # goes to tables/brk_master_dt.xlsx
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
It is frozen; `BRACKET.replace(model_name="BRK-HEAVY")` gives you a variant
|
|
205
|
+
without disturbing the original.
|
|
206
|
+
|
|
207
|
+
To start from an empty but valid file:
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
sw.blank_table("BRK-MASTER", [length, width], path="skeleton.xlsx")
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
That is also the cheapest way to find out whether SOLIDWORKS accepts a set of
|
|
214
|
+
headers: generate the skeleton, insert it with **From file**, and see what it
|
|
215
|
+
says before writing a generator around it.
|
|
216
|
+
|
|
217
|
+
## Suppression: `S`/`U` or `1`/`0`
|
|
218
|
+
|
|
219
|
+
Documentation describes `S` and `U`. Working tables in the wild use `1` and `0`.
|
|
220
|
+
Both are supported and neither is silently rewritten:
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
sw.DesignTable(..., state_format=sw.StateFormat.NUMERIC) # writes 1 / 0
|
|
224
|
+
sw.State.from_legacy_int(1) # -> State.SUPPRESSED
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Component suppression is a different vocabulary — `ComponentState` is `S`/`R`,
|
|
228
|
+
where `R` is Resolved — and mixing them up is caught.
|
|
229
|
+
|
|
230
|
+
## Migrating a script that already has header strings
|
|
231
|
+
|
|
232
|
+
`parse_header` turns an existing header string into the typed column that
|
|
233
|
+
renders it, so a list you already have keeps working:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
table = sw.DesignTable(
|
|
237
|
+
"Extrusion Profile",
|
|
238
|
+
columns=[sw.parse_header(h) for h in HEADERS],
|
|
239
|
+
state_format=sw.StateFormat.NUMERIC,
|
|
240
|
+
)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Anything unrecognized becomes a `raw()` column rather than an error.
|
|
244
|
+
|
|
245
|
+
## Validation
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
report = table.validate()
|
|
249
|
+
for issue in report.issues:
|
|
250
|
+
print(issue)
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Issue codes are stable across releases; message wording is not, so match on the
|
|
254
|
+
code. Errors stop the write, warnings do not.
|
|
255
|
+
|
|
256
|
+
A selection of what is caught: duplicate columns and configurations,
|
|
257
|
+
configuration names containing `/ \ : * ? " < > |`, values for undeclared
|
|
258
|
+
columns, `$PARENT` cycles and children placed before their parent, the reserved
|
|
259
|
+
`_SWX` sheet name, a state letter in a numeric column, and
|
|
260
|
+
`equations-dimension-conflict` — driving both a dimension and a global variable
|
|
261
|
+
of the same name, which usually means someone expected the dimension column to
|
|
262
|
+
win an argument it cannot win.
|
|
263
|
+
|
|
264
|
+
Three levels of strictness:
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
sw.DesignTable(...) # errors raise, warnings warn
|
|
268
|
+
sw.DesignTable(..., strict=False) # everything degrades to a warning
|
|
269
|
+
sw.DesignTable(..., ignore=("float-precision",)) # silence one code
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
In CI, promote warnings so they cannot rot:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
python -W error::swdesigntables.errors.DesignTableWarning build_tables.py
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### What validation cannot do
|
|
279
|
+
|
|
280
|
+
Without a live model there is nothing to check names against. A misspelled
|
|
281
|
+
feature name still produces a column SOLIDWORKS silently ignores. This package
|
|
282
|
+
only catches problems of *shape* — stray whitespace, an embedded `@`, a value of
|
|
283
|
+
the wrong kind. Claiming more is how people learn to stop reading warnings.
|
|
284
|
+
|
|
285
|
+
## Extra sheets, and why `_SWX` is refused
|
|
286
|
+
|
|
287
|
+
You can add your own sheets — source data, notes, a parameter legend — and hide
|
|
288
|
+
them:
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
table.add_sheet("Notes", [["Source"], ["main_db.xlsx"]], hidden=True)
|
|
292
|
+
table.add_defined_name("Lengths", "Sheet1!$B$3:$B$50")
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
`Sheet1` always stays first and visible. Hidden means `hidden`, never
|
|
296
|
+
`veryHidden`, so you can unhide it in Excel when something misbehaves.
|
|
297
|
+
|
|
298
|
+
**`_SWX` is rejected.** When SOLIDWORKS embeds a design table it creates a
|
|
299
|
+
hidden `_SWX` sheet and a `_SWX_0` defined name of its own. Authoring them here
|
|
300
|
+
produces a table SOLIDWORKS cannot reconcile. Likewise `Family` is created
|
|
301
|
+
automatically and adding it by hand is an error.
|
|
302
|
+
|
|
303
|
+
## Design tables are not the source of truth
|
|
304
|
+
|
|
305
|
+
When a table is generated by a script it stays an internal detail of the
|
|
306
|
+
generator. The source of truth is what lives outside: a database, a spreadsheet,
|
|
307
|
+
a configuration file. If the embedded table becomes the source, no other process
|
|
308
|
+
can read the data without opening SOLIDWORKS.
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
external source -> rules -> design table -> configurations
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Preparing the master model
|
|
315
|
+
|
|
316
|
+
The table can only be as good as the model underneath it:
|
|
317
|
+
|
|
318
|
+
1. **Name your dimensions.** Without a name they stay `D1@Sketch1`, and in three
|
|
319
|
+
weeks nobody knows which is which.
|
|
320
|
+
2. **Name the features you intend to suppress.** `$STATE@Cut-Extrude7` breaks
|
|
321
|
+
the moment someone reorders the tree.
|
|
322
|
+
3. **One brain only.** Equations or the table, not both governing the same thing.
|
|
323
|
+
A dimension driven by an equation cannot be driven by the table — drive the
|
|
324
|
+
global variable instead.
|
|
325
|
+
4. **Set document units to at least 2 decimals.** At 0 decimals a radius of 2.4
|
|
326
|
+
shows as `2`, in the model and on the drawing.
|
|
327
|
+
5. **Name the model after the family, not a variant.** Rename *before* creating
|
|
328
|
+
drawings or assemblies, or you break the references.
|
|
329
|
+
6. **Model the full case and suppress downwards.** Removing is easier than
|
|
330
|
+
creating.
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
MIT.
|