Skip to content

Commit 7cf5036

Browse files
committed
refactor: add support for Pydantic models in table data handling
1 parent 40da588 commit 7cf5036

File tree

5 files changed

+171
-2
lines changed

5 files changed

+171
-2
lines changed

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ dependencies = [
2727
[project.optional-dependencies]
2828
pandas = ["pandas>=2.0.0"]
2929
polars = ["polars>=0.20.0"]
30+
pydantic = ["pydantic>=2.0.0"]
3031
tool = [
3132
"rich>=14.0.0",
3233
"rich-argparse>=1.7.0",
@@ -36,6 +37,7 @@ tool = [
3637
dataframes = [
3738
"pandas",
3839
"polars",
40+
"pydantic",
3941
]
4042
dev = [
4143
"mypy>=1.15.0",

src/tppt/_features.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ class Dataclass(Protocol):
1515
__dataclass_fields__: ClassVar[dict]
1616

1717

18+
try:
19+
import pydantic # type: ignore[import] # noqa: F401
20+
21+
USE_PYDANTIC = True
22+
PydanticModel: TypeAlias = pydantic.BaseModel # type: ignore
23+
24+
except ImportError:
25+
USE_PYDANTIC = False
26+
PydanticModel: TypeAlias = _NotSupportFeature # type: ignore
27+
28+
1829
try:
1930
import pandas # type: ignore[import] # noqa: F401
2031

src/tppt/pptx/shape/table.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
PandasDataFrame,
2323
PolarsDataFrame,
2424
PolarsLazyFrame,
25+
PydanticModel,
2526
)
2627
from tppt.types._length import LiteralPoint, Points
2728

@@ -35,6 +36,7 @@
3536
DataFrame: TypeAlias = (
3637
list[list[str]]
3738
| list[Dataclass]
39+
| list[PydanticModel]
3840
| PandasDataFrame
3941
| PolarsDataFrame
4042
| PolarsLazyFrame
@@ -198,6 +200,15 @@ def dataframe2list(data: DataFrame) -> list[list[str]]:
198200
]
199201
rows.append(row)
200202
return [columns] + rows
203+
# Convert list of Pydantic model instances to list of lists
204+
elif isinstance(first_instance, PydanticModel):
205+
columns = list(first_instance.__class__.model_fields.keys())
206+
rows = []
207+
for instance in data:
208+
instance = cast(Any, instance)
209+
row = [str(getattr(instance, field)) for field in columns]
210+
rows.append(row)
211+
return [columns] + rows
201212
else:
202213
logger.warning("Empty data of table")
203214
return []

tests/test_table.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
from dataclasses import dataclass
55

66
import pytest
7+
from pydantic import BaseModel
78

89
import tppt
9-
from tppt._features import USE_PANDAS, USE_POLARS, Dataclass
10+
from tppt._features import USE_PANDAS, USE_POLARS, Dataclass, PydanticModel
1011

1112

1213
def test_create_table_with_list_data(output: pathlib.Path) -> None:
@@ -182,3 +183,40 @@ class Employee:
182183
.build()
183184
)
184185
presentation.save(output / "table_dataclass_data.pptx")
186+
187+
188+
def test_create_table_with_pydantic_model(output: pathlib.Path) -> None:
189+
"""Test creating a table with Pydantic model."""
190+
191+
class Product(BaseModel):
192+
"""Product model for testing."""
193+
194+
name: str
195+
category: str
196+
price: int
197+
stock: int
198+
199+
# Create product instances
200+
products: list[PydanticModel] = [
201+
Product(name="ノートPC", category="電子機器", price=150000, stock=10),
202+
Product(name="スマートフォン", category="電子機器", price=80000, stock=20),
203+
Product(name="タブレット", category="電子機器", price=50000, stock=15),
204+
]
205+
206+
presentation = (
207+
tppt.Presentation.builder()
208+
.slide(
209+
lambda slide: slide.BlankLayout()
210+
.builder()
211+
.table(
212+
products,
213+
left=(100, "pt"),
214+
top=(100, "pt"),
215+
width=(400, "pt"),
216+
height=(200, "pt"),
217+
first_row_header=True,
218+
)
219+
)
220+
.build()
221+
)
222+
presentation.save(output / "table_pydantic_data.pptx")

0 commit comments

Comments
 (0)