Skip to content

Commit 7491bfd

Browse files
blank-pdf: Consolidate page size parameters
Page size can be either a `str` literal or custom dimensions Assisted-by: Codex
1 parent 983c925 commit 7491bfd

5 files changed

Lines changed: 59 additions & 93 deletions

File tree

src/pdfrest/client.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3079,8 +3079,6 @@ def blank_pdf(
30793079
page_size: PdfPageSize,
30803080
page_count: int,
30813081
page_orientation: PdfPageOrientation | None = None,
3082-
custom_height: float | None = None,
3083-
custom_width: float | None = None,
30843082
output: str | None = None,
30853083
extra_query: Query | None = None,
30863084
extra_headers: AnyMapping | None = None,
@@ -3095,10 +3093,6 @@ def blank_pdf(
30953093
}
30963094
if page_orientation is not None:
30973095
payload["page_orientation"] = page_orientation
3098-
if custom_height is not None:
3099-
payload["custom_height"] = custom_height
3100-
if custom_width is not None:
3101-
payload["custom_width"] = custom_width
31023096
if output is not None:
31033097
payload["output"] = output
31043098

@@ -4498,8 +4492,6 @@ async def blank_pdf(
44984492
page_size: PdfPageSize,
44994493
page_count: int,
45004494
page_orientation: PdfPageOrientation | None = None,
4501-
custom_height: float | None = None,
4502-
custom_width: float | None = None,
45034495
output: str | None = None,
45044496
extra_query: Query | None = None,
45054497
extra_headers: AnyMapping | None = None,
@@ -4514,10 +4506,6 @@ async def blank_pdf(
45144506
}
45154507
if page_orientation is not None:
45164508
payload["page_orientation"] = page_orientation
4517-
if custom_height is not None:
4518-
payload["custom_height"] = custom_height
4519-
if custom_width is not None:
4520-
payload["custom_width"] = custom_width
45214509
if output is not None:
45224510
payload["output"] = output
45234511

src/pdfrest/models/_internal.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from __future__ import annotations
22

33
import re
4-
from collections.abc import Callable, Sequence
4+
from collections.abc import Callable, Mapping, Sequence
55
from pathlib import PurePath
6-
from typing import Annotated, Any, Generic, Literal, TypeVar
6+
from typing import Annotated, Any, Generic, Literal, TypeVar, cast
77

88
from langcodes import tag_is_valid
99
from pydantic import (
@@ -1347,7 +1347,7 @@ class PdfBlankPayload(BaseModel):
13471347
"""Adapt caller options into a pdfRest-ready blank PDF request payload."""
13481348

13491349
page_size: Annotated[
1350-
PdfPageSize,
1350+
PdfPageSize | Literal["custom"],
13511351
Field(serialization_alias="page_size"),
13521352
]
13531353
page_count: Annotated[
@@ -1372,6 +1372,33 @@ class PdfBlankPayload(BaseModel):
13721372
AfterValidator(_validate_output_prefix),
13731373
] = None
13741374

1375+
@model_validator(mode="before")
1376+
@classmethod
1377+
def _normalize_custom_page_size(cls, data: Any) -> Any:
1378+
if not isinstance(data, Mapping):
1379+
return data
1380+
1381+
request_data = cast(Mapping[str, Any], data)
1382+
page_size = request_data.get("page_size")
1383+
if not isinstance(page_size, Sequence) or isinstance(
1384+
page_size, (str, bytes, bytearray)
1385+
):
1386+
return request_data
1387+
1388+
custom_dimensions = list(page_size)
1389+
if len(custom_dimensions) != 2:
1390+
msg = (
1391+
"Custom page sizes must contain exactly two values: "
1392+
"custom_height and custom_width."
1393+
)
1394+
raise ValueError(msg)
1395+
1396+
normalized_data: dict[str, Any] = dict(request_data)
1397+
normalized_data["page_size"] = "custom"
1398+
normalized_data["custom_height"] = custom_dimensions[0]
1399+
normalized_data["custom_width"] = custom_dimensions[1]
1400+
return normalized_data
1401+
13751402
@model_validator(mode="after")
13761403
def _validate_page_configuration(self) -> PdfBlankPayload:
13771404
is_custom = self.page_size == "custom"

src/pdfrest/types/public.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,5 +199,7 @@ class PdfMergeSource(TypedDict, total=False):
199199
ALL_PDF_RESTRICTIONS: tuple[PdfRestriction, ...] = cast(
200200
tuple[PdfRestriction, ...], get_args(PdfRestriction)
201201
)
202-
PdfPageSize = Literal["letter", "legal", "ledger", "A3", "A4", "A5", "custom"]
202+
PdfPageSize = (
203+
Literal["letter", "legal", "ledger", "A3", "A4", "A5"] | tuple[float, float]
204+
)
203205
PdfPageOrientation = Literal["portrait", "landscape"]

tests/live/test_live_blank_pdf.py

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,86 +8,66 @@
88
pytest.param(
99
"letter",
1010
"portrait",
11-
None,
12-
None,
1311
"blank-letter",
1412
id="letter-portrait",
1513
),
1614
pytest.param(
1715
"legal",
1816
"landscape",
19-
None,
20-
None,
2117
"blank-legal",
2218
id="legal-landscape",
2319
),
2420
pytest.param(
2521
"ledger",
2622
"portrait",
27-
None,
28-
None,
2923
"blank-ledger",
3024
id="ledger-portrait",
3125
),
3226
pytest.param(
3327
"A3",
3428
"landscape",
35-
None,
36-
None,
3729
"blank-a3",
3830
id="a3-landscape",
3931
),
4032
pytest.param(
4133
"A4",
4234
"portrait",
43-
None,
44-
None,
4535
"blank-a4",
4636
id="a4-portrait",
4737
),
4838
pytest.param(
4939
"A5",
5040
"landscape",
51-
None,
52-
None,
5341
"blank-a5",
5442
id="a5-landscape",
5543
),
5644
pytest.param(
57-
"custom",
45+
(792.0, 612.0),
5846
None,
59-
792.0,
60-
612.0,
6147
"blank-custom",
6248
id="custom-dimensions",
6349
),
6450
]
6551

6652

6753
@pytest.mark.parametrize(
68-
("page_size", "page_orientation", "custom_height", "custom_width", "output_name"),
54+
("page_size", "page_orientation", "output_name"),
6955
BLANK_PDF_LITERAL_CASES,
7056
)
7157
def test_live_blank_pdf_success(
7258
pdfrest_api_key: str,
7359
pdfrest_live_base_url: str,
74-
page_size: str,
60+
page_size: str | tuple[float, float],
7561
page_orientation: str | None,
76-
custom_height: float | None,
77-
custom_width: float | None,
7862
output_name: str,
7963
) -> None:
80-
kwargs: dict[str, str | int | float] = {
64+
kwargs: dict[str, str | int | float | tuple[float, float]] = {
8165
"page_size": page_size,
8266
"page_count": 1,
8367
"output": output_name,
8468
}
8569
if page_orientation is not None:
8670
kwargs["page_orientation"] = page_orientation
87-
if custom_height is not None:
88-
kwargs["custom_height"] = custom_height
89-
if custom_width is not None:
90-
kwargs["custom_width"] = custom_width
9171

9272
with PdfRestClient(
9373
api_key=pdfrest_api_key,
@@ -105,29 +85,23 @@ def test_live_blank_pdf_success(
10585

10686
@pytest.mark.asyncio
10787
@pytest.mark.parametrize(
108-
("page_size", "page_orientation", "custom_height", "custom_width", "output_name"),
88+
("page_size", "page_orientation", "output_name"),
10989
BLANK_PDF_LITERAL_CASES,
11090
)
11191
async def test_live_async_blank_pdf_success(
11292
pdfrest_api_key: str,
11393
pdfrest_live_base_url: str,
114-
page_size: str,
94+
page_size: str | tuple[float, float],
11595
page_orientation: str | None,
116-
custom_height: float | None,
117-
custom_width: float | None,
11896
output_name: str,
11997
) -> None:
120-
kwargs: dict[str, str | int | float] = {
98+
kwargs: dict[str, str | int | float | tuple[float, float]] = {
12199
"page_size": page_size,
122100
"page_count": 2,
123101
"output": output_name,
124102
}
125103
if page_orientation is not None:
126104
kwargs["page_orientation"] = page_orientation
127-
if custom_height is not None:
128-
kwargs["custom_height"] = custom_height
129-
if custom_width is not None:
130-
kwargs["custom_width"] = custom_width
131105

132106
async with AsyncPdfRestClient(
133107
api_key=pdfrest_api_key,

tests/test_blank_pdf.py

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -297,18 +297,17 @@ async def test_async_blank_pdf_page_count_boundaries_validation(
297297

298298

299299
@pytest.mark.parametrize(
300-
("custom_height", "custom_width", "match"),
300+
("page_size", "match"),
301301
[
302-
pytest.param(0.0, 10.0, "greater than 0", id="height-zero"),
303-
pytest.param(-1.0, 10.0, "greater than 0", id="height-negative"),
304-
pytest.param(10.0, 0.0, "greater than 0", id="width-zero"),
305-
pytest.param(10.0, -1.0, "greater than 0", id="width-negative"),
302+
pytest.param((0.0, 10.0), "greater than 0", id="height-zero"),
303+
pytest.param((-1.0, 10.0), "greater than 0", id="height-negative"),
304+
pytest.param((10.0, 0.0), "greater than 0", id="width-zero"),
305+
pytest.param((10.0, -1.0), "greater than 0", id="width-negative"),
306306
],
307307
)
308308
def test_blank_pdf_custom_dimensions_validation(
309309
monkeypatch: pytest.MonkeyPatch,
310-
custom_height: float,
311-
custom_width: float,
310+
page_size: tuple[float, float],
312311
match: str,
313312
) -> None:
314313
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
@@ -319,27 +318,24 @@ def test_blank_pdf_custom_dimensions_validation(
319318
pytest.raises(ValidationError, match=match),
320319
):
321320
client.blank_pdf(
322-
page_size="custom",
321+
page_size=page_size,
323322
page_count=1,
324-
custom_height=custom_height,
325-
custom_width=custom_width,
326323
)
327324

328325

329326
@pytest.mark.asyncio
330327
@pytest.mark.parametrize(
331-
("custom_height", "custom_width", "match"),
328+
("page_size", "match"),
332329
[
333-
pytest.param(0.0, 10.0, "greater than 0", id="height-zero"),
334-
pytest.param(-1.0, 10.0, "greater than 0", id="height-negative"),
335-
pytest.param(10.0, 0.0, "greater than 0", id="width-zero"),
336-
pytest.param(10.0, -1.0, "greater than 0", id="width-negative"),
330+
pytest.param((0.0, 10.0), "greater than 0", id="height-zero"),
331+
pytest.param((-1.0, 10.0), "greater than 0", id="height-negative"),
332+
pytest.param((10.0, 0.0), "greater than 0", id="width-zero"),
333+
pytest.param((10.0, -1.0), "greater than 0", id="width-negative"),
337334
],
338335
)
339336
async def test_async_blank_pdf_custom_dimensions_validation(
340337
monkeypatch: pytest.MonkeyPatch,
341-
custom_height: float,
342-
custom_width: float,
338+
page_size: tuple[float, float],
343339
match: str,
344340
) -> None:
345341
monkeypatch.delenv("PDFREST_API_KEY", raising=False)
@@ -348,10 +344,8 @@ async def test_async_blank_pdf_custom_dimensions_validation(
348344
async with AsyncPdfRestClient(api_key=ASYNC_API_KEY, transport=transport) as client:
349345
with pytest.raises(ValidationError, match=match):
350346
await client.blank_pdf(
351-
page_size="custom",
347+
page_size=page_size,
352348
page_count=1,
353-
custom_height=custom_height,
354-
custom_width=custom_width,
355349
)
356350

357351

@@ -458,10 +452,8 @@ def handler(request: httpx.Request) -> httpx.Response:
458452
transport = httpx.MockTransport(handler)
459453
with PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client:
460454
response = client.blank_pdf(
461-
page_size="custom",
455+
page_size=(792, 612),
462456
page_count=3,
463-
custom_height=792,
464-
custom_width=612,
465457
output="custom",
466458
extra_query={"trace": "true"},
467459
extra_headers={"X-Debug": "sync"},
@@ -581,10 +573,8 @@ def handler(request: httpx.Request) -> httpx.Response:
581573
transport = httpx.MockTransport(handler)
582574
async with AsyncPdfRestClient(api_key=ASYNC_API_KEY, transport=transport) as client:
583575
response = await client.blank_pdf(
584-
page_size="custom",
576+
page_size=(100, 50),
585577
page_count=1,
586-
custom_height=100,
587-
custom_width=50,
588578
extra_query={"trace": "async"},
589579
extra_headers={"X-Debug": "async"},
590580
extra_body={"debug": "yes"},
@@ -615,33 +605,18 @@ def test_blank_pdf_validation(monkeypatch: pytest.MonkeyPatch) -> None:
615605

616606
with (
617607
PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client,
618-
pytest.raises(ValueError, match="custom_height and custom_width are required"),
608+
pytest.raises(ValueError, match="Custom page sizes must contain exactly two"),
619609
):
620-
client.blank_pdf(page_size="custom", page_count=1, custom_height=50)
621-
622-
with (
623-
PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client,
624-
pytest.raises(
625-
ValueError, match="custom_height and custom_width can only be provided"
626-
),
627-
):
628-
client.blank_pdf(
629-
page_size="A3",
630-
page_count=1,
631-
page_orientation="portrait",
632-
custom_width=10,
633-
)
610+
client.blank_pdf(page_size=(50,), page_count=1)
634611

635612
with (
636613
PdfRestClient(api_key=VALID_API_KEY, transport=transport) as client,
637614
pytest.raises(ValueError, match="page_orientation must be omitted"),
638615
):
639616
client.blank_pdf(
640-
page_size="custom",
617+
page_size=(10, 10),
641618
page_count=1,
642619
page_orientation="portrait",
643-
custom_width=10,
644-
custom_height=10,
645620
)
646621

647622
with (

0 commit comments

Comments
 (0)