svg-ultralight 0.44.0__py3-none-any.whl → 0.45.1__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.

@@ -0,0 +1,14 @@
1
+ """Type hints for pass-through arguments to lxml constructors.
2
+
3
+ :author: Shay Hill
4
+ :created: 2025-07-09
5
+ """
6
+
7
+ from collections.abc import Mapping
8
+ from typing import Union
9
+
10
+ # Types svg_ultralight can format to pass through to lxml constructors.
11
+ ElemAttrib = Union[str, float, None]
12
+
13
+ # Type for an optional dictionary of element attributes.
14
+ OptionalElemAttribMapping = Union[Mapping[str, ElemAttrib], None]
@@ -8,6 +8,7 @@ from __future__ import annotations
8
8
 
9
9
  from typing import TYPE_CHECKING
10
10
 
11
+ from lxml import etree
11
12
  from lxml.etree import _Element as EtreeElement # pyright: ignore[reportPrivateUsage]
12
13
 
13
14
  from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
@@ -19,14 +20,14 @@ from svg_ultralight.constructors import new_element
19
20
  if TYPE_CHECKING:
20
21
  import os
21
22
 
23
+ from svg_ultralight.attrib_hints import ElemAttrib
22
24
  from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
23
- from lxml import etree
24
25
 
25
26
  _Matrix = tuple[float, float, float, float, float, float]
26
27
 
27
28
 
28
29
  def new_element_union(
29
- *elems: EtreeElement | SupportsBounds, **attributes: float | str
30
+ *elems: EtreeElement | SupportsBounds, **attributes: ElemAttrib
30
31
  ) -> EtreeElement:
31
32
  """Get the union of any elements found in the given arguments.
32
33
 
@@ -186,13 +187,13 @@ def _get_view_box(elem: EtreeElement) -> tuple[float, float, float, float]:
186
187
  return x, y, width, height
187
188
 
188
189
 
189
- def parse_bound_element(svg_fil: str | os.PathLike[str]) -> BoundElement:
190
+ def parse_bound_element(svg_file: str | os.PathLike[str]) -> BoundElement:
190
191
  """Import an element as a BoundElement.
191
192
 
192
193
  :param elem: the element to import.
193
194
  :return: a BoundElement instance.
194
195
  """
195
- tree = etree.parse(svg_fil)
196
+ tree = etree.parse(svg_file)
196
197
  root = tree.getroot()
197
198
  elem = new_element("g")
198
199
  elem.extend(list(root))
@@ -27,10 +27,7 @@ from svg_ultralight.font_tools.font_info import (
27
27
  )
28
28
  from svg_ultralight.font_tools.globs import DEFAULT_FONT_SIZE
29
29
  from svg_ultralight.query import get_bounding_boxes
30
- from svg_ultralight.string_conversion import (
31
- format_attr_dict,
32
- format_number,
33
- )
30
+ from svg_ultralight.string_conversion import format_attr_dict, format_number
34
31
 
35
32
  if TYPE_CHECKING:
36
33
  import os
@@ -39,6 +36,8 @@ if TYPE_CHECKING:
39
36
  _Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
40
37
  )
41
38
 
39
+ from svg_ultralight.attrib_hints import ElemAttrib, OptionalElemAttribMapping
40
+
42
41
  DEFAULT_Y_BOUNDS_REFERENCE = "{[|gjpqyf"
43
42
 
44
43
 
@@ -99,7 +98,8 @@ def pad_text_ft(
99
98
  descent: float | None = None,
100
99
  *,
101
100
  y_bounds_reference: str | None = None,
102
- **attributes: str | float,
101
+ attrib: OptionalElemAttribMapping = None,
102
+ **attributes: ElemAttrib,
103
103
  ) -> PaddedText:
104
104
  """Create a new PaddedText instance using fontTools.
105
105
 
@@ -115,11 +115,15 @@ def pad_text_ft(
115
115
  extents of the capline reference. This argument is provided to mimic the
116
116
  behavior of the query module's `pad_text` function. `pad_text` does no
117
117
  inspect font files and relies on Inkscape to measure reference characters.
118
+ :param attrib: optionally pass additional attributes as a mapping instead of as
119
+ anonymous kwargs. This is useful for pleasing the linter when unpacking a
120
+ dictionary into a function call.
118
121
  :param attributes: additional attributes to set on the text element. There is a
119
122
  chance these will cause the font element to exceed the BoundingBox of the
120
123
  PaddedText instance.
121
124
  :return: a PaddedText instance with a line_gap defined.
122
125
  """
126
+ attributes.update(attrib or {})
123
127
  attributes_ = format_attr_dict(**attributes)
124
128
  attributes_.update(get_svg_font_attributes(font))
125
129
 
@@ -145,7 +149,8 @@ def pad_text_mix(
145
149
  descent: float | None = None,
146
150
  *,
147
151
  y_bounds_reference: str | None = None,
148
- **attributes: str | float,
152
+ attrib: OptionalElemAttribMapping = None,
153
+ **attributes: ElemAttrib,
149
154
  ) -> PaddedText:
150
155
  """Use Inkscape text bounds and fill missing with fontTools.
151
156
 
@@ -161,11 +166,15 @@ def pad_text_mix(
161
166
  extents of the capline reference. This argument is provided to mimic the
162
167
  behavior of the query module's `pad_text` function. `pad_text` does no
163
168
  inspect font files and relies on Inkscape to measure reference characters.
169
+ :param attrib: optionally pass additional attributes as a mapping instead of as
170
+ anonymous kwargs. This is useful for pleasing the linter when unpacking a
171
+ dictionary into a function call.
164
172
  :param attributes: additional attributes to set on the text element. There is a
165
173
  chance these will cause the font element to exceed the BoundingBox of the
166
174
  PaddedText instance.
167
175
  :return: a PaddedText instance with a line_gap defined.
168
176
  """
177
+ attributes.update(attrib or {})
169
178
  elem = new_element("text", text=text, **attributes)
170
179
  padded_inkscape = pad_text(inkscape, elem, y_bounds_reference, font=font)
171
180
  padded_fonttools = pad_text_ft(
@@ -175,7 +184,7 @@ def pad_text_mix(
175
184
  ascent,
176
185
  descent,
177
186
  y_bounds_reference=y_bounds_reference,
178
- **attributes,
187
+ attrib=attributes,
179
188
  )
180
189
  bbox = padded_inkscape.unpadded_bbox
181
190
  rpad = padded_inkscape.rpad
@@ -25,8 +25,10 @@ if TYPE_CHECKING:
25
25
  _Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
26
26
  )
27
27
 
28
+ from svg_ultralight.attrib_hints import ElemAttrib
28
29
 
29
- def new_element(tag: str | QName, **attributes: str | float) -> EtreeElement:
30
+
31
+ def new_element(tag: str | QName, **attributes: ElemAttrib) -> EtreeElement:
30
32
  """Create an etree.Element, make every kwarg value a string.
31
33
 
32
34
  :param tag: element tag
@@ -62,7 +64,7 @@ def new_element(tag: str | QName, **attributes: str | float) -> EtreeElement:
62
64
 
63
65
 
64
66
  def new_sub_element(
65
- parent: EtreeElement, tag: str | QName, **attributes: str | float
67
+ parent: EtreeElement, tag: str | QName, **attributes: ElemAttrib
66
68
  ) -> EtreeElement:
67
69
  """Create an etree.SubElement, make every kwarg value a string.
68
70
 
@@ -81,7 +83,7 @@ def new_sub_element(
81
83
  return elem
82
84
 
83
85
 
84
- def update_element(elem: EtreeElement, **attributes: str | float) -> EtreeElement:
86
+ def update_element(elem: EtreeElement, **attributes: ElemAttrib) -> EtreeElement:
85
87
  """Update an existing etree.Element with additional params.
86
88
 
87
89
  :param elem: at etree element
@@ -94,7 +96,7 @@ def update_element(elem: EtreeElement, **attributes: str | float) -> EtreeElemen
94
96
  return elem
95
97
 
96
98
 
97
- def deepcopy_element(elem: EtreeElement, **attributes: str | float) -> EtreeElement:
99
+ def deepcopy_element(elem: EtreeElement, **attributes: ElemAttrib) -> EtreeElement:
98
100
  """Create a deepcopy of an element. Optionally pass additional params.
99
101
 
100
102
  :param elem: at etree element or list of elements
@@ -281,11 +281,11 @@ def _test_every_font_on_my_system(
281
281
 
282
282
  if __name__ == "__main__":
283
283
  _INKSCAPE = Path(r"C:\Program Files\Inkscape\bin\inkscape")
284
- # _FONT_DIRS = [
285
- # Path(r"C:\Windows\Fonts"),
286
- # Path(r"C:\Users\shaya\AppData\Local\Microsoft\Windows\Fonts"),
287
- # ]
288
- # _test_every_font_on_my_system(_INKSCAPE, _FONT_DIRS)
284
+ _FONT_DIRS = [
285
+ Path(r"C:\Windows\Fonts"),
286
+ Path(r"C:\Users\shaya\AppData\Local\Microsoft\Windows\Fonts"),
287
+ ]
288
+ _test_every_font_on_my_system(_INKSCAPE, _FONT_DIRS)
289
289
 
290
290
  font = Path(r"C:\Windows\Fonts\arial.ttf")
291
291
  font = Path("C:/Windows/Fonts/Aptos-Display-Bold.ttf")
@@ -119,12 +119,28 @@ if TYPE_CHECKING:
119
119
 
120
120
  from lxml.etree import _Element as EtreeElement
121
121
 
122
+ from svg_ultralight.attrib_hints import ElemAttrib
123
+
122
124
  logging.getLogger("fontTools").setLevel(logging.ERROR)
123
125
 
124
126
 
127
+ _ESCAPE_CHARS = {"&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&apos;"}
128
+
129
+
130
+ def _sanitize_svg_data_text(text: str) -> str:
131
+ """Sanitize a string for use in an SVG data-text attribute.
132
+
133
+ :param text: The input string to sanitize.
134
+ :return: The sanitized string with XML characters escaped.
135
+ """
136
+ for char, escape_seq in _ESCAPE_CHARS.items():
137
+ text = text.replace(char, escape_seq)
138
+ return text
139
+
140
+
125
141
  # extract_gpos_kerning is an unfinished attempt to extract kerning from the GPOS
126
142
  # table.
127
- def get_gpos_kerning(font: TTFont) -> dict[tuple[str, str], int]:
143
+ def _get_gpos_kerning(font: TTFont) -> dict[tuple[str, str], int]:
128
144
  """Extract kerning pairs from the GPOS table of a font.
129
145
 
130
146
  :param font: A fontTools TTFont object.
@@ -323,7 +339,7 @@ class FTFontInfo:
323
339
  except (KeyError, AttributeError):
324
340
  kern = {}
325
341
  with suppress(Exception):
326
- kern.update(get_gpos_kerning(self.font))
342
+ kern.update(_get_gpos_kerning(self.font))
327
343
 
328
344
  return kern
329
345
 
@@ -520,7 +536,7 @@ class FTTextInfo:
520
536
  """
521
537
  return self.font_size / self.font.units_per_em
522
538
 
523
- def new_element(self, **attributes: str | float) -> EtreeElement:
539
+ def new_element(self, **attributes: ElemAttrib) -> EtreeElement:
524
540
  """Return an svg text element with the appropriate font attributes."""
525
541
  matrix_vals = (self.scale, 0, 0, -self.scale, 0, 0)
526
542
  matrix = f"matrix({' '.join(format_numbers(matrix_vals))})"
@@ -530,7 +546,7 @@ class FTTextInfo:
530
546
  attributes["stroke-width"] = float(stroke_width) / self.scale
531
547
  return new_element(
532
548
  "path",
533
- data_text=self.text,
549
+ data_text=_sanitize_svg_data_text(self.text),
534
550
  d=self.font.get_text_svgd(self.text),
535
551
  **attributes,
536
552
  )
svg_ultralight/main.py CHANGED
@@ -36,6 +36,7 @@ if TYPE_CHECKING:
36
36
  _Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
37
37
  )
38
38
 
39
+ from svg_ultralight.attrib_hints import ElemAttrib, OptionalElemAttribMapping
39
40
  from svg_ultralight.layout import PadArg
40
41
 
41
42
 
@@ -68,7 +69,8 @@ def new_svg_root(
68
69
  print_height_: float | str | None = None,
69
70
  dpu_: float = 1,
70
71
  nsmap: dict[str | None, str] | None = None,
71
- **attributes: float | str,
72
+ attrib: OptionalElemAttribMapping | None = None,
73
+ **attributes: ElemAttrib,
72
74
  ) -> EtreeElement:
73
75
  """Create an svg root element from viewBox style parameters.
74
76
 
@@ -87,6 +89,9 @@ def new_svg_root(
87
89
  different from print_width_ and print_height_ in that dpu_ scales the
88
90
  *padded* output.
89
91
  :param nsmap: optionally pass a namespace map of your choosing
92
+ :param attrib: optionally pass additional attributes as a mapping instead of as
93
+ anonymous kwargs. This is useful for pleasing the linter when unpacking a
94
+ dictionary into a function call.
90
95
  :param attributes: element attribute names and values
91
96
  :return: root svg element
92
97
 
@@ -97,10 +102,11 @@ def new_svg_root(
97
102
  will be passed to ``etree.Element`` as element parameters. These will
98
103
  supercede any parameters inferred from the trailing underscore parameters.
99
104
  """
105
+ attributes.update(attrib or {})
100
106
  if nsmap is None:
101
107
  nsmap = NSMAP
102
108
 
103
- inferred_attribs: dict[str, float | str] = {}
109
+ inferred_attribs: dict[str, ElemAttrib] = {}
104
110
  view_box_args = (x_, y_, width_, height_)
105
111
  if _is_four_floats(view_box_args):
106
112
  assert isinstance(x_, (float, int))
@@ -17,6 +17,7 @@ if TYPE_CHECKING:
17
17
  _Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
18
18
  )
19
19
 
20
+ from svg_ultralight.attrib_hints import ElemAttrib, OptionalElemAttribMapping
20
21
  from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
21
22
  from svg_ultralight.layout import PadArg
22
23
 
@@ -43,7 +44,8 @@ def new_svg_root_around_bounds(
43
44
  print_height_: float | str | None = None,
44
45
  dpu_: float = 1,
45
46
  nsmap: dict[str | None, str] | None = None,
46
- **attributes: float | str,
47
+ attrib: OptionalElemAttribMapping = None,
48
+ **attributes: ElemAttrib,
47
49
  ) -> EtreeElement:
48
50
  """Create svg root around BoundElements.
49
51
 
@@ -61,10 +63,14 @@ def new_svg_root_around_bounds(
61
63
  different from print_width_ and print_height_ in that dpu_ scales the
62
64
  *padded* output.
63
65
  :param nsmap: optionally pass a namespace map of your choosing
66
+ :param attrib: optionally pass additional attributes as a mapping instead of as
67
+ anonymous kwargs. This is useful for pleasing the linter when unpacking a
68
+ dictionary into a function call.
64
69
  :param attributes: element attribute names and values
65
70
  :return: root svg element
66
71
  :raise ValueError: if no bounding boxes are found in bounded
67
72
  """
73
+ attributes.update(attrib or {})
68
74
  bbox = bound.new_bbox_union(*bounded)
69
75
  viewbox = _viewbox_args_from_bboxes(bbox)
70
76
  return new_svg_root(
@@ -77,5 +83,5 @@ def new_svg_root_around_bounds(
77
83
  print_height_=print_height_,
78
84
  dpu_=dpu_,
79
85
  nsmap=nsmap,
80
- **attributes,
86
+ attrib=attributes,
81
87
  )
@@ -26,6 +26,8 @@ if TYPE_CHECKING:
26
26
  _Element as EtreeElement, # pyright: ignore[reportPrivateUsage]
27
27
  )
28
28
 
29
+ from svg_ultralight.attrib_hints import ElemAttrib
30
+
29
31
 
30
32
  def format_number(num: float | str, resolution: int | None = 6) -> str:
31
33
  """Format a number into an svg-readable float string with resolution = 6.
@@ -50,7 +52,7 @@ def format_numbers(
50
52
  return [format_number(num) for num in nums]
51
53
 
52
54
 
53
- def _fix_key_and_format_val(key: str, val: str | float) -> tuple[str, str]:
55
+ def _fix_key_and_format_val(key: str, val: ElemAttrib) -> tuple[str, str]:
54
56
  """Format one key, value pair for an svg element.
55
57
 
56
58
  :param key: element attribute name
@@ -82,7 +84,9 @@ def _fix_key_and_format_val(key: str, val: str | float) -> tuple[str, str]:
82
84
  else:
83
85
  key_ = key.rstrip("_").replace("_", "-")
84
86
 
85
- if isinstance(val, (int, float)):
87
+ if val is None:
88
+ val_ = "none"
89
+ elif isinstance(val, (int, float)):
86
90
  val_ = format_number(val)
87
91
  else:
88
92
  val_ = val
@@ -90,7 +94,7 @@ def _fix_key_and_format_val(key: str, val: str | float) -> tuple[str, str]:
90
94
  return key_, val_
91
95
 
92
96
 
93
- def format_attr_dict(**attributes: str | float) -> dict[str, str]:
97
+ def format_attr_dict(**attributes: ElemAttrib) -> dict[str, str]:
94
98
  """Use svg_ultralight key / value fixer to create a dict of attributes.
95
99
 
96
100
  :param attributes: element attribute names and values.
@@ -99,7 +103,7 @@ def format_attr_dict(**attributes: str | float) -> dict[str, str]:
99
103
  return dict(_fix_key_and_format_val(key, val) for key, val in attributes.items())
100
104
 
101
105
 
102
- def set_attributes(elem: EtreeElement, **attributes: str | float) -> None:
106
+ def set_attributes(elem: EtreeElement, **attributes: ElemAttrib) -> None:
103
107
  """Set name: value items as element attributes. Make every value a string.
104
108
 
105
109
  :param elem: element to receive element.set(keyword, str(value)) calls
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: svg-ultralight
3
- Version: 0.44.0
3
+ Version: 0.45.1
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
@@ -1,34 +1,35 @@
1
1
  svg_ultralight/__init__.py,sha256=3YdTZfa0xUDrPCbOVyx39D9ENks-JEtsi9DFZzvaTf0,2755
2
2
  svg_ultralight/animate.py,sha256=SMcQkeWAP9dD08Iyzy9qGG8Qk1p-14WfrB7WSN8Pj_4,1133
3
+ svg_ultralight/attrib_hints.py,sha256=oCF20eG06vg2Tuapk1A14ovN7ZqZoZ43d-um_Zh0BPs,418
3
4
  svg_ultralight/image_ops.py,sha256=6V9YkxnhZCBw_hbVyY0uxDj0pZgiEWBSGRuPuOYKY4w,4694
4
5
  svg_ultralight/inkscape.py,sha256=ySCxWnQwEt1sosa1b4mEkR-ugpfoAeg9gs1OLPS69iI,9597
5
6
  svg_ultralight/layout.py,sha256=7LV2I3u4EhqSc6ASvgwDtTZyV-Y1qt2wtvRtH2uKVAE,12799
6
- svg_ultralight/main.py,sha256=_zY6F8zc1tAGSe8isBOK5ajpDB8d4I7x7zD2fjsP4SE,7475
7
+ svg_ultralight/main.py,sha256=zaqWc5y9tsJoyNhpX2gIHKj1ZGEcfJebxNCcRQyoziU,7857
7
8
  svg_ultralight/metadata.py,sha256=xaIfqhKu52Dl4JOrRlpUsWkkE7Umw8j5Z4waFTli-kI,4234
8
9
  svg_ultralight/nsmap.py,sha256=y63upO78Rr-JJT56RWWZuyrsILh6HPoY4GhbYnK1A0g,1244
9
10
  svg_ultralight/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
11
  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=omCmiwyu5AIDHltPiXIEYQG3KiII1twlUJN2oven0mM,8749
12
+ svg_ultralight/root_elements.py,sha256=H_J7GMO8yqoie169uDUB1LxWSpc7BgUH6H657ZPRahg,3292
13
+ svg_ultralight/string_conversion.py,sha256=NWguHAmuKWON7Fh2EkVDfMIwp-jk6k7SW8hAUh72H0o,8850
13
14
  svg_ultralight/transformations.py,sha256=T3vSxcTWOwWnwu3OF610LHMbKScUIVWICUAvru5zLnU,4488
14
15
  svg_ultralight/unit_conversion.py,sha256=g07nhzXdjPvGcJmkhLdFbeDLrSmbI8uFoVgPo7G62Bg,9258
15
16
  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=tPQ5ilZnSm83HH852euoe0V77Nf-78BG7wlE7K8FqnM,7668
17
+ svg_ultralight/bounding_boxes/bound_helpers.py,sha256=iCinp_kFsxi29gJEMnDZpKs13Fj1fj8SWqbbWO94UTI,7203
18
+ svg_ultralight/bounding_boxes/padded_text_initializers.py,sha256=LytVTNwdkJvh914DXIzB4zfrbk563K30ODlk8BmuotA,8328
18
19
  svg_ultralight/bounding_boxes/supports_bounds.py,sha256=T7LGse58fDBgmlzupSC63C1ZMXjFbyzBTsTUaqD_4Sw,4513
19
20
  svg_ultralight/bounding_boxes/type_bound_collection.py,sha256=NAEpqo9H9ewhuLcOmBnMWUE0zQ1t4bvckovgvWy6hIo,2645
20
21
  svg_ultralight/bounding_boxes/type_bound_element.py,sha256=Sc-R0uXkb0aS8-OcyM5pDukKhFUka0G6KCp6LcYDcIU,2204
21
22
  svg_ultralight/bounding_boxes/type_bounding_box.py,sha256=bABFT-BwVdOmRJ-BHOLE_7LZv57MDwqABHvRDcVmvtI,13509
22
23
  svg_ultralight/bounding_boxes/type_padded_text.py,sha256=WNIoqC9pfB8g_00P6RHcBdNE6VniqlLJXw_bh-GNjFA,13098
23
24
  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/constructors/new_element.py,sha256=kGRaVsT1yugADUCKz3NjFW_14Ts1M8UQeLPTarTXtBY,3529
25
26
  svg_ultralight/font_tools/__init__.py,sha256=NX3C0vvoB-G4S-h1f0NLWePjYAMMR37D1cl_G4WBjHc,83
26
- svg_ultralight/font_tools/comp_results.py,sha256=ypqIqt7pe4tCCRGMJl7hVJtmQyUAYlQj1HZHmTcVThE,10697
27
- svg_ultralight/font_tools/font_info.py,sha256=QztVHygo-qkp0IOe5bRnvjiR1rehEVxUyvsMZDJm5A0,29343
27
+ svg_ultralight/font_tools/comp_results.py,sha256=gFxdqY1D5z8MGt1UyWOK8O_t50AHgg-B846uWdzoLco,10687
28
+ svg_ultralight/font_tools/font_info.py,sha256=rIoEmEWhNYw04Jos_ETXQ11SkDhi6YlLd3VjZMLETXs,29875
28
29
  svg_ultralight/font_tools/globs.py,sha256=JdrrGMqDtD4WcY7YGUWV43DUW63RVev-x9vWqsQUhxU,119
29
30
  svg_ultralight/strings/__init__.py,sha256=BMGhF1pulscIgkiYvZLr6kPRR0L4lW0jUNFxkul4_EM,295
30
31
  svg_ultralight/strings/svg_strings.py,sha256=FQNxNmMkR2M-gCFo_woQKXLgCHi3ncUlRMiaRR_a9nQ,1978
31
- svg_ultralight-0.44.0.dist-info/METADATA,sha256=mHPgja-zNjke16M_4iZCj5gAS3orif2qnJTgkogwHvc,9052
32
- svg_ultralight-0.44.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
- svg_ultralight-0.44.0.dist-info/top_level.txt,sha256=se-6yqM_0Yg5orJKvKWdjQZ4iR4G_EjhL7oRgju-fdY,15
34
- svg_ultralight-0.44.0.dist-info/RECORD,,
32
+ svg_ultralight-0.45.1.dist-info/METADATA,sha256=_5egao_AkYDDIGZ7iN4anNt2FzM9KeVuK_ZSUvI_UVs,9052
33
+ svg_ultralight-0.45.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ svg_ultralight-0.45.1.dist-info/top_level.txt,sha256=se-6yqM_0Yg5orJKvKWdjQZ4iR4G_EjhL7oRgju-fdY,15
35
+ svg_ultralight-0.45.1.dist-info/RECORD,,