pdfdancer-client-python 0.3.6__tar.gz → 0.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/PKG-INFO +1 -1
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/pyproject.toml +1 -1
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/__init__.py +0 -2
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/models.py +15 -9
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/pdfdancer_v1.py +40 -16
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer_client_python.egg-info/PKG-INFO +1 -1
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_template_replace.py +75 -33
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/.claude/commands/discuss.md +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/.claude/commands/implement-new-api-features.md +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/.flake8 +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/.github/workflows/ci.yml +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/.github/workflows/daily-tests.yml +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/.gitignore +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/CLAUDE.md +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/LICENSE +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/NOTICE +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/README.md +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/TODO.md +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/check.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/docs/api-schemas/v0.yml +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/docs/api-schemas/v1.yml +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/media/logo-orange-512h.webp +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/media/logo-orange-60h.webp +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/release.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/setup.cfg +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/exceptions.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/fingerprint.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/image_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/page_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/paragraph_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/path_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/text_line_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/types.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer_client_python.egg-info/SOURCES.txt +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer_client_python.egg-info/dependency_links.txt +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer_client_python.egg-info/requires.txt +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer_client_python.egg-info/top_level.txt +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/test.sh +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/__init__.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/conftest.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/__init__.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/pdf_assertions.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_acroform.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_bezier_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_context_manager.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_form_x_objects.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_image.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_image_transform.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_line.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_line_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_new_pdf.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_page.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_paragraph.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_path.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_path_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_path_builder_rectangle.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_path_comprehensive.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_pdfdancer.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_positioning.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_rectangle_builder.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_redact.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_singular_selection.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_snapshot.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_text_line_edit.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/DancingScript-Regular.ttf +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/Empty.pdf +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/JetBrainsMono-Regular.ttf +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/Showcase.pdf +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/basic-paths.pdf +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/form-xobject-example.pdf +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/logo-80.png +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/mixed-form-types.pdf +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_anonymous_token.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_fingerprint.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_models.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_openapi_compliance.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_path_models.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_pdf_object_equality.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_rate_limit.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_standard_fonts.py +0 -0
- {pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/update-api-spec.sh +0 -0
|
@@ -44,7 +44,6 @@ from .models import (
|
|
|
44
44
|
ShapeType,
|
|
45
45
|
Size,
|
|
46
46
|
StandardFonts,
|
|
47
|
-
TemplateReplacement,
|
|
48
47
|
TextObjectRef,
|
|
49
48
|
TextStatus,
|
|
50
49
|
)
|
|
@@ -93,7 +92,6 @@ __all__ = [
|
|
|
93
92
|
"RedactTarget",
|
|
94
93
|
"RedactResponse",
|
|
95
94
|
"ReflowPreset",
|
|
96
|
-
"TemplateReplacement",
|
|
97
95
|
"PdfDancerException",
|
|
98
96
|
"FontNotFoundException",
|
|
99
97
|
"ValidationException",
|
|
@@ -1686,25 +1686,31 @@ class TemplateReplacement:
|
|
|
1686
1686
|
Parameters:
|
|
1687
1687
|
- placeholder: The exact text to find and replace in the PDF.
|
|
1688
1688
|
- text: The text to replace the placeholder with.
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
```python
|
|
1692
|
-
replacement = TemplateReplacement(
|
|
1693
|
-
placeholder="{{NAME}}",
|
|
1694
|
-
text="John Doe"
|
|
1695
|
-
)
|
|
1696
|
-
```
|
|
1689
|
+
- font: Optional font for the replacement text.
|
|
1690
|
+
- color: Optional color for the replacement text.
|
|
1697
1691
|
"""
|
|
1698
1692
|
|
|
1699
1693
|
placeholder: str
|
|
1700
1694
|
text: str
|
|
1695
|
+
font: Optional[Font] = None
|
|
1696
|
+
color: Optional[Color] = None
|
|
1701
1697
|
|
|
1702
1698
|
def to_dict(self) -> dict:
|
|
1703
1699
|
"""Convert to dictionary for JSON serialization."""
|
|
1704
|
-
|
|
1700
|
+
result: Dict[str, Any] = {
|
|
1705
1701
|
"placeholder": self.placeholder,
|
|
1706
1702
|
"text": self.text,
|
|
1707
1703
|
}
|
|
1704
|
+
if self.font:
|
|
1705
|
+
result["font"] = {"name": self.font.name, "size": self.font.size}
|
|
1706
|
+
if self.color:
|
|
1707
|
+
result["color"] = {
|
|
1708
|
+
"red": self.color.r,
|
|
1709
|
+
"green": self.color.g,
|
|
1710
|
+
"blue": self.color.b,
|
|
1711
|
+
"alpha": self.color.a,
|
|
1712
|
+
}
|
|
1713
|
+
return result
|
|
1708
1714
|
|
|
1709
1715
|
|
|
1710
1716
|
@dataclass
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/pdfdancer_v1.py
RENAMED
|
@@ -16,7 +16,7 @@ import time
|
|
|
16
16
|
from datetime import datetime, timezone
|
|
17
17
|
from importlib.metadata import version as get_package_version
|
|
18
18
|
from pathlib import Path
|
|
19
|
-
from typing import TYPE_CHECKING, Any, BinaryIO, List, Mapping, Optional, Union
|
|
19
|
+
from typing import TYPE_CHECKING, Any, BinaryIO, Dict, List, Mapping, Optional, Union
|
|
20
20
|
|
|
21
21
|
import httpx
|
|
22
22
|
from dotenv import load_dotenv
|
|
@@ -123,6 +123,26 @@ DEFAULT_RETRY_BACKOFF_FACTOR = float(
|
|
|
123
123
|
)
|
|
124
124
|
|
|
125
125
|
|
|
126
|
+
def _dict_to_replacements(
|
|
127
|
+
replacements: Dict[str, Union[str, dict]]
|
|
128
|
+
) -> List[TemplateReplacement]:
|
|
129
|
+
"""Convert dict-based replacements to TemplateReplacement list."""
|
|
130
|
+
result = []
|
|
131
|
+
for placeholder, value in replacements.items():
|
|
132
|
+
if isinstance(value, str):
|
|
133
|
+
result.append(TemplateReplacement(placeholder=placeholder, text=value))
|
|
134
|
+
else:
|
|
135
|
+
result.append(
|
|
136
|
+
TemplateReplacement(
|
|
137
|
+
placeholder=placeholder,
|
|
138
|
+
text=value["text"],
|
|
139
|
+
font=value.get("font"),
|
|
140
|
+
color=value.get("color"),
|
|
141
|
+
)
|
|
142
|
+
)
|
|
143
|
+
return result
|
|
144
|
+
|
|
145
|
+
|
|
126
146
|
def _generate_timestamp() -> str:
|
|
127
147
|
"""
|
|
128
148
|
Generate a timestamp string in the format expected by the API.
|
|
@@ -611,7 +631,7 @@ class PageClient:
|
|
|
611
631
|
|
|
612
632
|
def apply_replacements(
|
|
613
633
|
self,
|
|
614
|
-
replacements:
|
|
634
|
+
replacements: Dict[str, Union[str, dict]],
|
|
615
635
|
reflow_preset: Optional[ReflowPreset] = None,
|
|
616
636
|
) -> bool:
|
|
617
637
|
"""
|
|
@@ -621,8 +641,9 @@ class PageClient:
|
|
|
621
641
|
content. All placeholders must be found or the operation fails atomically.
|
|
622
642
|
|
|
623
643
|
Args:
|
|
624
|
-
replacements:
|
|
625
|
-
|
|
644
|
+
replacements: Dict mapping placeholder strings to replacement values.
|
|
645
|
+
- Simple: {"{{NAME}}": "John Doe"}
|
|
646
|
+
- With options: {"{{NAME}}": {"text": "John", "font": Font(...), "color": Color(...)}}
|
|
626
647
|
reflow_preset: Optional ReflowPreset to control text reflow behavior.
|
|
627
648
|
- BEST_EFFORT: Attempt to reflow, proceed even if imperfect
|
|
628
649
|
- FIT_OR_FAIL: Reflow must succeed or operation fails
|
|
@@ -633,14 +654,15 @@ class PageClient:
|
|
|
633
654
|
|
|
634
655
|
Example:
|
|
635
656
|
```python
|
|
636
|
-
page.apply_replacements(
|
|
637
|
-
|
|
638
|
-
|
|
657
|
+
page.apply_replacements({
|
|
658
|
+
"{{NAME}}": "John Doe",
|
|
659
|
+
})
|
|
639
660
|
```
|
|
640
661
|
"""
|
|
662
|
+
replacement_list = _dict_to_replacements(replacements)
|
|
641
663
|
# noinspection PyProtectedMember
|
|
642
664
|
return self.root._apply_replacements(
|
|
643
|
-
replacements=
|
|
665
|
+
replacements=replacement_list,
|
|
644
666
|
page_number=self.page_number,
|
|
645
667
|
reflow_preset=reflow_preset,
|
|
646
668
|
)
|
|
@@ -2246,7 +2268,7 @@ class PDFDancer:
|
|
|
2246
2268
|
|
|
2247
2269
|
def apply_replacements(
|
|
2248
2270
|
self,
|
|
2249
|
-
replacements:
|
|
2271
|
+
replacements: Dict[str, Union[str, dict]],
|
|
2250
2272
|
reflow_preset: Optional[ReflowPreset] = None,
|
|
2251
2273
|
) -> bool:
|
|
2252
2274
|
"""
|
|
@@ -2256,8 +2278,9 @@ class PDFDancer:
|
|
|
2256
2278
|
content. All placeholders must be found or the operation fails atomically.
|
|
2257
2279
|
|
|
2258
2280
|
Args:
|
|
2259
|
-
replacements:
|
|
2260
|
-
|
|
2281
|
+
replacements: Dict mapping placeholder strings to replacement values.
|
|
2282
|
+
- Simple: {"{{NAME}}": "John Doe"}
|
|
2283
|
+
- With options: {"{{NAME}}": {"text": "John", "font": Font(...), "color": Color(...)}}
|
|
2261
2284
|
reflow_preset: Optional ReflowPreset to control text reflow behavior.
|
|
2262
2285
|
- BEST_EFFORT: Attempt to reflow, proceed even if imperfect
|
|
2263
2286
|
- FIT_OR_FAIL: Reflow must succeed or operation fails
|
|
@@ -2268,14 +2291,15 @@ class PDFDancer:
|
|
|
2268
2291
|
|
|
2269
2292
|
Example:
|
|
2270
2293
|
```python
|
|
2271
|
-
pdf.apply_replacements(
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2294
|
+
pdf.apply_replacements({
|
|
2295
|
+
"{{NAME}}": "John Doe",
|
|
2296
|
+
"{{DATE}}": "2025-01-15",
|
|
2297
|
+
})
|
|
2275
2298
|
```
|
|
2276
2299
|
"""
|
|
2300
|
+
replacement_list = _dict_to_replacements(replacements)
|
|
2277
2301
|
return self._apply_replacements(
|
|
2278
|
-
replacements=
|
|
2302
|
+
replacements=replacement_list,
|
|
2279
2303
|
page_number=None,
|
|
2280
2304
|
reflow_preset=reflow_preset,
|
|
2281
2305
|
)
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_template_replace.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
|
|
5
|
-
from pdfdancer import
|
|
5
|
+
from pdfdancer import Color, Font, ReflowPreset, ValidationException
|
|
6
6
|
from pdfdancer.pdfdancer_v1 import PDFDancer
|
|
7
7
|
from tests.e2e import _require_env_and_fixture
|
|
8
8
|
from tests.e2e.pdf_assertions import PDFAssertions
|
|
@@ -21,9 +21,7 @@ def test_replace_single_template():
|
|
|
21
21
|
)
|
|
22
22
|
|
|
23
23
|
# Replace the existing "Showcase" text
|
|
24
|
-
result = pdf.apply_replacements(
|
|
25
|
-
TemplateReplacement(placeholder="Showcase", text="Replaced"),
|
|
26
|
-
])
|
|
24
|
+
result = pdf.apply_replacements({"Showcase": "Replaced"})
|
|
27
25
|
|
|
28
26
|
assert result is True
|
|
29
27
|
|
|
@@ -42,10 +40,10 @@ def test_replace_multiple_templates():
|
|
|
42
40
|
|
|
43
41
|
with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
|
|
44
42
|
# Replace multiple placeholders
|
|
45
|
-
result = pdf.apply_replacements(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
result = pdf.apply_replacements({
|
|
44
|
+
"PDFDancer": "TestApp",
|
|
45
|
+
"Engine": "System",
|
|
46
|
+
})
|
|
49
47
|
|
|
50
48
|
assert result is True
|
|
51
49
|
|
|
@@ -71,9 +69,7 @@ def test_replace_template_on_specific_page():
|
|
|
71
69
|
)
|
|
72
70
|
|
|
73
71
|
# Replace only on page 1
|
|
74
|
-
result = pdf.page(1).apply_replacements(
|
|
75
|
-
TemplateReplacement(placeholder="Showcase", text="PageOneOnly"),
|
|
76
|
-
])
|
|
72
|
+
result = pdf.page(1).apply_replacements({"Showcase": "PageOneOnly"})
|
|
77
73
|
|
|
78
74
|
assert result is True
|
|
79
75
|
|
|
@@ -98,7 +94,7 @@ def test_replace_template_with_reflow_best_effort():
|
|
|
98
94
|
|
|
99
95
|
# Replace with longer text using BEST_EFFORT reflow
|
|
100
96
|
result = pdf.apply_replacements(
|
|
101
|
-
|
|
97
|
+
{"Showcase": "ThisIsAMuchLongerReplacementText"},
|
|
102
98
|
reflow_preset=ReflowPreset.BEST_EFFORT,
|
|
103
99
|
)
|
|
104
100
|
|
|
@@ -125,7 +121,7 @@ def test_replace_template_with_reflow_none():
|
|
|
125
121
|
|
|
126
122
|
# Replace without reflow
|
|
127
123
|
result = pdf.apply_replacements(
|
|
128
|
-
|
|
124
|
+
{"Showcase": "NoReflow"},
|
|
129
125
|
reflow_preset=ReflowPreset.NONE,
|
|
130
126
|
)
|
|
131
127
|
|
|
@@ -139,40 +135,86 @@ def test_replace_template_with_reflow_none():
|
|
|
139
135
|
)
|
|
140
136
|
|
|
141
137
|
|
|
142
|
-
def
|
|
143
|
-
"""Test that replacing with an empty
|
|
138
|
+
def test_replace_template_empty_dict_raises():
|
|
139
|
+
"""Test that replacing with an empty dict raises ValidationException."""
|
|
144
140
|
base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
|
|
145
141
|
|
|
146
142
|
with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
|
|
147
143
|
with pytest.raises(ValidationException):
|
|
148
|
-
pdf.apply_replacements(
|
|
144
|
+
pdf.apply_replacements({})
|
|
149
145
|
|
|
150
146
|
|
|
151
|
-
def
|
|
152
|
-
"""Test that page-level replacement with empty
|
|
147
|
+
def test_replace_template_page_level_empty_dict_raises():
|
|
148
|
+
"""Test that page-level replacement with empty dict raises ValidationException."""
|
|
153
149
|
base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
|
|
154
150
|
|
|
155
151
|
with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
|
|
156
152
|
with pytest.raises(ValidationException):
|
|
157
|
-
pdf.page(1).apply_replacements(
|
|
153
|
+
pdf.page(1).apply_replacements({})
|
|
158
154
|
|
|
159
155
|
|
|
160
|
-
def
|
|
161
|
-
"""Test
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
156
|
+
def test_replace_template_with_font():
|
|
157
|
+
"""Test template replacement with custom font."""
|
|
158
|
+
base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
|
|
159
|
+
|
|
160
|
+
with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
|
|
161
|
+
result = pdf.apply_replacements({
|
|
162
|
+
"Showcase": {
|
|
163
|
+
"text": "FontTest",
|
|
164
|
+
"font": Font("Helvetica-Bold", 14),
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
assert result is True
|
|
169
|
+
|
|
170
|
+
(
|
|
171
|
+
PDFAssertions(pdf)
|
|
172
|
+
.assert_textline_does_not_exist("Showcase")
|
|
173
|
+
.assert_textline_exists("FontTest")
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_replace_template_with_color():
|
|
178
|
+
"""Test template replacement with custom color."""
|
|
179
|
+
base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
|
|
180
|
+
|
|
181
|
+
with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
|
|
182
|
+
result = pdf.apply_replacements({
|
|
183
|
+
"Showcase": {
|
|
184
|
+
"text": "ColorTest",
|
|
185
|
+
"color": Color(255, 0, 0),
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
assert result is True
|
|
190
|
+
|
|
191
|
+
(
|
|
192
|
+
PDFAssertions(pdf)
|
|
193
|
+
.assert_textline_does_not_exist("Showcase")
|
|
194
|
+
.assert_textline_exists("ColorTest")
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def test_replace_template_with_font_and_color():
|
|
199
|
+
"""Test template replacement with both font and color."""
|
|
200
|
+
base_url, token, pdf_path = _require_env_and_fixture("Showcase.pdf")
|
|
201
|
+
|
|
202
|
+
with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
|
|
203
|
+
result = pdf.apply_replacements({
|
|
204
|
+
"Showcase": {
|
|
205
|
+
"text": "StyledText",
|
|
206
|
+
"font": Font("Helvetica-Bold", 16),
|
|
207
|
+
"color": Color(0, 100, 0),
|
|
208
|
+
}
|
|
209
|
+
})
|
|
166
210
|
|
|
167
|
-
|
|
168
|
-
assert replacement.text == "John Doe"
|
|
211
|
+
assert result is True
|
|
169
212
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
213
|
+
(
|
|
214
|
+
PDFAssertions(pdf)
|
|
215
|
+
.assert_textline_does_not_exist("Showcase")
|
|
216
|
+
.assert_textline_exists("StyledText")
|
|
217
|
+
)
|
|
176
218
|
|
|
177
219
|
|
|
178
220
|
def test_reflow_preset_values():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/.github/workflows/daily-tests.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/fingerprint.py
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/image_builder.py
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/page_builder.py
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/paragraph_builder.py
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/path_builder.py
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/src/pdfdancer/text_line_builder.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_bezier_builder.py
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_context_manager.py
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_form_x_objects.py
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_image_transform.py
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_line_builder.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_path_builder.py
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_path_comprehensive.py
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_positioning.py
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_rectangle_builder.py
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_singular_selection.py
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/e2e/test_text_line_edit.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/basic-paths.pdf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/fixtures/mixed-form-types.pdf
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_anonymous_token.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_openapi_compliance.py
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_pdf_object_equality.py
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.3.6 → pdfdancer_client_python-0.3.7}/tests/test_standard_fonts.py
RENAMED
|
File without changes
|
|
File without changes
|