svg-ultralight 0.39.0__py3-none-any.whl → 0.40.0__py3-none-any.whl

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.

@@ -36,11 +36,13 @@ if TYPE_CHECKING:
36
36
 
37
37
 
38
38
  def write_png_from_svg(
39
- inkscape: Path | str, svg: Path | str, png: Path | str | None = None
39
+ inkscape: str | os.PathLike[str],
40
+ svg: str | os.PathLike[str],
41
+ png: str | os.PathLike[str] | None = None,
40
42
  ) -> str:
41
43
  """Convert an svg file to a png.
42
44
 
43
- :param inkscape: path to inkscape executable (without .exe extension!)
45
+ :param inkscape: path to inkscape executable
44
46
  :param svg: path to svg file
45
47
  :param png: optional path to png output file
46
48
  :return: png filename
@@ -51,6 +53,7 @@ def write_png_from_svg(
51
53
  If no output png path is given, the output path will be inferred from the ``svg``
52
54
  filename.
53
55
  """
56
+ inkscape = Path(inkscape).with_suffix("") # remove .exe if present
54
57
  png = str(Path(svg).with_suffix(".png")) if png is None else str(png)
55
58
 
56
59
  # inkscape versions >= 1.0
@@ -69,14 +72,14 @@ def write_png_from_svg(
69
72
 
70
73
 
71
74
  def write_png(
72
- inkscape: Path | str,
73
- png: Path | str,
75
+ inkscape: str | os.PathLike[str],
76
+ png: str | os.PathLike[str],
74
77
  root: EtreeElement,
75
- stylesheet: str | None = None,
78
+ stylesheet: str | os.PathLike[str] | None = None,
76
79
  ) -> str:
77
80
  """Create a png file without writing an intermediate svg file.
78
81
 
79
- :param inkscape: path to inkscape executable (without .exe extension!)
82
+ :param inkscape: path to inkscape executable
80
83
  :param png: path to output png file
81
84
  :param root: root node of your svg geometry
82
85
  :param stylesheet: optional path to css stylesheet
@@ -95,11 +98,13 @@ def write_png(
95
98
 
96
99
 
97
100
  def write_pdf_from_svg(
98
- inkscape: Path | str, svg: Path | str, pdf: Path | str | None = None
101
+ inkscape: str | os.PathLike[str],
102
+ svg: str | os.PathLike[str],
103
+ pdf: str | os.PathLike[str] | None = None,
99
104
  ) -> str:
100
105
  """Convert an svg file to a pdf.
101
106
 
102
- :param inkscape: path to inkscape executable (without .exe extension!)
107
+ :param inkscape: path to inkscape executable
103
108
  :param svg: path to svg file
104
109
  :param pdf: optional path to png output file
105
110
  :return: pdf filename
@@ -110,6 +115,7 @@ def write_pdf_from_svg(
110
115
  If no output png path is given, the output path will be inferred from the ``svg``
111
116
  filename.
112
117
  """
118
+ inkscape = Path(inkscape).with_suffix("") # remove .exe if present
113
119
  pdf = str(Path(svg).with_suffix(".pdf")) if pdf is None else str(pdf)
114
120
 
115
121
  # inkscape versions >= 1.0
@@ -128,14 +134,14 @@ def write_pdf_from_svg(
128
134
 
129
135
 
130
136
  def write_pdf(
131
- inkscape: Path | str,
132
- pdf: Path | str,
137
+ inkscape: str | os.PathLike[str],
138
+ pdf: str | os.PathLike[str],
133
139
  root: EtreeElement,
134
- stylesheet: Path | str | None = None,
140
+ stylesheet: str | os.PathLike[str] | None = None,
135
141
  ) -> str:
136
142
  """Create a pdf file without writing an intermediate svg file.
137
143
 
138
- :param inkscape: path to inkscape executable (without .exe extension!)
144
+ :param inkscape: path to inkscape executable
139
145
  :param pdf: path to output pdf file
140
146
  :param root: root node of your svg geometry
141
147
  :param stylesheet: optional path to css stylesheet
@@ -154,7 +160,9 @@ def write_pdf(
154
160
 
155
161
 
156
162
  def export_text_to_path(
157
- inkscape: str | Path, input_file: str | Path, export_file: str | Path
163
+ inkscape: str | os.PathLike[str],
164
+ input_file: str | os.PathLike[str],
165
+ export_file: str | os.PathLike[str],
158
166
  ) -> str:
159
167
  """Export copy of svg file with text converted to paths.
160
168
 
@@ -166,6 +174,7 @@ def export_text_to_path(
166
174
 
167
175
  Find any text objects in an svg file and convert them to paths.
168
176
  """
177
+ inkscape = Path(inkscape).with_suffix("") # remove .exe if present
169
178
  command = [
170
179
  str(inkscape),
171
180
  "--export-text-to-path",
@@ -177,7 +186,9 @@ def export_text_to_path(
177
186
  return str(export_file)
178
187
 
179
188
 
180
- def convert_text_to_path(inkscape: str | Path, root: EtreeElement) -> EtreeElement:
189
+ def convert_text_to_path(
190
+ inkscape: str | os.PathLike[str], root: EtreeElement
191
+ ) -> EtreeElement:
181
192
  """Convert text to path in a root svg element.
182
193
 
183
194
  :param inkscape: Path to inkscape executable.
@@ -196,14 +207,14 @@ def convert_text_to_path(inkscape: str | Path, root: EtreeElement) -> EtreeEleme
196
207
 
197
208
 
198
209
  def write_root(
199
- inkscape: str | Path,
200
- filename: str | Path,
210
+ inkscape: str | os.PathLike[str],
211
+ filename: str | os.PathLike[str],
201
212
  root: EtreeElement,
202
213
  *,
203
214
  do_text_to_path: bool = True,
204
215
  do_svg: bool = True,
205
- do_png: bool | str | Path = False,
206
- do_pdf: bool | str | Path = False,
216
+ do_png: bool | str | os.PathLike[str] = False,
217
+ do_pdf: bool | str | os.PathLike[str] = False,
207
218
  ) -> EtreeElement:
208
219
  """Save xml in multiple file formats, optionally updating text to paths.
209
220
 
svg_ultralight/main.py CHANGED
@@ -30,6 +30,8 @@ else:
30
30
  from typing_extensions import TypeGuard
31
31
 
32
32
  if TYPE_CHECKING:
33
+ import os
34
+
33
35
  from lxml.etree import (
34
36
  _Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
35
37
  )
@@ -117,9 +119,9 @@ def new_svg_root(
117
119
 
118
120
 
119
121
  def write_svg(
120
- svg: Path | str | IO[bytes],
122
+ svg: str | Path | IO[bytes],
121
123
  root: EtreeElement,
122
- stylesheet: Path | str | None = None,
124
+ stylesheet: str | os.PathLike[str] | None = None,
123
125
  *,
124
126
  do_link_css: bool = False,
125
127
  **tostring_kwargs: str | bool,
@@ -182,7 +184,7 @@ def write_svg(
182
184
  if _is_io_bytes(svg):
183
185
  _ = svg.write(svg_contents)
184
186
  return svg.name
185
- if isinstance(svg, (Path, str)):
187
+ if isinstance(svg, (str, Path)):
186
188
  with Path(svg).open("wb") as svg_file:
187
189
  _ = svg_file.write(svg_contents)
188
190
  return str(svg)
svg_ultralight/query.py CHANGED
@@ -27,7 +27,6 @@ from warnings import warn
27
27
  from lxml import etree
28
28
 
29
29
  from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
30
- from svg_ultralight.bounding_boxes.type_padded_text import PaddedText
31
30
  from svg_ultralight.main import new_svg_root, write_svg
32
31
 
33
32
  if TYPE_CHECKING:
@@ -102,7 +101,7 @@ def _split_bb_string(bb_string: str) -> tuple[str, BoundingBox]:
102
101
 
103
102
 
104
103
  def map_elems_to_bounding_boxes(
105
- inkscape: str | Path, *elem_args: EtreeElement
104
+ inkscape: str | os.PathLike[str], *elem_args: EtreeElement
106
105
  ) -> dict[EtreeElement | Literal["svg"], BoundingBox]:
107
106
  r"""Query an svg file for bounding-box dimensions.
108
107
 
@@ -161,7 +160,9 @@ def map_elems_to_bounding_boxes(
161
160
  elem_id = elem.attrib.get("id")
162
161
  if not (elem_id): # id removed in a previous loop
163
162
  continue
164
- elem2bbox[elem] = id2bbox[elem_id]
163
+ with suppress(KeyError):
164
+ # some elems like <style> don't have a bounding box
165
+ elem2bbox[elem] = id2bbox[elem_id]
165
166
  if elem_id.startswith(_TEMP_ID_PREFIX):
166
167
  del elem.attrib["id"]
167
168
  elem2bbox["svg"] = BoundingBox.merged(*id2bbox.values())
@@ -198,7 +199,7 @@ def _try_bbox_cache(elem_hash: str) -> BoundingBox | None:
198
199
 
199
200
 
200
201
  def get_bounding_boxes(
201
- inkscape: str | Path, *elem_args: EtreeElement
202
+ inkscape: str | os.PathLike[str], *elem_args: EtreeElement
202
203
  ) -> tuple[BoundingBox, ...]:
203
204
  r"""Get bounding box around a single element (or multiple elements).
204
205
 
@@ -228,7 +229,9 @@ def get_bounding_boxes(
228
229
  return tuple(hash2bbox[h] for h in elem2hash.values())
229
230
 
230
231
 
231
- def get_bounding_box(inkscape: str | Path, elem: EtreeElement) -> BoundingBox:
232
+ def get_bounding_box(
233
+ inkscape: str | os.PathLike[str], elem: EtreeElement
234
+ ) -> BoundingBox:
232
235
  r"""Get bounding box around a single element.
233
236
 
234
237
  :param inkscape: path to an inkscape executable on your local file system
@@ -244,35 +247,3 @@ def clear_svg_ultralight_cache() -> None:
244
247
  """Clear all cached bounding boxes."""
245
248
  for cache_file in _CACHE_DIR.glob("*"):
246
249
  cache_file.unlink()
247
-
248
-
249
- def pad_text(
250
- inkscape: str | Path, text_elem: EtreeElement, capline_reference_char: str = "M"
251
- ) -> PaddedText:
252
- r"""Create a PaddedText instance from a text element.
253
-
254
- :param inkscape: path to an inkscape executable on your local file system
255
- IMPORTANT: path cannot end with ``.exe``.
256
- Use something like ``"C:\\Program Files\\Inkscape\\inkscape"``
257
- :param text_elem: an etree element with a text tag
258
- :param capline_reference_char: a character to use to determine the baseline and
259
- capline. The default "M" is a good choice, but you might need something else
260
- if using a weird font, or if you'd like to use the x-height instead of the
261
- capline.
262
- :return: a PaddedText instance
263
- """
264
- rmargin_ref = deepcopy(text_elem)
265
- capline_ref = deepcopy(text_elem)
266
- _ = rmargin_ref.attrib.pop("id", None)
267
- _ = capline_ref.attrib.pop("id", None)
268
- rmargin_ref.attrib["text-anchor"] = "end"
269
- capline_ref.text = capline_reference_char
270
-
271
- bboxes = get_bounding_boxes(inkscape, text_elem, rmargin_ref, capline_ref)
272
- bbox, rmargin_bbox, capline_bbox = bboxes
273
-
274
- tpad = bbox.y - capline_bbox.y
275
- rpad = -rmargin_bbox.x2
276
- bpad = capline_bbox.y2 - bbox.y2
277
- lpad = bbox.x
278
- return PaddedText(text_elem, bbox, tpad, rpad, bpad, lpad)
@@ -5,11 +5,11 @@
5
5
 
6
6
  Rounding some numbers to ensure quality svg rendering:
7
7
  * Rounding floats to six digits after the decimal
8
- * Rounding viewBox dimensions to ints
9
8
  """
10
9
 
11
10
  from __future__ import annotations
12
11
 
12
+ import binascii
13
13
  import re
14
14
  from contextlib import suppress
15
15
  from enum import Enum
@@ -216,3 +216,71 @@ def get_viewBox_str(
216
216
  format_number(x) for x in (x - pad_l, y - pad_t, width + pad_h, height + pad_v)
217
217
  ]
218
218
  return " ".join(dims)
219
+
220
+
221
+ # ===================================================================================
222
+ # Encode and decode arbitrary strings to / from valid CSS class names.
223
+ # ===================================================================================
224
+
225
+
226
+ # insert his before any class name that would otherwise start with a digit
227
+ _NAME_PREFIX = "__"
228
+
229
+ _DELIMITED_HEX = re.compile(r"_[0-9a-fA-F]{2,8}_")
230
+
231
+
232
+ def _encode_class_name_invalid_char_to_hex(char: str) -> str:
233
+ """Encode any invalid single char to a hex representation prefixed with '_x'.
234
+
235
+ :param char: The character to encode.
236
+ :return: A string in the format '_x' followed by the hex value of the character.
237
+
238
+ Return valid css-class-name characters unchanged. Encode others. Exception: This
239
+ function encodes `_`, which *are* valid CSS class characters, in order to reserve
240
+ underscores for `_` hex delimiters and `__` -name prefixes.
241
+ """
242
+ if re.match(r"[a-zA-Z0-9-]", char):
243
+ return char
244
+ hex_ = binascii.hexlify(char.encode("utf-8")).decode("ascii")
245
+ return f"_{hex_}_"
246
+
247
+
248
+ def encode_to_css_class_name(text: str) -> str:
249
+ """Convert text to a valid CSS class name in a reversible way.
250
+
251
+ :param text: The text to convert.
252
+ :return: A valid CSS class name derived from the text. The intended use is to pass
253
+ a font filename, so the filename can be decoded from the contents of an SVG
254
+ file and each css class created from a font file will, if the style is not
255
+ altered, have a unique class name.
256
+
257
+ Non-ascii characters like `é` will be encoded as hex, even if they are, by
258
+ documentation, valid CSS class characters. The class name will be ascii only.
259
+ """
260
+ css_class = "".join(_encode_class_name_invalid_char_to_hex(c) for c in text)
261
+ # add a prefix if the name starts with a digit or is empty
262
+ if not css_class or not re.match(r"^[a-zA-Z_]", css_class):
263
+ css_class = _NAME_PREFIX + css_class
264
+ return css_class
265
+
266
+
267
+ def decode_from_css_class_name(css_class: str) -> str:
268
+ """Reverse the conversion from `filename_to_css_class`.
269
+
270
+ :param css_class: The CSS class name to convert back to text. This will not
271
+ be meaningful if the class name was not created by encode_css_class_name. If
272
+ you use another string, there is a potential for a hex decoding error.
273
+ :return: The original filename passed to `filename_to_css_class`.
274
+ """
275
+ css_class = css_class.removeprefix(_NAME_PREFIX)
276
+
277
+ result = ""
278
+ while css_class:
279
+ if match := _DELIMITED_HEX.match(css_class):
280
+ hex_str = match.group(0)[1:-1]
281
+ result += binascii.unhexlify(hex_str).decode("utf-8")
282
+ css_class = css_class[len(match.group(0)) :]
283
+ else:
284
+ result += css_class[0]
285
+ css_class = css_class[1:]
286
+ return result
@@ -105,7 +105,7 @@ def get_transform_matrix(elem: EtreeElement) -> _Matrix:
105
105
  def new_transformation_matrix(
106
106
  transformation: _Matrix | None = None,
107
107
  *,
108
- scale: tuple[float, float] | None = None,
108
+ scale: tuple[float, float] | float | None = None,
109
109
  dx: float | None = None,
110
110
  dy: float | None = None,
111
111
  ) -> _Matrix:
@@ -115,10 +115,17 @@ def new_transformation_matrix(
115
115
  svg-style transformation matrix.
116
116
  """
117
117
  transformation = transformation or (1, 0, 0, 1, 0, 0)
118
- scale = scale or (1, 1)
118
+
119
+ if isinstance(scale, float):
120
+ scale_x, scale_y = (scale, scale)
121
+ elif scale is None:
122
+ scale_x, scale_y = (1, 1)
123
+ else:
124
+ scale_x, scale_y = cast("tuple[float, float]", scale)
125
+
119
126
  dx = dx or 0
120
127
  dy = dy or 0
121
- return mat_dot((scale[0], 0, 0, scale[1], dx, dy), transformation)
128
+ return mat_dot((scale_x, 0, 0, scale_y, dx, dy), transformation)
122
129
 
123
130
 
124
131
  def transform_element(elem: EtreeElement, matrix: _Matrix) -> EtreeElement:
@@ -1,14 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: svg-ultralight
3
- Version: 0.39.0
3
+ Version: 0.40.0
4
4
  Summary: a sensible way to create svg files with Python
5
5
  Author-email: Shay Hill <shay_public@hotmail.com>
6
6
  License: MIT
7
7
  Requires-Python: >=3.9
8
8
  Description-Content-Type: text/markdown
9
+ Requires-Dist: cssutils
10
+ Requires-Dist: fonttools
9
11
  Requires-Dist: lxml
10
- Requires-Dist: pillow
11
12
  Requires-Dist: paragraphs
13
+ Requires-Dist: pillow
12
14
  Requires-Dist: types-lxml
13
15
  Requires-Dist: typing-extensions
14
16
  Provides-Extra: dev
@@ -0,0 +1,35 @@
1
+ svg_ultralight/__init__.py,sha256=vINKVO2LVeGHBpD18mSWGC4qh-eS4ULk9JoGZSBuYoU,2705
2
+ svg_ultralight/animate.py,sha256=SMcQkeWAP9dD08Iyzy9qGG8Qk1p-14WfrB7WSN8Pj_4,1133
3
+ svg_ultralight/image_ops.py,sha256=6V9YkxnhZCBw_hbVyY0uxDj0pZgiEWBSGRuPuOYKY4w,4694
4
+ svg_ultralight/inkscape.py,sha256=ySCxWnQwEt1sosa1b4mEkR-ugpfoAeg9gs1OLPS69iI,9597
5
+ svg_ultralight/layout.py,sha256=7LV2I3u4EhqSc6ASvgwDtTZyV-Y1qt2wtvRtH2uKVAE,12799
6
+ svg_ultralight/main.py,sha256=_zY6F8zc1tAGSe8isBOK5ajpDB8d4I7x7zD2fjsP4SE,7475
7
+ svg_ultralight/metadata.py,sha256=xaIfqhKu52Dl4JOrRlpUsWkkE7Umw8j5Z4waFTli-kI,4234
8
+ svg_ultralight/nsmap.py,sha256=y63upO78Rr-JJT56RWWZuyrsILh6HPoY4GhbYnK1A0g,1244
9
+ svg_ultralight/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ svg_ultralight/query.py,sha256=iFFsK78TuUT6h3iv_V8_fwCggIAdYa97K7oOPhhoPuY,9711
11
+ svg_ultralight/root_elements.py,sha256=E_H7HXk0M5F3IyFVOxO8PQmhww1-sHTzJhx8hBJPZvg,2911
12
+ svg_ultralight/string_conversion.py,sha256=ZUehoKh1lzys1jqRDIhHWfpxi4TSUhNFHiQl57OCAr8,10324
13
+ svg_ultralight/transformations.py,sha256=T3vSxcTWOwWnwu3OF610LHMbKScUIVWICUAvru5zLnU,4488
14
+ svg_ultralight/unit_conversion.py,sha256=g07nhzXdjPvGcJmkhLdFbeDLrSmbI8uFoVgPo7G62Bg,9258
15
+ svg_ultralight/bounding_boxes/__init__.py,sha256=qUEn3r4s-1QNHaguhWhhaNfdP4tl_B6YEqxtiTFuzhQ,78
16
+ svg_ultralight/bounding_boxes/bound_helpers.py,sha256=LFkVsdYFKYCnEL6vLvEa_5cfu8D44ZGYeEEb7_0MnC0,7146
17
+ svg_ultralight/bounding_boxes/padded_text_initializers.py,sha256=ZR5IsRKuH8beU0Qe2aVldmWXwH4aji003uxU353ulFg,7611
18
+ svg_ultralight/bounding_boxes/supports_bounds.py,sha256=T7LGse58fDBgmlzupSC63C1ZMXjFbyzBTsTUaqD_4Sw,4513
19
+ svg_ultralight/bounding_boxes/type_bound_collection.py,sha256=NAEpqo9H9ewhuLcOmBnMWUE0zQ1t4bvckovgvWy6hIo,2645
20
+ svg_ultralight/bounding_boxes/type_bound_element.py,sha256=Sc-R0uXkb0aS8-OcyM5pDukKhFUka0G6KCp6LcYDcIU,2204
21
+ svg_ultralight/bounding_boxes/type_bounding_box.py,sha256=bABFT-BwVdOmRJ-BHOLE_7LZv57MDwqABHvRDcVmvtI,13509
22
+ svg_ultralight/bounding_boxes/type_padded_text.py,sha256=WNIoqC9pfB8g_00P6RHcBdNE6VniqlLJXw_bh-GNjFA,13098
23
+ svg_ultralight/constructors/__init__.py,sha256=XLOInLhzMERWNnFAs-itMs-OZrBOpvQthZJ2T5duqBE,327
24
+ svg_ultralight/constructors/new_element.py,sha256=hRUW2hR_BTkthEqPClYV7-IeFe9iv2zwb6ehp1k1xDk,3475
25
+ svg_ultralight/font_tools/__init__.py,sha256=NX3C0vvoB-G4S-h1f0NLWePjYAMMR37D1cl_G4WBjHc,83
26
+ svg_ultralight/font_tools/comp_results.py,sha256=gB1RHIHcltbOqWZ0s4xCRKEIMob7MWgPWjKv5hA7B8Q,10481
27
+ svg_ultralight/font_tools/font_css.py,sha256=oKChLEwE18q-rKrt7hEkpBzGQBp8u9VWFxPpIKH67o4,2780
28
+ svg_ultralight/font_tools/font_info.py,sha256=8bXdsbIY2rbZ3Q1UnxR3B4nPf31MZivS40mEOcCsb44,20849
29
+ svg_ultralight/font_tools/globs.py,sha256=JdrrGMqDtD4WcY7YGUWV43DUW63RVev-x9vWqsQUhxU,119
30
+ svg_ultralight/strings/__init__.py,sha256=BMGhF1pulscIgkiYvZLr6kPRR0L4lW0jUNFxkul4_EM,295
31
+ svg_ultralight/strings/svg_strings.py,sha256=FQNxNmMkR2M-gCFo_woQKXLgCHi3ncUlRMiaRR_a9nQ,1978
32
+ svg_ultralight-0.40.0.dist-info/METADATA,sha256=hUDb0ZUHgfMWRmLELiaw9XW55FtZlFV0CF5f36S4Ms8,9022
33
+ svg_ultralight-0.40.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ svg_ultralight-0.40.0.dist-info/top_level.txt,sha256=se-6yqM_0Yg5orJKvKWdjQZ4iR4G_EjhL7oRgju-fdY,15
35
+ svg_ultralight-0.40.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,29 +0,0 @@
1
- svg_ultralight/__init__.py,sha256=wUc79mKsG6lGZ1xaYijyJ4Sm9lG5-5XgRArVsCI0niY,2554
2
- svg_ultralight/animate.py,sha256=JSrBm-59BcNXDF0cGgl4-C89eBunjevZnwZxIWt48TU,1112
3
- svg_ultralight/image_ops.py,sha256=PXN_p5GX91UTvhnwwU-bPuj6WzM9wCx1SqfzR5icNnQ,4686
4
- svg_ultralight/inkscape.py,sha256=tVFPtwsUcGKGODmYhC9IdGLyT7OAeNCVsDN0hPBSSgg,9194
5
- svg_ultralight/layout.py,sha256=7LV2I3u4EhqSc6ASvgwDtTZyV-Y1qt2wtvRtH2uKVAE,12799
6
- svg_ultralight/main.py,sha256=VA7tVMO7fiRI_JkEGaH7UFgzJ5YIbHKx4VHfMnT50hI,7446
7
- svg_ultralight/metadata.py,sha256=xaIfqhKu52Dl4JOrRlpUsWkkE7Umw8j5Z4waFTli-kI,4234
8
- svg_ultralight/nsmap.py,sha256=y63upO78Rr-JJT56RWWZuyrsILh6HPoY4GhbYnK1A0g,1244
9
- svg_ultralight/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- svg_ultralight/query.py,sha256=wR8oixRYA489k03RU5apXaoami2KvYl8BKmwypQGTi0,10972
11
- svg_ultralight/root_elements.py,sha256=E_H7HXk0M5F3IyFVOxO8PQmhww1-sHTzJhx8hBJPZvg,2911
12
- svg_ultralight/string_conversion.py,sha256=7gaUWEJptAVZawlvoAJ7JoP996nALoJrAByM3o219Tc,7462
13
- svg_ultralight/transformations.py,sha256=h1GUD4hvo10ugnSwShDmrwzF048yfug7lCWqCzOTxWs,4296
14
- svg_ultralight/unit_conversion.py,sha256=g07nhzXdjPvGcJmkhLdFbeDLrSmbI8uFoVgPo7G62Bg,9258
15
- svg_ultralight/bounding_boxes/__init__.py,sha256=qUEn3r4s-1QNHaguhWhhaNfdP4tl_B6YEqxtiTFuzhQ,78
16
- svg_ultralight/bounding_boxes/bound_helpers.py,sha256=LFkVsdYFKYCnEL6vLvEa_5cfu8D44ZGYeEEb7_0MnC0,7146
17
- svg_ultralight/bounding_boxes/supports_bounds.py,sha256=Yi696oJ393y29vql0U6kLMR3soSggLB3_wSACHppoJo,4505
18
- svg_ultralight/bounding_boxes/type_bound_collection.py,sha256=yW-gwehTrLhgG4Rk-wd6XWP0oLj7Yh_Njrudm8Dn1fk,2637
19
- svg_ultralight/bounding_boxes/type_bound_element.py,sha256=v-XwW1bxA3tT0CzLWOrRO5EHtLA3ivds8DyA5KFju6w,2196
20
- svg_ultralight/bounding_boxes/type_bounding_box.py,sha256=XsjM6nR5bKRLFa8z1U84GIC-YbleKoXa0s-UScz9Ewo,13621
21
- svg_ultralight/bounding_boxes/type_padded_text.py,sha256=fiDZoHIaQbGK8ETrPRa2wa5ykbdFBeeDHw9zGqKtD6E,10674
22
- svg_ultralight/constructors/__init__.py,sha256=XLOInLhzMERWNnFAs-itMs-OZrBOpvQthZJ2T5duqBE,327
23
- svg_ultralight/constructors/new_element.py,sha256=hRUW2hR_BTkthEqPClYV7-IeFe9iv2zwb6ehp1k1xDk,3475
24
- svg_ultralight/strings/__init__.py,sha256=BMGhF1pulscIgkiYvZLr6kPRR0L4lW0jUNFxkul4_EM,295
25
- svg_ultralight/strings/svg_strings.py,sha256=FQNxNmMkR2M-gCFo_woQKXLgCHi3ncUlRMiaRR_a9nQ,1978
26
- svg_ultralight-0.39.0.dist-info/METADATA,sha256=--QD3_OuduOUZx2fsCx6FsgTaDAuPAFHkkeKxCKY5Dw,8971
27
- svg_ultralight-0.39.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
28
- svg_ultralight-0.39.0.dist-info/top_level.txt,sha256=se-6yqM_0Yg5orJKvKWdjQZ4iR4G_EjhL7oRgju-fdY,15
29
- svg_ultralight-0.39.0.dist-info/RECORD,,