pdfdancer-client-python 0.3.1__py3-none-any.whl → 0.3.2__py3-none-any.whl
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/__init__.py +4 -0
- pdfdancer/models.py +49 -0
- pdfdancer/pdfdancer_v1.py +78 -3
- pdfdancer/types.py +8 -0
- {pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/METADATA +3 -3
- {pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/RECORD +10 -10
- {pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/WHEEL +0 -0
- {pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/licenses/LICENSE +0 -0
- {pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/licenses/NOTICE +0 -0
- {pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/top_level.txt +0 -0
pdfdancer/__init__.py
CHANGED
|
@@ -35,6 +35,8 @@ from .models import (
|
|
|
35
35
|
Point,
|
|
36
36
|
Position,
|
|
37
37
|
PositionMode,
|
|
38
|
+
RedactResponse,
|
|
39
|
+
RedactTarget,
|
|
38
40
|
ShapeType,
|
|
39
41
|
StandardFonts,
|
|
40
42
|
TextObjectRef,
|
|
@@ -78,6 +80,8 @@ __all__ = [
|
|
|
78
80
|
"Line",
|
|
79
81
|
"Bezier",
|
|
80
82
|
"Path",
|
|
83
|
+
"RedactTarget",
|
|
84
|
+
"RedactResponse",
|
|
81
85
|
"PdfDancerException",
|
|
82
86
|
"FontNotFoundException",
|
|
83
87
|
"ValidationException",
|
pdfdancer/models.py
CHANGED
|
@@ -893,6 +893,55 @@ class MoveRequest:
|
|
|
893
893
|
}
|
|
894
894
|
|
|
895
895
|
|
|
896
|
+
@dataclass
|
|
897
|
+
class RedactTarget:
|
|
898
|
+
"""A single redaction target identifying an object by its internal ID."""
|
|
899
|
+
|
|
900
|
+
id: str
|
|
901
|
+
replacement: str
|
|
902
|
+
|
|
903
|
+
def to_dict(self) -> dict:
|
|
904
|
+
return {"id": self.id, "replacement": self.replacement}
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
@dataclass
|
|
908
|
+
class RedactRequest:
|
|
909
|
+
"""Request for redacting content from a PDF document."""
|
|
910
|
+
|
|
911
|
+
targets: List["RedactTarget"]
|
|
912
|
+
default_replacement: str
|
|
913
|
+
placeholder_color: "Color"
|
|
914
|
+
|
|
915
|
+
def to_dict(self) -> dict:
|
|
916
|
+
return {
|
|
917
|
+
"targets": [t.to_dict() for t in self.targets],
|
|
918
|
+
"defaultReplacement": self.default_replacement,
|
|
919
|
+
"placeholderColor": {
|
|
920
|
+
"r": self.placeholder_color.r,
|
|
921
|
+
"g": self.placeholder_color.g,
|
|
922
|
+
"b": self.placeholder_color.b,
|
|
923
|
+
"a": self.placeholder_color.a,
|
|
924
|
+
},
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
@dataclass
|
|
929
|
+
class RedactResponse:
|
|
930
|
+
"""Response from a redaction operation."""
|
|
931
|
+
|
|
932
|
+
count: int
|
|
933
|
+
success: bool
|
|
934
|
+
warnings: List[str]
|
|
935
|
+
|
|
936
|
+
@classmethod
|
|
937
|
+
def from_dict(cls, data: dict) -> "RedactResponse":
|
|
938
|
+
return cls(
|
|
939
|
+
count=data.get("count", 0),
|
|
940
|
+
success=data.get("success", False),
|
|
941
|
+
warnings=data.get("warnings", []),
|
|
942
|
+
)
|
|
943
|
+
|
|
944
|
+
|
|
896
945
|
@dataclass
|
|
897
946
|
class PageMoveRequest:
|
|
898
947
|
"""Request to reorder pages.
|
pdfdancer/pdfdancer_v1.py
CHANGED
|
@@ -14,6 +14,7 @@ import os
|
|
|
14
14
|
import sys
|
|
15
15
|
import time
|
|
16
16
|
from datetime import datetime, timezone
|
|
17
|
+
from importlib.metadata import version as get_package_version
|
|
17
18
|
from pathlib import Path
|
|
18
19
|
from typing import TYPE_CHECKING, Any, BinaryIO, List, Mapping, Optional, Union
|
|
19
20
|
|
|
@@ -35,6 +36,7 @@ from .models import (
|
|
|
35
36
|
AddPageRequest,
|
|
36
37
|
AddRequest,
|
|
37
38
|
ChangeFormFieldRequest,
|
|
39
|
+
Color,
|
|
38
40
|
CommandResult,
|
|
39
41
|
DeleteRequest,
|
|
40
42
|
DocumentSnapshot,
|
|
@@ -57,6 +59,9 @@ from .models import (
|
|
|
57
59
|
Paragraph,
|
|
58
60
|
Position,
|
|
59
61
|
PositionMode,
|
|
62
|
+
RedactRequest,
|
|
63
|
+
RedactResponse,
|
|
64
|
+
RedactTarget,
|
|
60
65
|
ShapeType,
|
|
61
66
|
TextLine,
|
|
62
67
|
TextObjectRef,
|
|
@@ -69,6 +74,7 @@ from .types import (
|
|
|
69
74
|
ImageObject,
|
|
70
75
|
ParagraphObject,
|
|
71
76
|
PathObject,
|
|
77
|
+
PDFObjectBase,
|
|
72
78
|
TextLineObject,
|
|
73
79
|
)
|
|
74
80
|
|
|
@@ -78,6 +84,14 @@ if TYPE_CHECKING:
|
|
|
78
84
|
|
|
79
85
|
load_dotenv()
|
|
80
86
|
|
|
87
|
+
# Client identifier header for all HTTP requests
|
|
88
|
+
# Always reads from installed package metadata (stays in sync with pyproject.toml)
|
|
89
|
+
try:
|
|
90
|
+
CLIENT_HEADER_VALUE = f"python/{get_package_version('pdfdancer-client-python')}"
|
|
91
|
+
except Exception:
|
|
92
|
+
# Fallback in case package metadata is not available
|
|
93
|
+
CLIENT_HEADER_VALUE = "python/unknown"
|
|
94
|
+
|
|
81
95
|
# Global variable to disable SSL certificate verification
|
|
82
96
|
# Set to True to skip SSL verification (useful for testing with self-signed certificates)
|
|
83
97
|
# WARNING: Only use in development/testing environments
|
|
@@ -748,7 +762,10 @@ class PDFDancer:
|
|
|
748
762
|
|
|
749
763
|
while attempt <= max_retries:
|
|
750
764
|
try:
|
|
751
|
-
headers = {
|
|
765
|
+
headers = {
|
|
766
|
+
"X-Fingerprint": Fingerprint.generate(),
|
|
767
|
+
"X-PDFDancer-Client": CLIENT_HEADER_VALUE,
|
|
768
|
+
}
|
|
752
769
|
|
|
753
770
|
response = temp_client.post(
|
|
754
771
|
cls._cleanup_url_path(base_url, "/keys/anon"),
|
|
@@ -910,7 +927,10 @@ class PDFDancer:
|
|
|
910
927
|
# Create HTTP client for connection reuse with HTTP/2 support
|
|
911
928
|
instance._client = httpx.Client(
|
|
912
929
|
http2=True,
|
|
913
|
-
headers={
|
|
930
|
+
headers={
|
|
931
|
+
"Authorization": f"Bearer {instance._token}",
|
|
932
|
+
"X-PDFDancer-Client": CLIENT_HEADER_VALUE,
|
|
933
|
+
},
|
|
914
934
|
verify=not DISABLE_SSL_VERIFY,
|
|
915
935
|
)
|
|
916
936
|
|
|
@@ -976,7 +996,10 @@ class PDFDancer:
|
|
|
976
996
|
# Create HTTP client for connection reuse with HTTP/2 support
|
|
977
997
|
self._client = httpx.Client(
|
|
978
998
|
http2=True,
|
|
979
|
-
headers={
|
|
999
|
+
headers={
|
|
1000
|
+
"Authorization": f"Bearer {self._token}",
|
|
1001
|
+
"X-PDFDancer-Client": CLIENT_HEADER_VALUE,
|
|
1002
|
+
},
|
|
980
1003
|
verify=not DISABLE_SSL_VERIFY,
|
|
981
1004
|
)
|
|
982
1005
|
|
|
@@ -2054,6 +2077,58 @@ class PDFDancer:
|
|
|
2054
2077
|
|
|
2055
2078
|
return result
|
|
2056
2079
|
|
|
2080
|
+
def _redact(
|
|
2081
|
+
self,
|
|
2082
|
+
targets: List["RedactTarget"],
|
|
2083
|
+
default_replacement: str = "[REDACTED]",
|
|
2084
|
+
placeholder_color: Optional[Color] = None,
|
|
2085
|
+
) -> "RedactResponse":
|
|
2086
|
+
"""
|
|
2087
|
+
Redacts specified objects from the PDF document.
|
|
2088
|
+
|
|
2089
|
+
Args:
|
|
2090
|
+
targets: List of RedactTarget objects identifying what to redact
|
|
2091
|
+
default_replacement: Default replacement text for redacted content
|
|
2092
|
+
placeholder_color: Color for image/path placeholder rectangles
|
|
2093
|
+
|
|
2094
|
+
Returns:
|
|
2095
|
+
RedactResponse with count, success status, and any warnings
|
|
2096
|
+
"""
|
|
2097
|
+
if not targets:
|
|
2098
|
+
raise ValidationException("At least one redaction target is required")
|
|
2099
|
+
|
|
2100
|
+
if placeholder_color is None:
|
|
2101
|
+
placeholder_color = Color(0, 0, 0)
|
|
2102
|
+
|
|
2103
|
+
request = RedactRequest(targets, default_replacement, placeholder_color)
|
|
2104
|
+
response = self._make_request("POST", "/pdf/redact", data=request.to_dict())
|
|
2105
|
+
result = RedactResponse.from_dict(response.json())
|
|
2106
|
+
|
|
2107
|
+
if result.success:
|
|
2108
|
+
self._invalidate_snapshots()
|
|
2109
|
+
|
|
2110
|
+
return result
|
|
2111
|
+
|
|
2112
|
+
def redact(
|
|
2113
|
+
self,
|
|
2114
|
+
objects: List["PDFObjectBase"],
|
|
2115
|
+
replacement: str = "[REDACTED]",
|
|
2116
|
+
placeholder_color: Optional[Color] = None,
|
|
2117
|
+
) -> "RedactResponse":
|
|
2118
|
+
"""
|
|
2119
|
+
Redacts multiple objects from the PDF document.
|
|
2120
|
+
|
|
2121
|
+
Args:
|
|
2122
|
+
objects: List of PDF objects to redact
|
|
2123
|
+
replacement: Replacement text for all redacted content
|
|
2124
|
+
placeholder_color: Color for image/path placeholder rectangles
|
|
2125
|
+
|
|
2126
|
+
Returns:
|
|
2127
|
+
RedactResponse with count, success status, and any warnings
|
|
2128
|
+
"""
|
|
2129
|
+
targets = [RedactTarget(obj.internal_id, replacement) for obj in objects]
|
|
2130
|
+
return self._redact(targets, replacement, placeholder_color)
|
|
2131
|
+
|
|
2057
2132
|
# Add Operations
|
|
2058
2133
|
|
|
2059
2134
|
def _add_image(self, image: Image, position: Optional[Position] = None) -> bool:
|
pdfdancer/types.py
CHANGED
|
@@ -64,6 +64,14 @@ class PDFObjectBase:
|
|
|
64
64
|
Position.at_page_coordinates(self.position.page_number, x, y),
|
|
65
65
|
)
|
|
66
66
|
|
|
67
|
+
def redact(self, replacement: str = "[REDACTED]") -> bool:
|
|
68
|
+
"""Redact this object from the PDF document."""
|
|
69
|
+
from .models import RedactTarget
|
|
70
|
+
|
|
71
|
+
target = RedactTarget(self.internal_id, replacement)
|
|
72
|
+
result = self._client._redact([target], replacement)
|
|
73
|
+
return result.success
|
|
74
|
+
|
|
67
75
|
|
|
68
76
|
# -------------------------------------------------------------------
|
|
69
77
|
# Subclasses
|
{pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pdfdancer-client-python
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Python client for PDFDancer API
|
|
5
5
|
Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
|
|
6
6
|
License:
|
|
@@ -300,7 +300,7 @@ with PDFDancer.open(
|
|
|
300
300
|
.font(StandardFonts.HELVETICA, 12) \
|
|
301
301
|
.color(Color(70, 70, 70)) \
|
|
302
302
|
.line_spacing(1.4) \
|
|
303
|
-
.at(page_number=
|
|
303
|
+
.at(page_number=1, x=72, y=520) \
|
|
304
304
|
.add()
|
|
305
305
|
|
|
306
306
|
# Persist the modified document
|
|
@@ -321,7 +321,7 @@ with PDFDancer.new(token="your-api-token") as pdf:
|
|
|
321
321
|
.font(StandardFonts.TIMES_BOLD, 18) \
|
|
322
322
|
.color(Color(10, 10, 80)) \
|
|
323
323
|
.line_spacing(1.2) \
|
|
324
|
-
.at(page_number=
|
|
324
|
+
.at(page_number=1, x=72, y=730) \
|
|
325
325
|
.add()
|
|
326
326
|
|
|
327
327
|
pdf.new_image() \
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
pdfdancer/__init__.py,sha256=
|
|
1
|
+
pdfdancer/__init__.py,sha256=m_buZKsE08oJSuU_ofWjN--IdPvnSiWrin6xwCYYL80,2507
|
|
2
2
|
pdfdancer/exceptions.py,sha256=mJacmUJTPGUsB8Bo_FgfeXYkvZkH5OPJCVBfilBVmQo,2058
|
|
3
3
|
pdfdancer/fingerprint.py,sha256=eL3PHPgv-knMya7s95RXg3qzzpkAA1aevxqb6tuOb34,3061
|
|
4
4
|
pdfdancer/image_builder.py,sha256=aBxMFAMFzzbGTjlVH0hi94mA81cH8tp37Pk84HRPV00,1892
|
|
5
|
-
pdfdancer/models.py,sha256=
|
|
5
|
+
pdfdancer/models.py,sha256=JKvncVzzkXJy47XIQP9Ydvl2xkbi4IPXO60weXPoBiw,51856
|
|
6
6
|
pdfdancer/page_builder.py,sha256=ARWLRtlrLGbES-0nbiigTOsRVmodRX0DNK8YIAkA9Ig,3850
|
|
7
7
|
pdfdancer/paragraph_builder.py,sha256=OmhzYazMnq0n0rhrjWcKbo0LQfEC7BZoiLB29ycF630,20504
|
|
8
8
|
pdfdancer/path_builder.py,sha256=safKb_IeHRWlQbyBTIXfcoBfXxUZhuzYvBIob5Tbp-8,23938
|
|
9
|
-
pdfdancer/pdfdancer_v1.py,sha256=
|
|
9
|
+
pdfdancer/pdfdancer_v1.py,sha256=aLAdyhvxxQrjKQxDHgoIrUxwcIgIAYS4twL6TOOeSQ0,122812
|
|
10
10
|
pdfdancer/text_line_builder.py,sha256=8jYknV4hw0fyzwX0OI_oLvnh5aMmCV3jXaVkmYLu6MQ,10273
|
|
11
|
-
pdfdancer/types.py,sha256=
|
|
12
|
-
pdfdancer_client_python-0.3.
|
|
13
|
-
pdfdancer_client_python-0.3.
|
|
14
|
-
pdfdancer_client_python-0.3.
|
|
15
|
-
pdfdancer_client_python-0.3.
|
|
16
|
-
pdfdancer_client_python-0.3.
|
|
17
|
-
pdfdancer_client_python-0.3.
|
|
11
|
+
pdfdancer/types.py,sha256=gRpAOSmp9pESHjHdsrda8d2E6q8fGxZKVg59guxXg3g,16658
|
|
12
|
+
pdfdancer_client_python-0.3.2.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
13
|
+
pdfdancer_client_python-0.3.2.dist-info/licenses/NOTICE,sha256=xaC4l-IChAmtViNDie8ZWzUk0O6XRMyzOl0zLmVZ2HE,232
|
|
14
|
+
pdfdancer_client_python-0.3.2.dist-info/METADATA,sha256=VAUegFatdCjjiRZyldhJ5jP8gbq-2W3vTRqw-iOyoEs,24736
|
|
15
|
+
pdfdancer_client_python-0.3.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
16
|
+
pdfdancer_client_python-0.3.2.dist-info/top_level.txt,sha256=ICwSVRpcCKrdBF9QlaX9Y0e_N3Nk1p7QVxadGOnbxeY,10
|
|
17
|
+
pdfdancer_client_python-0.3.2.dist-info/RECORD,,
|
|
File without changes
|
{pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/licenses/NOTICE
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.3.1.dist-info → pdfdancer_client_python-0.3.2.dist-info}/top_level.txt
RENAMED
|
File without changes
|