shapemesh 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. shapemesh-0.1.0/.github/workflows/ci.yml +249 -0
  2. shapemesh-0.1.0/.gitignore +23 -0
  3. shapemesh-0.1.0/.python-version +1 -0
  4. shapemesh-0.1.0/AGENTS.md +122 -0
  5. shapemesh-0.1.0/CHANGELOG.md +16 -0
  6. shapemesh-0.1.0/COPYING +674 -0
  7. shapemesh-0.1.0/COPYING.LESSER +165 -0
  8. shapemesh-0.1.0/PKG-INFO +144 -0
  9. shapemesh-0.1.0/README.md +114 -0
  10. shapemesh-0.1.0/design-v1.md +666 -0
  11. shapemesh-0.1.0/docs/index.md +6 -0
  12. shapemesh-0.1.0/docs/labels.md +39 -0
  13. shapemesh-0.1.0/docs/release-review-0.1.0.md +552 -0
  14. shapemesh-0.1.0/docs/threading.md +28 -0
  15. shapemesh-0.1.0/docs/version-policy.md +10 -0
  16. shapemesh-0.1.0/examples/beam_with_hole.py +42 -0
  17. shapemesh-0.1.0/examples/frame.py +52 -0
  18. shapemesh-0.1.0/examples/pilecap.py +56 -0
  19. shapemesh-0.1.0/pyproject.toml +105 -0
  20. shapemesh-0.1.0/src/shapemesh/__init__.py +103 -0
  21. shapemesh-0.1.0/src/shapemesh/builder.py +301 -0
  22. shapemesh-0.1.0/src/shapemesh/constants.py +32 -0
  23. shapemesh-0.1.0/src/shapemesh/errors.py +62 -0
  24. shapemesh-0.1.0/src/shapemesh/mesh.py +1096 -0
  25. shapemesh-0.1.0/src/shapemesh/py.typed +0 -0
  26. shapemesh-0.1.0/src/shapemesh/settings.py +158 -0
  27. shapemesh-0.1.0/src/shapemesh/shapes.py +1007 -0
  28. shapemesh-0.1.0/tests/test_booleans.py +82 -0
  29. shapemesh-0.1.0/tests/test_mesh_io.py +458 -0
  30. shapemesh-0.1.0/tests/test_pipeline.py +349 -0
  31. shapemesh-0.1.0/tests/test_primitives.py +97 -0
  32. shapemesh-0.1.0/tests/test_settings.py +106 -0
  33. shapemesh-0.1.0/tests/test_shapes.py +310 -0
  34. shapemesh-0.1.0/tests/test_threading.py +59 -0
  35. shapemesh-0.1.0/uv.lock +232 -0
@@ -0,0 +1,249 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ tags:
8
+ - "v*"
9
+ pull_request:
10
+ workflow_dispatch:
11
+
12
+ concurrency:
13
+ group: ci-${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ env:
20
+ UV_VERSION: "0.13.5"
21
+
22
+ jobs:
23
+ quality:
24
+ name: Lint, format, and type check
25
+ runs-on: ubuntu-latest
26
+ timeout-minutes: 15
27
+ env:
28
+ UV_PYTHON: "3.13"
29
+ steps:
30
+ - name: Check out repository
31
+ uses: actions/checkout@v7
32
+ with:
33
+ persist-credentials: false
34
+
35
+ - name: Install uv and Python
36
+ uses: astral-sh/setup-uv@v10.3.2
37
+ with:
38
+ version: ${{ env.UV_VERSION }}
39
+ python-version: "3.13"
40
+ enable-cache: true
41
+ cache-dependency-glob: uv.lock
42
+
43
+ - name: Install dependencies
44
+ run: uv sync --locked --python 3.13
45
+
46
+ - name: Check lockfile
47
+ run: uv lock --check
48
+
49
+ - name: Lint
50
+ run: uv run --no-sync ruff check .
51
+
52
+ - name: Check formatting
53
+ run: uv run --no-sync ruff format --check .
54
+
55
+ - name: Type check
56
+ run: uv run --no-sync pyright
57
+
58
+ test:
59
+ name: Test (${{ matrix.os }}, Python ${{ matrix.python-version }})
60
+ runs-on: ${{ matrix.os }}
61
+ timeout-minutes: 20
62
+ env:
63
+ UV_PYTHON: ${{ matrix.python-version }}
64
+ strategy:
65
+ fail-fast: false
66
+ matrix:
67
+ os:
68
+ - ubuntu-latest
69
+ - macos-latest
70
+ - windows-latest
71
+ python-version:
72
+ - "3.12"
73
+ - "3.13"
74
+ - "3.14"
75
+ - "3.15"
76
+ steps:
77
+ - name: Check out repository
78
+ uses: actions/checkout@v7
79
+ with:
80
+ persist-credentials: false
81
+
82
+ - name: Install Gmsh system libraries (Linux)
83
+ if: runner.os == 'Linux'
84
+ run: |
85
+ sudo apt-get update
86
+ sudo apt-get install --yes --no-install-recommends \
87
+ libglu1-mesa libgl1 libxrender1 libxcursor1 libxft2 \
88
+ libxinerama1 libfontconfig1
89
+
90
+ - name: Install uv and Python
91
+ uses: astral-sh/setup-uv@v10.3.2
92
+ with:
93
+ version: ${{ env.UV_VERSION }}
94
+ python-version: ${{ matrix.python-version }}
95
+ enable-cache: true
96
+ cache-dependency-glob: uv.lock
97
+
98
+ - name: Install dependencies
99
+ run: uv sync --locked --python ${{ matrix.python-version }}
100
+
101
+ - name: Verify Gmsh version
102
+ run: uv run --no-sync python -c "import gmsh; assert gmsh.__version__ == '4.15.2', gmsh.__version__"
103
+
104
+ - name: Run tests
105
+ run: uv run --no-sync pytest -q -W error
106
+
107
+ package:
108
+ name: Build and verify distributions
109
+ runs-on: ubuntu-latest
110
+ timeout-minutes: 20
111
+ env:
112
+ UV_PYTHON: "3.13"
113
+ steps:
114
+ - name: Check out repository
115
+ uses: actions/checkout@v7
116
+ with:
117
+ persist-credentials: false
118
+
119
+ - name: Install Gmsh system libraries (Linux)
120
+ run: |
121
+ sudo apt-get update
122
+ sudo apt-get install --yes --no-install-recommends \
123
+ libglu1-mesa libgl1 libxrender1 libxcursor1 libxft2 \
124
+ libxinerama1 libfontconfig1
125
+
126
+ - name: Install uv and Python
127
+ uses: astral-sh/setup-uv@v10.3.2
128
+ with:
129
+ version: ${{ env.UV_VERSION }}
130
+ python-version: "3.13"
131
+ enable-cache: true
132
+ cache-dependency-glob: uv.lock
133
+
134
+ - name: Install dependencies
135
+ run: uv sync --locked --python 3.13
136
+
137
+ - name: Build distributions
138
+ run: |
139
+ rm -rf dist
140
+ uv build
141
+
142
+ - name: Check distribution metadata
143
+ run: uvx twine check --strict dist/*
144
+
145
+ - name: Verify distribution contents
146
+ run: |
147
+ uv run --no-sync python - <<'PY'
148
+ import pathlib
149
+ import tarfile
150
+ import zipfile
151
+
152
+ dist = pathlib.Path("dist")
153
+ wheels = sorted(dist.glob("*.whl"))
154
+ sdists = sorted(dist.glob("*.tar.gz"))
155
+ assert len(wheels) == 1, wheels
156
+ assert len(sdists) == 1, sdists
157
+ wheel, sdist = wheels[0], sdists[0]
158
+
159
+ required_wheel = {
160
+ "shapemesh/__init__.py",
161
+ "shapemesh/builder.py",
162
+ "shapemesh/constants.py",
163
+ "shapemesh/errors.py",
164
+ "shapemesh/mesh.py",
165
+ "shapemesh/py.typed",
166
+ "shapemesh/settings.py",
167
+ "shapemesh/shapes.py",
168
+ }
169
+
170
+ with zipfile.ZipFile(wheel) as archive:
171
+ wheel_entries = {info.filename: info for info in archive.infolist()}
172
+
173
+ missing = required_wheel - wheel_entries.keys()
174
+ assert not missing, f"{wheel.name} is missing {sorted(missing)}"
175
+ for license_name in ("COPYING", "COPYING.LESSER"):
176
+ matches = [
177
+ info
178
+ for name, info in wheel_entries.items()
179
+ if name.endswith(f"dist-info/licenses/{license_name}")
180
+ ]
181
+ assert matches, f"{wheel.name} is missing {license_name}"
182
+ assert all(info.file_size > 0 for info in matches)
183
+
184
+ required_sdist = {
185
+ "COPYING",
186
+ "COPYING.LESSER",
187
+ "README.md",
188
+ "pyproject.toml",
189
+ "examples/beam_with_hole.py",
190
+ "examples/frame.py",
191
+ "examples/pilecap.py",
192
+ "src/shapemesh/py.typed",
193
+ }
194
+
195
+ with tarfile.open(sdist) as archive:
196
+ sdist_entries = {member.name: member for member in archive.getmembers()}
197
+
198
+ for suffix in required_sdist:
199
+ matches = [
200
+ member
201
+ for name, member in sdist_entries.items()
202
+ if name == suffix or name.endswith(f"/{suffix}")
203
+ ]
204
+ assert matches, f"{sdist.name} is missing {suffix}"
205
+ if suffix != "src/shapemesh/py.typed":
206
+ assert all(member.size > 0 for member in matches)
207
+
208
+ print(f"{wheel.name}: {len(wheel_entries)} entries")
209
+ print(f"{sdist.name}: {len(sdist_entries)} entries")
210
+ PY
211
+
212
+ - name: Install the built wheel
213
+ run: uv pip install --python .venv/bin/python --no-deps --force-reinstall dist/*.whl
214
+
215
+ - name: Verify the installed wheel
216
+ run: |
217
+ uv run --no-sync python - <<'PY'
218
+ import pathlib
219
+
220
+ import shapemesh
221
+
222
+ path = pathlib.Path(shapemesh.__file__).resolve()
223
+ assert "site-packages" in path.parts, f"imported the source tree instead: {path}"
224
+ print(f"Imported shapemesh {shapemesh.__version__} from {path}")
225
+ PY
226
+
227
+ - name: Run tests against the installed wheel
228
+ run: uv run --no-sync pytest -q -W error
229
+
230
+ - name: Smoke-test the examples
231
+ working-directory: ${{ runner.temp }}
232
+ run: |
233
+ set -euo pipefail
234
+ for example in "$GITHUB_WORKSPACE"/examples/*.py; do
235
+ echo "::group::$(basename "$example")"
236
+ "$GITHUB_WORKSPACE/.venv/bin/python" "$example"
237
+ echo "::endgroup::"
238
+ done
239
+ test -s beam_with_hole.msh
240
+ test -s frame.msh
241
+ test -s pilecap.msh
242
+
243
+ - name: Upload distributions
244
+ uses: actions/upload-artifact@v7
245
+ with:
246
+ name: distributions
247
+ path: dist/
248
+ if-no-files-found: error
249
+ retention-days: 7
@@ -0,0 +1,23 @@
1
+ # Byte-compiled / optimized / cache files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ .pytest_cache/
6
+ .mypy_cache/
7
+ .ruff_cache/
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+
13
+ # Build artifacts
14
+ build/
15
+ dist/
16
+ *.egg-info/
17
+ .eggs/
18
+
19
+ # Editor settings
20
+ .vscode/settings.json
21
+
22
+ # Output files
23
+ *.msh
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,122 @@
1
+ # AGENTS.md
2
+
3
+ Guidance for contributors and AI agents working in this repository.
4
+
5
+ ## Design
6
+
7
+ The source of truth for the current scope is `design-v1.md`. Keep it up
8
+ to date as you implement within its scope.
9
+
10
+ ## License
11
+
12
+ The project is LGPL-3.0-or-later. The license is split across two files because
13
+ the LGPL is the GPL plus additional permissions:
14
+
15
+ - `COPYING` — the GNU GPL-3.0 text.
16
+ - `COPYING.LESSER` — the LGPL-3.0 supplement.
17
+
18
+ Every new source file must start with the full notice below (copyright holder:
19
+ Mads Kruse). Files under `examples/` may instead use the short notice shown
20
+ after it, so documentation-focused examples stay concise:
21
+
22
+ ```text
23
+ # Copyright (C) 2026 Mads Kruse
24
+ #
25
+ # This file is part of shapemesh.
26
+ #
27
+ # shapemesh is free software: you can redistribute it and/or modify it under
28
+ # the terms of the GNU Lesser General Public License as published by the Free
29
+ # Software Foundation, either version 3 of the License, or (at your option)
30
+ # any later version.
31
+ #
32
+ # shapemesh is distributed in the hope that it will be useful, but WITHOUT
33
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
34
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
35
+ # for more details.
36
+ #
37
+ # You should have received a copy of the GNU Lesser General Public License
38
+ # along with shapemesh. If not, see <https://www.gnu.org/licenses/>.
39
+ ```
40
+
41
+ The permitted short form for files under `examples/` is:
42
+
43
+ ```text
44
+ # Copyright (C) 2026 Mads Kruse
45
+ # SPDX-License-Identifier: LGPL-3.0-or-later
46
+ ```
47
+
48
+ ## Docstrings
49
+
50
+ Public API docstrings use **Google style**:
51
+
52
+ - A one-line summary, then a blank line, then sections.
53
+ - Sections are ``Args:``, ``Returns:`` (or ``Yields:``), ``Raises:``, and
54
+ ``Examples:``. Each entry is ``name: description``, indented 4 spaces, with
55
+ continuation lines indented to align under the description.
56
+ - Omit the type in ``Args``/``Returns`` when the signature already annotates it.
57
+ - Cross-reference project objects with single backticks (`` `Mesh` ``) and
58
+ inline code with double backticks (`` ``.msh`` ``). Do not use Sphinx roles
59
+ (``:class:``, ``:meth:``, ``:func:``).
60
+ - Document every public class, function, method, and property. Include a
61
+ ``Raises:`` section whenever it can raise.
62
+
63
+ ```python
64
+ def build(shapes, settings):
65
+ """Realize ``shapes`` with Gmsh and return the resulting `Mesh`.
66
+
67
+ Args:
68
+ shapes: A shape or a sequence of shapes to mesh.
69
+ settings: The mesh settings.
70
+
71
+ Returns:
72
+ The entity-classified mesh.
73
+
74
+ Raises:
75
+ BuildError: If a Gmsh call fails.
76
+ """
77
+ ```
78
+
79
+ ## Commit messages
80
+
81
+ We follow the spirit of [Common Changelog](https://common-changelog.org/):
82
+ commits and changelogs are written for humans, not machines.
83
+
84
+ - Write the subject in the **past tense, active voice**, leading with a verb:
85
+ `Added ...`, `Fixed ...`, `Refactored ...`, `Removed ...`, `Documented ...`,
86
+ `Bumped ...`.
87
+ - Capitalize the first word; no trailing period.
88
+ - Do **not** use Conventional Commits prefixes (`feat:`, `fix:`, `chore:`).
89
+ - Keep the subject to a single line; put the "why" and detail in the body.
90
+ - Lead with `Breaking:` when a change is breaking.
91
+
92
+ ## Remote pushes
93
+
94
+ Never push commits, tags, or branches to a remote without explicit approval.
95
+ Prepare the commit locally, show it for review, and wait for the user to approve
96
+ the push. Approval applies only to the reviewed changes. Do not rewrite
97
+ published history or force-push without separate explicit approval.
98
+
99
+ ## Changelog
100
+
101
+ `CHANGELOG.md` follows [Common Changelog](https://common-changelog.org/) and is
102
+ updated when a release is prepared, not with every commit. Do not add an
103
+ `Unreleased` section.
104
+
105
+ - Start each release with `## [VERSION] - YYYY-MM-DD` and link the version to
106
+ its GitHub release with a reference-style link at the bottom of the file.
107
+ - Add a one-sentence italic notice when useful. First releases use
108
+ `_First release._`.
109
+ - Group changes under `### Changed`, `### Added`, `### Removed`, and
110
+ `### Fixed`, in that order, and omit empty groups.
111
+ - Write each change in the imperative mood on one line, starting with a verb
112
+ such as `Add`, `Fix`, `Remove`, or `Refactor`.
113
+ - End each change with one or more Markdown links to the most relevant commits,
114
+ for example
115
+ ``([`53bd922`](https://github.com/MEMAndersen/shapemesh/commit/53bd922))``.
116
+ - Add the author after the references, for example `(Mads Kruse)`.
117
+ - Follow [3.4. Merge related changes](https://common-changelog.org/#34-merge-related-changes):
118
+ merge commits that implement one change and leave out maintenance that does
119
+ not affect users. Keep the list short.
120
+ - Prefix breaking changes with `**Breaking:**` and list them first.
121
+ - Keep releases latest-first, and tag each release with the same version
122
+ (`vX.Y.Z`).
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## [0.1.0] - 2026-10-27
4
+
5
+ _First release._
6
+
7
+ ### Added
8
+
9
+ - Add 12 shape primitives and n-ary `Union`, `Intersection`, and `Difference` with operator overloads ([`821888c`](https://github.com/MEMAndersen/shapemesh/commit/821888c), [`f315cf6`](https://github.com/MEMAndersen/shapemesh/commit/f315cf6)) (Mads Kruse)
10
+ - Add `build()` with label-preserving physical groups and `MeshSettings` for element size, element order, 2D and 3D algorithms, and advanced Gmsh options ([`821888c`](https://github.com/MEMAndersen/shapemesh/commit/821888c), [`647c5e5`](https://github.com/MEMAndersen/shapemesh/commit/647c5e5)) (Mads Kruse)
11
+ - Add MSH 4.1 ASCII I/O and the `Mesh` query and NumPy API ([`41efc2b`](https://github.com/MEMAndersen/shapemesh/commit/41efc2b), [`d02d866`](https://github.com/MEMAndersen/shapemesh/commit/d02d866)) (Mads Kruse)
12
+ - Add a typed public API with `py.typed` and a structured exception hierarchy ([`821888c`](https://github.com/MEMAndersen/shapemesh/commit/821888c), [`4e30f0e`](https://github.com/MEMAndersen/shapemesh/commit/4e30f0e)) (Mads Kruse)
13
+ - Add 1D, 2D, and 3D examples and documentation for labels, threading, and the Gmsh version policy ([`cde6dc0`](https://github.com/MEMAndersen/shapemesh/commit/cde6dc0), [`413dc02`](https://github.com/MEMAndersen/shapemesh/commit/413dc02)) (Mads Kruse)
14
+ - Support Python 3.12 through 3.15 on Linux, macOS, and Windows with Gmsh 4.0 or later ([`4f941e1`](https://github.com/MEMAndersen/shapemesh/commit/4f941e1), [`b605815`](https://github.com/MEMAndersen/shapemesh/commit/b605815)) (Mads Kruse)
15
+
16
+ [0.1.0]: https://github.com/MEMAndersen/shapemesh/releases/tag/v0.1.0