PyPDFForm 1.4.34__tar.gz → 1.4.36__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 PyPDFForm might be problematic. Click here for more details.
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PKG-INFO +1 -1
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/__init__.py +1 -1
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/filler.py +1 -1
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/patterns.py +9 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/template.py +47 -4
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/widgets/base.py +1 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/wrapper.py +17 -1
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm.egg-info/PKG-INFO +1 -1
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_create_widget.py +24 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_functional.py +41 -17
- {pypdfform-1.4.34 → pypdfform-1.4.36}/LICENSE +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/adapter.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/constants.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/coordinate.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/font.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/image.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/middleware/__init__.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/middleware/base.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/middleware/checkbox.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/middleware/dropdown.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/middleware/image.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/middleware/radio.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/middleware/signature.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/middleware/text.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/utils.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/watermark.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/widgets/__init__.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/widgets/checkbox.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/widgets/dropdown.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm/widgets/text.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm.egg-info/SOURCES.txt +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm.egg-info/dependency_links.txt +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm.egg-info/requires.txt +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/PyPDFForm.egg-info/top_level.txt +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/README.md +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/setup.cfg +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/setup.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_adobe_mode.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_dropdown.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_dropdown_simple.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_fill_max_length_text_field.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_fill_max_length_text_field_simple.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_functional_simple.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_paragraph.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_paragraph_simple.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_preview.py +0 -0
- {pypdfform-1.4.34 → pypdfform-1.4.36}/tests/test_signature.py +0 -0
|
@@ -128,7 +128,7 @@ def fill(
|
|
|
128
128
|
widget_dict, widgets[key], radio_button_tracker
|
|
129
129
|
)
|
|
130
130
|
elif isinstance(widgets[key], (Signature, Image)):
|
|
131
|
-
any_image_to_draw
|
|
131
|
+
any_image_to_draw |= signature_image_handler(
|
|
132
132
|
widget_dict, widgets[key], images_to_draw[page]
|
|
133
133
|
)
|
|
134
134
|
else:
|
|
@@ -160,6 +160,15 @@ def simple_flatten_generic(annot: DictionaryObject) -> None:
|
|
|
160
160
|
)
|
|
161
161
|
|
|
162
162
|
|
|
163
|
+
def update_annotation_name(annot: DictionaryObject, val: str) -> None:
|
|
164
|
+
"""Patterns to update the name of an annotation."""
|
|
165
|
+
|
|
166
|
+
if Parent in annot and T not in annot:
|
|
167
|
+
annot[NameObject(Parent)][NameObject(T)] = TextStringObject(val) # noqa
|
|
168
|
+
else:
|
|
169
|
+
annot[NameObject(T)] = TextStringObject(val) # noqa
|
|
170
|
+
|
|
171
|
+
|
|
163
172
|
def update_created_text_field_alignment(annot: DictionaryObject, val: int) -> None:
|
|
164
173
|
"""Patterns to update text alignment for text annotations created by the library."""
|
|
165
174
|
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
"""Contains helpers for generic template related processing."""
|
|
3
3
|
|
|
4
4
|
from functools import lru_cache
|
|
5
|
+
from io import BytesIO
|
|
5
6
|
from sys import maxsize
|
|
6
|
-
from typing import Dict, List, Tuple, Union
|
|
7
|
+
from typing import Dict, List, Tuple, Union, cast
|
|
7
8
|
|
|
8
|
-
from pypdf import PdfReader
|
|
9
|
+
from pypdf import PdfReader, PdfWriter
|
|
10
|
+
from pypdf.generic import DictionaryObject
|
|
9
11
|
from reportlab.pdfbase.pdfmetrics import stringWidth
|
|
10
12
|
|
|
11
13
|
from .constants import (COMB, DEFAULT_FONT_SIZE, MULTILINE, NEW_LINE_SYMBOL,
|
|
12
|
-
WIDGET_TYPES, MaxLen, Rect)
|
|
14
|
+
WIDGET_TYPES, Annots, MaxLen, Rect)
|
|
13
15
|
from .font import (adjust_paragraph_font_size, adjust_text_field_font_size,
|
|
14
16
|
auto_detect_font, get_text_field_font_color,
|
|
15
17
|
get_text_field_font_size, text_field_font_size)
|
|
@@ -19,7 +21,8 @@ from .middleware.radio import Radio
|
|
|
19
21
|
from .middleware.text import Text
|
|
20
22
|
from .patterns import (BUTTON_STYLE_PATTERNS, DROPDOWN_CHOICE_PATTERNS,
|
|
21
23
|
TEXT_FIELD_FLAG_PATTERNS, WIDGET_ALIGNMENT_PATTERNS,
|
|
22
|
-
WIDGET_KEY_PATTERNS, WIDGET_TYPE_PATTERNS
|
|
24
|
+
WIDGET_KEY_PATTERNS, WIDGET_TYPE_PATTERNS,
|
|
25
|
+
update_annotation_name)
|
|
23
26
|
from .utils import find_pattern_match, stream_to_io, traverse_pattern
|
|
24
27
|
from .watermark import create_watermarks_and_draw
|
|
25
28
|
|
|
@@ -403,3 +406,43 @@ def get_paragraph_auto_wrap_length(widget_middleware: Text) -> int:
|
|
|
403
406
|
result = min(result, len(line))
|
|
404
407
|
|
|
405
408
|
return result
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def update_widget_key(
|
|
412
|
+
template: bytes,
|
|
413
|
+
widgets: Dict[str, WIDGET_TYPES],
|
|
414
|
+
old_key: str,
|
|
415
|
+
new_key: str,
|
|
416
|
+
index: int,
|
|
417
|
+
) -> bytes:
|
|
418
|
+
"""Updates the key of a widget."""
|
|
419
|
+
# pylint: disable=R0801
|
|
420
|
+
|
|
421
|
+
pdf = PdfReader(stream_to_io(template))
|
|
422
|
+
out = PdfWriter()
|
|
423
|
+
out.append(pdf)
|
|
424
|
+
|
|
425
|
+
tracker = -1
|
|
426
|
+
|
|
427
|
+
for page in out.pages:
|
|
428
|
+
for annot in page.get(Annots, []): # noqa
|
|
429
|
+
annot = cast(DictionaryObject, annot.get_object())
|
|
430
|
+
key = get_widget_key(annot.get_object())
|
|
431
|
+
|
|
432
|
+
widget = widgets.get(key)
|
|
433
|
+
if widget is None:
|
|
434
|
+
continue
|
|
435
|
+
|
|
436
|
+
if old_key != key:
|
|
437
|
+
continue
|
|
438
|
+
|
|
439
|
+
tracker += 1
|
|
440
|
+
if not isinstance(widget, Radio) and tracker != index:
|
|
441
|
+
continue
|
|
442
|
+
|
|
443
|
+
update_annotation_name(annot, new_key)
|
|
444
|
+
|
|
445
|
+
with BytesIO() as f:
|
|
446
|
+
out.write(f)
|
|
447
|
+
f.seek(0)
|
|
448
|
+
return f.read()
|
|
@@ -18,7 +18,7 @@ from .middleware.dropdown import Dropdown
|
|
|
18
18
|
from .middleware.text import Text
|
|
19
19
|
from .template import (build_widgets, dropdown_to_text,
|
|
20
20
|
set_character_x_paddings, update_text_field_attributes,
|
|
21
|
-
widget_rect_watermarks)
|
|
21
|
+
update_widget_key, widget_rect_watermarks)
|
|
22
22
|
from .utils import (get_page_streams, merge_two_pdfs, preview_widget_to_draw,
|
|
23
23
|
remove_all_widgets)
|
|
24
24
|
from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
|
|
@@ -235,6 +235,22 @@ class PdfWrapper(FormWrapper):
|
|
|
235
235
|
|
|
236
236
|
return self
|
|
237
237
|
|
|
238
|
+
def update_widget_key(
|
|
239
|
+
self, old_key: str, new_key: str, index: int = 0
|
|
240
|
+
) -> PdfWrapper:
|
|
241
|
+
"""Updates the key of an existed widget on a PDF form."""
|
|
242
|
+
|
|
243
|
+
self.__init__(
|
|
244
|
+
template=update_widget_key(
|
|
245
|
+
self.read(), self.widgets, old_key, new_key, index
|
|
246
|
+
),
|
|
247
|
+
global_font=self.global_font,
|
|
248
|
+
global_font_size=self.global_font_size,
|
|
249
|
+
global_font_color=self.global_font_color,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
return self
|
|
253
|
+
|
|
238
254
|
def draw_text(
|
|
239
255
|
self,
|
|
240
256
|
text: str,
|
|
@@ -198,6 +198,30 @@ def test_create_text_default(template_stream, pdf_samples, request):
|
|
|
198
198
|
assert obj.stream == expected
|
|
199
199
|
|
|
200
200
|
|
|
201
|
+
def test_create_text_alpha_bg_color(template_stream, pdf_samples, request):
|
|
202
|
+
expected_path = os.path.join(
|
|
203
|
+
pdf_samples, "widget", "create_text_alpha_bg_color.pdf"
|
|
204
|
+
)
|
|
205
|
+
with open(expected_path, "rb+") as f:
|
|
206
|
+
obj = PdfWrapper(template_stream).create_widget(
|
|
207
|
+
"text",
|
|
208
|
+
"foo",
|
|
209
|
+
1,
|
|
210
|
+
100,
|
|
211
|
+
100,
|
|
212
|
+
bg_color=(0, 0, 1, 0),
|
|
213
|
+
)
|
|
214
|
+
assert obj.schema["properties"]["foo"]["type"] == "string"
|
|
215
|
+
|
|
216
|
+
request.config.results["expected_path"] = expected_path
|
|
217
|
+
request.config.results["stream"] = obj.read()
|
|
218
|
+
|
|
219
|
+
expected = f.read()
|
|
220
|
+
|
|
221
|
+
assert len(obj.stream) == len(expected)
|
|
222
|
+
assert obj.stream == expected
|
|
223
|
+
|
|
224
|
+
|
|
201
225
|
def test_create_text_align_center(template_stream, pdf_samples, request):
|
|
202
226
|
expected_path = os.path.join(pdf_samples, "widget", "create_text_align_center.pdf")
|
|
203
227
|
with open(expected_path, "rb+") as f:
|
|
@@ -258,7 +258,7 @@ def test_draw_image_on_one_page(template_stream, image_samples, pdf_samples, req
|
|
|
258
258
|
|
|
259
259
|
expected = f.read()
|
|
260
260
|
|
|
261
|
-
if os.name
|
|
261
|
+
if os.name != "nt":
|
|
262
262
|
request.config.results["expected_path"] = expected_path
|
|
263
263
|
request.config.results["stream"] = obj.read()
|
|
264
264
|
assert len(obj.stream) == len(expected)
|
|
@@ -281,7 +281,7 @@ def test_draw_png_image_on_one_page(
|
|
|
281
281
|
|
|
282
282
|
expected = f.read()
|
|
283
283
|
|
|
284
|
-
if os.name
|
|
284
|
+
if os.name != "nt":
|
|
285
285
|
request.config.results["expected_path"] = expected_path
|
|
286
286
|
request.config.results["stream"] = obj.read()
|
|
287
287
|
assert len(obj.stream) == len(expected)
|
|
@@ -304,7 +304,7 @@ def test_draw_transparent_png_image_on_one_page(
|
|
|
304
304
|
|
|
305
305
|
expected = f.read()
|
|
306
306
|
|
|
307
|
-
if os.name
|
|
307
|
+
if os.name != "nt":
|
|
308
308
|
request.config.results["expected_path"] = expected_path
|
|
309
309
|
request.config.results["stream"] = obj.read()
|
|
310
310
|
assert len(obj.stream) == len(expected)
|
|
@@ -510,24 +510,15 @@ def test_fill_complex_fonts(sample_template_with_complex_fonts, pdf_samples, req
|
|
|
510
510
|
assert obj.stream == expected
|
|
511
511
|
|
|
512
512
|
|
|
513
|
-
def test_pages(template_stream, pdf_samples):
|
|
513
|
+
def test_pages(template_stream, pdf_samples, request):
|
|
514
|
+
expected_path = os.path.join(pdf_samples, "pages", "sample_template_page_1.pdf")
|
|
514
515
|
obj = PdfWrapper(template_stream)
|
|
515
516
|
|
|
516
|
-
with open(
|
|
517
|
-
|
|
518
|
-
|
|
517
|
+
with open(expected_path, "rb+") as f:
|
|
518
|
+
request.config.results["expected_path"] = expected_path
|
|
519
|
+
request.config.results["stream"] = obj.pages[0].read()
|
|
519
520
|
assert obj.pages[0].read() == f.read()
|
|
520
521
|
|
|
521
|
-
with open(
|
|
522
|
-
os.path.join(pdf_samples, "pages", "sample_template_page_2.pdf"), "rb+"
|
|
523
|
-
) as f:
|
|
524
|
-
assert obj.pages[1].read() == f.read()
|
|
525
|
-
|
|
526
|
-
with open(
|
|
527
|
-
os.path.join(pdf_samples, "pages", "sample_template_page_3.pdf"), "rb+"
|
|
528
|
-
) as f:
|
|
529
|
-
assert obj.pages[2].read() == f.read()
|
|
530
|
-
|
|
531
522
|
|
|
532
523
|
def test_generate_coordinate_grid(template_stream, pdf_samples, request):
|
|
533
524
|
expected_path = os.path.join(pdf_samples, "test_generate_coordinate_grid.pdf")
|
|
@@ -635,3 +626,36 @@ def test_fill_image(
|
|
|
635
626
|
|
|
636
627
|
assert len(obj.read()) == len(expected)
|
|
637
628
|
assert obj.stream == expected
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
def test_update_radio_key(template_with_radiobutton_stream, pdf_samples, request):
|
|
632
|
+
expected_path = os.path.join(pdf_samples, "test_update_radio_key.pdf")
|
|
633
|
+
with open(expected_path, "rb+") as f:
|
|
634
|
+
obj = PdfWrapper(template_with_radiobutton_stream)
|
|
635
|
+
obj.update_widget_key("radio_3", "RADIO")
|
|
636
|
+
|
|
637
|
+
request.config.results["expected_path"] = expected_path
|
|
638
|
+
request.config.results["stream"] = obj.read()
|
|
639
|
+
|
|
640
|
+
expected = f.read()
|
|
641
|
+
|
|
642
|
+
assert len(obj.preview) == len(expected)
|
|
643
|
+
assert obj.preview == expected
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
def test_update_sejda_key(sejda_template, pdf_samples, request):
|
|
647
|
+
expected_path = os.path.join(pdf_samples, "test_update_sejda_key.pdf")
|
|
648
|
+
with open(expected_path, "rb+") as f:
|
|
649
|
+
obj = PdfWrapper(sejda_template)
|
|
650
|
+
obj.update_widget_key("year", "YEAR")
|
|
651
|
+
obj.update_widget_key("at_future_date", "FUTURE_DATE")
|
|
652
|
+
obj.update_widget_key("purchase_option", "PURCHASE_OPTION")
|
|
653
|
+
obj.update_widget_key("buyer_signed_date", "BUYER_SIGNED_DATE")
|
|
654
|
+
|
|
655
|
+
request.config.results["expected_path"] = expected_path
|
|
656
|
+
request.config.results["stream"] = obj.read()
|
|
657
|
+
|
|
658
|
+
expected = f.read()
|
|
659
|
+
|
|
660
|
+
assert len(obj.preview) == len(expected)
|
|
661
|
+
assert obj.preview == expected
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|