svg-ultralight 0.27.0__tar.gz → 0.29.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 (49) hide show
  1. svg_ultralight-0.29.0/.gitignore +3 -0
  2. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/PKG-INFO +1 -1
  3. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/pyproject.toml +2 -2
  4. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/__init__.py +4 -0
  5. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/animate.py +2 -2
  6. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/bounding_boxes/bound_helpers.py +2 -0
  7. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/bounding_boxes/supports_bounds.py +22 -0
  8. svg_ultralight-0.29.0/src/svg_ultralight/bounding_boxes/type_bound_confederation.py +71 -0
  9. svg_ultralight-0.29.0/src/svg_ultralight/bounding_boxes/type_bound_element.py +66 -0
  10. svg_ultralight-0.29.0/src/svg_ultralight/bounding_boxes/type_bounding_box.py +501 -0
  11. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/bounding_boxes/type_padded_text.py +32 -8
  12. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/query.py +2 -1
  13. svg_ultralight-0.29.0/src/svg_ultralight/transformations.py +108 -0
  14. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight.egg-info/PKG-INFO +1 -1
  15. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight.egg-info/SOURCES.txt +4 -0
  16. svg_ultralight-0.29.0/tests/test_bounding.py +180 -0
  17. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/test_queries.py +11 -15
  18. svg_ultralight-0.27.0/src/svg_ultralight/bounding_boxes/type_bound_element.py +0 -196
  19. svg_ultralight-0.27.0/src/svg_ultralight/bounding_boxes/type_bounding_box.py +0 -308
  20. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/.pre-commit-config.yaml +0 -0
  21. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/README.md +0 -0
  22. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/setup.cfg +0 -0
  23. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/bounding_boxes/__init__.py +0 -0
  24. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/constructors/__init__.py +0 -0
  25. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/constructors/new_element.py +0 -0
  26. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/inkscape.py +0 -0
  27. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/layout.py +0 -0
  28. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/main.py +0 -0
  29. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/metadata.py +0 -0
  30. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/nsmap.py +0 -0
  31. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/py.typed +0 -0
  32. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/root_elements.py +0 -0
  33. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/string_conversion.py +0 -0
  34. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/strings/__init__.py +0 -0
  35. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/strings/svg_strings.py +0 -0
  36. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight/unit_conversion.py +0 -0
  37. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight.egg-info/dependency_links.txt +0 -0
  38. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight.egg-info/requires.txt +0 -0
  39. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/src/svg_ultralight.egg-info/top_level.txt +0 -0
  40. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/__init__.py +0 -0
  41. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/conftest.py +0 -0
  42. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/test_inkscape.py +0 -0
  43. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/test_layout.py +0 -0
  44. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/test_metadata.py +0 -0
  45. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/test_new_element.py +0 -0
  46. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/test_root_elements.py +0 -0
  47. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/test_string_conversion.py +0 -0
  48. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tests/test_svg_ultralight.py +0 -0
  49. {svg_ultralight-0.27.0 → svg_ultralight-0.29.0}/tox.ini +0 -0
@@ -0,0 +1,3 @@
1
+ Update-PythonVenv.ps1
2
+ requirements.txt
3
+ dev_requirements.txt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: svg-ultralight
3
- Version: 0.27.0
3
+ Version: 0.29.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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "svg-ultralight"
3
- version = "0.27.0"
3
+ version = "0.29.0"
4
4
  description = "a sensible way to create svg files with Python"
5
5
  authors = [{ name = "Shay Hill", email = "shay_public@hotmail.com" }]
6
6
  license = { text = "MIT" }
@@ -37,7 +37,7 @@ legacy_tox_ini = """
37
37
 
38
38
  [tool.commitizen]
39
39
  name = "cz_conventional_commits"
40
- version = "0.27.0"
40
+ version = "0.29.0"
41
41
  tag_format = "$version"
42
42
  version_files = ["pyproject.toml:^version"]
43
43
  annotated_tag = true
@@ -10,6 +10,7 @@ from svg_ultralight.bounding_boxes.bound_helpers import (
10
10
  new_element_union,
11
11
  )
12
12
  from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
13
+ from svg_ultralight.bounding_boxes.type_bound_confederation import BoundConfederation
13
14
  from svg_ultralight.bounding_boxes.type_bound_element import BoundElement
14
15
  from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
15
16
  from svg_ultralight.bounding_boxes.type_padded_text import PaddedText
@@ -37,8 +38,10 @@ from svg_ultralight.string_conversion import (
37
38
  format_numbers,
38
39
  format_numbers_in_string,
39
40
  )
41
+ from svg_ultralight.transformations import transform_element
40
42
 
41
43
  __all__ = [
44
+ "BoundConfederation",
42
45
  "BoundElement",
43
46
  "BoundingBox",
44
47
  "NSMAP",
@@ -59,6 +62,7 @@ __all__ = [
59
62
  "new_svg_root",
60
63
  "new_svg_root_around_bounds",
61
64
  "pad_text",
65
+ "transform_element",
62
66
  "update_element",
63
67
  "write_pdf",
64
68
  "write_pdf_from_svg",
@@ -34,7 +34,7 @@ def write_gif(
34
34
  :param loop: how many times to loop gif. 0 -> forever
35
35
  :effects: write file to gif
36
36
  """
37
- images = [Image.open(x) for x in pngs]
38
- images[0].save(
37
+ images = [Image.open(x) for x in pngs] # type: ignore
38
+ images[0].save( # type: ignore
39
39
  gif, save_all=True, append_images=images[1:], duration=duration, loop=loop
40
40
  )
@@ -18,6 +18,8 @@ from svg_ultralight.constructors import new_element
18
18
  if TYPE_CHECKING:
19
19
  from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
20
20
 
21
+ _Matrix = tuple[float, float, float, float, float, float]
22
+
21
23
 
22
24
  def new_element_union(
23
25
  *elems: EtreeElement | SupportsBounds, **attributes: float | str
@@ -16,13 +16,19 @@ Attributes:
16
16
  :created: 2023-02-15
17
17
  """
18
18
 
19
+ from __future__ import annotations
20
+
19
21
  from typing import Protocol
20
22
 
23
+ _Matrix = tuple[float, float, float, float, float, float]
24
+
21
25
 
22
26
  class SupportsBounds(Protocol):
23
27
  """Protocol for objects that can have bounds.
24
28
 
25
29
  Attributes:
30
+ transformation (_Matrix): An svg-style transformation matrix.
31
+ transform (method): Apply a transformation to the object.
26
32
  x (float): The minimum x coordinate.
27
33
  x2 (float): The maximum x coordinate.
28
34
  cx (float): The center x coordinate.
@@ -39,6 +45,22 @@ class SupportsBounds(Protocol):
39
45
  set width and height.
40
46
  """
41
47
 
48
+ @property
49
+ def transformation(self) -> _Matrix:
50
+ """Return an svg-style transformation matrix."""
51
+ ...
52
+
53
+ def transform(
54
+ self,
55
+ transformation: _Matrix | None = None,
56
+ *,
57
+ scale: float | None = None,
58
+ dx: float | None = None,
59
+ dy: float | None = None,
60
+ ):
61
+ """Apply a transformation to the object."""
62
+ ...
63
+
42
64
  @property
43
65
  def x(self) -> float:
44
66
  """Return minimum x coordinate."""
@@ -0,0 +1,71 @@
1
+ """A class to hold a list of bound elements and transform them together.
2
+
3
+ :author: Shay Hill
4
+ :created: 2024-05-05
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import dataclasses
10
+ from typing import TYPE_CHECKING
11
+
12
+ from lxml.etree import _Element as EtreeElement # type: ignore
13
+
14
+ from svg_ultralight.bounding_boxes.bound_helpers import new_bbox_union
15
+ from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
16
+ from svg_ultralight.bounding_boxes.type_bounding_box import HasBoundingBox
17
+ from svg_ultralight.transformations import new_transformation_matrix, transform_element
18
+
19
+ if TYPE_CHECKING:
20
+ from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
21
+
22
+ _Matrix = tuple[float, float, float, float, float, float]
23
+
24
+
25
+ @dataclasses.dataclass
26
+ class BoundConfederation(HasBoundingBox):
27
+ """A class to hold a list of bound elements and transform them together.
28
+
29
+ This will transform the individual elements in place.
30
+ """
31
+
32
+ blems: list[SupportsBounds | EtreeElement] = dataclasses.field(init=False)
33
+ bbox: BoundingBox = dataclasses.field(init=False)
34
+
35
+ def __init__(self, *blems: SupportsBounds | EtreeElement) -> None:
36
+ """Initialize the bound confederation.
37
+
38
+ :param blems: bound elements to be transformed together
39
+ """
40
+ self.blems = list(blems)
41
+ self.bbox = new_bbox_union(*self.blems)
42
+
43
+ def transform(
44
+ self,
45
+ transformation: _Matrix | None = None,
46
+ *,
47
+ scale: float | None = None,
48
+ dx: float | None = None,
49
+ dy: float | None = None,
50
+ ):
51
+ """Transform each bound element in self.blems.
52
+
53
+ :param transformation: 2D transformation matrix
54
+ :param scale: optional scale factor
55
+ :param dx: optional x translation
56
+ :param dy: optional y translation
57
+
58
+ Keep track of all compounding transformations in order to have a value for
59
+ self.scale (required for membersh and to provide access to cumulative
60
+ transforms should this be useful for any reason. This means all
61
+ transformations must be applied to two bounding boxes: a persistant bbox to
62
+ keep track of the scale property and a temporary bbox to isolate each
63
+ transformation.
64
+ """
65
+ tmat = new_transformation_matrix(transformation, scale=scale, dx=dx, dy=dy)
66
+ self.bbox.transform(tmat)
67
+ for blem in self.blems:
68
+ if isinstance(blem, EtreeElement):
69
+ _ = transform_element(blem, tmat)
70
+ else:
71
+ blem.transform(tmat)
@@ -0,0 +1,66 @@
1
+ """An element tied to a BoundingBox instance.
2
+
3
+ Take an element, associate it to a BoundingBox instance, transform the BoundingBox
4
+ instance. The element will be transformed accordingly.
5
+
6
+ It is critical to remember that self.elem is a reference. It is not necessary to
7
+ access self.elem through the BoundElement instance. Earlier and later references will
8
+ all be updated as the BoundElement instance is updated.
9
+
10
+ :author: Shay Hill
11
+ :created: 2022-12-09
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ from typing import TYPE_CHECKING
17
+
18
+ from svg_ultralight.bounding_boxes.type_bounding_box import HasBoundingBox
19
+ from svg_ultralight.transformations import new_transformation_matrix, transform_element
20
+
21
+ if TYPE_CHECKING:
22
+ from lxml.etree import _Element as EtreeElement # type: ignore
23
+
24
+ from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
25
+
26
+ _Matrix = tuple[float, float, float, float, float, float]
27
+
28
+
29
+ class BoundElement(HasBoundingBox):
30
+ """An element with a bounding box.
31
+
32
+ Updates the element when x, y, x2, y2, width, or height are set.
33
+
34
+ Can access these BoundingBox attributes (plus scale) as attributes of this object.
35
+ """
36
+
37
+ def __init__(self, element: EtreeElement, bounding_box: BoundingBox) -> None:
38
+ """Initialize a BoundElement instance.
39
+
40
+ :param element: the element to be bound
41
+ :param bounding_box: the bounding box around the element
42
+ """
43
+ self.elem = element
44
+ self.bbox = bounding_box
45
+
46
+ def _update_elem(self):
47
+ self.elem.attrib["transform"] = self.bbox.transform_string
48
+
49
+ def transform(
50
+ self,
51
+ transformation: _Matrix | None = None,
52
+ *,
53
+ scale: float | None = None,
54
+ dx: float | None = None,
55
+ dy: float | None = None,
56
+ ):
57
+ """Transform the element and bounding box.
58
+
59
+ :param transformation: a 6-tuple transformation matrix
60
+ :param scale: a scaling factor
61
+ :param dx: the x translation
62
+ :param dy: the y translation
63
+ """
64
+ tmat = new_transformation_matrix(transformation, scale=scale, dx=dx, dy=dy)
65
+ self.bbox.transform(tmat)
66
+ _ = transform_element(self.elem, tmat)