pdfdancer-client-python 0.2.5__py3-none-any.whl → 0.2.6__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.

Potentially problematic release.


This version of pdfdancer-client-python might be problematic. Click here for more details.

@@ -0,0 +1,189 @@
1
+ Metadata-Version: 2.4
2
+ Name: pdfdancer-client-python
3
+ Version: 0.2.6
4
+ Summary: Python client for PDFDancer API
5
+ Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://www.pdfdancer.com/
8
+ Project-URL: Repository, https://github.com/MenschMachine/pdfdancer-client-python
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: requests>=2.25.0
18
+ Requires-Dist: pydantic>=1.8.0
19
+ Requires-Dist: typing-extensions>=4.0.0
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest>=7.0; extra == "dev"
22
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
23
+ Requires-Dist: black>=22.0; extra == "dev"
24
+ Requires-Dist: flake8>=5.0; extra == "dev"
25
+ Requires-Dist: mypy>=1.0; extra == "dev"
26
+
27
+ # PDFDancer Python Client
28
+
29
+ Automate PDF clean-up, redaction, form filling, and content injection against the PDFDancer API from Python. The client gives you page-scoped selectors, fluent editors, and builders so you can read, modify, and export PDFs programmatically in just a few lines.
30
+
31
+ ## Highlights
32
+
33
+ - Locate anything inside a PDF—paragraphs, text lines, images, vector paths, pages, AcroForm fields—by page, coordinates, or text prefixes
34
+ - Edit or delete existing content with fluent paragraph/text editors and safe apply-on-exit context managers
35
+ - Fill or update form fields and propagate the changes back to the document instantly
36
+ - Add brand-new content with paragraph/image builders, custom fonts, and precise page positioning
37
+ - Download results as bytes for downstream processing or save directly to disk with one method call
38
+
39
+ ## Core Capabilities
40
+
41
+ - Clean up layout by moving or deleting paragraphs, text lines, or shapes on specific pages
42
+ - Search and filter content (e.g., paragraphs starting with "Invoice") to drive custom workflows
43
+ - Redact or replace text in bulk with chained editor operations
44
+ - Populate AcroForms for contract generation or onboarding flows
45
+ - Insert logos, signatures, and generated paragraphs at deterministic coordinates
46
+ - Export modified PDFs as bytes for APIs, S3 uploads, or direct file saves
47
+
48
+ ## Requirements
49
+
50
+ - Python 3.9 or newer
51
+ - A PDFDancer API token (set `PDFDANCER_TOKEN` or pass `token=...`)
52
+ - Network access to a PDFDancer service (defaults to `https://api.pdfdancer.com`; override with `PDFDANCER_BASE_URL`)
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pip install pdfdancer-client-python
58
+
59
+ # Editable install for local development
60
+ pip install -e .
61
+ ```
62
+
63
+ ## Getting Started
64
+
65
+ ```python
66
+ from pathlib import Path
67
+ from pdfdancer import Color, PDFDancer
68
+
69
+ with PDFDancer.open(
70
+ pdf_data=Path("input.pdf"),
71
+ token="your-api-token", # optional when PDFDANCER_TOKEN is set
72
+ base_url="https://api.pdfdancer.com",
73
+ ) as pdf:
74
+ # Locate existing content
75
+ heading = pdf.page(0).select_paragraphs_starting_with("Executive Summary")[0]
76
+ heading.edit().replace("Overview").apply()
77
+
78
+ # Add a new paragraph using the fluent builder
79
+ pdf.new_paragraph() \
80
+ .text("Generated with PDFDancer") \
81
+ .font("Helvetica", 12) \
82
+ .color(Color(70, 70, 70)) \
83
+ .line_spacing(1.4) \
84
+ .at(page_index=0, x=72, y=520) \
85
+ .add()
86
+
87
+ # Persist the modified document
88
+ pdf.save("output.pdf")
89
+ ```
90
+
91
+ ### Authentication Tips
92
+
93
+ - Prefer setting `PDFDANCER_TOKEN` in your environment for local development.
94
+ - Override the API host by setting `PDFDANCER_BASE_URL` or passing `base_url="https://sandbox.pdfdancer.com"`.
95
+ - Use the `timeout` parameter on `PDFDancer.open()` to adjust HTTP read timeouts.
96
+
97
+ ## Selecting PDF Content
98
+
99
+ ```python
100
+ with PDFDancer.open("report.pdf") as pdf: # environment variables provide token/URL
101
+ all_paragraphs = pdf.select_paragraphs()
102
+ page_zero_images = pdf.page(0).select_images()
103
+ form_fields = pdf.page(2).select_form_fields()
104
+ paths_at_cursor = pdf.page(3).select_paths_at(x=150, y=320)
105
+
106
+ page = pdf.page(0).get()
107
+ print(page.internal_id, page.position.bounding_rect)
108
+ ```
109
+
110
+ Selectors return rich objects (`ParagraphObject`, `TextLineObject`, `ImageObject`, `FormFieldObject`, etc.) with helpers such as `delete()`, `move_to(x, y)`, or `edit()` depending on the object type.
111
+
112
+ ## Editing Text and Forms
113
+
114
+ ```python
115
+ with PDFDancer.open("report.pdf") as pdf:
116
+ paragraph = pdf.page(0).select_paragraphs_starting_with("Disclaimer")[0]
117
+
118
+ # Chain updates explicitly…
119
+ paragraph.edit() \
120
+ .replace("Updated disclaimer text") \
121
+ .font("Roboto-Regular", 11) \
122
+ .line_spacing(1.1) \
123
+ .move_to(72, 140) \
124
+ .apply()
125
+
126
+ # …or use the context manager to auto-apply on success
127
+ with paragraph.edit() as edit:
128
+ edit.replace("Context-managed update").color(Color(120, 0, 0))
129
+
130
+ # Update an AcroForm field
131
+ field = pdf.page(1).select_form_fields_by_name("signature")[0]
132
+ field.edit().value("Signed by Jane Doe").apply()
133
+ ```
134
+
135
+ ## Adding New Content
136
+
137
+ ```python
138
+ with PDFDancer.open("report.pdf") as pdf:
139
+ # Register fonts from the service
140
+ fonts = pdf.find_fonts("Roboto", 12)
141
+ pdf.register_font("/path/to/custom.ttf")
142
+
143
+ # Paragraphs
144
+ pdf.new_paragraph() \
145
+ .text("Greetings from PDFDancer!") \
146
+ .font(fonts[0].name, fonts[0].size) \
147
+ .at(page_index=0, x=220, y=480) \
148
+ .add()
149
+
150
+ # Raster images
151
+ pdf.new_image() \
152
+ .from_file(Path("logo.png")) \
153
+ .at(page=0, x=48, y=700) \
154
+ .add()
155
+ ```
156
+
157
+ ## Downloading Results
158
+
159
+ - `pdf.get_pdf_file()` returns the modified PDF as `bytes` (ideal for storage services or HTTP responses).
160
+ - `pdf.save("output.pdf")` writes directly to disk, creating directories when needed.
161
+
162
+ ## Error Handling
163
+
164
+ Most operations raise subclasses of `PdfDancerException`:
165
+
166
+ - `ValidationException` for client-side validation issues (missing token, invalid coordinates, etc.).
167
+ - `FontNotFoundException` when the service cannot locate a requested font.
168
+ - `HttpClientException` for transport or server errors with detailed messages.
169
+ - `SessionException` when session creation fails.
170
+
171
+ Wrap complex workflows in `try/except` blocks to surface actionable errors to your users.
172
+
173
+ ## Local Development
174
+
175
+ ```bash
176
+ python -m venv venv
177
+ source venv/bin/activate # Windows: venv\Scripts\activate
178
+ pip install -e .
179
+ pip install -r requirements-dev.txt
180
+
181
+ pytest -q # run the fast unit suite
182
+ pytest tests/e2e # integration tests (requires live API + fixtures)
183
+ ```
184
+
185
+ Package builds are handled by `python -m build`, and release artifacts are published via `python release.py`.
186
+
187
+ ## License
188
+
189
+ MIT © The Famous Cat Ltd.
@@ -5,7 +5,7 @@ pdfdancer/models.py,sha256=SmkKScr47uVs6FCWUAVIg6rucYrYHvbIxZngyA50XyI,15498
5
5
  pdfdancer/paragraph_builder.py,sha256=bAfwX9U2YT1UGX9EKkPnGYvGK3SQP3X1ocxlgyLE_rU,8872
6
6
  pdfdancer/pdfdancer_v1.py,sha256=Pgv-2L0pYQdOUVK2nUntrGB6hCDKUOMWHYuN8loBM3Q,35540
7
7
  pdfdancer/types.py,sha256=05zvjA6MEQomNucUUKf5Z33dA7NVFCRu_6LR3Yom1yo,7633
8
- pdfdancer_client_python-0.2.5.dist-info/METADATA,sha256=YqAuXltFAL3ypn0x7r72dxhJDYMwArPUMzOLCFxNt7A,9253
9
- pdfdancer_client_python-0.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
- pdfdancer_client_python-0.2.5.dist-info/top_level.txt,sha256=ICwSVRpcCKrdBF9QlaX9Y0e_N3Nk1p7QVxadGOnbxeY,10
11
- pdfdancer_client_python-0.2.5.dist-info/RECORD,,
8
+ pdfdancer_client_python-0.2.6.dist-info/METADATA,sha256=mQUfTZ7xhjoCWdo6g_5sAerVGtq-tBdaV93Nesj5CcI,6769
9
+ pdfdancer_client_python-0.2.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ pdfdancer_client_python-0.2.6.dist-info/top_level.txt,sha256=ICwSVRpcCKrdBF9QlaX9Y0e_N3Nk1p7QVxadGOnbxeY,10
11
+ pdfdancer_client_python-0.2.6.dist-info/RECORD,,
@@ -1,305 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: pdfdancer-client-python
3
- Version: 0.2.5
4
- Summary: Python client for PDFDancer API
5
- Author-email: "The Famous Cat Ltd." <hi@thefamouscat.com>
6
- License: MIT
7
- Project-URL: Homepage, https://www.pdfdancer.com/
8
- Project-URL: Repository, https://github.com/MenschMachine/pdfdancer-client-python
9
- Classifier: Development Status :: 4 - Beta
10
- Classifier: Intended Audience :: Developers
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Programming Language :: Python :: 3.9
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Description-Content-Type: text/markdown
17
- Requires-Dist: requests>=2.25.0
18
- Requires-Dist: pydantic>=1.8.0
19
- Requires-Dist: typing-extensions>=4.0.0
20
- Provides-Extra: dev
21
- Requires-Dist: pytest>=7.0; extra == "dev"
22
- Requires-Dist: pytest-cov>=4.0; extra == "dev"
23
- Requires-Dist: black>=22.0; extra == "dev"
24
- Requires-Dist: flake8>=5.0; extra == "dev"
25
- Requires-Dist: mypy>=1.0; extra == "dev"
26
-
27
- # PDFDancer Python Client
28
-
29
- A Python client library for the PDFDancer PDF manipulation API that closely mirrors the Java client structure and functionality.
30
-
31
- ## Features
32
-
33
- - **100% Manual Implementation** - Pure Python, no code generation
34
- - **Java Client Compatibility** - Same methods, validation, and patterns
35
- - **Session-based Operations** - Automatic session management
36
- - **Builder Pattern** - Fluent ParagraphBuilder interface
37
- - **Strict Validation** - Matches Java client validation exactly
38
- - **Python Enhancements** - Type hints, context managers, Pathlib support
39
- - **Comprehensive Testing** - 77 tests covering all functionality
40
-
41
- ## Installation
42
-
43
- ```bash
44
- pip install pdfdancer-client-python
45
- # Or for development:
46
- pip install -e .
47
- ```
48
-
49
- ## Quick Start
50
-
51
- ```python
52
- from pdfdancer import ClientV1, Position, Font, Color
53
-
54
- # Create client (mirrors Java: new Client(token, pdfFile))
55
- client = ClientV1(token="your-jwt-token", pdf_data="document.pdf")
56
-
57
- # Find operations (mirrors Java client methods)
58
- paragraphs = client.find_paragraphs(None)
59
- images = client.find_images(Position.at_page(0))
60
-
61
- # Manipulation operations (mirrors Java client methods)
62
- client._delete(paragraphs[0])
63
- client._move(images[0], Position.at_page_coordinates(0, 100, 200))
64
-
65
- # Builder pattern (mirrors Java ParagraphBuilder)
66
- paragraph = (client._paragraph_builder()
67
- .from_string("Hello World")
68
- .with_font(Font("Arial", 12))
69
- .with_color(Color(255, 0, 0))
70
- .with_position(Position.at_page(0))
71
- .build())
72
-
73
- client._add_paragraph(paragraph)
74
-
75
- # Save result (mirrors Java savePDF)
76
- client.save_pdf("output.pdf")
77
- ```
78
-
79
- ## Context Manager (Python Enhancement)
80
-
81
- ```python
82
- from pdfdancer import ClientV1
83
-
84
- # Automatic resource management
85
- with ClientV1(token="jwt-token", pdf_data="input.pdf") as client:
86
- paragraphs = client.find_paragraphs(None)
87
- client._delete(paragraphs[0])
88
- client.save_pdf("output.pdf")
89
- # Session automatically cleaned up
90
- ```
91
-
92
- ## API Methods
93
-
94
- ### Constructor Patterns
95
- ```python
96
- # File path (Java: new Client(token, new File("pdf")))
97
- client = ClientV1(token="jwt-token", pdf_data="document.pdf")
98
-
99
- # Bytes (Java: new Client(token, pdfBytes, httpClient))
100
- client = ClientV1(token="jwt-token", pdf_data=pdf_bytes)
101
-
102
- # Custom server
103
- client = ClientV1(token="jwt-token", pdf_data=pdf_file, base_url="https://api.server")
104
- ```
105
-
106
- ### Find Operations
107
-
108
- ```python
109
- # Generic find (Java: client.find())
110
- objects = client._find(ObjectType.PARAGRAPH, position)
111
-
112
- # Specific finders (Java: client.findParagraphs(), etc.)
113
- paragraphs = client._find_paragraphs(position)
114
- images = client._find_images(position)
115
- forms = client._find_form_x_objects(position)
116
- paths = client._find_paths(position)
117
- text_lines = client._find_text_lines(position)
118
-
119
- # Page operations (Java: client.getPages(), client.getPage())
120
- pages = client.get_pages()
121
- page = client._get_page(1) # 1-based indexing
122
- ```
123
-
124
- ### Manipulation Operations
125
-
126
- ```python
127
- # Delete (Java: client.delete(), client.deletePage())
128
- result = client._delete(object_ref)
129
- result = client._delete_page(page_ref)
130
-
131
- # Move (Java: client.move())
132
- result = client._move(object_ref, new_position)
133
-
134
- # Add (Java: client.addImage(), client.addParagraph())
135
- result = client._add_image(image, position)
136
- result = client._add_paragraph(paragraph)
137
-
138
- # Modify (Java: client.modifyParagraph(), client.modifyTextLine())
139
- result = client._modify_paragraph(ref, new_paragraph)
140
- result = client.modify_text_line(ref, "new text")
141
- ```
142
-
143
- ### Builder Pattern
144
-
145
- ```python
146
- # Java: client.paragraphBuilder()
147
- builder = client._paragraph_builder()
148
-
149
- # Fluent interface (mirrors Java ParagraphBuilder)
150
- paragraph = (builder
151
- .from_string("Text content") # Java: fromString()
152
- .with_font(Font("Arial", 12)) # Java: withFont()
153
- .with_color(Color(255, 0, 0)) # Java: withColor()
154
- .with_line_spacing(1.5) # Java: withLineSpacing()
155
- .with_position(position) # Java: withPosition()
156
- .build()) # Java: build()
157
-
158
- # Font file registration (Java: withFont(File, double))
159
- paragraph = (builder
160
- .with_font_file("custom.ttf", 14.0) # Java: withFont(File, double)
161
- .from_string("Custom font text")
162
- .with_position(position)
163
- .build())
164
- ```
165
-
166
- ### Position API
167
-
168
- ```python
169
- from pdfdancer import Position
170
-
171
- # Factory methods (Java: Position.fromPageNumber(), Position.onPageCoordinates())
172
- position = Position.at_page(0)
173
- position = Position.at_page_coordinates(0, 100, 200)
174
-
175
- # Coordinate access (Java: position.getX(), position.getY())
176
- x = position.x()
177
- y = position.y()
178
-
179
- # Movement (Java: position.moveX(), position.moveY())
180
- position.move_x(50.0)
181
- position.move_y(-25.0)
182
-
183
- # Copy (Java: position.copy())
184
- position_copy = position.copy()
185
- ```
186
-
187
- ### Font Operations
188
- ```python
189
- # Find fonts (Java: client.findFonts())
190
- fonts = client.find_fonts("Arial", 12)
191
-
192
- # Register custom font (Java: client.registerFont())
193
- font_name = client.register_font("custom.ttf")
194
- font_name = client.register_font(Path("font.ttf"))
195
- font_name = client.register_font(font_bytes)
196
- ```
197
-
198
- ### Document Operations
199
- ```python
200
- # Get PDF content (Java: client.getPDFFile())
201
- pdf_bytes = client.get_pdf_file()
202
-
203
- # Save PDF (Java: client.savePDF())
204
- client.save_pdf("output.pdf")
205
- client.save_pdf(Path("output.pdf"))
206
- ```
207
-
208
- ## Exception Handling
209
-
210
- ```python
211
- from pdfdancer import (
212
- PdfDancerException, ValidationException,
213
- FontNotFoundException, HttpClientException
214
- )
215
-
216
- try:
217
- client = ClientV1(token="", pdf_data=b"pdf")
218
- except ValidationException as e: # Java: IllegalArgumentException
219
- print(f"Validation error: {e}")
220
-
221
- try:
222
- fonts = client.find_fonts("NonExistentFont", 12)
223
- except FontNotFoundException as e: # Java: FontNotFoundException
224
- print(f"Font not found: {e}")
225
- ```
226
-
227
- ## Data Models
228
-
229
- ```python
230
- from pdfdancer import ObjectRef, Position, Font, Color, ObjectType
231
-
232
- # Object reference (Java: ObjectRef)
233
- obj_ref = ObjectRef(internal_id="obj-123", position=position, type=ObjectType.PARAGRAPH)
234
-
235
- # Font (Java: Font)
236
- font = Font(name="Arial", size=12.0)
237
-
238
- # Color (Java: Color) - RGB values 0-255
239
- color = Color(r=255, g=128, b=0)
240
-
241
- # Position with bounding rectangle (Java: Position, BoundingRect)
242
- position = Position.at_page_coordinates(page=0, x=100.0, y=200.0)
243
- ```
244
-
245
- ## Development
246
-
247
- ### Setup
248
- ```bash
249
- python -m venv venv
250
- source venv/bin/activate # On Windows: venv\Scripts\activate
251
- pip install -e .
252
- pip install -r requirements-dev.txt
253
- ```
254
-
255
- ### Testing
256
- ```bash
257
- # Run all tests (77 tests)
258
- python -m pytest tests/ -v
259
-
260
- # Run specific test files
261
- python -m pytest tests/test_client_v1.py -v
262
- python -m pytest tests/test_paragraph_builder.py -v
263
- python -m pytest tests/test_models.py -v
264
- ```
265
-
266
- ### Build Package
267
- ```bash
268
- python -m build
269
- python -m twine check dist/*
270
- ```
271
-
272
- ## Java Client Mapping
273
-
274
- | Java Method | Python Method | Description |
275
- |-------------|---------------|-------------|
276
- | `new Client(token, file)` | `ClientV1(token="", pdf_data="")` | Constructor |
277
- | `findParagraphs(position)` | `find_paragraphs(position)` | Find paragraphs |
278
- | `findImages(position)` | `find_images(position)` | Find images |
279
- | `delete(objectRef)` | `delete(object_ref)` | Delete object |
280
- | `move(objectRef, position)` | `move(object_ref, position)` | Move object |
281
- | `addParagraph(paragraph)` | `add_paragraph(paragraph)` | Add paragraph |
282
- | `getPDFFile()` | `get_pdf_file()` | Get PDF bytes |
283
- | `savePDF(path)` | `save_pdf(path)` | Save to file |
284
- | `paragraphBuilder()` | `paragraph_builder()` | Create builder |
285
- | `findFonts(name, size)` | `find_fonts(name, size)` | Find fonts |
286
- | `registerFont(ttfFile)` | `register_font(ttf_file)` | Register font |
287
-
288
- ## Architecture
289
-
290
- - **Pure Manual Implementation** - No code generation, uses `requests` for HTTP
291
- - **Session-based** - Constructor creates session, all operations use session ID
292
- - **Strict Validation** - Matches Java client validation exactly
293
- - **Type Safety** - Full type hints throughout
294
- - **Error Handling** - Complete exception hierarchy
295
- - **Python Conventions** - snake_case methods, context managers, Pathlib support
296
-
297
- ## Requirements
298
-
299
- - Python 3.8+
300
- - `requests` library for HTTP communication
301
- - `pathlib` for file handling (built-in)
302
-
303
- ## License
304
-
305
- [Add your license information here]