Skip to content

Commit 1c70903

Browse files
committed
feat: add MasterLayoutNotFoundError exception and implement get_master_layout and get_layouts functions
1 parent fa80ff8 commit 1c70903

File tree

3 files changed

+95
-4
lines changed

3 files changed

+95
-4
lines changed

src/tppt/exception.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,14 @@ def __init__(self, slide_layout_name: str) -> None:
6262
@property
6363
def message(self) -> str:
6464
return f"The slide master does not have an attribute for the {self.slide_layout_name} layout"
65+
66+
67+
class MasterLayoutNotFoundError(TpptException, ValueError):
68+
"""Slide with MasterLayout tag not found."""
69+
70+
def __init__(self, slide_master_name: str) -> None:
71+
self.slide_master_name = slide_master_name
72+
73+
@property
74+
def message(self) -> str:
75+
return f"No slide with MasterLayout tag found in {self.slide_master_name}"

src/tppt/slide_master.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing_extensions import TypeVar, dataclass_transform
44

55
from tppt.exception import (
6+
MasterLayoutNotFoundError,
67
SlideMasterAttributeMustBeSlideLayoutError,
78
SlideMasterAttributeNotFoundError,
89
)
@@ -27,17 +28,17 @@
2728

2829
class _SlideMasterMeta(type):
2930
def __getattr__(self, key: str) -> "type[SlideLayout]":
30-
# 1. クラス自身の属性を確認
31+
# 1. Check the class's own attributes
3132
if key in self.__dict__:
3233
value = self.__dict__[key]
3334
if isinstance(value, type) and issubclass(value, SlideLayout):
3435
return value
3536

36-
# 2. アノテーションを確認
37+
# 2. Check annotations
3738
if hasattr(self, "__annotations__") and key in self.__annotations__:
3839
annotation = self.__annotations__[key]
3940

40-
# Annotated型からの抽出
41+
# Extract from Annotated type
4142
origin = get_origin(annotation)
4243
if origin is Annotated:
4344
args = get_args(annotation)
@@ -49,7 +50,7 @@ def __getattr__(self, key: str) -> "type[SlideLayout]":
4950
return args[0]
5051
else:
5152
raise SlideMasterAttributeMustBeSlideLayoutError(key)
52-
# クラスの場合は直接チェック
53+
# Direct check for class type
5354
elif isinstance(annotation, type) and issubclass(annotation, SlideLayout):
5455
return annotation
5556
else:
@@ -103,3 +104,34 @@ class DefaultSlideMaster(SlideMaster):
103104
"GenericTpptSlideMaster",
104105
bound=SlideMaster,
105106
)
107+
108+
def get_master_layout(slide_master: type[SlideMaster]) -> type[SlideLayout]:
109+
"""Get the slide tagged with MasterLayout."""
110+
for attr_name, annotation in slide_master.__annotations__.items():
111+
origin = get_origin(annotation)
112+
if origin is Annotated:
113+
args = get_args(annotation)
114+
# Check the class name instead of directly checking the type of args[1]
115+
if len(args) > 1 and args[1].__class__.__name__ == "MasterLayout":
116+
return getattr(slide_master, attr_name)
117+
118+
raise MasterLayoutNotFoundError(slide_master.__name__)
119+
120+
121+
def get_layouts(slide_master: type[SlideMaster]) -> list[type[SlideLayout]]:
122+
"""Get an array of slides tagged with Layout."""
123+
layouts = []
124+
125+
for attr_name, annotation in slide_master.__annotations__.items():
126+
origin = get_origin(annotation)
127+
if origin is Annotated:
128+
args = get_args(annotation)
129+
# Identify Layout and MasterLayout using class names
130+
if len(args) > 1:
131+
if args[1].__class__.__name__ == "Layout":
132+
layouts.append(getattr(slide_master, attr_name))
133+
elif args[1].__class__.__name__ == "MasterLayout":
134+
# Exclude MasterLayout
135+
pass
136+
137+
return layouts

tests/test_slide_master.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
from tppt.slide_layout import (
3+
DefaultBlankSlide,
4+
DefaultComparisonSlide,
5+
DefaultContentWithCaptionSlide,
6+
DefaultMasterSlide,
7+
DefaultPictureWithCaptionSlide,
8+
DefaultSectionHeaderSlide,
9+
DefaultTitleAndContentSlide,
10+
DefaultTitleAndVerticalTextSlide,
11+
DefaultTitleOnlySlide,
12+
DefaultTitleSlide,
13+
DefaultTwoContentSlide,
14+
DefaultVerticalTitleAndTextSlide,
15+
)
16+
from tppt.slide_master import DefaultSlideMaster, get_layouts, get_master_layout
17+
18+
19+
def test_get_master_layout():
20+
"""Test that get_master_layout function correctly retrieves the MasterLayout"""
21+
master_layout = get_master_layout(DefaultSlideMaster)
22+
assert master_layout == DefaultMasterSlide
23+
24+
25+
def test_get_layouts():
26+
"""Test that get_layouts function correctly retrieves the list of Layouts"""
27+
layouts = get_layouts(DefaultSlideMaster)
28+
29+
# Verify that all Layouts are included
30+
expected_layouts = [
31+
DefaultTitleSlide,
32+
DefaultTitleAndContentSlide,
33+
DefaultSectionHeaderSlide,
34+
DefaultTwoContentSlide,
35+
DefaultComparisonSlide,
36+
DefaultTitleOnlySlide,
37+
DefaultBlankSlide,
38+
DefaultContentWithCaptionSlide,
39+
DefaultPictureWithCaptionSlide,
40+
DefaultTitleAndVerticalTextSlide,
41+
DefaultVerticalTitleAndTextSlide,
42+
]
43+
44+
# Convert to sets for comparison as the order is not guaranteed
45+
assert set(layouts) == set(expected_layouts)
46+
47+
# Verify that MasterLayout is not included
48+
assert DefaultMasterSlide not in layouts

0 commit comments

Comments
 (0)