pdfdancer-client-python 0.2.7__tar.gz → 0.2.9__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.
Potentially problematic release.
This version of pdfdancer-client-python might be problematic. Click here for more details.
- {pdfdancer_client_python-0.2.7/src/pdfdancer_client_python.egg-info → pdfdancer_client_python-0.2.9}/PKG-INFO +1 -1
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/pyproject.toml +1 -1
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/paragraph_builder.py +11 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/pdfdancer_v1.py +6 -2
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9/src/pdfdancer_client_python.egg-info}/PKG-INFO +1 -1
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer_client_python.egg-info/SOURCES.txt +1 -1
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/test_paragraph.py +14 -1
- pdfdancer_client_python-0.2.9/tests/e2e/test_pdfdancer.py +33 -0
- pdfdancer_client_python-0.2.7/tests/test_authentication.py +0 -36
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/.github/workflows/ci.yml +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/.gitignore +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/CLAUDE.md +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/README.md +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/docs/openapi.yml +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/release.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/requirements-dev.txt +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/requirements.txt +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/setup.cfg +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/__init__.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/exceptions.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/image_builder.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/models.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/types.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer_client_python.egg-info/dependency_links.txt +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer_client_python.egg-info/requires.txt +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer_client_python.egg-info/top_level.txt +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/__init__.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/conftest.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/__init__.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/test_acroform.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/test_form_x_objects.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/test_image.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/test_line.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/test_page.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/test_path.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/DancingScript-Regular.ttf +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/JetBrainsMono-Regular.ttf +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/ObviouslyAwesome.pdf +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/basic-paths.pdf +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/form-xobject-example.pdf +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/logo-80.png +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/mixed-form-types.pdf +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/test_models.py +0 -0
- {pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/test_openapi_compliance.py +0 -0
{pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/paragraph_builder.py
RENAMED
|
@@ -268,3 +268,14 @@ class ParagraphBuilder:
|
|
|
268
268
|
|
|
269
269
|
def add(self):
|
|
270
270
|
self._client._add_paragraph(self.build())
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class ParagraphPageBuilder(ParagraphBuilder):
|
|
274
|
+
|
|
275
|
+
def __init__(self, client: 'PDFDancer', page_index: int):
|
|
276
|
+
super().__init__(client)
|
|
277
|
+
self._page_index: Optional[int] = page_index
|
|
278
|
+
|
|
279
|
+
# noinspection PyMethodOverriding
|
|
280
|
+
def at(self, x: float, y: float) -> 'ParagraphBuilder':
|
|
281
|
+
return super().at(self._page_index, x, y)
|
{pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/pdfdancer_v1.py
RENAMED
|
@@ -26,6 +26,7 @@ from .models import (
|
|
|
26
26
|
FindRequest, DeleteRequest, MoveRequest, AddRequest, ModifyRequest, ModifyTextRequest, ChangeFormFieldRequest,
|
|
27
27
|
ShapeType, PositionMode
|
|
28
28
|
)
|
|
29
|
+
from .paragraph_builder import ParagraphPageBuilder
|
|
29
30
|
from .types import PathObject, ParagraphObject, TextLineObject, ImageObject, FormObject, FormFieldObject
|
|
30
31
|
|
|
31
32
|
|
|
@@ -114,6 +115,9 @@ class PageClient:
|
|
|
114
115
|
def _ref(self):
|
|
115
116
|
return ObjectRef(internal_id=self.internal_id, position=self.position, type=self.object_type)
|
|
116
117
|
|
|
118
|
+
def new_paragraph(self):
|
|
119
|
+
return ParagraphPageBuilder(self.root, self.page_index)
|
|
120
|
+
|
|
117
121
|
|
|
118
122
|
class PDFDancer:
|
|
119
123
|
"""
|
|
@@ -779,7 +783,7 @@ class PDFDancer:
|
|
|
779
783
|
|
|
780
784
|
# Document Operations
|
|
781
785
|
|
|
782
|
-
def
|
|
786
|
+
def get_bytes(self) -> bytes:
|
|
783
787
|
"""
|
|
784
788
|
Downloads the current state of the PDF document with all modifications applied.
|
|
785
789
|
|
|
@@ -804,7 +808,7 @@ class PDFDancer:
|
|
|
804
808
|
raise ValidationException("File path cannot be null or empty")
|
|
805
809
|
|
|
806
810
|
try:
|
|
807
|
-
pdf_data = self.
|
|
811
|
+
pdf_data = self.get_bytes()
|
|
808
812
|
output_path = Path(file_path)
|
|
809
813
|
|
|
810
814
|
# Create parent directories if they don't exist
|
|
@@ -21,7 +21,6 @@ src/pdfdancer_client_python.egg-info/requires.txt
|
|
|
21
21
|
src/pdfdancer_client_python.egg-info/top_level.txt
|
|
22
22
|
tests/__init__.py
|
|
23
23
|
tests/conftest.py
|
|
24
|
-
tests/test_authentication.py
|
|
25
24
|
tests/test_models.py
|
|
26
25
|
tests/test_openapi_compliance.py
|
|
27
26
|
tests/e2e/__init__.py
|
|
@@ -32,6 +31,7 @@ tests/e2e/test_line.py
|
|
|
32
31
|
tests/e2e/test_page.py
|
|
33
32
|
tests/e2e/test_paragraph.py
|
|
34
33
|
tests/e2e/test_path.py
|
|
34
|
+
tests/e2e/test_pdfdancer.py
|
|
35
35
|
tests/fixtures/DancingScript-Regular.ttf
|
|
36
36
|
tests/fixtures/JetBrainsMono-Regular.ttf
|
|
37
37
|
tests/fixtures/ObviouslyAwesome.pdf
|
|
@@ -116,6 +116,19 @@ def test_add_paragraph_with_custom_font1_1():
|
|
|
116
116
|
_assert_new_paragraph_exists(pdf)
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
def test_add_paragraph_on_page_with_custom_font1_1():
|
|
120
|
+
base_url, token, pdf_path = _require_env_and_fixture("ObviouslyAwesome.pdf")
|
|
121
|
+
|
|
122
|
+
with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
|
|
123
|
+
pdf.page(0).new_paragraph() \
|
|
124
|
+
.text("Awesomely\nObvious!") \
|
|
125
|
+
.font("Roboto-Regular", 14) \
|
|
126
|
+
.line_spacing(0.7) \
|
|
127
|
+
.at(300.1, 500) \
|
|
128
|
+
.add()
|
|
129
|
+
_assert_new_paragraph_exists(pdf)
|
|
130
|
+
|
|
131
|
+
|
|
119
132
|
def test_add_paragraph_with_custom_font1_2():
|
|
120
133
|
base_url, token, pdf_path = _require_env_and_fixture("ObviouslyAwesome.pdf")
|
|
121
134
|
|
|
@@ -161,7 +174,7 @@ def test_add_paragraph_with_custom_font3():
|
|
|
161
174
|
with PDFDancer.open(pdf_path, token=token, base_url=base_url, timeout=30.0) as pdf:
|
|
162
175
|
pdf.new_paragraph() \
|
|
163
176
|
.text("Awesomely\nObvious!") \
|
|
164
|
-
.font_file(
|
|
177
|
+
.font_file(ttf_path, 24) \
|
|
165
178
|
.line_spacing(1.8) \
|
|
166
179
|
.color(Color(0, 0, 255)) \
|
|
167
180
|
.at(0, 300.1, 500) \
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from tests.e2e import _require_env_and_fixture
|
|
6
|
+
from pdfdancer import PDFDancer, ValidationException, HttpClientException
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_env_vars():
|
|
10
|
+
base_url, _, pdf_path = _require_env_and_fixture("ObviouslyAwesome.pdf")
|
|
11
|
+
os.environ.pop("PDFDANCER_TOKEN", None)
|
|
12
|
+
|
|
13
|
+
with pytest.raises(ValidationException) as exc_info:
|
|
14
|
+
with PDFDancer.open(pdf_path, base_url=base_url) as pdf:
|
|
15
|
+
pass
|
|
16
|
+
assert "Missing PDFDancer API token. Pass a token via the `token` argument or set the PDFDANCER_TOKEN environment variable." == str(
|
|
17
|
+
exc_info.value)
|
|
18
|
+
|
|
19
|
+
os.environ["PDFDANCER_TOKEN"] = "42"
|
|
20
|
+
with PDFDancer.open(pdf_path, base_url=base_url) as pdf:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
os.environ["PDFDANCER_BASE_URL"] = "http://www.google.com"
|
|
24
|
+
with pytest.raises(HttpClientException) as exc_info:
|
|
25
|
+
with PDFDancer.open(pdf_path) as pdf:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
os.environ["PDFDANCER_BASE_URL"] = "https://api.pdfdancer.com"
|
|
29
|
+
with pytest.raises(ValidationException) as exc_info:
|
|
30
|
+
with PDFDancer.open(pdf_path) as pdf:
|
|
31
|
+
pass
|
|
32
|
+
assert "Authentication with the PDFDancer API failed. Confirm that your API token is valid, has not expired" in str(
|
|
33
|
+
exc_info.value)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
import pytest
|
|
3
|
-
|
|
4
|
-
from pdfdancer import ValidationException
|
|
5
|
-
from pdfdancer.pdfdancer_v1 import PDFDancer
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def test_open_without_token_reports_actionable_message():
|
|
9
|
-
with pytest.raises(ValidationException) as exc_info:
|
|
10
|
-
PDFDancer.open(pdf_data=b"%PDF", token="")
|
|
11
|
-
|
|
12
|
-
message = str(exc_info.value)
|
|
13
|
-
assert "Missing PDFDancer API token" in message
|
|
14
|
-
assert "PDFDANCER_TOKEN" in message
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def test_create_session_unauthorized_reports_guidance(monkeypatch):
|
|
18
|
-
class FakeResponse:
|
|
19
|
-
status_code = 401
|
|
20
|
-
text = "Unauthorized"
|
|
21
|
-
|
|
22
|
-
def json(self):
|
|
23
|
-
return {"message": "Unauthorized"}
|
|
24
|
-
|
|
25
|
-
def fake_post(self, *args, **kwargs):
|
|
26
|
-
return FakeResponse()
|
|
27
|
-
|
|
28
|
-
monkeypatch.setattr(requests.Session, "post", fake_post)
|
|
29
|
-
|
|
30
|
-
with pytest.raises(ValidationException) as exc_info:
|
|
31
|
-
PDFDancer(token="bad-token", pdf_data=b"%PDF", base_url="https://api.example.com")
|
|
32
|
-
|
|
33
|
-
message = str(exc_info.value)
|
|
34
|
-
assert "Authentication with the PDFDancer API failed" in message
|
|
35
|
-
assert "Server response: Unauthorized" in message
|
|
36
|
-
assert "PDFDANCER_TOKEN" in message
|
|
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.2.7 → pdfdancer_client_python-0.2.9}/src/pdfdancer/image_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
|
{pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/e2e/test_form_x_objects.py
RENAMED
|
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.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/ObviouslyAwesome.pdf
RENAMED
|
File without changes
|
{pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/basic-paths.pdf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/fixtures/mixed-form-types.pdf
RENAMED
|
File without changes
|
|
File without changes
|
{pdfdancer_client_python-0.2.7 → pdfdancer_client_python-0.2.9}/tests/test_openapi_compliance.py
RENAMED
|
File without changes
|