weasysvg 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.
- weasysvg-0.1.0/.gitignore +52 -0
- weasysvg-0.1.0/CHANGELOG.md +46 -0
- weasysvg-0.1.0/LICENSE +21 -0
- weasysvg-0.1.0/PKG-INFO +209 -0
- weasysvg-0.1.0/README.md +169 -0
- weasysvg-0.1.0/pyproject.toml +113 -0
- weasysvg-0.1.0/src/weasysvg/__init__.py +100 -0
- weasysvg-0.1.0/src/weasysvg/_core.py +450 -0
- weasysvg-0.1.0/src/weasysvg/conditional.py +169 -0
- weasysvg-0.1.0/src/weasysvg/fetch.py +48 -0
- weasysvg-0.1.0/src/weasysvg/filters.py +1234 -0
- weasysvg-0.1.0/src/weasysvg/fonts.py +150 -0
- weasysvg-0.1.0/src/weasysvg/foreign_object.py +433 -0
- weasysvg-0.1.0/src/weasysvg/glyphs.py +200 -0
- weasysvg-0.1.0/src/weasysvg/ink.py +235 -0
- weasysvg-0.1.0/src/weasysvg/markers.py +122 -0
- weasysvg-0.1.0/src/weasysvg/paint.py +564 -0
- weasysvg-0.1.0/src/weasysvg/pathdata.py +357 -0
- weasysvg-0.1.0/src/weasysvg/py.typed +0 -0
- weasysvg-0.1.0/src/weasysvg/text.py +740 -0
- weasysvg-0.1.0/src/weasysvg/textpath.py +167 -0
- weasysvg-0.1.0/src/weasysvg/turbulence.py +185 -0
- weasysvg-0.1.0/src/weasysvg/vertical.py +194 -0
- weasysvg-0.1.0/tests/conftest.py +5 -0
- weasysvg-0.1.0/tests/helpers.py +140 -0
- weasysvg-0.1.0/tests/test_conditional.py +218 -0
- weasysvg-0.1.0/tests/test_fetch.py +54 -0
- weasysvg-0.1.0/tests/test_filters.py +991 -0
- weasysvg-0.1.0/tests/test_fonts.py +84 -0
- weasysvg-0.1.0/tests/test_foreign_object.py +468 -0
- weasysvg-0.1.0/tests/test_install.py +156 -0
- weasysvg-0.1.0/tests/test_markers.py +167 -0
- weasysvg-0.1.0/tests/test_paint.py +706 -0
- weasysvg-0.1.0/tests/test_text.py +1042 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# IDE
|
|
2
|
+
.idea/
|
|
3
|
+
.vscode/
|
|
4
|
+
*.swp
|
|
5
|
+
*.swo
|
|
6
|
+
|
|
7
|
+
# macOS
|
|
8
|
+
.DS_Store
|
|
9
|
+
|
|
10
|
+
# Python
|
|
11
|
+
__pycache__/
|
|
12
|
+
*.py[cod]
|
|
13
|
+
*$py.class
|
|
14
|
+
*.so
|
|
15
|
+
.Python
|
|
16
|
+
build/
|
|
17
|
+
develop-eggs/
|
|
18
|
+
dist/
|
|
19
|
+
downloads/
|
|
20
|
+
eggs/
|
|
21
|
+
.eggs/
|
|
22
|
+
lib/
|
|
23
|
+
lib64/
|
|
24
|
+
parts/
|
|
25
|
+
sdist/
|
|
26
|
+
var/
|
|
27
|
+
wheels/
|
|
28
|
+
*.egg-info/
|
|
29
|
+
.installed.cfg
|
|
30
|
+
*.egg
|
|
31
|
+
|
|
32
|
+
# Virtual environments
|
|
33
|
+
.venv/
|
|
34
|
+
venv/
|
|
35
|
+
ENV/
|
|
36
|
+
|
|
37
|
+
# Testing
|
|
38
|
+
.pytest_cache/
|
|
39
|
+
.coverage
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
|
|
44
|
+
# Type checking
|
|
45
|
+
.mypy_cache/
|
|
46
|
+
|
|
47
|
+
# Ruff
|
|
48
|
+
.ruff_cache/
|
|
49
|
+
coverage.xml
|
|
50
|
+
|
|
51
|
+
# Visual regression bench output
|
|
52
|
+
tools/visual/out/
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2026-10-21
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `weasysvg.install()` patches WeasyPrint 70.x to render SVG close to Chromium: `<foreignObject>` with
|
|
15
|
+
the list markers of Chromium and the white space of empty inline boxes collapsed as there,
|
|
16
|
+
conditional processing, vector filter chains (blur, exact for a plain rect, color matrices and
|
|
17
|
+
transfer functions included), masks set before the path, pattern and gradient fixes, `mix-blend-mode`, unclipped
|
|
18
|
+
opacity groups, marker orientation, text baselines from font metrics, text-anchor per text chunk, filters, masks and clips on text, circles of the right length, dots of zero-length dashes in place in PDFium, negative dash offsets of odd dash arrays, decorations placed as in Chromium with underlines that skip the ink of the glyphs (laid out whole or character by character), font-size
|
|
19
|
+
keywords, relative font sizes inherited as computed, `ex` from the x-height of the font, and Chromium font selection. No SVG content is rasterized: the PDF stays vector.
|
|
20
|
+
- `feTurbulence`, drawn as an image of the noise, and `feComposite` arithmetic.
|
|
21
|
+
- `systemLanguage` reads the `lang` of the document where the image sits, else `install(language=...)`,
|
|
22
|
+
`en` by default: a German document shows the German branch of a `<switch>`.
|
|
23
|
+
- Arabic laid out one character at a time, on a path or down a column, takes its joining forms and runs
|
|
24
|
+
right to left, numbers in it read left to right.
|
|
25
|
+
- Upright CJK in vertical text hangs from the vertical origin of its font (`VORG`, `vmtx`), as in Chromium
|
|
26
|
+
and resvg, and `rotate` turns it about that point.
|
|
27
|
+
- Python 3.10 to 3.14 and PyPy 3.11, the versions WeasyPrint 70 supports.
|
|
28
|
+
- Releases on PyPI (`pip install weasysvg`), with publish attestations, and on GitHub, with signed
|
|
29
|
+
build provenance of the same files.
|
|
30
|
+
- Upstream tracking for WeasyPrint upgrades (UPGRADING.md): probes of the gaps weasysvg covers, a
|
|
31
|
+
snapshot of the internals it hooks, a bench baseline, and a weekly run against the newest WeasyPrint.
|
|
32
|
+
- A visual regression corpus of 115 SVGs with Chromium and resvg references, and a bench that
|
|
33
|
+
compares weasysvg with Chromium.
|
|
34
|
+
- `corpus/COMPARISON.md` and the interactive `corpus/comparison.html` on GitHub Pages: every corpus SVG
|
|
35
|
+
in Chromium, resvg, WeasyPrint alone and with weasysvg, each panel at 2x as lossless WebP, sharp when zoomed.
|
|
36
|
+
- Each corpus SVG names its reference (Chromium, resvg, or both). The verdicts say
|
|
37
|
+
whether a rendering is better than it, matches it, comes close or differs, and what differs, in a
|
|
38
|
+
table with an icon per status. The comparison page shows the SVG in your own browser too, and a swipe
|
|
39
|
+
between any two renderers.
|
|
40
|
+
- `make review`: the renderings of each corpus SVG compared region by region at twice the resolution of the
|
|
41
|
+
references, with sheets of the cells that differ, to judge the verdicts at full size.
|
|
42
|
+
- The visual image has Trebuchet MS, the first font of Mermaid, as Safari has it: Mermaid labels fit their
|
|
43
|
+
boxes in the references.
|
|
44
|
+
- Chromium prints the references with the Accept-Language list of a desktop Chrome in English
|
|
45
|
+
(`en-US,en`): `systemLanguage` matches English as there.
|
|
46
|
+
- `corpus/fonts`: the fonts the resvg tests ask for. The references, weasysvg, resvg and the browser panel of the comparison page all use them.
|
weasysvg-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sergey Grigoriev
|
|
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.
|
weasysvg-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: weasysvg
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Native SVG rendering for WeasyPrint, close to Chromium: foreignObject, filters, masks, blending and text.
|
|
5
|
+
Project-URL: Homepage, https://github.com/grigoriev/weasysvg
|
|
6
|
+
Project-URL: Repository, https://github.com/grigoriev/weasysvg
|
|
7
|
+
Project-URL: Issues, https://github.com/grigoriev/weasysvg/issues
|
|
8
|
+
Author-email: Sergey Grigoriev <grigoriev@fastmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
23
|
+
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
|
|
24
|
+
Classifier: Topic :: Printing
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Requires-Dist: fonttools>=4.59.2
|
|
28
|
+
Requires-Dist: weasyprint<71,>=70
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: mypy==2.4.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pypdfium2==5.14.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest-cov==7.1.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest==9.1.1; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff==0.17.1; extra == 'dev'
|
|
35
|
+
Provides-Extra: visual
|
|
36
|
+
Requires-Dist: numpy==2.5.4; (python_version >= '3.12') and extra == 'visual'
|
|
37
|
+
Requires-Dist: playwright==1.64.0; extra == 'visual'
|
|
38
|
+
Requires-Dist: resvg-py==0.5.0; extra == 'visual'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
# weasysvg
|
|
42
|
+
|
|
43
|
+
[](https://github.com/grigoriev/weasysvg/actions/workflows/ci.yml)
|
|
44
|
+
[](https://scorecard.dev/viewer/?uri=github.com/grigoriev/weasysvg)
|
|
45
|
+
[](https://github.com/grigoriev/weasysvg/releases)
|
|
46
|
+
[](https://www.python.org/downloads/)
|
|
47
|
+
[](https://mypy-lang.org/)
|
|
48
|
+
[](https://github.com/astral-sh/ruff)
|
|
49
|
+
[](https://github.com/grigoriev/weasysvg/blob/main/LICENSE)
|
|
50
|
+
|
|
51
|
+
[](https://sonarcloud.io/summary/new_code?id=grigoriev_weasysvg)
|
|
52
|
+
[](https://sonarcloud.io/summary/new_code?id=grigoriev_weasysvg)
|
|
53
|
+
|
|
54
|
+
A plugin for [WeasyPrint](https://weasyprint.org) 70.x that renders SVG natively, close to Chromium.
|
|
55
|
+
|
|
56
|
+
## Why?
|
|
57
|
+
|
|
58
|
+
WeasyPrint draws SVG as vector graphics, but it lacks `<foreignObject>` and has gaps in filters, masks,
|
|
59
|
+
blending and text. Diagram tools depend on these: draw.io and Mermaid put their labels in
|
|
60
|
+
`<foreignObject>`, D2 masks its edge labels, and many tools draw shadows with filters. Services that
|
|
61
|
+
turn HTML into PDF therefore rasterize SVG in a headless Chromium first.
|
|
62
|
+
|
|
63
|
+
weasysvg closes these gaps inside WeasyPrint. The SVG stays vector, text stays selectable, and the
|
|
64
|
+
service needs no browser.
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
weasysvg runs on CPython 3.10 to 3.14 and on PyPy 3.11, as WeasyPrint 70 does. On PyPy a C compiler
|
|
69
|
+
must be present: zopfli, which WeasyPrint needs, has no PyPy wheel and builds from source.
|
|
70
|
+
|
|
71
|
+
Install it from PyPI:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
pip install weasysvg
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
weasysvg depends on WeasyPrint only. Every SVG feature it adds stays vector in the PDF, blur included.
|
|
78
|
+
The one exception is the noise of `feTurbulence`: it has no vector form, so it is an image, computed in
|
|
79
|
+
Python.
|
|
80
|
+
|
|
81
|
+
WeasyPrint needs Pango, see its
|
|
82
|
+
[installation guide](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html).
|
|
83
|
+
|
|
84
|
+
### Verify
|
|
85
|
+
|
|
86
|
+
The build of each release has signed provenance on GitHub, and the GitHub release carries its bundle.
|
|
87
|
+
PyPI and the GitHub release hold the same files, so verify a file from either with
|
|
88
|
+
`gh attestation verify <file> --repo grigoriev/weasysvg`. On PyPI each file also has a publish
|
|
89
|
+
attestation (PEP 740): it ties the upload to `release.yml` of this repository.
|
|
90
|
+
|
|
91
|
+
## Usage
|
|
92
|
+
|
|
93
|
+
Call `install()` once, before the first rendering:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
import weasyprint
|
|
97
|
+
import weasysvg
|
|
98
|
+
|
|
99
|
+
weasysvg.install()
|
|
100
|
+
weasyprint.HTML("report.html").write_pdf("report.pdf")
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`install()` patches WeasyPrint in place, for the whole process. It is idempotent, and it returns the
|
|
104
|
+
names of the installed features. Each feature can be turned off:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
weasysvg.install(filters=False, fonts=False)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
| Argument | Default | Effect |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `conditional_processing` | `True` | `<switch>`, `requiredExtensions`, `systemLanguage` |
|
|
113
|
+
| `foreign_object` | `True` | `<foreignObject>` content laid out by WeasyPrint |
|
|
114
|
+
| `filters` | `True` | filter chains, `drop-shadow()` and `blur()` |
|
|
115
|
+
| `paint` | `True` | gradients, patterns and masks |
|
|
116
|
+
| `blend` | `True` | `mix-blend-mode` (needs `paint`) |
|
|
117
|
+
| `text` | `True` | text baselines, decorations, font-size keywords |
|
|
118
|
+
| `fonts` | `True` | font family selection as Chromium does it |
|
|
119
|
+
| `fetch_cache` | `True` | one fetch per URL and SVG |
|
|
120
|
+
| `markers` | `True` | marker orientation as in Chromium |
|
|
121
|
+
| `language` | `"en"` | the language `systemLanguage` reads where the document has no `lang` |
|
|
122
|
+
|
|
123
|
+
weasysvg targets WeasyPrint 70.x and warns on any other major version: it patches internals that
|
|
124
|
+
change between releases.
|
|
125
|
+
|
|
126
|
+
## Features
|
|
127
|
+
|
|
128
|
+
| Area | What weasysvg adds |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `<foreignObject>` | The XHTML inside is laid out as a WeasyPrint document and drawn in place. The SVG stylesheet still matches it. All objects of one SVG share one layout run. Tables taller than their rows grow their rows, as browsers do. Disc, circle and square list markers are the shapes Chromium paints, placed from the ascent of the font. |
|
|
131
|
+
| Conditional processing | `<switch>` draws its first matching child. `requiredExtensions` and `systemLanguage` hide elements, so draw.io no longer draws both the label and its fallback. XHTML counts as supported only with `foreign_object` on; without it the fallback wins. `systemLanguage` reads the `lang` of the element that holds the image (`<html lang="de">`), else the `language` of `install()`, and matches as Chromium does with the Accept-Language list of that language (`de-CH` reads `de-CH,de`). An SVG from CSS (`background-image`, `list-style-image`, `content: url()`) reads `language`. |
|
|
132
|
+
| Filters | `feGaussianBlur`, `feOffset`, `feFlood`, `feDropShadow`, `feMerge`, `feBlend` normal, `feComposite` over, in and arithmetic, `feColorMatrix`, `feComponentTransfer`, `primitiveUnits="objectBoundingBox"`, and the CSS `drop-shadow()` and `blur()` functions, all in vector. `feTurbulence` noise is an image. A blur is a soft mask: exact for a plain rect, as the product of two Gaussian profiles, and in steps through the profile for other shapes. A color matrix or transfer function recolors each fill, stroke and gradient stop. |
|
|
133
|
+
| Masks and clips | A mask is set before the path starts, so viewers apply it. `maskContentUnits`, the region of an `objectBoundingBox` mask, self-referencing masks, and `mask` on a `<mask>` ignored as in Chromium. A clip path with `clip-rule="evenodd"`, text, `<use>` or clipped children becomes a soft mask. |
|
|
134
|
+
| Gradients and patterns | Tiles start at the user space origin, `patternTransform` moves the tile origin too, patterns used twice, a gradient cell that covers the shape under any `gradientTransform`, colors mixed unpremultiplied as in Chromium, radial `r` and `fr` percentages, `href` stops used twice, a gradient cell that Quartz and Splash do not drop. |
|
|
135
|
+
| Blending and opacity | `mix-blend-mode` as an isolated group. Opacity groups are no longer clipped to the bounding box, which cut off shifted text. |
|
|
136
|
+
| Text | Vertical `writing-mode` (`tb`, `vertical-rl`): CJK upright from the vertical origin of the font (`VORG`, `vmtx`), other scripts sideways, `rotate` about the origin of each glyph as in resvg. `textPath` (SVG 2 `path` attribute, `href`, `startOffset`, `text-anchor`, `<tspan>` inside, decorations). A run with one position at most is laid out whole, so Arabic joins, bidi orders and kerning and ligatures apply; laid out one character at a time, on a path or down a column, Arabic in one text node still takes its joining forms and runs right to left; `letter-spacing` skips cursive scripts. `dominant-baseline` and `alignment-baseline` from real font metrics, `text-decoration` placed and sized as in Chromium, underlines and overlines skip the ink of the glyphs, font-size keywords, a relative font size inherited as computed and `ex` from the x-height of the font, nested `<text>` ignored, `text-anchor` per text chunk. A filter, mask or clip on text uses the box of the text as drawn. |
|
|
137
|
+
| Fonts | A CSS family list resolves to one family as Chromium on Linux does, with its metric-compatible replacements (Arial to Liberation Sans). A character the family lacks comes from the sans-serif list, as in Chromium. |
|
|
138
|
+
| Markers | `orient="auto"` follows the tangents of lines, curves and arcs, and a mid marker bisects its vertex with the angle wrap of Chromium. |
|
|
139
|
+
| Presentation attributes | An empty attribute such as `fill=""` is ignored, as in browsers. |
|
|
140
|
+
|
|
141
|
+
## How it compares to Chromium
|
|
142
|
+
|
|
143
|
+
The bench in [`tools/visual`](https://github.com/grigoriev/weasysvg/tree/main/tools/visual) renders a corpus of 115 SVGs. The corpus holds draw.io,
|
|
144
|
+
Mermaid, PlantUML, Graphviz, D2 and BPMN diagrams, real-world files from Wikimedia Commons, and tests of
|
|
145
|
+
the resvg suite. Every SVG has a reference: Chromium, resvg, or both where they agree (69 SVGs). For the resvg tests the expected
|
|
146
|
+
image of the resvg suite decides between Chromium and resvg where they differ. `make review` compares the
|
|
147
|
+
renderings at twice the resolution of the panels, in an 8 x 8 grid, and a look at each cell that differs
|
|
148
|
+
gives the verdict:
|
|
149
|
+
|
|
150
|
+
| Verdict | WeasyPrint 70 | WeasyPrint 70 with weasysvg |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| ⬆️ better than the reference | 0 | 1 |
|
|
153
|
+
| ✅ matches the reference | 39 | 110 |
|
|
154
|
+
| 🟡 close to the reference | 22 | 4 |
|
|
155
|
+
| ❌ differs from the reference | 54 | 0 |
|
|
156
|
+
|
|
157
|
+
Of the 35 diagrams from draw.io, kroki and mermaid.ink, 34 match the reference and 1 is close.
|
|
158
|
+
Each verdict says what differs. The verdicts are in [`corpus/verdicts.json`](https://github.com/grigoriev/weasysvg/blob/main/corpus/verdicts.json). The [comparison page](https://grigoriev.github.io/weasysvg/corpus/comparison.html)
|
|
159
|
+
shows every SVG in Chromium, your own browser, resvg, WeasyPrint alone and WeasyPrint with weasysvg, in a row,
|
|
160
|
+
with the reference marked and a swipe between any two of them, as GitHub compares images;
|
|
161
|
+
[`corpus/COMPARISON.md`](https://github.com/grigoriev/weasysvg/blob/main/corpus/COMPARISON.md) holds the same in the repository.
|
|
162
|
+
|
|
163
|
+
## Known gaps
|
|
164
|
+
|
|
165
|
+
- On a `textPath` and in vertical text each character is laid out alone. Arabic takes its joining forms,
|
|
166
|
+
but loses the forms and ligatures some fonts pick from the whole word (Amiri): such a word runs longer.
|
|
167
|
+
- On a `textPath` and in vertical text, joining and right-to-left order stop at the edge of a `<tspan>`: an
|
|
168
|
+
Arabic word split by one falls apart there.
|
|
169
|
+
- An underline or overline skips no ink under a turned character (`rotate`) or on vertical text.
|
|
170
|
+
- Text with several `y` or `dy` values draws no decoration line.
|
|
171
|
+
- A plain rect is blurred exactly. Any other shape is blurred in levels by the distance to its nearest
|
|
172
|
+
edge, which knows nothing of the far edge: a filled shape thinner than about two deviations comes out
|
|
173
|
+
darker and sharper than in Chromium, and corners come out mitered inside the shape.
|
|
174
|
+
- Lighting, morphology, convolution and displacement have no vector form: the element draws
|
|
175
|
+
unfiltered, with a warning.
|
|
176
|
+
- `feComposite` arithmetic needs one input to be a flood of the whole filter region, or both inputs to
|
|
177
|
+
be the same. A translucent result composites over the value of the formula on nothing.
|
|
178
|
+
- Except on a plain rect, a blur with two different deviations uses their mean.
|
|
179
|
+
|
|
180
|
+
## Development
|
|
181
|
+
|
|
182
|
+
Tests and the bench run in Docker, since WeasyPrint needs Pango. See [CONTRIBUTING.md](https://github.com/grigoriev/weasysvg/blob/main/CONTRIBUTING.md).
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
make lint # ruff and mypy, on the host
|
|
186
|
+
make test # pytest with coverage, in Docker
|
|
187
|
+
make visual # the visual bench, report in tools/visual/out/report.html
|
|
188
|
+
make comparison # corpus/COMPARISON.md, the renderings of every SVG side by side
|
|
189
|
+
make upstream # probes of the WeasyPrint gaps and of the hooked internals
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
weasysvg supports the latest WeasyPrint major only. [UPGRADING.md](https://github.com/grigoriev/weasysvg/blob/main/UPGRADING.md) describes how a new one
|
|
193
|
+
is taken: which patches it makes redundant, which internals changed, what renders worse.
|
|
194
|
+
|
|
195
|
+
## Contributing
|
|
196
|
+
|
|
197
|
+
See [CONTRIBUTING.md](https://github.com/grigoriev/weasysvg/blob/main/CONTRIBUTING.md). Report vulnerabilities privately, see [SECURITY.md](https://github.com/grigoriev/weasysvg/blob/main/SECURITY.md).
|
|
198
|
+
|
|
199
|
+
## Disclaimer
|
|
200
|
+
|
|
201
|
+
This software is provided "as is", without warranty of any kind, as the LICENSE states. Use
|
|
202
|
+
it at your own risk. Sergey Grigoriev is not liable for damage from its use, as far as the law
|
|
203
|
+
allows. It is published free of charge, outside of any commercial offering, with no
|
|
204
|
+
obligation to support it. Security reports are welcome, see [SECURITY.md](https://github.com/grigoriev/weasysvg/blob/main/SECURITY.md).
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT, see [LICENSE](https://github.com/grigoriev/weasysvg/blob/main/LICENSE). The test corpus keeps the licenses of its sources, see
|
|
209
|
+
[corpus/SOURCES.md](https://github.com/grigoriev/weasysvg/blob/main/corpus/SOURCES.md).
|
weasysvg-0.1.0/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# weasysvg
|
|
2
|
+
|
|
3
|
+
[](https://github.com/grigoriev/weasysvg/actions/workflows/ci.yml)
|
|
4
|
+
[](https://scorecard.dev/viewer/?uri=github.com/grigoriev/weasysvg)
|
|
5
|
+
[](https://github.com/grigoriev/weasysvg/releases)
|
|
6
|
+
[](https://www.python.org/downloads/)
|
|
7
|
+
[](https://mypy-lang.org/)
|
|
8
|
+
[](https://github.com/astral-sh/ruff)
|
|
9
|
+
[](https://github.com/grigoriev/weasysvg/blob/main/LICENSE)
|
|
10
|
+
|
|
11
|
+
[](https://sonarcloud.io/summary/new_code?id=grigoriev_weasysvg)
|
|
12
|
+
[](https://sonarcloud.io/summary/new_code?id=grigoriev_weasysvg)
|
|
13
|
+
|
|
14
|
+
A plugin for [WeasyPrint](https://weasyprint.org) 70.x that renders SVG natively, close to Chromium.
|
|
15
|
+
|
|
16
|
+
## Why?
|
|
17
|
+
|
|
18
|
+
WeasyPrint draws SVG as vector graphics, but it lacks `<foreignObject>` and has gaps in filters, masks,
|
|
19
|
+
blending and text. Diagram tools depend on these: draw.io and Mermaid put their labels in
|
|
20
|
+
`<foreignObject>`, D2 masks its edge labels, and many tools draw shadows with filters. Services that
|
|
21
|
+
turn HTML into PDF therefore rasterize SVG in a headless Chromium first.
|
|
22
|
+
|
|
23
|
+
weasysvg closes these gaps inside WeasyPrint. The SVG stays vector, text stays selectable, and the
|
|
24
|
+
service needs no browser.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
weasysvg runs on CPython 3.10 to 3.14 and on PyPy 3.11, as WeasyPrint 70 does. On PyPy a C compiler
|
|
29
|
+
must be present: zopfli, which WeasyPrint needs, has no PyPy wheel and builds from source.
|
|
30
|
+
|
|
31
|
+
Install it from PyPI:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
pip install weasysvg
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
weasysvg depends on WeasyPrint only. Every SVG feature it adds stays vector in the PDF, blur included.
|
|
38
|
+
The one exception is the noise of `feTurbulence`: it has no vector form, so it is an image, computed in
|
|
39
|
+
Python.
|
|
40
|
+
|
|
41
|
+
WeasyPrint needs Pango, see its
|
|
42
|
+
[installation guide](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html).
|
|
43
|
+
|
|
44
|
+
### Verify
|
|
45
|
+
|
|
46
|
+
The build of each release has signed provenance on GitHub, and the GitHub release carries its bundle.
|
|
47
|
+
PyPI and the GitHub release hold the same files, so verify a file from either with
|
|
48
|
+
`gh attestation verify <file> --repo grigoriev/weasysvg`. On PyPI each file also has a publish
|
|
49
|
+
attestation (PEP 740): it ties the upload to `release.yml` of this repository.
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
Call `install()` once, before the first rendering:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import weasyprint
|
|
57
|
+
import weasysvg
|
|
58
|
+
|
|
59
|
+
weasysvg.install()
|
|
60
|
+
weasyprint.HTML("report.html").write_pdf("report.pdf")
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`install()` patches WeasyPrint in place, for the whole process. It is idempotent, and it returns the
|
|
64
|
+
names of the installed features. Each feature can be turned off:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
weasysvg.install(filters=False, fonts=False)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| Argument | Default | Effect |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `conditional_processing` | `True` | `<switch>`, `requiredExtensions`, `systemLanguage` |
|
|
73
|
+
| `foreign_object` | `True` | `<foreignObject>` content laid out by WeasyPrint |
|
|
74
|
+
| `filters` | `True` | filter chains, `drop-shadow()` and `blur()` |
|
|
75
|
+
| `paint` | `True` | gradients, patterns and masks |
|
|
76
|
+
| `blend` | `True` | `mix-blend-mode` (needs `paint`) |
|
|
77
|
+
| `text` | `True` | text baselines, decorations, font-size keywords |
|
|
78
|
+
| `fonts` | `True` | font family selection as Chromium does it |
|
|
79
|
+
| `fetch_cache` | `True` | one fetch per URL and SVG |
|
|
80
|
+
| `markers` | `True` | marker orientation as in Chromium |
|
|
81
|
+
| `language` | `"en"` | the language `systemLanguage` reads where the document has no `lang` |
|
|
82
|
+
|
|
83
|
+
weasysvg targets WeasyPrint 70.x and warns on any other major version: it patches internals that
|
|
84
|
+
change between releases.
|
|
85
|
+
|
|
86
|
+
## Features
|
|
87
|
+
|
|
88
|
+
| Area | What weasysvg adds |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `<foreignObject>` | The XHTML inside is laid out as a WeasyPrint document and drawn in place. The SVG stylesheet still matches it. All objects of one SVG share one layout run. Tables taller than their rows grow their rows, as browsers do. Disc, circle and square list markers are the shapes Chromium paints, placed from the ascent of the font. |
|
|
91
|
+
| Conditional processing | `<switch>` draws its first matching child. `requiredExtensions` and `systemLanguage` hide elements, so draw.io no longer draws both the label and its fallback. XHTML counts as supported only with `foreign_object` on; without it the fallback wins. `systemLanguage` reads the `lang` of the element that holds the image (`<html lang="de">`), else the `language` of `install()`, and matches as Chromium does with the Accept-Language list of that language (`de-CH` reads `de-CH,de`). An SVG from CSS (`background-image`, `list-style-image`, `content: url()`) reads `language`. |
|
|
92
|
+
| Filters | `feGaussianBlur`, `feOffset`, `feFlood`, `feDropShadow`, `feMerge`, `feBlend` normal, `feComposite` over, in and arithmetic, `feColorMatrix`, `feComponentTransfer`, `primitiveUnits="objectBoundingBox"`, and the CSS `drop-shadow()` and `blur()` functions, all in vector. `feTurbulence` noise is an image. A blur is a soft mask: exact for a plain rect, as the product of two Gaussian profiles, and in steps through the profile for other shapes. A color matrix or transfer function recolors each fill, stroke and gradient stop. |
|
|
93
|
+
| Masks and clips | A mask is set before the path starts, so viewers apply it. `maskContentUnits`, the region of an `objectBoundingBox` mask, self-referencing masks, and `mask` on a `<mask>` ignored as in Chromium. A clip path with `clip-rule="evenodd"`, text, `<use>` or clipped children becomes a soft mask. |
|
|
94
|
+
| Gradients and patterns | Tiles start at the user space origin, `patternTransform` moves the tile origin too, patterns used twice, a gradient cell that covers the shape under any `gradientTransform`, colors mixed unpremultiplied as in Chromium, radial `r` and `fr` percentages, `href` stops used twice, a gradient cell that Quartz and Splash do not drop. |
|
|
95
|
+
| Blending and opacity | `mix-blend-mode` as an isolated group. Opacity groups are no longer clipped to the bounding box, which cut off shifted text. |
|
|
96
|
+
| Text | Vertical `writing-mode` (`tb`, `vertical-rl`): CJK upright from the vertical origin of the font (`VORG`, `vmtx`), other scripts sideways, `rotate` about the origin of each glyph as in resvg. `textPath` (SVG 2 `path` attribute, `href`, `startOffset`, `text-anchor`, `<tspan>` inside, decorations). A run with one position at most is laid out whole, so Arabic joins, bidi orders and kerning and ligatures apply; laid out one character at a time, on a path or down a column, Arabic in one text node still takes its joining forms and runs right to left; `letter-spacing` skips cursive scripts. `dominant-baseline` and `alignment-baseline` from real font metrics, `text-decoration` placed and sized as in Chromium, underlines and overlines skip the ink of the glyphs, font-size keywords, a relative font size inherited as computed and `ex` from the x-height of the font, nested `<text>` ignored, `text-anchor` per text chunk. A filter, mask or clip on text uses the box of the text as drawn. |
|
|
97
|
+
| Fonts | A CSS family list resolves to one family as Chromium on Linux does, with its metric-compatible replacements (Arial to Liberation Sans). A character the family lacks comes from the sans-serif list, as in Chromium. |
|
|
98
|
+
| Markers | `orient="auto"` follows the tangents of lines, curves and arcs, and a mid marker bisects its vertex with the angle wrap of Chromium. |
|
|
99
|
+
| Presentation attributes | An empty attribute such as `fill=""` is ignored, as in browsers. |
|
|
100
|
+
|
|
101
|
+
## How it compares to Chromium
|
|
102
|
+
|
|
103
|
+
The bench in [`tools/visual`](https://github.com/grigoriev/weasysvg/tree/main/tools/visual) renders a corpus of 115 SVGs. The corpus holds draw.io,
|
|
104
|
+
Mermaid, PlantUML, Graphviz, D2 and BPMN diagrams, real-world files from Wikimedia Commons, and tests of
|
|
105
|
+
the resvg suite. Every SVG has a reference: Chromium, resvg, or both where they agree (69 SVGs). For the resvg tests the expected
|
|
106
|
+
image of the resvg suite decides between Chromium and resvg where they differ. `make review` compares the
|
|
107
|
+
renderings at twice the resolution of the panels, in an 8 x 8 grid, and a look at each cell that differs
|
|
108
|
+
gives the verdict:
|
|
109
|
+
|
|
110
|
+
| Verdict | WeasyPrint 70 | WeasyPrint 70 with weasysvg |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| ⬆️ better than the reference | 0 | 1 |
|
|
113
|
+
| ✅ matches the reference | 39 | 110 |
|
|
114
|
+
| 🟡 close to the reference | 22 | 4 |
|
|
115
|
+
| ❌ differs from the reference | 54 | 0 |
|
|
116
|
+
|
|
117
|
+
Of the 35 diagrams from draw.io, kroki and mermaid.ink, 34 match the reference and 1 is close.
|
|
118
|
+
Each verdict says what differs. The verdicts are in [`corpus/verdicts.json`](https://github.com/grigoriev/weasysvg/blob/main/corpus/verdicts.json). The [comparison page](https://grigoriev.github.io/weasysvg/corpus/comparison.html)
|
|
119
|
+
shows every SVG in Chromium, your own browser, resvg, WeasyPrint alone and WeasyPrint with weasysvg, in a row,
|
|
120
|
+
with the reference marked and a swipe between any two of them, as GitHub compares images;
|
|
121
|
+
[`corpus/COMPARISON.md`](https://github.com/grigoriev/weasysvg/blob/main/corpus/COMPARISON.md) holds the same in the repository.
|
|
122
|
+
|
|
123
|
+
## Known gaps
|
|
124
|
+
|
|
125
|
+
- On a `textPath` and in vertical text each character is laid out alone. Arabic takes its joining forms,
|
|
126
|
+
but loses the forms and ligatures some fonts pick from the whole word (Amiri): such a word runs longer.
|
|
127
|
+
- On a `textPath` and in vertical text, joining and right-to-left order stop at the edge of a `<tspan>`: an
|
|
128
|
+
Arabic word split by one falls apart there.
|
|
129
|
+
- An underline or overline skips no ink under a turned character (`rotate`) or on vertical text.
|
|
130
|
+
- Text with several `y` or `dy` values draws no decoration line.
|
|
131
|
+
- A plain rect is blurred exactly. Any other shape is blurred in levels by the distance to its nearest
|
|
132
|
+
edge, which knows nothing of the far edge: a filled shape thinner than about two deviations comes out
|
|
133
|
+
darker and sharper than in Chromium, and corners come out mitered inside the shape.
|
|
134
|
+
- Lighting, morphology, convolution and displacement have no vector form: the element draws
|
|
135
|
+
unfiltered, with a warning.
|
|
136
|
+
- `feComposite` arithmetic needs one input to be a flood of the whole filter region, or both inputs to
|
|
137
|
+
be the same. A translucent result composites over the value of the formula on nothing.
|
|
138
|
+
- Except on a plain rect, a blur with two different deviations uses their mean.
|
|
139
|
+
|
|
140
|
+
## Development
|
|
141
|
+
|
|
142
|
+
Tests and the bench run in Docker, since WeasyPrint needs Pango. See [CONTRIBUTING.md](https://github.com/grigoriev/weasysvg/blob/main/CONTRIBUTING.md).
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
make lint # ruff and mypy, on the host
|
|
146
|
+
make test # pytest with coverage, in Docker
|
|
147
|
+
make visual # the visual bench, report in tools/visual/out/report.html
|
|
148
|
+
make comparison # corpus/COMPARISON.md, the renderings of every SVG side by side
|
|
149
|
+
make upstream # probes of the WeasyPrint gaps and of the hooked internals
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
weasysvg supports the latest WeasyPrint major only. [UPGRADING.md](https://github.com/grigoriev/weasysvg/blob/main/UPGRADING.md) describes how a new one
|
|
153
|
+
is taken: which patches it makes redundant, which internals changed, what renders worse.
|
|
154
|
+
|
|
155
|
+
## Contributing
|
|
156
|
+
|
|
157
|
+
See [CONTRIBUTING.md](https://github.com/grigoriev/weasysvg/blob/main/CONTRIBUTING.md). Report vulnerabilities privately, see [SECURITY.md](https://github.com/grigoriev/weasysvg/blob/main/SECURITY.md).
|
|
158
|
+
|
|
159
|
+
## Disclaimer
|
|
160
|
+
|
|
161
|
+
This software is provided "as is", without warranty of any kind, as the LICENSE states. Use
|
|
162
|
+
it at your own risk. Sergey Grigoriev is not liable for damage from its use, as far as the law
|
|
163
|
+
allows. It is published free of charge, outside of any commercial offering, with no
|
|
164
|
+
obligation to support it. Security reports are welcome, see [SECURITY.md](https://github.com/grigoriev/weasysvg/blob/main/SECURITY.md).
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT, see [LICENSE](https://github.com/grigoriev/weasysvg/blob/main/LICENSE). The test corpus keeps the licenses of its sources, see
|
|
169
|
+
[corpus/SOURCES.md](https://github.com/grigoriev/weasysvg/blob/main/corpus/SOURCES.md).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "weasysvg"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Native SVG rendering for WeasyPrint, close to Chromium: foreignObject, filters, masks, blending and text."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Sergey Grigoriev", email = "grigoriev@fastmail.com" }
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
26
|
+
"Programming Language :: Python :: Implementation :: PyPy",
|
|
27
|
+
"Topic :: Multimedia :: Graphics :: Graphics Conversion",
|
|
28
|
+
"Topic :: Printing",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
requires-python = ">=3.10"
|
|
32
|
+
dependencies = [
|
|
33
|
+
# ink.py reads glyph outlines; WeasyPrint 70 requires it already
|
|
34
|
+
"fonttools>=4.59.2",
|
|
35
|
+
"weasyprint>=70,<71",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest==9.1.1",
|
|
41
|
+
"pytest-cov==7.1.0",
|
|
42
|
+
"mypy==2.4.0",
|
|
43
|
+
"ruff==0.17.1",
|
|
44
|
+
"pypdfium2==5.14.0",
|
|
45
|
+
]
|
|
46
|
+
# The visual regression bench in tools/visual, run in Docker
|
|
47
|
+
visual = [
|
|
48
|
+
"numpy==2.5.4; python_version >= '3.12'",
|
|
49
|
+
"playwright==1.64.0",
|
|
50
|
+
"resvg-py==0.5.0",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[project.urls]
|
|
54
|
+
Homepage = "https://github.com/grigoriev/weasysvg"
|
|
55
|
+
Repository = "https://github.com/grigoriev/weasysvg"
|
|
56
|
+
Issues = "https://github.com/grigoriev/weasysvg/issues"
|
|
57
|
+
|
|
58
|
+
[tool.hatch.build.targets.wheel]
|
|
59
|
+
packages = ["src/weasysvg"]
|
|
60
|
+
|
|
61
|
+
[tool.hatch.build.targets.sdist]
|
|
62
|
+
include = ["src/weasysvg", "tests", "README.md", "LICENSE", "CHANGELOG.md"]
|
|
63
|
+
|
|
64
|
+
[tool.pytest.ini_options]
|
|
65
|
+
testpaths = ["tests"]
|
|
66
|
+
|
|
67
|
+
[tool.ruff]
|
|
68
|
+
line-length = 240
|
|
69
|
+
target-version = "py310"
|
|
70
|
+
|
|
71
|
+
[tool.ruff.lint]
|
|
72
|
+
select = ["E", "F", "W", "I", "UP", "B", "C4", "SIM"]
|
|
73
|
+
ignore = []
|
|
74
|
+
|
|
75
|
+
[tool.ruff.lint.isort]
|
|
76
|
+
known-first-party = ["weasysvg"]
|
|
77
|
+
|
|
78
|
+
[tool.uv]
|
|
79
|
+
required-version = ">=0.5.0"
|
|
80
|
+
|
|
81
|
+
[tool.coverage.run]
|
|
82
|
+
source = ["weasysvg"]
|
|
83
|
+
branch = true
|
|
84
|
+
|
|
85
|
+
[tool.coverage.report]
|
|
86
|
+
fail_under = 90
|
|
87
|
+
show_missing = true
|
|
88
|
+
exclude_lines = [
|
|
89
|
+
"pragma: no cover",
|
|
90
|
+
"if TYPE_CHECKING:",
|
|
91
|
+
"if __name__ == .__main__.:",
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
[tool.mypy]
|
|
95
|
+
python_version = "3.10"
|
|
96
|
+
strict = true
|
|
97
|
+
warn_return_any = true
|
|
98
|
+
warn_unused_configs = true
|
|
99
|
+
disallow_untyped_defs = true
|
|
100
|
+
disallow_incomplete_defs = true
|
|
101
|
+
check_untyped_defs = true
|
|
102
|
+
disallow_untyped_decorators = true
|
|
103
|
+
no_implicit_optional = true
|
|
104
|
+
warn_redundant_casts = true
|
|
105
|
+
warn_unused_ignores = true
|
|
106
|
+
warn_no_return = true
|
|
107
|
+
follow_imports = "normal"
|
|
108
|
+
show_error_codes = true
|
|
109
|
+
|
|
110
|
+
# WeasyPrint ships no type information
|
|
111
|
+
[[tool.mypy.overrides]]
|
|
112
|
+
module = ["weasyprint.*", "weasyprint", "pypdfium2.*", "numpy.*", "fontTools.*"]
|
|
113
|
+
ignore_missing_imports = true
|