python-pptx2 2.15.0__py3-none-any.whl → 2.17.0__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.
- pptx2/__init__.py +1 -1
- pptx2/_textstyle.py +1 -0
- pptx2/audit.py +36 -3
- pptx2/shapes/shapetree.py +35 -3
- pptx2/skill/references/lint.md +16 -0
- {python_pptx2-2.15.0.dist-info → python_pptx2-2.17.0.dist-info}/METADATA +1 -1
- {python_pptx2-2.15.0.dist-info → python_pptx2-2.17.0.dist-info}/RECORD +11 -11
- {python_pptx2-2.15.0.dist-info → python_pptx2-2.17.0.dist-info}/WHEEL +0 -0
- {python_pptx2-2.15.0.dist-info → python_pptx2-2.17.0.dist-info}/entry_points.txt +0 -0
- {python_pptx2-2.15.0.dist-info → python_pptx2-2.17.0.dist-info}/licenses/LICENSE +0 -0
- {python_pptx2-2.15.0.dist-info → python_pptx2-2.17.0.dist-info}/top_level.txt +0 -0
pptx2/__init__.py
CHANGED
pptx2/_textstyle.py
CHANGED
|
@@ -28,6 +28,7 @@ ALIGN_MAP = {
|
|
|
28
28
|
ANCHOR_MAP = {
|
|
29
29
|
"top": MSO_VERTICAL_ANCHOR.TOP,
|
|
30
30
|
"middle": MSO_VERTICAL_ANCHOR.MIDDLE,
|
|
31
|
+
"mid": MSO_VERTICAL_ANCHOR.MIDDLE,
|
|
31
32
|
"center": MSO_VERTICAL_ANCHOR.MIDDLE,
|
|
32
33
|
"centre": MSO_VERTICAL_ANCHOR.MIDDLE,
|
|
33
34
|
"bottom": MSO_VERTICAL_ANCHOR.BOTTOM,
|
pptx2/audit.py
CHANGED
|
@@ -30,7 +30,7 @@ The audit is read-only — it never mutates the deck.
|
|
|
30
30
|
from __future__ import annotations
|
|
31
31
|
|
|
32
32
|
from dataclasses import dataclass, field
|
|
33
|
-
from typing import TYPE_CHECKING, Any
|
|
33
|
+
from typing import TYPE_CHECKING, Any, Iterable
|
|
34
34
|
|
|
35
35
|
if TYPE_CHECKING:
|
|
36
36
|
from pptx2.api import Presentation
|
|
@@ -41,7 +41,8 @@ __all__ = ["AuditReport", "audit"]
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
# Fonts that ship with stock Windows / macOS / Office installs. Used as
|
|
44
|
-
# a (very conservative) safe-list for the font_warnings probe.
|
|
44
|
+
# a (very conservative) safe-list for the font_warnings probe. Aptos and
|
|
45
|
+
# family are the Microsoft 365 default theme fonts since 2024.
|
|
45
46
|
_COMMON_FONTS = frozenset(
|
|
46
47
|
name.lower()
|
|
47
48
|
for name in (
|
|
@@ -51,9 +52,17 @@ _COMMON_FONTS = frozenset(
|
|
|
51
52
|
"Lucida Console", "Palatino", "Palatino Linotype", "Symbol",
|
|
52
53
|
"Wingdings", "Wingdings 2", "Wingdings 3", "Webdings",
|
|
53
54
|
"Inter", "Roboto", "Open Sans", "Lato", "Noto Sans",
|
|
55
|
+
"Aptos", "Aptos Display", "Aptos Narrow", "Aptos Serif", "Aptos Mono",
|
|
56
|
+
"Aptos Symbols",
|
|
54
57
|
)
|
|
55
58
|
)
|
|
56
59
|
|
|
60
|
+
# Environment variable merged into the safe-list on every audit() call, so
|
|
61
|
+
# rendering environments (sandboxes, CI) can declare their font inventory
|
|
62
|
+
# once instead of every caller passing ``extra_safe_fonts``. Comma- or
|
|
63
|
+
# semicolon-separated font names.
|
|
64
|
+
_SAFE_FONTS_ENV_VAR = "PPTX2_SAFE_FONTS"
|
|
65
|
+
|
|
57
66
|
|
|
58
67
|
@dataclass
|
|
59
68
|
class AuditReport:
|
|
@@ -174,15 +183,39 @@ def audit(
|
|
|
174
183
|
*,
|
|
175
184
|
size_warn_bytes: int = 2_000_000,
|
|
176
185
|
check_fonts: bool = True,
|
|
186
|
+
extra_safe_fonts: "Iterable[str] | None" = None,
|
|
177
187
|
) -> AuditReport:
|
|
178
188
|
"""Walk the deck and return an :class:`AuditReport` summary.
|
|
179
189
|
|
|
180
190
|
Read-only — never mutates the presentation. Each slide is linted
|
|
181
191
|
in passing-defaults mode; per-slide overrides should be supplied
|
|
182
192
|
via the slide-level ``slide.lint(...)`` API directly.
|
|
193
|
+
|
|
194
|
+
*extra_safe_fonts* names additional fonts to treat as safe for the
|
|
195
|
+
font-warning probe, on top of the common Windows/macOS/Office set
|
|
196
|
+
(matching is case-insensitive). Use it where the rendering
|
|
197
|
+
environment genuinely ships the font — e.g. ``DejaVu Sans`` in a
|
|
198
|
+
sandbox whose font policy standardizes on it, or a corporate font
|
|
199
|
+
you embed in every deck.
|
|
200
|
+
|
|
201
|
+
The ``PPTX2_SAFE_FONTS`` environment variable (comma- or
|
|
202
|
+
semicolon-separated font names) is merged into the safe-list on
|
|
203
|
+
every call, so an environment can declare its font inventory once
|
|
204
|
+
for all callers.
|
|
183
205
|
"""
|
|
206
|
+
import os
|
|
207
|
+
|
|
184
208
|
from pptx2.shapes.picture import Picture
|
|
185
209
|
|
|
210
|
+
safe_fonts = _COMMON_FONTS
|
|
211
|
+
extra_names = list(extra_safe_fonts) if extra_safe_fonts else []
|
|
212
|
+
for env_raw in os.environ.get(_SAFE_FONTS_ENV_VAR, "").replace(";", ",").split(","):
|
|
213
|
+
env_name = env_raw.strip()
|
|
214
|
+
if env_name:
|
|
215
|
+
extra_names.append(env_name)
|
|
216
|
+
if extra_names:
|
|
217
|
+
safe_fonts = _COMMON_FONTS | frozenset(f.lower() for f in extra_names)
|
|
218
|
+
|
|
186
219
|
report = AuditReport()
|
|
187
220
|
slides = list(prs.slides)
|
|
188
221
|
report.total_slides = len(slides)
|
|
@@ -249,7 +282,7 @@ def audit(
|
|
|
249
282
|
for para in tf.paragraphs:
|
|
250
283
|
for run in para.runs:
|
|
251
284
|
name = run.font.name
|
|
252
|
-
if name and name.lower() not in
|
|
285
|
+
if name and name.lower() not in safe_fonts:
|
|
253
286
|
report.font_warnings.append((idx, name))
|
|
254
287
|
|
|
255
288
|
if content_shapes == 0:
|
pptx2/shapes/shapetree.py
CHANGED
|
@@ -557,6 +557,24 @@ class _BaseShapes(ParentedElementProxy):
|
|
|
557
557
|
return BaseShapeFactory(shape_elm, self)
|
|
558
558
|
|
|
559
559
|
|
|
560
|
+
def _resolve_alias(method: str, arg: str, canonical, alias):
|
|
561
|
+
"""Return *canonical*, falling back to its *alias* kwarg (both nullable).
|
|
562
|
+
|
|
563
|
+
Code generators (matplotlib-trained models among them) habitually spell
|
|
564
|
+
``font`` as ``font_family`` and ``anchor`` as ``valign``; accepting the
|
|
565
|
+
alias removes a whole class of one-keyword-away TypeErrors. Passing
|
|
566
|
+
both with different values is a genuine caller bug and still raises.
|
|
567
|
+
"""
|
|
568
|
+
if canonical is not None:
|
|
569
|
+
if alias is not None and alias != canonical:
|
|
570
|
+
raise TypeError(
|
|
571
|
+
f"{method}(): pass either {arg}= or its alias, not two "
|
|
572
|
+
f"different values ({canonical!r} vs {alias!r})"
|
|
573
|
+
)
|
|
574
|
+
return canonical
|
|
575
|
+
return alias
|
|
576
|
+
|
|
577
|
+
|
|
560
578
|
class _BaseGroupShapes(_BaseShapes):
|
|
561
579
|
"""Base class for shape-trees that can add shapes."""
|
|
562
580
|
|
|
@@ -900,12 +918,14 @@ class _BaseGroupShapes(_BaseShapes):
|
|
|
900
918
|
*bbox_or_positional,
|
|
901
919
|
text: str = "",
|
|
902
920
|
font: str | None = None,
|
|
921
|
+
font_family: str | None = None,
|
|
903
922
|
size_pt: float | None = None,
|
|
904
923
|
bold: bool | None = None,
|
|
905
924
|
italic: bool | None = None,
|
|
906
925
|
color=None,
|
|
907
926
|
align: str | None = None,
|
|
908
927
|
anchor: str | None = None,
|
|
928
|
+
valign: str | None = None,
|
|
909
929
|
margin_pt: float | tuple[float, float, float, float] | None = None,
|
|
910
930
|
word_wrap: bool | None = True,
|
|
911
931
|
) -> Shape:
|
|
@@ -922,14 +942,17 @@ class _BaseGroupShapes(_BaseShapes):
|
|
|
922
942
|
Keyword args:
|
|
923
943
|
|
|
924
944
|
* ``font`` — typeface name (e.g. ``"Inter"``); ``None`` inherits.
|
|
945
|
+
``font_family`` is accepted as an alias (matplotlib habits die
|
|
946
|
+
hard).
|
|
925
947
|
* ``size_pt`` — font size in points; ``None`` inherits.
|
|
926
948
|
* ``bold`` / ``italic`` — ``True``/``False``/``None``.
|
|
927
949
|
* ``color`` — any "color-like" (``"#RRGGBB"``, ``RGBColor``,
|
|
928
950
|
``(r, g, b)``).
|
|
929
951
|
* ``align`` — ``"left"`` / ``"center"`` / ``"right"`` /
|
|
930
952
|
``"justify"``; ``None`` inherits.
|
|
931
|
-
* ``anchor`` — vertical anchor: ``"top"`` / ``"middle"``
|
|
932
|
-
``"bottom"``; ``None`` inherits.
|
|
953
|
+
* ``anchor`` — vertical anchor: ``"top"`` / ``"middle"`` (also
|
|
954
|
+
``"mid"`` / ``"center"``) / ``"bottom"``; ``None`` inherits.
|
|
955
|
+
``valign`` is accepted as an alias.
|
|
933
956
|
* ``margin_pt`` — uniform margin in points, or a 4-tuple
|
|
934
957
|
``(top, right, bottom, left)``.
|
|
935
958
|
* ``word_wrap`` — defaults to ``True``.
|
|
@@ -940,6 +963,9 @@ class _BaseGroupShapes(_BaseShapes):
|
|
|
940
963
|
from pptx2._textstyle import apply_margins, apply_text_style, coerce_anchor
|
|
941
964
|
from pptx2.geometry import BBox
|
|
942
965
|
|
|
966
|
+
font = _resolve_alias("add_text", "font", font, font_family)
|
|
967
|
+
anchor = _resolve_alias("add_text", "anchor", anchor, valign)
|
|
968
|
+
|
|
943
969
|
if len(bbox_or_positional) == 1 and isinstance(bbox_or_positional[0], BBox):
|
|
944
970
|
box = bbox_or_positional[0]
|
|
945
971
|
left, top, width, height = box.left, box.top, box.width, box.height
|
|
@@ -986,10 +1012,12 @@ class _BaseGroupShapes(_BaseShapes):
|
|
|
986
1012
|
latex: str,
|
|
987
1013
|
display: bool = True,
|
|
988
1014
|
font: str | None = None,
|
|
1015
|
+
font_family: str | None = None,
|
|
989
1016
|
size_pt: float | None = None,
|
|
990
1017
|
color=None,
|
|
991
1018
|
align: str | None = "center",
|
|
992
1019
|
anchor: str | None = "middle",
|
|
1020
|
+
valign: str | None = None,
|
|
993
1021
|
margin_pt: float | tuple[float, float, float, float] | None = None,
|
|
994
1022
|
) -> Shape:
|
|
995
1023
|
"""Add a text box containing a native PowerPoint equation from LaTeX.
|
|
@@ -1008,13 +1036,17 @@ class _BaseGroupShapes(_BaseShapes):
|
|
|
1008
1036
|
equation editor.
|
|
1009
1037
|
|
|
1010
1038
|
Keyword args match :meth:`add_text` for *font* / *size_pt* /
|
|
1011
|
-
*color* / *align* / *anchor* / *margin_pt
|
|
1039
|
+
*color* / *align* / *anchor* / *margin_pt* (including the
|
|
1040
|
+
``font_family`` / ``valign`` aliases). *display* (default
|
|
1012
1041
|
|True|) emits a display-math paragraph; set |False| for inline
|
|
1013
1042
|
OMML.
|
|
1014
1043
|
"""
|
|
1015
1044
|
from pptx2._textstyle import apply_margins, coerce_align, coerce_anchor
|
|
1016
1045
|
from pptx2.geometry import BBox
|
|
1017
1046
|
|
|
1047
|
+
font = _resolve_alias("add_equation", "font", font, font_family)
|
|
1048
|
+
anchor = _resolve_alias("add_equation", "anchor", anchor, valign)
|
|
1049
|
+
|
|
1018
1050
|
if len(bbox_or_positional) == 1 and isinstance(bbox_or_positional[0], BBox):
|
|
1019
1051
|
box = bbox_or_positional[0]
|
|
1020
1052
|
left, top, width, height = box.left, box.top, box.width, box.height
|
pptx2/skill/references/lint.md
CHANGED
|
@@ -178,6 +178,22 @@ if data["has_errors"]:
|
|
|
178
178
|
... # hand `data` straight to the model to fix
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
+
`audit()` also warns on fonts outside the common Windows/macOS/Office
|
|
182
|
+
safe-list. When the rendering environment genuinely ships a font (e.g.
|
|
183
|
+
DejaVu Sans in a Linux sandbox), pass it instead of letting the deck
|
|
184
|
+
drown in noise:
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
report = audit(prs, extra_safe_fonts=["DejaVu Sans", "Noto Sans CJK JP"])
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Or declare the inventory once for every caller via the environment
|
|
191
|
+
(merged into the safe-list on each `audit()`):
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
export PPTX2_SAFE_FONTS="DejaVu Sans; Noto Sans CJK JP"
|
|
195
|
+
```
|
|
196
|
+
|
|
181
197
|
## Save-time hooks (via `from_spec`)
|
|
182
198
|
|
|
183
199
|
If you build the deck through `pptx2.compose.from_spec`, the spec dict
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-pptx2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.17.0
|
|
4
4
|
Summary: Create, read, and update PowerPoint 2007+ (.pptx) files. Fork of power-pptx / python-pptx, published as python-pptx2.
|
|
5
5
|
Author: Matěj Štágl
|
|
6
6
|
Author-email: stagl@wattlescript.org
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
pptx2/__init__.py,sha256=
|
|
1
|
+
pptx2/__init__.py,sha256=lLf03V_PykqZkDfLk7wwFUMFnN9JnqDoW3ziwibWXfE,4076
|
|
2
2
|
pptx2/_color.py,sha256=Ureg4dSEdHbwpVZ5eJIyt0kLx_W3mGftmznejth_oLQ,2889
|
|
3
3
|
pptx2/_slide_importer.py,sha256=Ot3lW20eS7fMKsaGaeqPyeS9zVzt5D1WkovwozWwbYY,27033
|
|
4
4
|
pptx2/_svg.py,sha256=pMURsUQaJ9-dqRl4nEZKt1VECNpA8Ghp4EwNRWcBG-c,5973
|
|
5
5
|
pptx2/_template_applier.py,sha256=H1pu7bgUMUhJzTvABuQFT7zkjSWas5NfdJIipamCvXw,12699
|
|
6
|
-
pptx2/_textstyle.py,sha256=
|
|
6
|
+
pptx2/_textstyle.py,sha256=INb0JvqeHwP7cmlxoRe65ImV3vR_AbUKMFKEWOUfAr4,6354
|
|
7
7
|
pptx2/accessibility.py,sha256=SDVPX6FK77B3OXBMvr65qowzJFVzcRsnMybjVMQ0oi4,11981
|
|
8
8
|
pptx2/action.py,sha256=BiDtM80P6oFsNOtLIT1nX82LXEvaGOg4Usaf5CA7kNY,9648
|
|
9
9
|
pptx2/animation.py,sha256=g0OxAkCoGu0QEx3QB9Yu4BOnGLjD3tcLpKoYBAtUW6s,83756
|
|
10
10
|
pptx2/api.py,sha256=n98a5qUhVxSwZ_yG_aXxtDCxtnEp37LPsSIsYsbwsfA,1841
|
|
11
|
-
pptx2/audit.py,sha256=
|
|
11
|
+
pptx2/audit.py,sha256=xg1QAs-ByW3xwBEcJ-Y9ptYe2WHKmVuVWAgRKQZfcr8,11276
|
|
12
12
|
pptx2/diagrams.py,sha256=5NqGg-CMj6ZYoEsI9pBD1UHmwQhSAK8oAFYD89NPsVg,24654
|
|
13
13
|
pptx2/exc.py,sha256=k6p-e9h5cKal09-sAv3E1QTXmVDuF8FqewW1CKFQmfw,1276
|
|
14
14
|
pptx2/formats.py,sha256=w0b8YXBjBbPhDu1UV9-1iUJdL62d9_gcQSp9sHKVr_s,5081
|
|
@@ -136,7 +136,7 @@ pptx2/shapes/graphfrm.py,sha256=mwA9Wb4WRKBy6sA7KzOZFl3aHlpN-TmWRcE-kiMoqRI,1189
|
|
|
136
136
|
pptx2/shapes/group.py,sha256=xlcGi3MAzBHX2IM16IATxRgw8NwsPFzTMVbRPYQ7OKg,11036
|
|
137
137
|
pptx2/shapes/picture.py,sha256=U7rwiy7OXn0RgFSEdh07bdhIplWsI82OjFk-mt975J0,14938
|
|
138
138
|
pptx2/shapes/placeholder.py,sha256=9tIeNscnV46hWyMr8ZSiZO3TZr-tt4kZgx6BRB0tCvc,17838
|
|
139
|
-
pptx2/shapes/shapetree.py,sha256=
|
|
139
|
+
pptx2/shapes/shapetree.py,sha256=bbrwutelMOcRX8pT88qRLvPyE3x6avIhripnUGalH1I,82851
|
|
140
140
|
pptx2/skill/SKILL.md,sha256=6w7sWflZvhYYIzBsXLjx2uVKqB0793ZTvoZ_SUfzQxg,23668
|
|
141
141
|
pptx2/skill/__init__.py,sha256=bUkfMETwf3K6J7GSE-tLQjdNziS_JceunComLiLIeGI,2665
|
|
142
142
|
pptx2/skill/__main__.py,sha256=ohMLGy1jbjKV5_FqY6aGj4tm_isJ6fznvqUKiE1H6s8,1777
|
|
@@ -148,7 +148,7 @@ pptx2/skill/references/design.md,sha256=ne3xVyIwqpkhEkd8XK74QEija040eHve5zBHBx9L
|
|
|
148
148
|
pptx2/skill/references/effects.md,sha256=B4Z_rbxm5CjVeLt8rJZ-UydLPq62FgcDP32CZ1KUrvY,7668
|
|
149
149
|
pptx2/skill/references/end-to-end-deck.md,sha256=6ApwoK1wJ--Oeadyjy4Iq3E0czyPBME6RYAAWQijhNU,8021
|
|
150
150
|
pptx2/skill/references/geometry-and-arrows.md,sha256=kiy2KIpzcrWbfUH0tWgfdaHRH4k0QPNu0SEkk7JAKNE,10163
|
|
151
|
-
pptx2/skill/references/lint.md,sha256=
|
|
151
|
+
pptx2/skill/references/lint.md,sha256=VAWhb9hlump9Fkw3JGZQEODGc13HhthJuigu-bvC-lA,10344
|
|
152
152
|
pptx2/skill/references/math.md,sha256=C8j5FcjpJgBacKwetL6HfdM2d3zRaTAcLrkyYVP-9H8,2572
|
|
153
153
|
pptx2/skill/references/picture-effects.md,sha256=NCGIqICQOd7DfEif8m_OY5teS75NVQU_micGysgsi1w,3735
|
|
154
154
|
pptx2/skill/references/render.md,sha256=4mUI5sYbkY5sT_oCA5YEcuQG2ddzvs_gPe4XEiSL3WQ,4671
|
|
@@ -170,9 +170,9 @@ pptx2/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
170
170
|
pptx2/text/fonts.py,sha256=ECa9HuBfeTqOi-uJTz_bu7eurC7e1_64RTwDatxmkpk,16498
|
|
171
171
|
pptx2/text/layout.py,sha256=k8bqod6GyshHJtfoqFtH9W-eHTI43IB0e6SLT1ibSUU,12815
|
|
172
172
|
pptx2/text/text.py,sha256=LPqF1B4GSQNSnSlVMm1v7pgtHCymOJPTUG_Kdt5_ou4,55039
|
|
173
|
-
python_pptx2-2.
|
|
174
|
-
python_pptx2-2.
|
|
175
|
-
python_pptx2-2.
|
|
176
|
-
python_pptx2-2.
|
|
177
|
-
python_pptx2-2.
|
|
178
|
-
python_pptx2-2.
|
|
173
|
+
python_pptx2-2.17.0.dist-info/licenses/LICENSE,sha256=hLdud18ZPS9iSG3kBCBLiGYzj4A6zedCHiDejIDBXNg,1230
|
|
174
|
+
python_pptx2-2.17.0.dist-info/METADATA,sha256=mx9AhEC2xmYL-p2zCSn6iHbmj4GaBnNVBBg81sHNg88,14374
|
|
175
|
+
python_pptx2-2.17.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
176
|
+
python_pptx2-2.17.0.dist-info/entry_points.txt,sha256=UpD1_pA-2BPeN0iDeD-u4NZ_yC78TvBdWu3V1xLsSRE,105
|
|
177
|
+
python_pptx2-2.17.0.dist-info/top_level.txt,sha256=NDdhJ4rOySlDU-cw4g-bQMoZCiy41WszlRXmIiReSRs,6
|
|
178
|
+
python_pptx2-2.17.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|