svg-ultralight 0.24.0__tar.gz → 0.54.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.

Potentially problematic release.


This version of svg-ultralight might be problematic. Click here for more details.

Files changed (59) hide show
  1. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/PKG-INFO +208 -208
  2. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/README.md +190 -190
  3. svg_ultralight-0.54.0/pyproject.toml +75 -0
  4. svg_ultralight-0.54.0/src/svg_ultralight/__init__.py +108 -0
  5. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/animate.py +40 -40
  6. svg_ultralight-0.54.0/src/svg_ultralight/attrib_hints.py +14 -0
  7. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/bounding_boxes/__init__.py +5 -5
  8. svg_ultralight-0.54.0/src/svg_ultralight/bounding_boxes/bound_helpers.py +189 -0
  9. svg_ultralight-0.54.0/src/svg_ultralight/bounding_boxes/padded_text_initializers.py +343 -0
  10. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/bounding_boxes/supports_bounds.py +167 -149
  11. svg_ultralight-0.54.0/src/svg_ultralight/bounding_boxes/type_bound_collection.py +74 -0
  12. svg_ultralight-0.54.0/src/svg_ultralight/bounding_boxes/type_bound_element.py +68 -0
  13. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/bounding_boxes/type_bounding_box.py +402 -315
  14. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/bounding_boxes/type_padded_text.py +424 -414
  15. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/constructors/__init__.py +14 -14
  16. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/constructors/new_element.py +120 -110
  17. svg_ultralight-0.54.0/src/svg_ultralight/font_tools/__init__.py +5 -0
  18. svg_ultralight-0.54.0/src/svg_ultralight/font_tools/comp_results.py +295 -0
  19. svg_ultralight-0.54.0/src/svg_ultralight/font_tools/font_info.py +820 -0
  20. svg_ultralight-0.54.0/src/svg_ultralight/image_ops.py +156 -0
  21. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/inkscape.py +261 -248
  22. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/layout.py +291 -279
  23. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/main.py +183 -182
  24. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/metadata.py +122 -122
  25. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/nsmap.py +36 -36
  26. svg_ultralight-0.54.0/src/svg_ultralight/py.typed +5 -0
  27. svg_ultralight-0.54.0/src/svg_ultralight/query.py +254 -0
  28. svg_ultralight-0.54.0/src/svg_ultralight/read_svg.py +58 -0
  29. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/root_elements.py +87 -87
  30. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/string_conversion.py +244 -207
  31. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/strings/__init__.py +21 -13
  32. svg_ultralight-0.54.0/src/svg_ultralight/strings/svg_strings.py +106 -0
  33. svg_ultralight-0.54.0/src/svg_ultralight/transformations.py +152 -0
  34. {svg-ultralight-0.24.0 → svg_ultralight-0.54.0}/src/svg_ultralight/unit_conversion.py +247 -248
  35. svg-ultralight-0.24.0/.pre-commit-config.yaml +0 -151
  36. svg-ultralight-0.24.0/dev-requirements.txt +0 -102
  37. svg-ultralight-0.24.0/pyproject.toml +0 -61
  38. svg-ultralight-0.24.0/setup.cfg +0 -4
  39. svg-ultralight-0.24.0/src/svg_ultralight/__init__.py +0 -54
  40. svg-ultralight-0.24.0/src/svg_ultralight/bounding_boxes/type_bound_element.py +0 -196
  41. svg-ultralight-0.24.0/src/svg_ultralight/py.typed +0 -0
  42. svg-ultralight-0.24.0/src/svg_ultralight/query.py +0 -179
  43. svg-ultralight-0.24.0/src/svg_ultralight/strings/svg_strings.py +0 -46
  44. svg-ultralight-0.24.0/src/svg_ultralight.egg-info/PKG-INFO +0 -208
  45. svg-ultralight-0.24.0/src/svg_ultralight.egg-info/SOURCES.txt +0 -41
  46. svg-ultralight-0.24.0/src/svg_ultralight.egg-info/dependency_links.txt +0 -1
  47. svg-ultralight-0.24.0/src/svg_ultralight.egg-info/requires.txt +0 -10
  48. svg-ultralight-0.24.0/src/svg_ultralight.egg-info/top_level.txt +0 -1
  49. svg-ultralight-0.24.0/tests/__init__.py +0 -0
  50. svg-ultralight-0.24.0/tests/conftest.py +0 -11
  51. svg-ultralight-0.24.0/tests/test_inkscape.py +0 -58
  52. svg-ultralight-0.24.0/tests/test_layout.py +0 -232
  53. svg-ultralight-0.24.0/tests/test_metadata.py +0 -87
  54. svg-ultralight-0.24.0/tests/test_new_element.py +0 -60
  55. svg-ultralight-0.24.0/tests/test_queries.py +0 -196
  56. svg-ultralight-0.24.0/tests/test_root_elements.py +0 -55
  57. svg-ultralight-0.24.0/tests/test_string_conversion.py +0 -71
  58. svg-ultralight-0.24.0/tests/test_svg_ultralight.py +0 -179
  59. svg-ultralight-0.24.0/tox.ini +0 -6
@@ -1,208 +1,208 @@
1
- Metadata-Version: 2.1
2
- Name: svg-ultralight
3
- Version: 0.24.0
4
- Summary: a sensible way to create svg files with Python
5
- Author-email: Shay Hill <shay_public@hotmail.com>
6
- License: MIT
7
- Requires-Python: >=3.9
8
- Description-Content-Type: text/markdown
9
- Requires-Dist: lxml
10
- Requires-Dist: pillow
11
- Requires-Dist: paragraphs
12
- Requires-Dist: types-lxml
13
- Provides-Extra: dev
14
- Requires-Dist: pytest; extra == "dev"
15
- Requires-Dist: commitizen; extra == "dev"
16
- Requires-Dist: pre-commit; extra == "dev"
17
- Requires-Dist: tox; extra == "dev"
18
-
19
- # svg_ultralight
20
-
21
- The most straightforward way to create SVG files with Python.
22
-
23
- ## Four principal functions:
24
-
25
- from svg_ultralight import new_svg_root, write_svg, write_png_from_svg, write_png
26
-
27
- ## One convenience:
28
-
29
- from svg_ultralight import NSMAP
30
-
31
- ### new_svg_root
32
- x_: Optional[float],
33
- y_: Optional[float],
34
- width_: Optional[float],
35
- height_: Optional[float],
36
- pad_: float = 0
37
- dpu_: float = 1
38
- nsmap: Optional[Dict[str, str]] = None (svg_ultralight.NSMAP if None)
39
- **attributes: Union[float, str],
40
- -> etree.Element
41
-
42
- Create an svg root element from viewBox style arguments and provide the necessary svg-specific attributes and namespaces. This is your window onto the scene.
43
-
44
- Three ways to call:
45
-
46
- 1. The trailing-underscore arguments are the same you'd use to create a `rect` element (plus `pad_` and `dpu_`). `new_svg_root` will infer `viewBox`, `width`, and `height` svg attributes from these values.
47
- 2. Use the svg attributes you already know: `viewBox`, `width`, `height`, etc. These will be written to the xml file.
48
- 3. Of course, you can combine 1. and 2. if you know what you're doing.
49
-
50
- See `namespaces` below.
51
-
52
- * `x_`: x value in upper-left corner
53
- * `y_`: y value in upper-left corner
54
- * `width_`: width of viewBox
55
- * `height_`: height of viewBox
56
- * `pad_`: the one small convenience I've provided. Optionally increase viewBox by `pad` in all directions.
57
- * `dpu_`: pixels per viewBox unit for output png images.
58
- * `nsmap`: namespaces. (defaults to svg_ultralight.NSMAP). Available as an argument should you wish to add additional namespaces. To do this, add items to NSMAP then call with `nsmap=NSMAP`.
59
- * `**attributes`: the trailing-underscore arguments are an *optional* shortcut for creating a scene. The entire svg interface is available to you through kwargs. See `A few helpers` below for details on attribute-name translation between Python and xml (the short version: `this_name` becomes `this-name` and `this_` becomes `this`)
60
-
61
- ### namespaces (svg_ultralight.NSMAP)
62
-
63
- `new_svg_root` will create a root with several available namespaces.
64
-
65
- * `"dc": "http://purl.org/dc/elements/1.1/"`
66
- * `"cc": "http://creativecommons.org/ns#"`
67
- * `"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#"`
68
- * `"svg": "http://www.w3.org/2000/svg"`
69
- * `"xlink": "http://www.w3.org/1999/xlink"`
70
- * `"sodipodi": "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"`
71
- * `"inkscape": "http://www.inkscape.org/namespaces/inkscape"`
72
-
73
- I have made these available to you as `svg_ultralight.NSMAP`
74
-
75
- ### write_svg
76
- svg: str,
77
- xml: etree.Element,
78
- stylesheet: Optional[str] = None,
79
- do_link_css: bool = False,
80
- **tostring_kwargs,
81
- -> str:
82
-
83
- Write an xml element as an svg file. This will link or inline your css code and insert the necessary declaration, doctype, and processing instructions.
84
-
85
- * `svg`: path to output file (include extension .svg)
86
- * `param xml`: root node of your svg geometry (created by `new_svg_root`)
87
- * `stylesheet`: optional path to a css stylesheet
88
- * `do_link_css`: link to stylesheet, else (default) write contents of stylesheet into svg (ignored if `stylesheet` is None). If you have a stylesheet somewhere, the default action is to dump the entire contents into your svg file. Linking to the stylesheet is more elegant, but inlining *always* works.
89
- * `**tostring_kwargs`: optional kwarg arguments for `lxml.etree.tostring`. Passing `xml_declaration=True` by itself will create an xml declaration with encoding set to UTF-8 and an svg DOCTYPE. These defaults can be overridden with keyword arguments `encoding` and `doctype`. If you don't know what this is, you can probably get away without it.
90
- * `returns`: for convenience, returns svg filename (`svg`)
91
- * `effects`: creates svg file at `svg`
92
-
93
- ### write_png_from_svg
94
-
95
- inkscape_exe: str,
96
- svg: str
97
- png: Optional[str]
98
- -> str
99
-
100
- Convert an svg file to a png. Python does not have a library for this. That has an upside, as any library would be one more set of svg implementation idiosyncrasies we'd have to deal with. Inkscape will convert the file. This function provides the necessary command-line arguments.
101
-
102
- * `inkscape_exe`: path to inkscape.exe
103
- * `svg`: path to svg file
104
- * `png`: optional path to png output (if not given, png name will be inferred from `svg`: `'name.svg'` becomes `'name.png'`)
105
- * `return`: png filename
106
- * `effects`: creates png file at `png` (or infers png path and filename from `svg`)
107
-
108
- ### write_png
109
-
110
- inkscape_exe: str,
111
- png: str,
112
- xml: etree.Element,
113
- stylesheet: Optional[str] = None
114
- -> str
115
-
116
- Create a png without writing an initial svg to your filesystem. This is not faster (it may be slightly slower), but it may be important when writing many images (animation frames) to your filesystem.
117
-
118
- * `inkscape_exe`: path to inkscape.exe
119
- * `png`: path to output file (include extension .png)
120
- * `param xml`: root node of your svg geometry (created by `new_svg_root`)
121
- * `stylesheet`: optional path to a css stylesheet
122
- * `returns`: for convenience, returns png filename (`png`)
123
- * `effects`: creates png file at `png`
124
-
125
- ## A few helpers:
126
-
127
- from svg_ultralight.constructors import new_element, new_sub_element
128
-
129
- I do want to keep this ultralight and avoid creating some pseudo scripting language between Python and lxml, but here are two very simple, very optional functions to save your having to `str()` every argument to `etree.Element`.
130
-
131
- ### constructors.new_element
132
-
133
- tag: str
134
- **params: Union[str, float]
135
- -> etree.Element
136
-
137
- Python allows underscores in variable names; xml uses dashes.
138
-
139
- Python understands numbers; xml wants strings.
140
-
141
- This is a convenience function to swap `"_"` for `"-"` and `10.2` for `"10.2"` before creating an xml element.
142
-
143
- Translates numbers to strings
144
-
145
- >>> elem = new_element('line', x1=0, y1=0, x2=5, y2=5)
146
- >>> etree.tostring(elem)
147
- b'<line x1="0" y1="0" x2="5" y2="5"/>'
148
-
149
- Translates underscores to hyphens
150
-
151
- >>> elem = new_element('line', stroke_width=1)
152
- >>> etree.tostring(elem)
153
- b'<line stroke-width="1"/>'
154
-
155
- Removes trailing underscores. You'll almost certainly want to use reserved names like ``class`` as svg parameters. This
156
- can be done by passing the name with a trailing underscore.
157
-
158
- >>> elem = new_element('line', class_='thick_line')
159
- >>> etree.tostring(elem)
160
- b'<line class="thick_line"/>'
161
-
162
- Special handling for a 'text' argument. Places value between element tags.
163
-
164
- >>> elem = new_element('text', text='please star my project')
165
- >>> etree.tostring(elem)
166
- b'<text>please star my project</text>'
167
-
168
- ### constructors.new_sub_element
169
-
170
- parent: etree.Element
171
- tag: str
172
- **params: Union[str, float]
173
- -> etree.Element
174
-
175
- As above, but creates a subelement.
176
-
177
- >>> parent = etree.Element('g')
178
- >>> _ = new_sub_element('rect')
179
- >>> etree.tostring(parent)
180
- b'<g><rect/></g>'
181
-
182
- ### update_element
183
-
184
- Another way to add params through the new_element name / float translator. Again unnecessary, but potentially helpful. Easily understood from the code or docstrings.
185
-
186
- ## Extras:
187
-
188
- ### query.map_ids_to_bounding_boxes
189
-
190
- Python cannot parse an svg file. Python can *create* an svg file, and Inkscape can parse (and inspect) it. Inkscape has a command-line interface capable of reading an svg file and returning some limited information. This is the only way I know for a Python program to:
191
-
192
- 1. create an svg file (optionally without writing to filesystem)
193
- 2. query the svg file for bounding-box information
194
- 3. create an adjusted svg file.
195
-
196
- This would be necessary for, e.g., algorithmically fitting text in a box.
197
-
198
- from svg_ultralight.queries import map_ids_to_bounding_boxes
199
-
200
- You can get a tiny bit more sophisticated with Inkscape bounding-box queries, but not much. This will give you pretty much all you can get out of it.
201
-
202
- ### animate.write_gif
203
-
204
- Create an animated gif from a sequence of png filenames. This is a Pillow one-liner, but it's convenient for me to have it, so it might be convenient for you. Requires pillow, which is not a project dependency.
205
-
206
- from svg_ultralight.animate import write_gif
207
-
208
- [Full Documentation and Tutorial](https://shayallenhill.com/svg-with-css-in-python/)
1
+ Metadata-Version: 2.4
2
+ Name: svg-ultralight
3
+ Version: 0.54.0
4
+ Summary: a sensible way to create svg files with Python
5
+ Author: Shay Hill
6
+ Author-email: Shay Hill <shay_public@hotmail.com>
7
+ License-Expression: MIT
8
+ Requires-Dist: cssutils>=2.11.1
9
+ Requires-Dist: fonttools>=4.60.1
10
+ Requires-Dist: lxml>=6.0.2
11
+ Requires-Dist: paragraphs>=1.0.1
12
+ Requires-Dist: pillow>=11.3.0
13
+ Requires-Dist: svg-path-data>=0.5.3
14
+ Requires-Dist: types-lxml>=2025.8.25
15
+ Requires-Dist: typing-extensions>=4.15.0
16
+ Requires-Python: >=3.10
17
+ Description-Content-Type: text/markdown
18
+
19
+ # svg_ultralight
20
+
21
+ The most straightforward way to create SVG files with Python.
22
+
23
+ ## Four principal functions:
24
+
25
+ from svg_ultralight import new_svg_root, write_svg, write_png_from_svg, write_png
26
+
27
+ ## One convenience:
28
+
29
+ from svg_ultralight import NSMAP
30
+
31
+ ### new_svg_root
32
+ x_: Optional[float],
33
+ y_: Optional[float],
34
+ width_: Optional[float],
35
+ height_: Optional[float],
36
+ pad_: float = 0
37
+ dpu_: float = 1
38
+ nsmap: Optional[Dict[str, str]] = None (svg_ultralight.NSMAP if None)
39
+ **attributes: Union[float, str],
40
+ -> etree.Element
41
+
42
+ Create an svg root element from viewBox style arguments and provide the necessary svg-specific attributes and namespaces. This is your window onto the scene.
43
+
44
+ Three ways to call:
45
+
46
+ 1. The trailing-underscore arguments are the same you'd use to create a `rect` element (plus `pad_` and `dpu_`). `new_svg_root` will infer `viewBox`, `width`, and `height` svg attributes from these values.
47
+ 2. Use the svg attributes you already know: `viewBox`, `width`, `height`, etc. These will be written to the xml file.
48
+ 3. Of course, you can combine 1. and 2. if you know what you're doing.
49
+
50
+ See `namespaces` below.
51
+
52
+ * `x_`: x value in upper-left corner
53
+ * `y_`: y value in upper-left corner
54
+ * `width_`: width of viewBox
55
+ * `height_`: height of viewBox
56
+ * `pad_`: the one small convenience I've provided. Optionally increase viewBox by `pad` in all directions.
57
+ * `dpu_`: pixels per viewBox unit for output png images.
58
+ * `nsmap`: namespaces. (defaults to svg_ultralight.NSMAP). Available as an argument should you wish to add additional namespaces. To do this, add items to NSMAP then call with `nsmap=NSMAP`.
59
+ * `**attributes`: the trailing-underscore arguments are an *optional* shortcut for creating a scene. The entire svg interface is available to you through kwargs. See `A few helpers` below for details on attribute-name translation between Python and xml (the short version: `this_name` becomes `this-name` and `this_` becomes `this`)
60
+
61
+ ### namespaces (svg_ultralight.NSMAP)
62
+
63
+ `new_svg_root` will create a root with several available namespaces.
64
+
65
+ * `"dc": "http://purl.org/dc/elements/1.1/"`
66
+ * `"cc": "http://creativecommons.org/ns#"`
67
+ * `"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#"`
68
+ * `"svg": "http://www.w3.org/2000/svg"`
69
+ * `"xlink": "http://www.w3.org/1999/xlink"`
70
+ * `"sodipodi": "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"`
71
+ * `"inkscape": "http://www.inkscape.org/namespaces/inkscape"`
72
+
73
+ I have made these available to you as `svg_ultralight.NSMAP`
74
+
75
+ ### write_svg
76
+ svg: str,
77
+ xml: etree.Element,
78
+ stylesheet: Optional[str] = None,
79
+ do_link_css: bool = False,
80
+ **tostring_kwargs,
81
+ -> str:
82
+
83
+ Write an xml element as an svg file. This will link or inline your css code and insert the necessary declaration, doctype, and processing instructions.
84
+
85
+ * `svg`: path to output file (include extension .svg)
86
+ * `param xml`: root node of your svg geometry (created by `new_svg_root`)
87
+ * `stylesheet`: optional path to a css stylesheet
88
+ * `do_link_css`: link to stylesheet, else (default) write contents of stylesheet into svg (ignored if `stylesheet` is None). If you have a stylesheet somewhere, the default action is to dump the entire contents into your svg file. Linking to the stylesheet is more elegant, but inlining *always* works.
89
+ * `**tostring_kwargs`: optional kwarg arguments for `lxml.etree.tostring`. Passing `xml_declaration=True` by itself will create an xml declaration with encoding set to UTF-8 and an svg DOCTYPE. These defaults can be overridden with keyword arguments `encoding` and `doctype`. If you don't know what this is, you can probably get away without it.
90
+ * `returns`: for convenience, returns svg filename (`svg`)
91
+ * `effects`: creates svg file at `svg`
92
+
93
+ ### write_png_from_svg
94
+
95
+ inkscape_exe: str,
96
+ svg: str
97
+ png: Optional[str]
98
+ -> str
99
+
100
+ Convert an svg file to a png. Python does not have a library for this. That has an upside, as any library would be one more set of svg implementation idiosyncrasies we'd have to deal with. Inkscape will convert the file. This function provides the necessary command-line arguments.
101
+
102
+ * `inkscape_exe`: path to inkscape.exe
103
+ * `svg`: path to svg file
104
+ * `png`: optional path to png output (if not given, png name will be inferred from `svg`: `'name.svg'` becomes `'name.png'`)
105
+ * `return`: png filename
106
+ * `effects`: creates png file at `png` (or infers png path and filename from `svg`)
107
+
108
+ ### write_png
109
+
110
+ inkscape_exe: str,
111
+ png: str,
112
+ xml: etree.Element,
113
+ stylesheet: Optional[str] = None
114
+ -> str
115
+
116
+ Create a png without writing an initial svg to your filesystem. This is not faster (it may be slightly slower), but it may be important when writing many images (animation frames) to your filesystem.
117
+
118
+ * `inkscape_exe`: path to inkscape.exe
119
+ * `png`: path to output file (include extension .png)
120
+ * `param xml`: root node of your svg geometry (created by `new_svg_root`)
121
+ * `stylesheet`: optional path to a css stylesheet
122
+ * `returns`: for convenience, returns png filename (`png`)
123
+ * `effects`: creates png file at `png`
124
+
125
+ ## A few helpers:
126
+
127
+ from svg_ultralight.constructors import new_element, new_sub_element
128
+
129
+ I do want to keep this ultralight and avoid creating some pseudo scripting language between Python and lxml, but here are two very simple, very optional functions to save your having to `str()` every argument to `etree.Element`.
130
+
131
+ ### constructors.new_element
132
+
133
+ tag: str
134
+ **params: Union[str, float]
135
+ -> etree.Element
136
+
137
+ Python allows underscores in variable names; xml uses dashes.
138
+
139
+ Python understands numbers; xml wants strings.
140
+
141
+ This is a convenience function to swap `"_"` for `"-"` and `10.2` for `"10.2"` before creating an xml element.
142
+
143
+ Translates numbers to strings
144
+
145
+ >>> elem = new_element('line', x1=0, y1=0, x2=5, y2=5)
146
+ >>> etree.tostring(elem)
147
+ b'<line x1="0" y1="0" x2="5" y2="5"/>'
148
+
149
+ Translates underscores to hyphens
150
+
151
+ >>> elem = new_element('line', stroke_width=1)
152
+ >>> etree.tostring(elem)
153
+ b'<line stroke-width="1"/>'
154
+
155
+ Removes trailing underscores. You'll almost certainly want to use reserved names like ``class`` as svg parameters. This
156
+ can be done by passing the name with a trailing underscore.
157
+
158
+ >>> elem = new_element('line', class_='thick_line')
159
+ >>> etree.tostring(elem)
160
+ b'<line class="thick_line"/>'
161
+
162
+ Special handling for a 'text' argument. Places value between element tags.
163
+
164
+ >>> elem = new_element('text', text='please star my project')
165
+ >>> etree.tostring(elem)
166
+ b'<text>please star my project</text>'
167
+
168
+ ### constructors.new_sub_element
169
+
170
+ parent: etree.Element
171
+ tag: str
172
+ **params: Union[str, float]
173
+ -> etree.Element
174
+
175
+ As above, but creates a subelement.
176
+
177
+ >>> parent = etree.Element('g')
178
+ >>> _ = new_sub_element('rect')
179
+ >>> etree.tostring(parent)
180
+ b'<g><rect/></g>'
181
+
182
+ ### update_element
183
+
184
+ Another way to add params through the new_element name / float translator. Again unnecessary, but potentially helpful. Easily understood from the code or docstrings.
185
+
186
+ ## Extras:
187
+
188
+ ### query.map_elems_to_bounding_boxes
189
+
190
+ Python cannot parse an svg file. Python can *create* an svg file, and Inkscape can parse (and inspect) it. Inkscape has a command-line interface capable of reading an svg file and returning some limited information. This is the only way I know for a Python program to:
191
+
192
+ 1. create an svg file (optionally without writing to filesystem)
193
+ 2. query the svg file for bounding-box information
194
+ 3. create an adjusted svg file.
195
+
196
+ This would be necessary for, e.g., algorithmically fitting text in a box.
197
+
198
+ from svg_ultralight.queries import map_elems_to_bounding_boxes
199
+
200
+ You can get a tiny bit more sophisticated with Inkscape bounding-box queries, but not much. This will give you pretty much all you can get out of it.
201
+
202
+ ### animate.write_gif
203
+
204
+ Create an animated gif from a sequence of png filenames. This is a Pillow one-liner, but it's convenient for me to have it, so it might be convenient for you. Requires pillow, which is not a project dependency.
205
+
206
+ from svg_ultralight.animate import write_gif
207
+
208
+ [Full Documentation and Tutorial](https://shayallenhill.com/svg-with-css-in-python/)