svg-ultralight 0.26.0__tar.gz → 0.27.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 (43) hide show
  1. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/PKG-INFO +1 -1
  2. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/pyproject.toml +6 -2
  3. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/__init__.py +10 -0
  4. svg_ultralight-0.27.0/src/svg_ultralight/bounding_boxes/bound_helpers.py +95 -0
  5. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/root_elements.py +3 -11
  6. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight.egg-info/PKG-INFO +1 -1
  7. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight.egg-info/SOURCES.txt +1 -0
  8. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/test_inkscape.py +1 -4
  9. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/test_queries.py +1 -4
  10. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/test_root_elements.py +33 -5
  11. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/.pre-commit-config.yaml +0 -0
  12. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/README.md +0 -0
  13. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/setup.cfg +0 -0
  14. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/animate.py +0 -0
  15. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/bounding_boxes/__init__.py +0 -0
  16. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/bounding_boxes/supports_bounds.py +0 -0
  17. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/bounding_boxes/type_bound_element.py +0 -0
  18. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/bounding_boxes/type_bounding_box.py +0 -0
  19. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/bounding_boxes/type_padded_text.py +0 -0
  20. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/constructors/__init__.py +0 -0
  21. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/constructors/new_element.py +0 -0
  22. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/inkscape.py +0 -0
  23. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/layout.py +0 -0
  24. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/main.py +0 -0
  25. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/metadata.py +0 -0
  26. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/nsmap.py +0 -0
  27. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/py.typed +0 -0
  28. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/query.py +0 -0
  29. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/string_conversion.py +0 -0
  30. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/strings/__init__.py +0 -0
  31. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/strings/svg_strings.py +0 -0
  32. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight/unit_conversion.py +0 -0
  33. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight.egg-info/dependency_links.txt +0 -0
  34. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight.egg-info/requires.txt +0 -0
  35. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/src/svg_ultralight.egg-info/top_level.txt +0 -0
  36. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/__init__.py +0 -0
  37. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/conftest.py +0 -0
  38. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/test_layout.py +0 -0
  39. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/test_metadata.py +0 -0
  40. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/test_new_element.py +0 -0
  41. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/test_string_conversion.py +0 -0
  42. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tests/test_svg_ultralight.py +0 -0
  43. {svg_ultralight-0.26.0 → svg_ultralight-0.27.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: svg-ultralight
3
- Version: 0.26.0
3
+ Version: 0.27.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.26.0"
3
+ version = "0.27.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" }
@@ -20,6 +20,10 @@ build-backend = "setuptools.build_meta"
20
20
  addopts = "--doctest-modules"
21
21
 
22
22
 
23
+ [tool.isort]
24
+ profile = "black"
25
+
26
+
23
27
  [tool.tox]
24
28
  legacy_tox_ini = """
25
29
  [tox]
@@ -33,7 +37,7 @@ legacy_tox_ini = """
33
37
 
34
38
  [tool.commitizen]
35
39
  name = "cz_conventional_commits"
36
- version = "0.26.0"
40
+ version = "0.27.0"
37
41
  tag_format = "$version"
38
42
  version_files = ["pyproject.toml:^version"]
39
43
  annotated_tag = true
@@ -4,6 +4,11 @@
4
4
  :created: 12/22/2019.
5
5
  """
6
6
 
7
+ from svg_ultralight.bounding_boxes.bound_helpers import (
8
+ new_bbox_union,
9
+ new_bound_union,
10
+ new_element_union,
11
+ )
7
12
  from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
8
13
  from svg_ultralight.bounding_boxes.type_bound_element import BoundElement
9
14
  from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
@@ -27,6 +32,7 @@ from svg_ultralight.nsmap import NSMAP, new_qname
27
32
  from svg_ultralight.query import pad_text
28
33
  from svg_ultralight.root_elements import new_svg_root_around_bounds
29
34
  from svg_ultralight.string_conversion import (
35
+ format_attr_dict,
30
36
  format_number,
31
37
  format_numbers,
32
38
  format_numbers_in_string,
@@ -39,10 +45,14 @@ __all__ = [
39
45
  "PaddedText",
40
46
  "SupportsBounds",
41
47
  "deepcopy_element",
48
+ "format_attr_dict",
42
49
  "format_number",
43
50
  "format_numbers",
44
51
  "format_numbers_in_string",
52
+ "new_bbox_union",
53
+ "new_bound_union",
45
54
  "new_element",
55
+ "new_element_union",
46
56
  "new_metadata",
47
57
  "new_qname",
48
58
  "new_sub_element",
@@ -0,0 +1,95 @@
1
+ """Helper functions for dealing with BoundElements.
2
+
3
+ :author: Shay Hill
4
+ :created: 2024-05-03
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ from lxml.etree import _Element as EtreeElement # type: ignore
12
+
13
+ from svg_ultralight.bounding_boxes.type_bound_element import BoundElement
14
+ from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
15
+ from svg_ultralight.bounding_boxes.type_padded_text import PaddedText
16
+ from svg_ultralight.constructors import new_element
17
+
18
+ if TYPE_CHECKING:
19
+ from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
20
+
21
+
22
+ def new_element_union(
23
+ *elems: EtreeElement | SupportsBounds, **attributes: float | str
24
+ ) -> EtreeElement:
25
+ """Get the union of any elements found in the given arguments.
26
+
27
+ :param elems: BoundElements, PaddedTexts, or EtreeElements.
28
+ Other arguments will be ignored.
29
+ :return: a new group element containing all elements.
30
+
31
+ This does not support consolidating attributes. E.g., if all elements have the
32
+ same fill color, this will not be recognized and consilidated into a single
33
+ attribute for the group. Too many attributes change their behavior when applied
34
+ to a group.
35
+ """
36
+ elements_found: list[EtreeElement] = []
37
+ for elem in elems:
38
+ if isinstance(elem, (BoundElement, PaddedText)):
39
+ elements_found.append(elem.elem)
40
+ elif isinstance(elem, EtreeElement):
41
+ elements_found.append(elem)
42
+
43
+ if not elements_found:
44
+ msg = (
45
+ "Cannot find any elements to union. "
46
+ + "At least one argument must be a "
47
+ + "BoundElement, PaddedText, or EtreeElement."
48
+ )
49
+ raise ValueError(msg)
50
+ group = new_element("g", **attributes)
51
+ group.extend(elements_found)
52
+ return group
53
+
54
+
55
+ def new_bbox_union(*blems: SupportsBounds | EtreeElement) -> BoundingBox:
56
+ """Get the union of the bounding boxes of the given elements.
57
+
58
+ :param blems: BoundElements, BoundingBoxes, or PaddedTexts.
59
+ Other arguments will be ignored.
60
+ :return: the union of all bounding boxes as a BoundingBox instance.
61
+
62
+ Will used the padded_box attribute of PaddedText instances.
63
+ """
64
+ bboxes: list[BoundingBox] = []
65
+ for blem in blems:
66
+ if isinstance(blem, BoundingBox):
67
+ bboxes.append(blem)
68
+ elif isinstance(blem, BoundElement):
69
+ bboxes.append(blem.bbox)
70
+ elif isinstance(blem, PaddedText):
71
+ bboxes.append(blem.padded_bbox)
72
+
73
+ if not bboxes:
74
+ msg = (
75
+ "Cannot find any bounding boxes to union. "
76
+ + "At least one argument must be a "
77
+ + "BoundElement, BoundingBox, or PaddedText."
78
+ )
79
+ raise ValueError(msg)
80
+
81
+ return BoundingBox.merged(*bboxes)
82
+
83
+
84
+ def new_bound_union(*blems: SupportsBounds | EtreeElement) -> BoundElement:
85
+ """Get the union of the bounding boxes of the given elements.
86
+
87
+ :param blems: BoundElements or EtreeElements.
88
+ At least one argument must be a BoundElement, BoundingBox, or PaddedText.
89
+ :return: the union of all arguments as a BoundElement instance.
90
+
91
+ Will used the padded_box attribute of PaddedText instances.
92
+ """
93
+ group = new_element_union(*blems)
94
+ bbox = new_bbox_union(*blems)
95
+ return BoundElement(group, bbox)
@@ -8,9 +8,8 @@ from __future__ import annotations
8
8
 
9
9
  from typing import TYPE_CHECKING
10
10
 
11
- from svg_ultralight.bounding_boxes.type_bound_element import BoundElement
11
+ from svg_ultralight.bounding_boxes import bound_helpers as bound
12
12
  from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
13
- from svg_ultralight.bounding_boxes.type_padded_text import PaddedText
14
13
  from svg_ultralight.main import new_svg_root
15
14
 
16
15
  if TYPE_CHECKING:
@@ -64,15 +63,8 @@ def new_svg_root_around_bounds(
64
63
  :return: root svg element
65
64
  :raise ValueError: if no bounding boxes are found in bounded
66
65
  """
67
- bboxes = [x for x in bounded if isinstance(x, BoundingBox)]
68
- bboxes += [x.bbox for x in bounded if isinstance(x, BoundElement)]
69
- bboxes += [x.padded_bbox for x in bounded if isinstance(x, PaddedText)]
70
-
71
- if not bboxes:
72
- msg = "no bounding boxes found"
73
- raise ValueError(msg)
74
-
75
- viewbox = _viewbox_args_from_bboxes(*bboxes)
66
+ bbox = bound.new_bbox_union(*bounded)
67
+ viewbox = _viewbox_args_from_bboxes(bbox)
76
68
  return new_svg_root(
77
69
  x_=viewbox["x_"],
78
70
  y_=viewbox["y_"],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: svg-ultralight
3
- Version: 0.26.0
3
+ Version: 0.27.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
@@ -20,6 +20,7 @@ src/svg_ultralight.egg-info/dependency_links.txt
20
20
  src/svg_ultralight.egg-info/requires.txt
21
21
  src/svg_ultralight.egg-info/top_level.txt
22
22
  src/svg_ultralight/bounding_boxes/__init__.py
23
+ src/svg_ultralight/bounding_boxes/bound_helpers.py
23
24
  src/svg_ultralight/bounding_boxes/supports_bounds.py
24
25
  src/svg_ultralight/bounding_boxes/type_bound_element.py
25
26
  src/svg_ultralight/bounding_boxes/type_bounding_box.py
@@ -17,10 +17,7 @@ from svg_ultralight.inkscape import convert_text_to_path
17
17
  from svg_ultralight.main import new_svg_root
18
18
  from svg_ultralight.nsmap import NSMAP
19
19
 
20
- INKSCAPE = Path(
21
- r"C:\\Program Files\\WindowsApps\\25415Inkscape.Inkscape_1.3.2.0"
22
- + "_x64__9waqn51p1ttv2\\VFS\\ProgramFilesX64\\Inkscape\\bin\\inkscape.exe"
23
- )
20
+ INKSCAPE = Path(r"C:\Program Files\Inkscape\bin\inkscape")
24
21
 
25
22
  if not INKSCAPE.with_suffix(".exe").exists():
26
23
  msg = "Inkscape not found. Please install Inkscape or update the INKSCAPE path var."
@@ -17,10 +17,7 @@ from svg_ultralight import new_svg_root
17
17
  from svg_ultralight.constructors import new_sub_element
18
18
  from svg_ultralight.query import BoundingBox, map_ids_to_bounding_boxes
19
19
 
20
- INKSCAPE = Path(
21
- r"C:\\Program Files\\WindowsApps\\25415Inkscape.Inkscape_1.3.2.0"
22
- + "_x64__9waqn51p1ttv2\\VFS\\ProgramFilesX64\\Inkscape\\bin\\inkscape.exe"
23
- )
20
+ INKSCAPE = Path(r"C:\Program Files\Inkscape\bin\inkscape")
24
21
 
25
22
  if not INKSCAPE.with_suffix(".exe").exists():
26
23
  msg = "Inkscape not found. Please install Inkscape or update the INKSCAPE path var."
@@ -6,15 +6,13 @@
6
6
 
7
7
  import pytest
8
8
 
9
- from svg_ultralight.main import new_svg_root
10
- from svg_ultralight.bounding_boxes.supports_bounds import SupportsBounds
11
9
  from svg_ultralight.bounding_boxes.type_bounding_box import BoundingBox
12
10
  from svg_ultralight.bounding_boxes.type_bound_element import BoundElement
13
11
  from svg_ultralight.bounding_boxes.type_padded_text import PaddedText
14
12
  from svg_ultralight.constructors import new_element
15
13
  from svg_ultralight.root_elements import new_svg_root_around_bounds
14
+ from svg_ultralight.bounding_boxes.bound_helpers import new_bound_union
16
15
  from lxml.etree import _Element as EtreeElement # type: ignore
17
- from typing import Union
18
16
 
19
17
 
20
18
  class TestNewSvgRootAroundBounds:
@@ -23,13 +21,13 @@ class TestNewSvgRootAroundBounds:
23
21
  """Raise ValueError if no bounding boxes found."""
24
22
  with pytest.raises(ValueError) as excinfo:
25
23
  _ = new_svg_root_around_bounds()
26
- assert "no bounding boxes found" in str(excinfo.value)
24
+ assert "At least one argument" in str(excinfo.value)
27
25
 
28
26
  def test_no_bound_elements(self):
29
27
  """Raise ValueError if no BoundElements found."""
30
28
  with pytest.raises(ValueError) as excinfo:
31
29
  _ = new_svg_root_around_bounds(new_element("g"))
32
- assert "no bounding boxes found" in str(excinfo.value)
30
+ assert "At least one argument" in str(excinfo.value)
33
31
 
34
32
  def test_bounding_boxes(self):
35
33
  """Create svg root element from bounding boxes."""
@@ -53,3 +51,33 @@ class TestNewSvgRootAroundBounds:
53
51
  result = new_svg_root_around_bounds(*args)
54
52
  assert isinstance(result, EtreeElement)
55
53
  assert result.attrib["viewBox"] == "0 0 201 201"
54
+
55
+ class TestNewBoundUnion:
56
+
57
+ def test_bounding_boxes_only(self):
58
+ """Raise an error if no elements found."""
59
+ bboxes = [BoundingBox(0, 0, 100, 100), BoundingBox(50, 50, 150, 150)]
60
+ with pytest.raises(ValueError) as excinfo:
61
+ _ = new_bound_union(*bboxes)
62
+ assert "must be a BoundElement, PaddedText, or Etree" in str(excinfo.value)
63
+
64
+ def test_elements_only(self):
65
+ """Raise an error if no elements found."""
66
+ elems = [new_element("g"), new_element("g")]
67
+ with pytest.raises(ValueError) as excinfo:
68
+ _ = new_bound_union(*elems)
69
+ assert "must be a BoundElement, BoundingBox, or Padded" in str(excinfo.value)
70
+
71
+ def test_bound_elements(self):
72
+ """Create svg root element from BoundElements."""
73
+ bboxes = [BoundingBox(0, 0, 100, 100), BoundingBox(50, 50, 150, 150)]
74
+ args = bboxes[0], BoundElement(new_element("g"), bboxes[1])
75
+ result = new_bound_union(*args)
76
+ assert isinstance(result, BoundElement)
77
+
78
+ def test_padded_text(self):
79
+ """Create svg root element from BoundElements."""
80
+ bboxes = [BoundingBox(0, 0, 100, 100), BoundingBox(50, 50, 150, 150)]
81
+ args = bboxes[0], PaddedText(new_element("g"), bboxes[1], 1, 1, 1, 1)
82
+ result = new_bound_union(*args)
83
+ assert isinstance(result, BoundElement)
File without changes