pyOfficeEditor 0.2.0__tar.gz → 0.2.2__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.
Files changed (37) hide show
  1. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/PKG-INFO +1 -1
  2. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/docs/changelog.md +36 -1
  3. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/pyproject.toml +1 -1
  4. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/__init__.py +15 -1
  5. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_shapes.py +69 -0
  6. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/.gitignore +0 -0
  7. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/LICENSE.md +0 -0
  8. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/README.md +0 -0
  9. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/docs/architecture.md +0 -0
  10. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/_xml.py +0 -0
  11. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/_zip.py +0 -0
  12. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/__init__.py +0 -0
  13. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_addresses.py +0 -0
  14. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_conditional.py +0 -0
  15. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_dimensions.py +0 -0
  16. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_dxf.py +0 -0
  17. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_formats.py +0 -0
  18. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_formulas.py +0 -0
  19. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_hyperlinks.py +0 -0
  20. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_names.py +0 -0
  21. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_pagesetup.py +0 -0
  22. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_protection.py +0 -0
  23. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_reference.py +0 -0
  24. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_rowcol.py +0 -0
  25. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_schema.py +0 -0
  26. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_sharedstrings.py +0 -0
  27. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_styles.py +0 -0
  28. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_tables.py +0 -0
  29. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_tokens.py +0 -0
  30. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_validation.py +0 -0
  31. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/_values.py +0 -0
  32. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/workbook.py +0 -0
  33. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/excel/worksheet.py +0 -0
  34. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/exceptions.py +0 -0
  35. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/opc.py +0 -0
  36. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/src/pyofficeeditor/py.typed +0 -0
  37. {pyofficeeditor-0.2.0 → pyofficeeditor-0.2.2}/tests/fixtures/excel/README.md +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pyOfficeEditor
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: Edit the document surface of Excel, Word, PowerPoint and Access in pure Python, no dependencies.
5
5
  Project-URL: Homepage, https://github.com/WilliamSmithEdward/pyOfficeEditor
6
6
  Project-URL: Repository, https://github.com/WilliamSmithEdward/pyOfficeEditor
@@ -11,7 +11,9 @@ package and writing it back unchanged reproduces the input exactly.
11
11
  workflow extracts one section by reading to the next "## [" heading, so
12
12
  anything trailing the file is swept into the oldest release's notes. -->
13
13
 
14
- [Unreleased]: https://github.com/WilliamSmithEdward/pyOfficeEditor/compare/v0.2.0...HEAD
14
+ [Unreleased]: https://github.com/WilliamSmithEdward/pyOfficeEditor/compare/v0.2.2...HEAD
15
+ [0.2.2]: https://github.com/WilliamSmithEdward/pyOfficeEditor/compare/v0.2.1...v0.2.2
16
+ [0.2.1]: https://github.com/WilliamSmithEdward/pyOfficeEditor/compare/v0.2.0...v0.2.1
15
17
  [0.2.0]: https://github.com/WilliamSmithEdward/pyOfficeEditor/compare/v0.1.1...v0.2.0
16
18
  [0.1.1]: https://github.com/WilliamSmithEdward/pyOfficeEditor/compare/v0.1.0...v0.1.1
17
19
  [0.1.0]: https://github.com/WilliamSmithEdward/pyOfficeEditor/releases/tag/v0.1.0
@@ -20,6 +22,39 @@ anything trailing the file is swept into the oldest release's notes. -->
20
22
 
21
23
  Nothing yet.
22
24
 
25
+ ## [0.2.2] - 2026-09-20
26
+
27
+ ### Fixed
28
+
29
+ - **`__version__` reported 0.1.0 on every release since.** It was a literal
30
+ in `__init__.py` that nothing linked to the version in
31
+ `pyproject.toml`, so 0.1.1, 0.2.0 and 0.2.1 all imported saying 0.1.0.
32
+ The distribution metadata was right throughout; only the attribute was
33
+ wrong, so `pip` and the PyPI page were never affected and anything
34
+ reading `pyofficeeditor.__version__` was.
35
+
36
+ It is read from the installed distribution now, which cannot drift, and
37
+ `tests/test_version.py` fails if the attribute, the metadata and
38
+ `pyproject.toml` ever disagree. That test is the thing that was missing:
39
+ nothing checked, so nothing failed.
40
+
41
+ ## [0.2.1] - 2026-09-19
42
+
43
+ ### Added
44
+
45
+ - **The preset geometry each MsoAutoShapeType maps to**, and
46
+ `Shape.auto_shape_type` reporting it back, measured by having Excel make
47
+ one shape of each of 33 types and reading the drawing.
48
+
49
+ This is an addition rather than a fix: pyOfficeEditor never carried the
50
+ table. It is worth measuring rather than transcribing, because every
51
+ plausible wrong answer is a real preset name belonging to some other
52
+ shape. A table pairing 11 with `cross`, 12 with `star5`, 16 with `can`
53
+ and 17 with `cube` looks right and is wrong on all four: Excel writes
54
+ `plus`, `pentagon`, `foldedCorner` and `smileyFace`. Nothing complains,
55
+ the file is valid, and the wrong shape appears. The five-pointed star is
56
+ 92, not 12.
57
+
23
58
  ## [0.2.0] - 2026-09-19
24
59
 
25
60
  Conditional formatting, data validation, sheet protection, page setup,
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyOfficeEditor"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "Edit the document surface of Excel, Word, PowerPoint and Access in pure Python, no dependencies."
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -19,6 +19,8 @@ Access follow in that order.
19
19
 
20
20
  from __future__ import annotations
21
21
 
22
+ from importlib.metadata import PackageNotFoundError, version
23
+
22
24
  from pyofficeeditor._xml import Element, XmlDocument
23
25
  from pyofficeeditor.exceptions import (
24
26
  PackageError,
@@ -29,7 +31,19 @@ from pyofficeeditor.exceptions import (
29
31
  )
30
32
  from pyofficeeditor.opc import OpcPackage, Relationship, Relationships
31
33
 
32
- __version__ = "0.1.0"
34
+ try:
35
+ #: Read from the installed distribution rather than written here.
36
+ #:
37
+ #: A literal has to be remembered at every release and was not: 0.1.1,
38
+ #: 0.2.0 and 0.2.1 all shipped saying 0.1.0, because nothing links a
39
+ #: string in this file to the version in pyproject.toml. Asking the
40
+ #: metadata cannot drift, and ``tests/test_version.py`` fails if the
41
+ #: two ever disagree.
42
+ __version__ = version("pyOfficeEditor")
43
+ except PackageNotFoundError: # pragma: no cover - a source tree, uninstalled
44
+ # Importable straight from a checkout, where there is no distribution to
45
+ # ask. Saying so beats guessing a number.
46
+ __version__ = "0.0.0+source"
33
47
 
34
48
  __all__ = [
35
49
  "Element",
@@ -97,6 +97,63 @@ _ELEMENT_KINDS: dict[str, ShapeKind] = {
97
97
  "graphicFrame": "chart",
98
98
  }
99
99
 
100
+
101
+ #: The preset geometry Excel writes for each ``MsoAutoShapeType``, measured
102
+ #: by making one shape of each and reading the drawing back.
103
+ #:
104
+ #: Worth measuring rather than transcribing, because every plausible wrong
105
+ #: answer here is a real preset name belonging to some other shape. A table
106
+ #: that pairs 11 with ``cross``, 12 with ``star5``, 16 with ``can`` and 17
107
+ #: with ``cube`` looks right and is wrong on all four: Excel writes ``plus``,
108
+ #: ``pentagon``, ``foldedCorner`` and ``smileyFace``. Nothing complains. The
109
+ #: file is valid and the wrong shape appears.
110
+ #:
111
+ #: The five-pointed star is 92, not 12. The numbers are not contiguous:
112
+ #: ``MsoAutoShapeType`` leaves gaps, and only the ones Excel actually made
113
+ #: when asked are here.
114
+ PRESET_GEOMETRY: dict[int, str] = {
115
+ 1: "rect", # msoShapeRectangle
116
+ 2: "parallelogram",
117
+ 3: "trapezoid",
118
+ 4: "diamond",
119
+ 5: "roundRect", # msoShapeRoundedRectangle
120
+ 6: "octagon",
121
+ 7: "triangle", # msoShapeIsoscelesTriangle
122
+ 8: "rtTriangle",
123
+ 9: "ellipse", # msoShapeOval
124
+ 10: "hexagon",
125
+ 11: "plus", # msoShapeCross
126
+ 12: "pentagon", # msoShapeRegularPentagon
127
+ 13: "can",
128
+ 14: "cube",
129
+ 15: "bevel",
130
+ 16: "foldedCorner",
131
+ 17: "smileyFace",
132
+ 18: "donut",
133
+ 19: "noSmoking",
134
+ 20: "blockArc",
135
+ 21: "heart",
136
+ 22: "lightningBolt",
137
+ 23: "sun",
138
+ 24: "moon",
139
+ 25: "arc",
140
+ 26: "bracketPair",
141
+ 27: "bracePair",
142
+ 28: "plaque",
143
+ 92: "star5", # msoShape5pointStar
144
+ 93: "star8",
145
+ 94: "star16",
146
+ 95: "star24",
147
+ 96: "star32",
148
+ }
149
+
150
+ #: The same the other way round, for reporting what a shape read from a
151
+ #: file would answer for ``AutoShapeType``.
152
+ AUTO_SHAPE_TYPES: dict[str, int] = {
153
+ preset: number for number, preset in PRESET_GEOMETRY.items()
154
+ }
155
+
156
+
100
157
  #: The anchors a drawing is made of.
101
158
  ANCHORS = ("twoCellAnchor", "oneCellAnchor", "absoluteAnchor")
102
159
 
@@ -221,6 +278,16 @@ class Shape:
221
278
  """What ``Shape.Type`` answers for this kind."""
222
279
  return MSO_TYPE.get(self.kind, 1)
223
280
 
281
+ @property
282
+ def auto_shape_type(self) -> int | None:
283
+ """What ``Shape.AutoShapeType`` answers, or ``None`` for a geometry
284
+ this does not name.
285
+
286
+ A text box answers 1 as well as an AutoShape does, which is what
287
+ Excel reports, because both are drawn as a rectangle.
288
+ """
289
+ return AUTO_SHAPE_TYPES.get(self.geometry)
290
+
224
291
  def __repr__(self) -> str:
225
292
  where = f"{self.left:g},{self.top:g} {self.width:g}x{self.height:g}"
226
293
  macro = f" macro={self.macro}" if self.macro else ""
@@ -470,10 +537,12 @@ def _as_float(raw: str | None, fallback: float) -> float:
470
537
 
471
538
  __all__ = [
472
539
  "ANCHORS",
540
+ "AUTO_SHAPE_TYPES",
473
541
  "DEFAULT_COLUMN_POINTS",
474
542
  "DEFAULT_ROW_POINTS",
475
543
  "EMU_PER_POINT",
476
544
  "MSO_TYPE",
545
+ "PRESET_GEOMETRY",
477
546
  "Shape",
478
547
  "ShapeKind",
479
548
  "SheetGrid",
File without changes