svgo 0.1.0b1__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.
- svgo-0.1.0b1/LICENSE +21 -0
- svgo-0.1.0b1/PKG-INFO +403 -0
- svgo-0.1.0b1/README.md +381 -0
- svgo-0.1.0b1/pyproject.toml +36 -0
- svgo-0.1.0b1/src/svgo/__init__.py +89 -0
- svgo-0.1.0b1/src/svgo/__main__.py +4 -0
- svgo-0.1.0b1/src/svgo/centerline.py +850 -0
- svgo-0.1.0b1/src/svgo/cli.py +585 -0
- svgo-0.1.0b1/src/svgo/geometry.py +194 -0
- svgo-0.1.0b1/src/svgo/inspect_svg.py +269 -0
- svgo-0.1.0b1/src/svgo/measure.py +373 -0
- svgo-0.1.0b1/src/svgo/pathdata.py +1112 -0
- svgo-0.1.0b1/src/svgo/raster_trace.py +323 -0
- svgo-0.1.0b1/src/svgo/svg_optimize.py +1006 -0
- svgo-0.1.0b1/src/svgo/viewport.py +133 -0
svgo-0.1.0b1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xmodar
|
|
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.
|
svgo-0.1.0b1/PKG-INFO
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: svgo
|
|
3
|
+
Version: 0.1.0b1
|
|
4
|
+
Summary: Pure-Python SVG path editing, optimization, matrix geometry, measurement, sanitization, viewport editing, validation, tracing, and centerline reconstruction.
|
|
5
|
+
Keywords: svg,path,optimizer,matrix,measurement,sanitize,viewbox,viewport,validation,trace,centerline,cli
|
|
6
|
+
Author: xmodar
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Project-URL: Homepage, https://github.com/xmodar/svgo
|
|
19
|
+
Project-URL: Repository, https://github.com/xmodar/svgo
|
|
20
|
+
Project-URL: Issues, https://github.com/xmodar/svgo/issues
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# svgo
|
|
24
|
+
|
|
25
|
+
`svgo` is a pure-Python SVG toolchain for path editing, SVG optimization,
|
|
26
|
+
PNG icon tracing, centerline reconstruction, geometry conversion, matrix
|
|
27
|
+
transforms, measurement, sanitization, viewBox/viewport edits, and SVG
|
|
28
|
+
inspection. It ships as an importable Python package and as a single `svgo`
|
|
29
|
+
command-line program.
|
|
30
|
+
|
|
31
|
+
The package has no required runtime dependencies. If `numpy` is installed,
|
|
32
|
+
some centerline distance-transform work can use accelerated array operations;
|
|
33
|
+
otherwise the standard-library fallback is used.
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- Edit SVG path data with ordered operations: translate, scale, affine matrix,
|
|
38
|
+
rotate, relative/absolute serialization, subpath reversal, origin changes,
|
|
39
|
+
and path optimization profiles.
|
|
40
|
+
- Optimize whole SVG files with Python implementations of common
|
|
41
|
+
SVGO-style cleanup and minification operations.
|
|
42
|
+
- Trace simple PNG icons into filled SVG paths without shelling out to
|
|
43
|
+
external tracing tools.
|
|
44
|
+
- Convert filled stroke outlines into approximate stroked centerlines.
|
|
45
|
+
- Convert SVG geometry primitives to path data and create common affine
|
|
46
|
+
matrices from Python.
|
|
47
|
+
- Measure path/SVG length, bounds, and point-at-length coordinates.
|
|
48
|
+
- Set, fit, and resize root SVG `viewBox`, `width`, and `height` values.
|
|
49
|
+
- Validate SVG XML, inspect dimensions/element counts/fonts, and run
|
|
50
|
+
structural conversions such as shape-to-path conversion, plain cleanup,
|
|
51
|
+
CSS style inlining, sanitization, and transform flattening.
|
|
52
|
+
- Use the same functionality from Python APIs or from the documented CLI.
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
From PyPI, once published:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python -m pip install svgo
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
From this repository:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
python -m pip install .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
For local development with `uv`:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
uv sync
|
|
72
|
+
uv run svgo --help
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## CLI
|
|
76
|
+
|
|
77
|
+
The CLI entry point is `svgo`. It is organized into short subcommands, each
|
|
78
|
+
with a one-letter alias:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
svgo path --path "<d>" [--op OP ...] [--svgo] # alias: p
|
|
82
|
+
svgo path --input icon.svg --output icon.out.svg --select all|N|N,N --op OP
|
|
83
|
+
svgo opt --input icon.svg --output icon.min.svg [optimization options] # alias: o
|
|
84
|
+
svgo trace --input icon.png --output traced.svg [trace options] # alias: t
|
|
85
|
+
svgo center --input outline.svg --output stroke.svg [centerline options] # alias: c
|
|
86
|
+
svgo info --input icon.svg # alias: i
|
|
87
|
+
svgo validate --input icon.svg [--strict] # alias: v
|
|
88
|
+
svgo measure --input icon.svg # alias: m
|
|
89
|
+
svgo sanitize --input icon.svg --output safe.svg # alias: s
|
|
90
|
+
svgo viewbox --input icon.svg --fit-content --output fitted.svg # alias: b
|
|
91
|
+
svgo convert --input icon.svg --output converted.svg [conversion options] # alias: x
|
|
92
|
+
svgo plugins # alias: l
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Every command supports `--help`:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
svgo --help
|
|
99
|
+
svgo path --help
|
|
100
|
+
svgo opt --help
|
|
101
|
+
svgo trace --help
|
|
102
|
+
svgo center --help
|
|
103
|
+
svgo info --help
|
|
104
|
+
svgo validate --help
|
|
105
|
+
svgo measure --help
|
|
106
|
+
svgo sanitize --help
|
|
107
|
+
svgo viewbox --help
|
|
108
|
+
svgo convert --help
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Path Editing
|
|
112
|
+
|
|
113
|
+
Path operations are applied in order with repeated `--op` flags:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
svgo path --path "M10 10h5v5z" --op "matrix(-1,0,0,1,30,0)" --minify
|
|
117
|
+
svgo p --input icon.svg --output edited.svg --select 0,2 --op translate:2,-1 --op optimize:safe
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Supported operations:
|
|
121
|
+
|
|
122
|
+
- `translate:dx,dy`
|
|
123
|
+
- `scale:kx,ky`
|
|
124
|
+
- `matrix:a,b,c,d,e,f` or `matrix(a,b,c,d,e,f)`
|
|
125
|
+
- `rotate:ox,oy,degrees`
|
|
126
|
+
- `relative`
|
|
127
|
+
- `absolute`
|
|
128
|
+
- `reverse` or `reverse:itemIndex`
|
|
129
|
+
- `origin:itemIndex` or `origin:itemIndex:subpath`
|
|
130
|
+
- `cubics`, `cubic`, `to-cubics`, or `toCubics`
|
|
131
|
+
- `optimize:safe`, `optimize:size`, `optimize:closed`, `optimize:all`
|
|
132
|
+
- `optimize:remove-useless,use-shorthands,use-hv,use-relative-absolute,use-reverse,use-close-path,remove-orphan-dots`
|
|
133
|
+
|
|
134
|
+
The affine matrix uses SVG convention:
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
x' = a*x + c*y + e
|
|
138
|
+
y' = b*x + d*y + f
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Arcs are converted to cubic Beziers during arbitrary affine transforms so
|
|
142
|
+
reflections, rotations, scales, and skews stay fully Python based.
|
|
143
|
+
|
|
144
|
+
## SVG Optimization
|
|
145
|
+
|
|
146
|
+
`svgo opt` optimizes SVG documents. `svgo path --svgo` applies the same SVG
|
|
147
|
+
optimizer after path edits:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
svgo opt --input icon.svg --output icon.min.svg --svgo-multipass --svgo-precision 3
|
|
151
|
+
svgo o --input icon.svg --svgo-disable cleanupIds --svgo-plugin removeDimensions
|
|
152
|
+
svgo opt --input icon.svg --svgo-preset none --svgo-plugin convertShapeToPath --svgo-plugin sortAttrs
|
|
153
|
+
svgo l
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Supported options include:
|
|
157
|
+
|
|
158
|
+
- `--svgo-preset default|none`
|
|
159
|
+
- `--svgo-plugin NAME[:JSON]`
|
|
160
|
+
- `--svgo-disable NAME`
|
|
161
|
+
- `--svgo-precision N`
|
|
162
|
+
- `--svgo-multipass`
|
|
163
|
+
- `--svgo-pretty`
|
|
164
|
+
- `--svgo-indent N`
|
|
165
|
+
- `--svgo-eol lf|crlf`
|
|
166
|
+
- `--svgo-final-newline`
|
|
167
|
+
- `--svgo-datauri base64|enc|unenc`
|
|
168
|
+
- `--svgo-config FILE`
|
|
169
|
+
|
|
170
|
+
`--svgo-config` accepts JSON files and Python-readable TOML files. JavaScript
|
|
171
|
+
SVGO configs are intentionally rejected because this implementation does not
|
|
172
|
+
execute Node.js.
|
|
173
|
+
|
|
174
|
+
## PNG Tracing
|
|
175
|
+
|
|
176
|
+
PNG tracing decodes non-interlaced 8-bit PNGs with the standard library,
|
|
177
|
+
groups visible pixels, traces connected-component boundaries, and writes
|
|
178
|
+
filled SVG paths.
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
svgo trace --input icon.png --output traced.svg --mode palette --max-colors 8 --quantize 24 --min-area 8
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Modes:
|
|
185
|
+
|
|
186
|
+
- `palette`: group pixels into dominant quantized colors.
|
|
187
|
+
- `alpha`: trace a single alpha mask using the most common visible color.
|
|
188
|
+
- `exact`: keep exact quantized color buckets.
|
|
189
|
+
|
|
190
|
+
Useful options:
|
|
191
|
+
|
|
192
|
+
- `--drop-white`
|
|
193
|
+
- `--alpha-threshold N`
|
|
194
|
+
- `--white-threshold N`
|
|
195
|
+
- `--quantize N`
|
|
196
|
+
- `--max-colors N`
|
|
197
|
+
- `--min-area N`
|
|
198
|
+
- `--scale N`
|
|
199
|
+
- `--decimals N`
|
|
200
|
+
- `--title TEXT`
|
|
201
|
+
|
|
202
|
+
## Centerline Reconstruction
|
|
203
|
+
|
|
204
|
+
Centerline reconstruction converts filled stroke outlines into approximate
|
|
205
|
+
stroked paths by flattening path data, rasterizing with even-odd fill,
|
|
206
|
+
skeletonizing with Zhang-Suen thinning, estimating stroke width, and tracing
|
|
207
|
+
the skeleton.
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
svgo center --path "M0 0L100 0L100 20L0 20Z" --emit path
|
|
211
|
+
svgo c --input traced.svg --output centerline.svg --svg-paths all --mode all --simplify 4
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Important options:
|
|
215
|
+
|
|
216
|
+
- `--emit path|svg|d`
|
|
217
|
+
- `--mode longest|all`
|
|
218
|
+
- `--scale N`
|
|
219
|
+
- `--max-size N`
|
|
220
|
+
- `--curve-samples N`
|
|
221
|
+
- `--simplify N`
|
|
222
|
+
- `--min-length N`
|
|
223
|
+
- `--stroke-width auto|N`
|
|
224
|
+
- `--linecap VALUE`
|
|
225
|
+
- `--linejoin VALUE`
|
|
226
|
+
- `--polyline`
|
|
227
|
+
- `--svg-paths first|all`
|
|
228
|
+
- `--keep-failed`
|
|
229
|
+
|
|
230
|
+
Centerline output is intentionally approximate. For production icon work,
|
|
231
|
+
render and inspect the result before final minification.
|
|
232
|
+
|
|
233
|
+
## Inspection And Conversion
|
|
234
|
+
|
|
235
|
+
`svgo info` prints structured JSON metadata:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
svgo info --input icon.svg
|
|
239
|
+
svgo i --input icon.svg --compact
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`svgo validate` checks SVG XML and reports structural issues. Warnings do not
|
|
243
|
+
make the command fail unless `--strict` is used:
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
svgo validate --input icon.svg
|
|
247
|
+
svgo v --input icon.svg --strict --json
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
`svgo measure` reports path/SVG length and axis-aligned bounds. It accepts raw
|
|
251
|
+
path data, SVG files, or text files containing path data:
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
svgo measure --path "M0 0H10V10H0Z" --decimals 3
|
|
255
|
+
svgo m --input icon.svg --compact
|
|
256
|
+
svgo m --path "M0 0H10V10" --at 15
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
`svgo sanitize` removes active or unsafe content while keeping normal static
|
|
260
|
+
SVG geometry:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
svgo sanitize --input icon.svg --output icon.safe.svg
|
|
264
|
+
svgo s --input icon.svg --remove-external-refs --remove-styles
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`svgo viewbox` edits root viewport metadata:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
svgo viewbox --input icon.svg --set "0 0 24 24" --remove-dimensions
|
|
271
|
+
svgo b --input icon.svg --fit-content --padding 1 --precision 2
|
|
272
|
+
svgo b --input icon.svg --width 48 --height 48
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`svgo convert` runs pure-Python structural conversions. With no conversion
|
|
276
|
+
flags it converts basic shapes to paths:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
svgo convert --input shapes.svg --output paths.svg
|
|
280
|
+
svgo x --input drawing.svg --output plain.svg --to-plain
|
|
281
|
+
svgo x --input transformed.svg --output flat.svg --shapes-to-paths --flatten-transforms
|
|
282
|
+
svgo x --input styled.svg --output inline.svg --inline-styles
|
|
283
|
+
svgo x --input source.svg --output converted.svg --all --precision 3
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Conversion options:
|
|
287
|
+
|
|
288
|
+
- `--to-plain`: remove common editor metadata and editor-specific attributes.
|
|
289
|
+
- `--shapes-to-paths`: convert `rect`, `circle`, `ellipse`, `line`,
|
|
290
|
+
`polyline`, and `polygon` to `path`.
|
|
291
|
+
- `--flatten-transforms`: bake supported transforms into path coordinates.
|
|
292
|
+
- `--flatten-groups`: collapse empty unstyled groups.
|
|
293
|
+
- `--inline-styles`: inline simple style-element rules into presentation
|
|
294
|
+
attributes.
|
|
295
|
+
- `--sanitize`: remove scripts, event handlers, and unsafe links before
|
|
296
|
+
conversion.
|
|
297
|
+
- `--all`: enable every conversion pass.
|
|
298
|
+
- `--precision N`: control generated numeric precision.
|
|
299
|
+
|
|
300
|
+
## Python API
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
from svgo import (
|
|
304
|
+
PathData,
|
|
305
|
+
centerline_path_data,
|
|
306
|
+
circle_to_path,
|
|
307
|
+
get_svg_info,
|
|
308
|
+
fit_viewbox_svg,
|
|
309
|
+
inline_styles_svg,
|
|
310
|
+
optimize_svg,
|
|
311
|
+
path_metrics,
|
|
312
|
+
path_to_cubics,
|
|
313
|
+
rect_to_path,
|
|
314
|
+
resize_svg,
|
|
315
|
+
sanitize_svg,
|
|
316
|
+
set_viewbox_svg,
|
|
317
|
+
trace_png,
|
|
318
|
+
transform_2d,
|
|
319
|
+
translate_2d,
|
|
320
|
+
validate_svg,
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
path = PathData.parse("M0 0L10 0L10 10Z")
|
|
324
|
+
path.transform((1, 0, 0, 1, 2, -1))
|
|
325
|
+
path.optimize("safe")
|
|
326
|
+
print(path.to_string(decimals=3, minify=True))
|
|
327
|
+
|
|
328
|
+
svg = optimize_svg("<svg><rect width='10' height='10'/></svg>")
|
|
329
|
+
shape = rect_to_path(0, 0, 24, 12, rx=2, decimals=3, minify=True)
|
|
330
|
+
cubic = path_to_cubics("M0 0L10 0Q15 0 15 5", decimals=3, minify=True)
|
|
331
|
+
x, y = transform_2d(translate_2d(10, 5), 1, 2)
|
|
332
|
+
report = validate_svg("<svg viewBox='0 0 10 10'/>")
|
|
333
|
+
metrics = path_metrics("M0 0H10V10H0Z", decimals=3)
|
|
334
|
+
safe_svg = sanitize_svg("<svg onload='x()'><path d='M0 0H1'/></svg>")
|
|
335
|
+
fitted_svg = fit_viewbox_svg("<svg><path d='M2 3H6V7H2Z'/></svg>")
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
The lower-level modules are:
|
|
339
|
+
|
|
340
|
+
- `svgo.pathdata`
|
|
341
|
+
- `svgo.geometry`
|
|
342
|
+
- `svgo.measure`
|
|
343
|
+
- `svgo.viewport`
|
|
344
|
+
- `svgo.inspect_svg`
|
|
345
|
+
- `svgo.svg_optimize`
|
|
346
|
+
- `svgo.raster_trace`
|
|
347
|
+
- `svgo.centerline`
|
|
348
|
+
|
|
349
|
+
## Reference Tools
|
|
350
|
+
|
|
351
|
+
These projects are useful reference points for SVG feature coverage, command
|
|
352
|
+
shape, and API expectations:
|
|
353
|
+
|
|
354
|
+
- [SVGO](https://github.com/svg/svgo): Node.js SVG optimizer and plugin
|
|
355
|
+
ecosystem.
|
|
356
|
+
- [Scour](https://github.com/scour-project/scour): Python SVG optimizer and
|
|
357
|
+
cleaner.
|
|
358
|
+
- [svgpathtools](https://github.com/mathandy/svgpathtools): Python path,
|
|
359
|
+
Bezier, geometry, length, and bounds utilities.
|
|
360
|
+
- [svg.path](https://github.com/regebro/svg.path): Python SVG path parser and
|
|
361
|
+
path object model.
|
|
362
|
+
- [svg-matrix-python](https://github.com/Emasoft/svg-matrix-python): Python
|
|
363
|
+
wrapper around SVG matrix conversion and validation workflows.
|
|
364
|
+
- [Yqnn/svg-path-editor](https://github.com/Yqnn/svg-path-editor): SVG path
|
|
365
|
+
editing UI and path operation reference implementation.
|
|
366
|
+
- [svg-path-commander](https://github.com/thednp/svg-path-commander):
|
|
367
|
+
TypeScript path parsing, normalization, geometry, and transformation tools.
|
|
368
|
+
- [Iconify Tools](https://github.com/iconify/tools): TypeScript SVG import,
|
|
369
|
+
validation, cleanup, and export tooling.
|
|
370
|
+
- [resvg/usvg](https://github.com/linebender/resvg): Rust SVG rendering and
|
|
371
|
+
static SVG simplification/reference implementation.
|
|
372
|
+
- [VTracer](https://github.com/visioncortex/vtracer): Rust raster-to-vector
|
|
373
|
+
tracing tool.
|
|
374
|
+
|
|
375
|
+
## Development
|
|
376
|
+
|
|
377
|
+
This repository uses uv's native `uv_build` backend and has no required runtime
|
|
378
|
+
dependencies.
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
uv run python -m unittest discover -s tests
|
|
382
|
+
uv build
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Publishing
|
|
386
|
+
|
|
387
|
+
PyPI publishing is handled by GitHub Actions Trusted Publishing through
|
|
388
|
+
`.github/workflows/publish.yml`. The PyPI pending publisher must match this
|
|
389
|
+
repository, the `publish.yml` workflow filename, and the `pypi` environment.
|
|
390
|
+
|
|
391
|
+
To publish a release, update `project.version`, commit the change, and push a
|
|
392
|
+
matching tag:
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
git tag v0.1.0b1
|
|
396
|
+
git push origin v0.1.0b1
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
The workflow verifies that the pushed tag equals `v{project.version}`, runs the
|
|
400
|
+
test suite, builds the wheel and source distribution with `uv`, then publishes
|
|
401
|
+
to PyPI with Trusted Publishing.
|
|
402
|
+
|
|
403
|
+
The package targets Python 3.11 and newer.
|