Skip to content

Commit 251c6ca

Browse files
committed
Merge branch 'main' of github.com:yassun7010/pptxr
2 parents 82c1246 + 413d794 commit 251c6ca

39 files changed

+1290
-725
lines changed

examples/formatted_text.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def functional_text(
2424
text: str,
2525
bold: bool = False,
2626
italic: bool = False,
27-
color: tppt.types.RGBColor | tppt.types.LiteralColor | None = None,
27+
color: tppt.types.Color | tppt.types.LiteralColor | None = None,
2828
) -> tppt.pptx.Text:
2929
run = text_obj.text_frame.add_paragraph().add_run()
3030
run.text = text

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "tppt"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
description = "Typed Python PowerPoint Tool"
55
readme = "README.md"
66
requires-python = ">=3.11.0"

src/tppt/exception.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from abc import abstractmethod
2-
from typing import TYPE_CHECKING, Any
2+
from typing import TYPE_CHECKING, Any, Literal
33

44
if TYPE_CHECKING:
55
from pptx.slide import SlideLayouts as PptxSlideLayouts
@@ -31,6 +31,17 @@ def message(self) -> str:
3131
return f"Invalid color format: {self.color}"
3232

3333

34+
class ColorInvalidTupleSizeError(TpptException, ValueError):
35+
"""Color tuple size is invalid."""
36+
37+
def __init__(self, color: tuple[Any, ...]) -> None:
38+
self.color = color
39+
40+
@property
41+
def message(self) -> str:
42+
return f"Invalid color tuple size: {self.color}, expected 3(RGB) or 4(RGBA) elements."
43+
44+
3445
class SlideLayoutIndexError(TpptException, IndexError):
3546
"""Slide layout index is out of range."""
3647

@@ -87,3 +98,17 @@ def __init__(
8798
@property
8899
def message(self) -> str:
89100
return f"Invalid setter type. Expected type: {self.expected_type}, but got: {self.actual_type}."
101+
102+
103+
class InvalidColorValueError(TpptException, ValueError):
104+
"""Invalid color value."""
105+
106+
def __init__(
107+
self, type: Literal["red", "green", "blue", "alpha"], value: int
108+
) -> None:
109+
self.type = type
110+
self.value = value
111+
112+
@property
113+
def message(self) -> str:
114+
return f"Invalid {self.type} value: {self.value}. It must be between 0 and 255."

src/tppt/pptx/action.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from pptx.action import ActionSetting as _PptxActionSetting
2+
from pptx.action import Hyperlink as _PptxHyperlink
3+
from pptx.enum.action import PP_ACTION_TYPE
4+
5+
from tppt.pptx.converter import PptxConvertible
6+
from tppt.pptx.shape import SubShape
7+
from tppt.pptx.slide import Slide
8+
9+
10+
class Hyperlink(SubShape[_PptxHyperlink]):
11+
@property
12+
def address(self) -> str | None:
13+
return self._pptx.address
14+
15+
@address.setter
16+
def address(self, value: str | None):
17+
self._pptx.address = value
18+
19+
20+
class ActionSetting(PptxConvertible[_PptxActionSetting]):
21+
@property
22+
def action(self) -> PP_ACTION_TYPE:
23+
return self._pptx.action
24+
25+
@property
26+
def hyperlink(self) -> Hyperlink:
27+
return Hyperlink(self._pptx.hyperlink)
28+
29+
@property
30+
def target_slide(self) -> Slide | None:
31+
if target_slide := self._pptx.target_slide:
32+
return Slide(target_slide)
33+
return None
34+
35+
@target_slide.setter
36+
def target_slide(self, value: Slide | None):
37+
if value is None:
38+
self._pptx.target_slide = None
39+
else:
40+
self._pptx.target_slide = value._pptx

src/tppt/pptx/chart/chart.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Literal, Self, TypedDict, assert_never
1+
from typing import Literal, TypedDict, assert_never
22

33
from pptx.chart.chart import Chart as PptxChart
44
from pptx.chart.data import ChartData as PptxChartData
@@ -258,18 +258,5 @@ class ChartData(ChartProps):
258258
class Chart(PptxConvertible[PptxChart]):
259259
"""Chart data class."""
260260

261-
def __init__(
262-
self,
263-
pptx_obj: PptxChart,
264-
/,
265-
) -> None:
266-
self._pptx = pptx_obj
267-
268-
def to_pptx(self) -> PptxChart:
269-
"""Convert to pptx shape."""
270-
return self._pptx
271-
272-
@classmethod
273-
def from_pptx(cls, pptx_obj: PptxChart) -> Self:
274-
"""Create from pptx shape."""
275-
return cls(pptx_obj)
261+
def __init__(self, pptx_obj: PptxChart, /) -> None:
262+
super().__init__(pptx_obj)

src/tppt/pptx/converter.py

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
"""Type definitions for pptx wrapper."""
22

33
from typing import (
4-
Protocol,
4+
Generic,
55
Self,
66
TypeAlias,
77
TypeVar,
88
assert_never,
99
overload,
10-
runtime_checkable,
1110
)
1211

1312
from pptx.dml.color import RGBColor as PptxRGBColor
@@ -19,7 +18,7 @@
1918
from pptx.util import Pt as PptxPt
2019

2120
from tppt.types._angle import Angle, Degrees, LiteralAngle
22-
from tppt.types._color import LiteralColor, RGBColor, to_rgb_color
21+
from tppt.types._color import Color, LiteralColor, to_color
2322
from tppt.types._length import (
2423
CentiMeters,
2524
EnglishMetricUnits,
@@ -34,29 +33,35 @@
3433
PT = TypeVar("PT")
3534

3635

37-
@runtime_checkable
38-
class PptxConvertible(Protocol[PT]):
36+
class PptxConvertible(Generic[PT]):
3937
"""Protocol for objects that can be converted to and from pptx objects."""
4038

39+
def __init__(self, pptx_obj: PT, /) -> None:
40+
self._pptx: PT = pptx_obj
41+
4142
def to_pptx(self) -> PT:
4243
"""Convert to pptx object."""
43-
...
44+
return self._pptx
4445

4546
@classmethod
4647
def from_pptx(cls, pptx_obj: PT) -> Self:
4748
"""Create from pptx object."""
48-
...
49+
return cls(pptx_obj)
4950

5051

5152
@overload
52-
def to_pptx_length(length: Length | LiteralLength) -> PptxLength: ...
53+
def to_pptx_length(length: Length | LiteralLength | PptxLength) -> PptxLength: ...
5354

5455

5556
@overload
56-
def to_pptx_length(length: Length | LiteralLength | None) -> PptxLength | None: ...
57+
def to_pptx_length(
58+
length: Length | LiteralLength | PptxLength | None,
59+
) -> PptxLength | None: ...
5760

5861

59-
def to_pptx_length(length: Length | LiteralLength | None) -> PptxLength | None:
62+
def to_pptx_length(
63+
length: Length | LiteralLength | PptxLength | None,
64+
) -> PptxLength | None:
6065
if isinstance(length, tuple):
6166
length = to_length(length)
6267

@@ -71,6 +76,8 @@ def to_pptx_length(length: Length | LiteralLength | None) -> PptxLength | None:
7176
return PptxMm(length.value)
7277
case EnglishMetricUnits():
7378
return PptxEmu(length.value)
79+
case PptxLength():
80+
return length
7481
case None:
7582
return None
7683
case _:
@@ -90,32 +97,46 @@ def to_tppt_length(length: PptxLength | None) -> Length | None:
9097

9198

9299
@overload
93-
def to_pptx_rgb_color(color: RGBColor | LiteralColor) -> PptxRGBColor: ...
100+
def to_pptx_rgb_color(
101+
color: Color | LiteralColor | PptxRGBColor,
102+
) -> tuple[PptxRGBColor, int | None]: ...
94103

95104

96105
@overload
97-
def to_pptx_rgb_color(color: RGBColor | LiteralColor | None) -> PptxRGBColor | None: ...
98-
99-
100-
def to_pptx_rgb_color(color: RGBColor | LiteralColor | None) -> PptxRGBColor | None:
106+
def to_pptx_rgb_color(
107+
color: Color | LiteralColor | PptxRGBColor | None,
108+
) -> tuple[PptxRGBColor, int | None] | None: ...
109+
110+
111+
def to_pptx_rgb_color(
112+
color: Color | LiteralColor | PptxRGBColor | None,
113+
) -> (
114+
tuple[
115+
PptxRGBColor,
116+
int | None,
117+
]
118+
| None
119+
):
101120
if color is None:
102121
return None
103122

104-
color = to_rgb_color(color)
123+
color = to_color(color)
105124

106-
return PptxRGBColor(color.r, color.g, color.b)
125+
return PptxRGBColor(color.r, color.g, color.b), color.a
107126

108127

109128
@overload
110-
def to_tppt_rgb_color(color: PptxRGBColor) -> RGBColor: ...
129+
def to_tppt_rgb_color(color: PptxRGBColor, alpha: int | None) -> Color: ...
111130

112131

113132
@overload
114-
def to_tppt_rgb_color(color: PptxRGBColor | None) -> RGBColor | None: ...
133+
def to_tppt_rgb_color(
134+
color: PptxRGBColor | None, alpha: int | None
135+
) -> Color | None: ...
115136

116137

117-
def to_tppt_rgb_color(color: PptxRGBColor | None) -> RGBColor | None:
118-
return RGBColor(*color) if color else None
138+
def to_tppt_rgb_color(color: PptxRGBColor | None, alpha: int | None) -> Color | None:
139+
return Color(color[0], color[1], color[2], alpha) if color else None
119140

120141

121142
PptxAngle: TypeAlias = float

0 commit comments

Comments
 (0)