pdfdancer-client-python 0.1.1__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.1.1/.gitignore +7 -0
- pdfdancer_client_python-0.1.1/CLAUDE.md +121 -0
- pdfdancer_client_python-0.1.1/PKG-INFO +308 -0
- pdfdancer_client_python-0.1.1/README.md +281 -0
- pdfdancer_client_python-0.1.1/demo.py +365 -0
- pdfdancer_client_python-0.1.1/docs/openapi.yml +1190 -0
- pdfdancer_client_python-0.1.1/pyproject.toml +52 -0
- pdfdancer_client_python-0.1.1/requirements-dev.txt +17 -0
- pdfdancer_client_python-0.1.1/requirements.txt +4 -0
- pdfdancer_client_python-0.1.1/setup.cfg +4 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer/__init__.py +40 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer/client_v1.py +675 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer/exceptions.py +57 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer/models.py +417 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer/paragraph_builder.py +267 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer_client_python.egg-info/PKG-INFO +308 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer_client_python.egg-info/SOURCES.txt +38 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer_client_python.egg-info/dependency_links.txt +1 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer_client_python.egg-info/requires.txt +10 -0
- pdfdancer_client_python-0.1.1/src/pdfdancer_client_python.egg-info/top_level.txt +1 -0
- pdfdancer_client_python-0.1.1/test.py +455 -0
- pdfdancer_client_python-0.1.1/tests/__init__.py +1 -0
- pdfdancer_client_python-0.1.1/tests/e2e/__init__.py +46 -0
- pdfdancer_client_python-0.1.1/tests/e2e/test_form.py +33 -0
- pdfdancer_client_python-0.1.1/tests/e2e/test_image.py +84 -0
- pdfdancer_client_python-0.1.1/tests/e2e/test_line.py +92 -0
- pdfdancer_client_python-0.1.1/tests/e2e/test_page.py +29 -0
- pdfdancer_client_python-0.1.1/tests/e2e/test_paragraph.py +172 -0
- pdfdancer_client_python-0.1.1/tests/e2e/test_path.py +56 -0
- pdfdancer_client_python-0.1.1/tests/fixtures/JetBrainsMono-Regular.ttf +0 -0
- pdfdancer_client_python-0.1.1/tests/fixtures/ObviouslyAwesome.pdf +0 -0
- pdfdancer_client_python-0.1.1/tests/fixtures/basic-paths.pdf +0 -0
- pdfdancer_client_python-0.1.1/tests/fixtures/logo-80.png +0 -0
- pdfdancer_client_python-0.1.1/tests/fixtures/mixed-form-types.pdf +0 -0
- pdfdancer_client_python-0.1.1/tests/test_client_v1.py +444 -0
- pdfdancer_client_python-0.1.1/tests/test_error_extraction.py +117 -0
- pdfdancer_client_python-0.1.1/tests/test_exception_suppression.py +53 -0
- pdfdancer_client_python-0.1.1/tests/test_models.py +303 -0
- pdfdancer_client_python-0.1.1/tests/test_openapi_compliance.py +108 -0
- pdfdancer_client_python-0.1.1/tests/test_paragraph_builder.py +324 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with the PDFDancer Python client.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is a **Python client library** for the PDFDancer PDF manipulation API. It uses a **100% manual implementation** that:
|
|
8
|
+
|
|
9
|
+
- **Mirrors Java client structure exactly** - Same methods, validation, and patterns
|
|
10
|
+
- **Pure Python implementation** - Uses `requests` for HTTP calls, no code generation
|
|
11
|
+
- **Pythonic conventions** - Snake_case methods, type hints, context managers
|
|
12
|
+
- **Strict validation** - Matches Java client validation exactly
|
|
13
|
+
|
|
14
|
+
## Essential Commands
|
|
15
|
+
|
|
16
|
+
### Development
|
|
17
|
+
- `python -m venv venv` - Create virtual environment
|
|
18
|
+
- `venv/bin/pip install -e .` - Install in development mode
|
|
19
|
+
- `venv/bin/pip install -r requirements-dev.txt` - Install dev dependencies
|
|
20
|
+
|
|
21
|
+
### Testing
|
|
22
|
+
- `venv/bin/python -m pytest tests/ -v` - Run all tests (77 tests)
|
|
23
|
+
- `venv/bin/python -m pytest tests/test_client_v1.py -v` - Run client tests
|
|
24
|
+
- `venv/bin/python -m pytest tests/test_paragraph_builder.py -v` - Run builder tests
|
|
25
|
+
|
|
26
|
+
### Building & Publishing
|
|
27
|
+
- `venv/bin/python -m build` - Build distribution packages
|
|
28
|
+
- `venv/bin/python -m twine check dist/*` - Validate packages
|
|
29
|
+
- `venv/bin/python -m twine upload dist/*` - Publish to PyPI
|
|
30
|
+
|
|
31
|
+
## Architecture
|
|
32
|
+
|
|
33
|
+
### Manual Implementation
|
|
34
|
+
The client is a pure manual implementation that closely mirrors the Java client:
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
# Java-like API with Python conventions
|
|
38
|
+
client = ClientV1(token="jwt-token", pdf_data="document.pdf")
|
|
39
|
+
|
|
40
|
+
# Find operations (mirrors Java findParagraphs, findImages, etc.)
|
|
41
|
+
paragraphs = client.find_paragraphs(position)
|
|
42
|
+
images = client.find_images(position)
|
|
43
|
+
|
|
44
|
+
# Manipulation operations (mirrors Java delete, move, etc.)
|
|
45
|
+
client.delete(paragraphs[0])
|
|
46
|
+
client.move(images[0], new_position)
|
|
47
|
+
|
|
48
|
+
# Builder pattern (mirrors Java ParagraphBuilder)
|
|
49
|
+
paragraph = (client.paragraph_builder()
|
|
50
|
+
.from_string("Text content")
|
|
51
|
+
.with_font(Font("Arial", 12))
|
|
52
|
+
.with_position(Position.on_page_coordinates(0, 100, 200))
|
|
53
|
+
.build())
|
|
54
|
+
|
|
55
|
+
# Context manager support (Python enhancement)
|
|
56
|
+
with ClientV1(token="jwt-token", pdf_data=pdf_file) as client:
|
|
57
|
+
client.save_pdf("output.pdf")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Package Structure
|
|
61
|
+
- `src/pdfdancer/` - Main package
|
|
62
|
+
- `client_v1.py` - Main ClientV1 class (mirrors Java Client class)
|
|
63
|
+
- `paragraph_builder.py` - ParagraphBuilder for fluent construction
|
|
64
|
+
- `models.py` - All model classes (ObjectRef, Position, Font, etc.)
|
|
65
|
+
- `exceptions.py` - Exception hierarchy matching Java client
|
|
66
|
+
|
|
67
|
+
### Key Features
|
|
68
|
+
- **Session-based operations**: Constructor creates session automatically
|
|
69
|
+
- **Strict validation**: All validation matches Java client exactly
|
|
70
|
+
- **Builder pattern**: ParagraphBuilder with fluent interface
|
|
71
|
+
- **Exception handling**: FontNotFoundException, ValidationException, etc.
|
|
72
|
+
- **Type safety**: Full type hints throughout
|
|
73
|
+
- **Context manager**: Python enhancement for resource management
|
|
74
|
+
|
|
75
|
+
## Java Client Mapping
|
|
76
|
+
|
|
77
|
+
### Constructor Patterns
|
|
78
|
+
```python
|
|
79
|
+
# Java: new Client(token, pdfFile)
|
|
80
|
+
client = ClientV1(token="jwt-token", pdf_data="document.pdf")
|
|
81
|
+
|
|
82
|
+
# Java: new Client(token, bytesPDF, httpClient)
|
|
83
|
+
client = ClientV1(token="jwt-token", pdf_data=pdf_bytes, base_url="http://api.server")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Method Mapping
|
|
87
|
+
- `find()` → `find()`
|
|
88
|
+
- `findParagraphs()` → `find_paragraphs()`
|
|
89
|
+
- `findImages()` → `find_images()`
|
|
90
|
+
- `delete()` → `delete()`
|
|
91
|
+
- `move()` → `move()`
|
|
92
|
+
- `addParagraph()` → `add_paragraph()`
|
|
93
|
+
- `getPDFFile()` → `get_pdf_file()`
|
|
94
|
+
- `savePDF()` → `save_pdf()`
|
|
95
|
+
- `paragraphBuilder()` → `paragraph_builder()`
|
|
96
|
+
|
|
97
|
+
### Validation Matching
|
|
98
|
+
All validation matches Java client exactly:
|
|
99
|
+
- Null checks become None checks
|
|
100
|
+
- IllegalArgumentException becomes ValidationException
|
|
101
|
+
- FontNotFoundException preserved exactly
|
|
102
|
+
- Page number validation (must be positive)
|
|
103
|
+
- File existence and readability checks
|
|
104
|
+
|
|
105
|
+
## Development Notes
|
|
106
|
+
|
|
107
|
+
- **Python 3.8+ compatibility**
|
|
108
|
+
- **Uses `requests` library** for all HTTP communication
|
|
109
|
+
- **No code generation** - pure manual implementation
|
|
110
|
+
- **Virtual environment auto-setup** via parent Makefile
|
|
111
|
+
- **No code formatter configured** - follow existing style
|
|
112
|
+
- **Comprehensive tests** - 77 tests covering all functionality
|
|
113
|
+
|
|
114
|
+
## Important Instructions
|
|
115
|
+
|
|
116
|
+
- **ALWAYS mirror Java client behavior exactly** - same validation, same patterns
|
|
117
|
+
- **Use snake_case for method names** but preserve Java logic
|
|
118
|
+
- **Maintain strict validation** - don't be more lenient than Java client
|
|
119
|
+
- **Follow existing test patterns** when adding new functionality
|
|
120
|
+
- **Keep exception hierarchy matching Java client**
|
|
121
|
+
- **Preserve builder pattern fluent interface**
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pdfdancer-client-python
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Python client for PDFDancer API
|
|
5
|
+
Author-email: TFC <info@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/tfc/pdfdancer-python
|
|
8
|
+
Project-URL: Repository, https://github.com/tfc/pdfdancer-python.git
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: requests>=2.25.0
|
|
19
|
+
Requires-Dist: pydantic>=1.8.0
|
|
20
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
24
|
+
Requires-Dist: black>=22.0; extra == "dev"
|
|
25
|
+
Requires-Dist: flake8>=5.0; extra == "dev"
|
|
26
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
27
|
+
|
|
28
|
+
# PDFDancer Python Client
|
|
29
|
+
|
|
30
|
+
A Python client library for the PDFDancer PDF manipulation API that closely mirrors the Java client structure and functionality.
|
|
31
|
+
|
|
32
|
+
## Features
|
|
33
|
+
|
|
34
|
+
- **100% Manual Implementation** - Pure Python, no code generation
|
|
35
|
+
- **Java Client Compatibility** - Same methods, validation, and patterns
|
|
36
|
+
- **Session-based Operations** - Automatic session management
|
|
37
|
+
- **Builder Pattern** - Fluent ParagraphBuilder interface
|
|
38
|
+
- **Strict Validation** - Matches Java client validation exactly
|
|
39
|
+
- **Python Enhancements** - Type hints, context managers, Pathlib support
|
|
40
|
+
- **Comprehensive Testing** - 77 tests covering all functionality
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install pdfdancer-client-python
|
|
46
|
+
# Or for development:
|
|
47
|
+
pip install -e .
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from pdfdancer import ClientV1, Position, Font, Color
|
|
54
|
+
|
|
55
|
+
# Create client (mirrors Java: new Client(token, pdfFile))
|
|
56
|
+
client = ClientV1(token="your-jwt-token", pdf_data="document.pdf")
|
|
57
|
+
|
|
58
|
+
# Find operations (mirrors Java client methods)
|
|
59
|
+
paragraphs = client.find_paragraphs(None)
|
|
60
|
+
images = client.find_images(Position.from_page_index(0))
|
|
61
|
+
|
|
62
|
+
# Manipulation operations (mirrors Java client methods)
|
|
63
|
+
client.delete(paragraphs[0])
|
|
64
|
+
client.move(images[0], Position.on_page_coordinates(0, 100, 200))
|
|
65
|
+
|
|
66
|
+
# Builder pattern (mirrors Java ParagraphBuilder)
|
|
67
|
+
paragraph = (client.paragraph_builder()
|
|
68
|
+
.from_string("Hello World")
|
|
69
|
+
.with_font(Font("Arial", 12))
|
|
70
|
+
.with_color(Color(255, 0, 0))
|
|
71
|
+
.with_position(Position.from_page_index(0))
|
|
72
|
+
.build())
|
|
73
|
+
|
|
74
|
+
client.add_paragraph(paragraph)
|
|
75
|
+
|
|
76
|
+
# Save result (mirrors Java savePDF)
|
|
77
|
+
client.save_pdf("output.pdf")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Context Manager (Python Enhancement)
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from pdfdancer import ClientV1
|
|
84
|
+
|
|
85
|
+
# Automatic resource management
|
|
86
|
+
with ClientV1(token="jwt-token", pdf_data="input.pdf") as client:
|
|
87
|
+
paragraphs = client.find_paragraphs(None)
|
|
88
|
+
client.delete(paragraphs[0])
|
|
89
|
+
client.save_pdf("output.pdf")
|
|
90
|
+
# Session automatically cleaned up
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## API Methods
|
|
94
|
+
|
|
95
|
+
### Constructor Patterns
|
|
96
|
+
```python
|
|
97
|
+
# File path (Java: new Client(token, new File("pdf")))
|
|
98
|
+
client = ClientV1(token="jwt-token", pdf_data="document.pdf")
|
|
99
|
+
|
|
100
|
+
# Bytes (Java: new Client(token, pdfBytes, httpClient))
|
|
101
|
+
client = ClientV1(token="jwt-token", pdf_data=pdf_bytes)
|
|
102
|
+
|
|
103
|
+
# Custom server
|
|
104
|
+
client = ClientV1(token="jwt-token", pdf_data=pdf_file, base_url="https://api.server")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Find Operations
|
|
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_forms(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
|
+
```python
|
|
126
|
+
# Delete (Java: client.delete(), client.deletePage())
|
|
127
|
+
result = client.delete(object_ref)
|
|
128
|
+
result = client.delete_page(page_ref)
|
|
129
|
+
|
|
130
|
+
# Move (Java: client.move())
|
|
131
|
+
result = client.move(object_ref, new_position)
|
|
132
|
+
|
|
133
|
+
# Add (Java: client.addImage(), client.addParagraph())
|
|
134
|
+
result = client.add_image(image, position)
|
|
135
|
+
result = client.add_paragraph(paragraph)
|
|
136
|
+
|
|
137
|
+
# Modify (Java: client.modifyParagraph(), client.modifyTextLine())
|
|
138
|
+
result = client.modify_paragraph(ref, new_paragraph)
|
|
139
|
+
result = client.modify_text_line(ref, "new text")
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Builder Pattern
|
|
143
|
+
```python
|
|
144
|
+
# Java: client.paragraphBuilder()
|
|
145
|
+
builder = client.paragraph_builder()
|
|
146
|
+
|
|
147
|
+
# Fluent interface (mirrors Java ParagraphBuilder)
|
|
148
|
+
paragraph = (builder
|
|
149
|
+
.from_string("Text content") # Java: fromString()
|
|
150
|
+
.with_font(Font("Arial", 12)) # Java: withFont()
|
|
151
|
+
.with_color(Color(255, 0, 0)) # Java: withColor()
|
|
152
|
+
.with_line_spacing(1.5) # Java: withLineSpacing()
|
|
153
|
+
.with_position(position) # Java: withPosition()
|
|
154
|
+
.build()) # Java: build()
|
|
155
|
+
|
|
156
|
+
# Font file registration (Java: withFont(File, double))
|
|
157
|
+
paragraph = (builder
|
|
158
|
+
.with_font_file("custom.ttf", 14.0) # Java: withFont(File, double)
|
|
159
|
+
.from_string("Custom font text")
|
|
160
|
+
.with_position(position)
|
|
161
|
+
.build())
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Position API
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from pdfdancer import Position
|
|
168
|
+
|
|
169
|
+
# Factory methods (Java: Position.fromPageNumber(), Position.onPageCoordinates())
|
|
170
|
+
position = Position.from_page_index(0)
|
|
171
|
+
position = Position.on_page_coordinates(0, 100, 200)
|
|
172
|
+
|
|
173
|
+
# Coordinate access (Java: position.getX(), position.getY())
|
|
174
|
+
x = position.get_x()
|
|
175
|
+
y = position.get_y()
|
|
176
|
+
|
|
177
|
+
# Movement (Java: position.moveX(), position.moveY())
|
|
178
|
+
position.move_x(50.0)
|
|
179
|
+
position.move_y(-25.0)
|
|
180
|
+
|
|
181
|
+
# Copy (Java: position.copy())
|
|
182
|
+
position_copy = position.copy()
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Font Operations
|
|
186
|
+
```python
|
|
187
|
+
# Find fonts (Java: client.findFonts())
|
|
188
|
+
fonts = client.find_fonts("Arial", 12)
|
|
189
|
+
|
|
190
|
+
# Register custom font (Java: client.registerFont())
|
|
191
|
+
font_name = client.register_font("custom.ttf")
|
|
192
|
+
font_name = client.register_font(Path("font.ttf"))
|
|
193
|
+
font_name = client.register_font(font_bytes)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Document Operations
|
|
197
|
+
```python
|
|
198
|
+
# Get PDF content (Java: client.getPDFFile())
|
|
199
|
+
pdf_bytes = client.get_pdf_file()
|
|
200
|
+
|
|
201
|
+
# Save PDF (Java: client.savePDF())
|
|
202
|
+
client.save_pdf("output.pdf")
|
|
203
|
+
client.save_pdf(Path("output.pdf"))
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Exception Handling
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
from pdfdancer import (
|
|
210
|
+
PdfDancerException, ValidationException,
|
|
211
|
+
FontNotFoundException, HttpClientException
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
client = ClientV1(token="", pdf_data=b"pdf")
|
|
216
|
+
except ValidationException as e: # Java: IllegalArgumentException
|
|
217
|
+
print(f"Validation error: {e}")
|
|
218
|
+
|
|
219
|
+
try:
|
|
220
|
+
fonts = client.find_fonts("NonExistentFont", 12)
|
|
221
|
+
except FontNotFoundException as e: # Java: FontNotFoundException
|
|
222
|
+
print(f"Font not found: {e}")
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Data Models
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
from pdfdancer import ObjectRef, Position, Font, Color, ObjectType
|
|
229
|
+
|
|
230
|
+
# Object reference (Java: ObjectRef)
|
|
231
|
+
obj_ref = ObjectRef(internal_id="obj-123", position=position, type=ObjectType.PARAGRAPH)
|
|
232
|
+
|
|
233
|
+
# Font (Java: Font)
|
|
234
|
+
font = Font(name="Arial", size=12.0)
|
|
235
|
+
|
|
236
|
+
# Color (Java: Color) - RGB values 0-255
|
|
237
|
+
color = Color(r=255, g=128, b=0)
|
|
238
|
+
|
|
239
|
+
# Position with bounding rectangle (Java: Position, BoundingRect)
|
|
240
|
+
position = Position.on_page_coordinates(page=0, x=100.0, y=200.0)
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
### Setup
|
|
246
|
+
```bash
|
|
247
|
+
python -m venv venv
|
|
248
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
249
|
+
pip install -e .
|
|
250
|
+
pip install -r requirements-dev.txt
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Testing
|
|
254
|
+
```bash
|
|
255
|
+
# Run all tests (77 tests)
|
|
256
|
+
python -m pytest tests/ -v
|
|
257
|
+
|
|
258
|
+
# Run specific test files
|
|
259
|
+
python -m pytest tests/test_client_v1.py -v
|
|
260
|
+
python -m pytest tests/test_paragraph_builder.py -v
|
|
261
|
+
python -m pytest tests/test_models.py -v
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Run Demo
|
|
265
|
+
```bash
|
|
266
|
+
python demo.py
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Build Package
|
|
270
|
+
```bash
|
|
271
|
+
python -m build
|
|
272
|
+
python -m twine check dist/*
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Java Client Mapping
|
|
276
|
+
|
|
277
|
+
| Java Method | Python Method | Description |
|
|
278
|
+
|-------------|---------------|-------------|
|
|
279
|
+
| `new Client(token, file)` | `ClientV1(token="", pdf_data="")` | Constructor |
|
|
280
|
+
| `findParagraphs(position)` | `find_paragraphs(position)` | Find paragraphs |
|
|
281
|
+
| `findImages(position)` | `find_images(position)` | Find images |
|
|
282
|
+
| `delete(objectRef)` | `delete(object_ref)` | Delete object |
|
|
283
|
+
| `move(objectRef, position)` | `move(object_ref, position)` | Move object |
|
|
284
|
+
| `addParagraph(paragraph)` | `add_paragraph(paragraph)` | Add paragraph |
|
|
285
|
+
| `getPDFFile()` | `get_pdf_file()` | Get PDF bytes |
|
|
286
|
+
| `savePDF(path)` | `save_pdf(path)` | Save to file |
|
|
287
|
+
| `paragraphBuilder()` | `paragraph_builder()` | Create builder |
|
|
288
|
+
| `findFonts(name, size)` | `find_fonts(name, size)` | Find fonts |
|
|
289
|
+
| `registerFont(ttfFile)` | `register_font(ttf_file)` | Register font |
|
|
290
|
+
|
|
291
|
+
## Architecture
|
|
292
|
+
|
|
293
|
+
- **Pure Manual Implementation** - No code generation, uses `requests` for HTTP
|
|
294
|
+
- **Session-based** - Constructor creates session, all operations use session ID
|
|
295
|
+
- **Strict Validation** - Matches Java client validation exactly
|
|
296
|
+
- **Type Safety** - Full type hints throughout
|
|
297
|
+
- **Error Handling** - Complete exception hierarchy
|
|
298
|
+
- **Python Conventions** - snake_case methods, context managers, Pathlib support
|
|
299
|
+
|
|
300
|
+
## Requirements
|
|
301
|
+
|
|
302
|
+
- Python 3.8+
|
|
303
|
+
- `requests` library for HTTP communication
|
|
304
|
+
- `pathlib` for file handling (built-in)
|
|
305
|
+
|
|
306
|
+
## License
|
|
307
|
+
|
|
308
|
+
[Add your license information here]
|