svg-ultralight 0.33.0__py3-none-any.whl → 0.35.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.

@@ -5,9 +5,14 @@
5
5
  """
6
6
 
7
7
  from svg_ultralight.bounding_boxes.bound_helpers import (
8
+ bbox_dict,
9
+ cut_bbox,
10
+ new_bbox_rect,
8
11
  new_bbox_union,
9
12
  new_bound_union,
10
13
  new_element_union,
14
+ pad_bbox,
15
+ parse_bound_element,
11
16
  )
12
17
  from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
13
18
  from svg_ultralight.bounding_boxes.type_bound_collection import BoundCollection
@@ -31,10 +36,10 @@ from svg_ultralight.main import new_svg_root, write_svg
31
36
  from svg_ultralight.metadata import new_metadata
32
37
  from svg_ultralight.nsmap import NSMAP, new_qname
33
38
  from svg_ultralight.query import (
39
+ clear_svg_ultralight_cache,
34
40
  get_bounding_box,
35
41
  get_bounding_boxes,
36
42
  pad_text,
37
- clear_svg_ultralight_cache,
38
43
  )
39
44
  from svg_ultralight.root_elements import new_svg_root_around_bounds
40
45
  from svg_ultralight.string_conversion import (
@@ -51,13 +56,15 @@ from svg_ultralight.transformations import (
51
56
  )
52
57
 
53
58
  __all__ = [
59
+ "NSMAP",
54
60
  "BoundCollection",
55
61
  "BoundElement",
56
62
  "BoundingBox",
57
- "NSMAP",
58
63
  "PaddedText",
59
64
  "SupportsBounds",
65
+ "bbox_dict",
60
66
  "clear_svg_ultralight_cache",
67
+ "cut_bbox",
61
68
  "deepcopy_element",
62
69
  "format_attr_dict",
63
70
  "format_number",
@@ -68,6 +75,7 @@ __all__ = [
68
75
  "mat_apply",
69
76
  "mat_dot",
70
77
  "mat_invert",
78
+ "new_bbox_rect",
71
79
  "new_bbox_union",
72
80
  "new_bound_union",
73
81
  "new_element",
@@ -77,7 +85,9 @@ __all__ = [
77
85
  "new_sub_element",
78
86
  "new_svg_root",
79
87
  "new_svg_root_around_bounds",
88
+ "pad_bbox",
80
89
  "pad_text",
90
+ "parse_bound_element",
81
91
  "transform_element",
82
92
  "update_element",
83
93
  "write_pdf",
@@ -16,7 +16,10 @@ from svg_ultralight.bounding_boxes.type_padded_text import PaddedText
16
16
  from svg_ultralight.constructors import new_element
17
17
 
18
18
  if TYPE_CHECKING:
19
+ import os
20
+
19
21
  from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
22
+ from lxml import etree
20
23
 
21
24
  _Matrix = tuple[float, float, float, float, float, float]
22
25
 
@@ -95,3 +98,110 @@ def new_bound_union(*blems: SupportsBounds | EtreeElement) -> BoundElement:
95
98
  group = new_element_union(*blems)
96
99
  bbox = new_bbox_union(*blems)
97
100
  return BoundElement(group, bbox)
101
+
102
+
103
+ def _expand_pad(pad: float | tuple[float, ...]) -> tuple[float, float, float, float]:
104
+ """Expand a float pad argument into a 4-tuple."""
105
+ if isinstance(pad, (int, float)):
106
+ return pad, pad, pad, pad
107
+ if len(pad) == 1:
108
+ return pad[0], pad[0], pad[0], pad[0]
109
+ if len(pad) == 2:
110
+ return pad[0], pad[1], pad[0], pad[1]
111
+ if len(pad) == 3:
112
+ return pad[0], pad[1], pad[2], pad[1]
113
+ return pad[0], pad[1], pad[2], pad[3]
114
+
115
+
116
+ def cut_bbox(
117
+ bbox: SupportsBounds,
118
+ *,
119
+ x: float | None = None,
120
+ y: float | None = None,
121
+ x2: float | None = None,
122
+ y2: float | None = None,
123
+ ) -> BoundingBox:
124
+ """Return a new bounding box with updated limits.
125
+
126
+ :param bbox: the original bounding box or bounded element.
127
+ :param x: the new x-coordinate.
128
+ :param y: the new y-coordinate.
129
+ :param x2: the new x2-coordinate.
130
+ :param y2: the new y2-coordinate.
131
+ :return: a new bounding box with the updated limits.
132
+ """
133
+ x = bbox.x if x is None else x
134
+ y = bbox.y if y is None else y
135
+ x2 = bbox.x2 if x2 is None else x2
136
+ y2 = bbox.y2 if y2 is None else y2
137
+ width = x2 - x
138
+ height = y2 - y
139
+ return BoundingBox(x, y, width, height)
140
+
141
+
142
+ def pad_bbox(bbox: SupportsBounds, pad: float | tuple[float, ...]) -> BoundingBox:
143
+ """Return a new bounding box with padding.
144
+
145
+ :param bbox: the original bounding box or bounded element.
146
+ :param pad: the padding to apply.
147
+ If a single number, the same padding will be applied to all sides.
148
+ If a tuple, will be applied per css rules.
149
+ len = 1 : 0, 0, 0, 0
150
+ len = 2 : 0, 1, 0, 1
151
+ len = 3 : 0, 1, 2, 1
152
+ len = 4 : 0, 1, 2, 3
153
+ :return: a new bounding box with padding applied.
154
+ """
155
+ top, right, bottom, left = _expand_pad(pad)
156
+ return cut_bbox(
157
+ bbox, x=bbox.x - left, y=bbox.y - top, x2=bbox.x2 + right, y2=bbox.y2 + bottom
158
+ )
159
+
160
+
161
+ def bbox_dict(bbox: SupportsBounds) -> dict[str, float]:
162
+ """Return a dictionary representation of a bounding box.
163
+
164
+ :param bbox: the bounding box or bound element from which to extract dimensions.
165
+ :return: a dictionary with keys x, y, width, and height.
166
+ """
167
+ return {"x": bbox.x, "y": bbox.y, "width": bbox.width, "height": bbox.height}
168
+
169
+
170
+ def new_bbox_rect(bbox: BoundingBox, **kwargs: float | str) -> EtreeElement:
171
+ """Return a new rect element with the same dimensions as the bounding box.
172
+
173
+ :param bbox: the bounding box or bound element from which to extract dimensions.
174
+ :param kwargs: additional attributes for the rect element.
175
+ """
176
+ return new_element("rect", **bbox_dict(bbox), **kwargs)
177
+
178
+
179
+ def _get_view_box(elem: EtreeElement) -> tuple[float, float, float, float]:
180
+ """Return the view box of an element as a tuple of floats.
181
+
182
+ :param elem: the element from which to extract the view box.
183
+ :return: a tuple of floats representing the view box.
184
+
185
+ This will work on svg files created by this library and some others. Not all svg
186
+ files have a viewBox attribute.
187
+ """
188
+ view_box = elem.get("viewBox")
189
+ if view_box is None:
190
+ msg = "Element does not have a viewBox attribute."
191
+ raise ValueError(msg)
192
+ x, y, width, height = map(float, view_box.split())
193
+ return x, y, width, height
194
+
195
+
196
+ def parse_bound_element(svg_fil: str | os.PathLike[str]) -> BoundElement:
197
+ """Import an element as a BoundElement.
198
+
199
+ :param elem: the element to import.
200
+ :return: a BoundElement instance.
201
+ """
202
+ tree = etree.parse(svg_fil)
203
+ root = tree.getroot()
204
+ elem = new_element("g")
205
+ elem.extend(list(root))
206
+ bbox = BoundingBox(*_get_view_box(root))
207
+ return BoundElement(elem, bbox)
@@ -11,4 +11,4 @@ from svg_ultralight.constructors.new_element import (
11
11
  update_element,
12
12
  )
13
13
 
14
- __all__ = ["new_element", "new_sub_element", "update_element", "deepcopy_element"]
14
+ __all__ = ["deepcopy_element", "new_element", "new_sub_element", "update_element"]
@@ -20,7 +20,8 @@ from lxml import etree
20
20
  from svg_ultralight.string_conversion import set_attributes
21
21
 
22
22
  if TYPE_CHECKING:
23
- from lxml.etree import QName, _Element as EtreeElement # type: ignore
23
+ from lxml.etree import QName
24
+ from lxml.etree import _Element as EtreeElement # type: ignore
24
25
 
25
26
 
26
27
  def new_element(tag: str | QName, **attributes: str | float) -> EtreeElement:
svg_ultralight/layout.py CHANGED
@@ -43,7 +43,10 @@ def expand_pad_arg(pad: PadArg) -> tuple[float, float, float, float]:
43
43
  return expand_pad_arg([pad])
44
44
  as_ms = [m if isinstance(m, Measurement) else Measurement(m) for m in pad]
45
45
  as_units = [m.value for m in as_ms]
46
- as_units = [as_units[i % len(as_units)] for i in range(4)]
46
+ if len(as_units) == 3:
47
+ as_units = [*as_units, as_units[1]]
48
+ else:
49
+ as_units = [as_units[i % len(as_units)] for i in range(4)]
47
50
  return as_units[0], as_units[1], as_units[2], as_units[3]
48
51
 
49
52
 
svg_ultralight/query.py CHANGED
@@ -31,7 +31,6 @@ from svg_ultralight.bounding_boxes.type_padded_text import PaddedText
31
31
  from svg_ultralight.main import new_svg_root, write_svg
32
32
 
33
33
  if TYPE_CHECKING:
34
-
35
34
  from lxml.etree import _Element as EtreeElement # type: ignore
36
35
 
37
36
 
@@ -10,4 +10,4 @@ from svg_ultralight.strings.svg_strings import (
10
10
  svg_ints,
11
11
  )
12
12
 
13
- __all__ = ["svg_color_tuple", "svg_ints", "svg_float_tuples"]
13
+ __all__ = ["svg_color_tuple", "svg_float_tuples", "svg_ints"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: svg-ultralight
3
- Version: 0.33.0
3
+ Version: 0.35.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,28 +1,28 @@
1
- svg_ultralight/__init__.py,sha256=RNm7gHwJoffbMEbT4zx3Z5xmhvfvRnkvswA5IVlzoxw,2360
1
+ svg_ultralight/__init__.py,sha256=wUc79mKsG6lGZ1xaYijyJ4Sm9lG5-5XgRArVsCI0niY,2554
2
2
  svg_ultralight/animate.py,sha256=JSrBm-59BcNXDF0cGgl4-C89eBunjevZnwZxIWt48TU,1112
3
3
  svg_ultralight/inkscape.py,sha256=M8yTxXOu4NlXnhsMycvEJiIDpnDeiZ_bZakJBM38ZoU,9152
4
- svg_ultralight/layout.py,sha256=TTETT_8WLBXnQxDGXdAeczCFN5pFo5kKY3Q6zv4FPX4,12238
4
+ svg_ultralight/layout.py,sha256=FgR45FsHax4xDjGkk9HEVW4OcwhtM8aqw2JUdZs_m7Q,12326
5
5
  svg_ultralight/main.py,sha256=6oNkZfD27UMdP-oYqp5agS_IGcYb8NkUZwM9Zdyb3SA,7287
6
6
  svg_ultralight/metadata.py,sha256=xR3ObM0QV7OQ90IKvfigR5B6e0JW6GGVGvTlL5NswWI,4211
7
7
  svg_ultralight/nsmap.py,sha256=y63upO78Rr-JJT56RWWZuyrsILh6HPoY4GhbYnK1A0g,1244
8
8
  svg_ultralight/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- svg_ultralight/query.py,sha256=F_yl-zbNQSOFxiuHT4qZ0LqLoYdD36BGTREJady5sBc,9430
9
+ svg_ultralight/query.py,sha256=SufFumN11VTWloqjMpSuQ5eghAYx4ABQRIMXRJGs70o,9428
10
10
  svg_ultralight/root_elements.py,sha256=pt9J6mPrnoTAZVF6vKTZoM_o947I8UCj6MbGcD2JUCk,2869
11
11
  svg_ultralight/string_conversion.py,sha256=WEmpf75RJmJ2lfJluagAz2wPsz6wM8XvTEwkq4U0vEc,7353
12
12
  svg_ultralight/transformations.py,sha256=7-6NNh6xZ45mM_933fMuQfRGpI7q9Qrt5qse9e6FUek,4036
13
13
  svg_ultralight/unit_conversion.py,sha256=g07nhzXdjPvGcJmkhLdFbeDLrSmbI8uFoVgPo7G62Bg,9258
14
14
  svg_ultralight/bounding_boxes/__init__.py,sha256=qUEn3r4s-1QNHaguhWhhaNfdP4tl_B6YEqxtiTFuzhQ,78
15
- svg_ultralight/bounding_boxes/bound_helpers.py,sha256=YMClhdekeYbzD_ijXDAer-H3moWKN3lUNnZs1UNFFKc,3458
15
+ svg_ultralight/bounding_boxes/bound_helpers.py,sha256=V0BlBHDZ9xksVG5dGLPfcyRwPP3jSj6ODdtIpqT-FcI,7273
16
16
  svg_ultralight/bounding_boxes/supports_bounds.py,sha256=fbHV6mGdeIVV3lS15vBKSrHiHKR7DMg4K5X__4LLmCE,4569
17
17
  svg_ultralight/bounding_boxes/type_bound_collection.py,sha256=b89TM2UsdaeApyjTQeMbx_FG_WcCiLAImEiHiZ6EWPI,2600
18
18
  svg_ultralight/bounding_boxes/type_bound_element.py,sha256=9RdxH8osOlAvPdWR0Ww9NsasHLPYFDs-MbydoV48x4E,2239
19
19
  svg_ultralight/bounding_boxes/type_bounding_box.py,sha256=cDrMp6uwaA--KJIQS2puG10qh8n3TBmiscg-cfk1f3w,16149
20
20
  svg_ultralight/bounding_boxes/type_padded_text.py,sha256=QA6PfeO_sQYc5pEXuyfyQ3lRUcZAc4B2BthWXpdt3qQ,14848
21
- svg_ultralight/constructors/__init__.py,sha256=YcnO0iBQc19aL8Iemw0Y452MBMBIT2AN5nZCnoGxpn0,327
22
- svg_ultralight/constructors/new_element.py,sha256=VtMz9sPn9rMk6rui5Poysy3vezlOaS-tGIcGbu-SXmY,3406
23
- svg_ultralight/strings/__init__.py,sha256=Zalrf-ThFz7b7xKELx5lb2gOlBgV-6jk_k_EeSdVCVk,295
21
+ svg_ultralight/constructors/__init__.py,sha256=XLOInLhzMERWNnFAs-itMs-OZrBOpvQthZJ2T5duqBE,327
22
+ svg_ultralight/constructors/new_element.py,sha256=8nqmOEgt3j-aOVeRaMLFHqrwKg2Dm5w0AfuK9MP4ak8,3433
23
+ svg_ultralight/strings/__init__.py,sha256=BMGhF1pulscIgkiYvZLr6kPRR0L4lW0jUNFxkul4_EM,295
24
24
  svg_ultralight/strings/svg_strings.py,sha256=RYKMxOHq9abbZyGcFqsElBGLrBX-EjjNxln3s_ibi30,1296
25
- svg_ultralight-0.33.0.dist-info/METADATA,sha256=dQ7MJsfoX8zthow6dSWRi4onL4izCdqCnX2IhSVn1aE,8867
26
- svg_ultralight-0.33.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
27
- svg_ultralight-0.33.0.dist-info/top_level.txt,sha256=se-6yqM_0Yg5orJKvKWdjQZ4iR4G_EjhL7oRgju-fdY,15
28
- svg_ultralight-0.33.0.dist-info/RECORD,,
25
+ svg_ultralight-0.35.1.dist-info/METADATA,sha256=PRuCkp6xtBx_t8pkPEJR00TZRcb82eygu1EQTuROHaM,8867
26
+ svg_ultralight-0.35.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
27
+ svg_ultralight-0.35.1.dist-info/top_level.txt,sha256=se-6yqM_0Yg5orJKvKWdjQZ4iR4G_EjhL7oRgju-fdY,15
28
+ svg_ultralight-0.35.1.dist-info/RECORD,,