Skip to content

Commit 0ee284b

Browse files
committed
feat: enhance TpptSlideMaster with dynamic attribute retrieval for slide layouts
1 parent 38fd3dd commit 0ee284b

File tree

5 files changed

+75
-24
lines changed

5 files changed

+75
-24
lines changed

design/slide_master.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, ClassVar, Self, Type, TypeVar, overload
1+
from typing import Any, ClassVar, Self, overload
22

33
from typing_extensions import dataclass_transform
44

@@ -52,11 +52,6 @@ def __get__(self, instance: object | None, objtype: type[Any]) -> type[Self] | S
5252
return self
5353

5454

55-
# 型変数を調整
56-
TpptSlideMasterType = TypeVar("TpptSlideMasterType", bound=Type[TpptSlideMaster])
57-
TpptSlideLayoutType = TypeVar("TpptSlideLayoutType", bound=Type[TpptSlideLayout])
58-
59-
6055
class MyMasterSlide(TpptSlideLayout):
6156
def __init__(self, a: int, b: str): ...
6257

src/tppt/_pptx/presentation.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def tree(self) -> dict[str, Any]:
4040

4141
@classmethod
4242
def builder(
43-
cls, slide_master: GenericTpptSlideMaster | None = None
43+
cls, slide_master: "GenericTpptSlideMaster | None" = None
4444
) -> "PresentationBuilder[GenericTpptSlideMaster]":
4545
"""Get a builder for the presentation."""
4646
return PresentationBuilder(slide_master)
@@ -64,7 +64,7 @@ def from_pptx(cls, pptx_obj: PptxPresentation) -> Self:
6464
class PresentationBuilder(Generic[GenericTpptSlideMaster]):
6565
"""Builder for presentations."""
6666

67-
def __init__(self, slide_master: GenericTpptSlideMaster | None = None) -> None:
67+
def __init__(self, slide_master: "GenericTpptSlideMaster | None" = None) -> None:
6868
"""Initialize the builder."""
6969
import pptx
7070

src/tppt/_tppt/slide_layout.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
import datetime
2-
from abc import ABC
2+
from typing import Any, Self, overload
33

4-
from tppt._pptx.slide import SlideBuilder
54

5+
class TpptSlideLayout:
6+
@overload
7+
def __get__(self, instance: None, objtype: type[Any]) -> type[Self]: ...
68

7-
class TttpSlideLayout(ABC):
8-
@classmethod
9-
def builder(cls) -> "SlideBuilder":
10-
raise NotImplementedError("tppt.SlideLayout.builder must be implemented")
9+
@overload
10+
def __get__(self, instance: object, objtype: type[Any]) -> Self: ...
1111

12+
def __get__(self, instance: object | None, objtype: type[Any]) -> type[Self] | Self:
13+
if instance is None:
14+
return type(self)
1215

13-
class TitleSlide(TttpSlideLayout):
16+
else:
17+
return self
18+
19+
20+
class DefaultMasterSlide(TpptSlideLayout):
1421
def __init__(
1522
self,
1623
*,
@@ -25,7 +32,3 @@ def __init__(
2532
self.date = date
2633
self.footer = footer
2734
self.slide_number = slide_number
28-
29-
@classmethod
30-
def builder(cls) -> "SlideBuilder":
31-
return SlideBuilder()

src/tppt/_tppt/slide_master.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,38 @@
1-
from typing import TypeVar
1+
from typing import ClassVar, TypeVar
22

3+
from typing_extensions import dataclass_transform
34

4-
class TpptSlideMaster: ...
5+
from tppt.exception import (
6+
SlideMasterAttributeMustBeSlideLayoutError,
7+
SlideMasterAttributeNotFoundError,
8+
)
9+
10+
from .slide_layout import TpptSlideLayout
11+
12+
13+
class TpptSlideMasterMeta(type):
14+
def __getattr__(self, key: str) -> "type[TpptSlideLayout]":
15+
if key in self.__annotations__:
16+
annotation = self.__annotations__[key]
17+
if issubclass(annotation, TpptSlideLayout):
18+
return annotation
19+
else:
20+
raise SlideMasterAttributeMustBeSlideLayoutError(key)
21+
22+
raise SlideMasterAttributeNotFoundError(key)
23+
24+
25+
@dataclass_transform(
26+
eq_default=True,
27+
order_default=False,
28+
field_specifiers=(),
29+
)
30+
class TpptSlideMaster(metaclass=TpptSlideMasterMeta):
31+
_template_path: ClassVar[str | None] = None
32+
33+
@classmethod
34+
def get_template_path(cls) -> str | None:
35+
return cls._template_path
536

637

738
GenericTpptSlideMaster = TypeVar("GenericTpptSlideMaster", bound=TpptSlideMaster)

src/tppt/exception.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from pptx.slide import SlideLayouts as PptxSlideLayouts
55

66

7-
class tpptException(Exception):
7+
class TpptException(Exception):
88
"""Base exception for tppt."""
99

1010
@property
@@ -19,7 +19,7 @@ def __str__(self) -> str:
1919
return self.message
2020

2121

22-
class ColorInvalidFormatError(tpptException, ValueError):
22+
class ColorInvalidFormatError(TpptException, ValueError):
2323
"""Color format is invalid."""
2424

2525
def __init__(self, color: str) -> None:
@@ -30,7 +30,7 @@ def message(self) -> str:
3030
return f"Invalid color format: {self.color}"
3131

3232

33-
class SlideLayoutIndexError(tpptException, IndexError):
33+
class SlideLayoutIndexError(TpptException, IndexError):
3434
"""Slide layout index is out of range."""
3535

3636
def __init__(self, index: int, slide_layouts: PptxSlideLayouts) -> None:
@@ -40,3 +40,25 @@ def __init__(self, index: int, slide_layouts: PptxSlideLayouts) -> None:
4040
@property
4141
def message(self) -> str:
4242
return f"Slide layout index {self.index} is out of range. Available slide layouts: {[layout.name for layout in self.slide_layouts]}"
43+
44+
45+
class SlideMasterAttributeMustBeSlideLayoutError(TpptException, ValueError):
46+
"""Slide master attribute must be a slide layout."""
47+
48+
def __init__(self, slide_layout_name: str) -> None:
49+
self.slide_layout_name = slide_layout_name
50+
51+
@property
52+
def message(self) -> str:
53+
return f"The slide master attribute must be a slide layout. The {self.slide_layout_name} layout is not a slide layout."
54+
55+
56+
class SlideMasterAttributeNotFoundError(TpptException, ValueError):
57+
"""Slide master attribute not found."""
58+
59+
def __init__(self, slide_layout_name: str) -> None:
60+
self.slide_layout_name = slide_layout_name
61+
62+
@property
63+
def message(self) -> str:
64+
return f"The slide master does not have an attribute for the {self.slide_layout_name} layout"

0 commit comments

Comments
 (0)