PyPDFForm 1.4.37__tar.gz → 1.5.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 PyPDFForm might be problematic. Click here for more details.
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PKG-INFO +10 -2
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/__init__.py +1 -1
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/constants.py +1 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/middleware/base.py +8 -1
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/middleware/checkbox.py +1 -1
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/middleware/dropdown.py +6 -1
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/middleware/radio.py +5 -1
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/middleware/text.py +1 -1
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/patterns.py +3 -1
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/template.py +63 -28
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/wrapper.py +63 -24
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm.egg-info/PKG-INFO +10 -2
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm.egg-info/SOURCES.txt +2 -1
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_functional.py +3 -7
- pypdfform-1.5.1/tests/test_use_full_widget_name.py +49 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/LICENSE +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/adapter.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/coordinate.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/filler.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/font.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/image.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/middleware/__init__.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/middleware/image.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/middleware/signature.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/utils.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/watermark.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/widgets/__init__.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/widgets/base.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/widgets/checkbox.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/widgets/dropdown.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm/widgets/text.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm.egg-info/dependency_links.txt +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm.egg-info/requires.txt +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/PyPDFForm.egg-info/top_level.txt +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/README.md +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/setup.cfg +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/setup.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_adobe_mode.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_create_widget.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_dropdown.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_dropdown_simple.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_fill_max_length_text_field.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_fill_max_length_text_field_simple.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_fill_method.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_functional_simple.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_paragraph.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_paragraph_simple.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_preview.py +0 -0
- {pypdfform-1.4.37 → pypdfform-1.5.1}/tests/test_signature.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: PyPDFForm
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: The Python library for PDF forms.
|
|
5
5
|
Home-page: https://github.com/chinapandaman/PyPDFForm
|
|
6
6
|
Author: Jinge Li
|
|
@@ -24,6 +24,14 @@ Requires-Dist: cryptography
|
|
|
24
24
|
Requires-Dist: pillow
|
|
25
25
|
Requires-Dist: pypdf
|
|
26
26
|
Requires-Dist: reportlab
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: requires-dist
|
|
33
|
+
Dynamic: requires-python
|
|
34
|
+
Dynamic: summary
|
|
27
35
|
|
|
28
36
|
<p align="center"><img src="https://github.com/chinapandaman/PyPDFForm/raw/master/logo.png"></p>
|
|
29
37
|
<p align="center">
|
|
@@ -16,7 +16,9 @@ class Widget:
|
|
|
16
16
|
|
|
17
17
|
super().__init__()
|
|
18
18
|
self._name = name
|
|
19
|
+
self.full_name = None
|
|
19
20
|
self._value = value
|
|
21
|
+
self.desc = None
|
|
20
22
|
|
|
21
23
|
@property
|
|
22
24
|
def name(self) -> str:
|
|
@@ -40,7 +42,12 @@ class Widget:
|
|
|
40
42
|
def schema_definition(self) -> dict:
|
|
41
43
|
"""Json schema definition of the widget."""
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
result = {}
|
|
46
|
+
|
|
47
|
+
if self.desc is not None:
|
|
48
|
+
result["description"] = self.desc
|
|
49
|
+
|
|
50
|
+
return result
|
|
44
51
|
|
|
45
52
|
@property
|
|
46
53
|
def sample_value(self) -> Any:
|
|
@@ -31,7 +31,7 @@ class Checkbox(Widget):
|
|
|
31
31
|
def schema_definition(self) -> dict:
|
|
32
32
|
"""Json schema definition of the checkbox."""
|
|
33
33
|
|
|
34
|
-
return {"type": "boolean"}
|
|
34
|
+
return {"type": "boolean", **super().schema_definition}
|
|
35
35
|
|
|
36
36
|
@property
|
|
37
37
|
def sample_value(self) -> Union[bool, int]:
|
|
@@ -17,12 +17,17 @@ class Dropdown(Widget):
|
|
|
17
17
|
super().__init__(name, value)
|
|
18
18
|
|
|
19
19
|
self.choices = []
|
|
20
|
+
self.desc = None
|
|
20
21
|
|
|
21
22
|
@property
|
|
22
23
|
def schema_definition(self) -> dict:
|
|
23
24
|
"""Json schema definition of the dropdown."""
|
|
24
25
|
|
|
25
|
-
return {
|
|
26
|
+
return {
|
|
27
|
+
"type": "integer",
|
|
28
|
+
"maximum": len(self.choices) - 1,
|
|
29
|
+
**super().schema_definition,
|
|
30
|
+
}
|
|
26
31
|
|
|
27
32
|
@property
|
|
28
33
|
def sample_value(self) -> int:
|
|
@@ -22,7 +22,11 @@ class Radio(Checkbox):
|
|
|
22
22
|
def schema_definition(self) -> dict:
|
|
23
23
|
"""Json schema definition of the radiobutton."""
|
|
24
24
|
|
|
25
|
-
return {
|
|
25
|
+
return {
|
|
26
|
+
"maximum": self.number_of_options - 1,
|
|
27
|
+
**super().schema_definition,
|
|
28
|
+
"type": "integer",
|
|
29
|
+
}
|
|
26
30
|
|
|
27
31
|
@property
|
|
28
32
|
def sample_value(self) -> int:
|
|
@@ -5,7 +5,7 @@ from pypdf.generic import (DictionaryObject, NameObject, NumberObject,
|
|
|
5
5
|
TextStringObject)
|
|
6
6
|
|
|
7
7
|
from .constants import (AP, AS, CA, DA, DV, FT, IMAGE_FIELD_IDENTIFIER, JS, MK,
|
|
8
|
-
MULTILINE, READ_ONLY, A, Btn, Ch, Ff, N, Off, Opt,
|
|
8
|
+
MULTILINE, READ_ONLY, TU, A, Btn, Ch, Ff, N, Off, Opt,
|
|
9
9
|
Parent, Q, Sig, T, Tx, V, Yes)
|
|
10
10
|
from .middleware.checkbox import Checkbox
|
|
11
11
|
from .middleware.dropdown import Dropdown
|
|
@@ -68,6 +68,8 @@ WIDGET_KEY_PATTERNS = [
|
|
|
68
68
|
{Parent: {T: True}},
|
|
69
69
|
]
|
|
70
70
|
|
|
71
|
+
WIDGET_DESCRIPTION_PATTERNS = [{TU: True}, {Parent: {TU: True}}]
|
|
72
|
+
|
|
71
73
|
DROPDOWN_CHOICE_PATTERNS = [
|
|
72
74
|
{Opt: True},
|
|
73
75
|
{Parent: {Opt: True}},
|
|
@@ -11,7 +11,7 @@ from pypdf.generic import DictionaryObject
|
|
|
11
11
|
from reportlab.pdfbase.pdfmetrics import stringWidth
|
|
12
12
|
|
|
13
13
|
from .constants import (COMB, DEFAULT_FONT_SIZE, MULTILINE, NEW_LINE_SYMBOL,
|
|
14
|
-
WIDGET_TYPES, Annots, MaxLen, Rect)
|
|
14
|
+
WIDGET_TYPES, Annots, MaxLen, Parent, Rect, T)
|
|
15
15
|
from .font import (adjust_paragraph_font_size, adjust_text_field_font_size,
|
|
16
16
|
auto_detect_font, get_text_field_font_color,
|
|
17
17
|
get_text_field_font_size, text_field_font_size)
|
|
@@ -21,8 +21,8 @@ from .middleware.radio import Radio
|
|
|
21
21
|
from .middleware.text import Text
|
|
22
22
|
from .patterns import (BUTTON_STYLE_PATTERNS, DROPDOWN_CHOICE_PATTERNS,
|
|
23
23
|
TEXT_FIELD_FLAG_PATTERNS, WIDGET_ALIGNMENT_PATTERNS,
|
|
24
|
-
|
|
25
|
-
update_annotation_name)
|
|
24
|
+
WIDGET_DESCRIPTION_PATTERNS, WIDGET_KEY_PATTERNS,
|
|
25
|
+
WIDGET_TYPE_PATTERNS, update_annotation_name)
|
|
26
26
|
from .utils import find_pattern_match, stream_to_io, traverse_pattern
|
|
27
27
|
from .watermark import create_watermarks_and_draw
|
|
28
28
|
|
|
@@ -43,7 +43,9 @@ def set_character_x_paddings(
|
|
|
43
43
|
return widgets
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def build_widgets(
|
|
46
|
+
def build_widgets(
|
|
47
|
+
pdf_stream: bytes, use_full_widget_name: bool
|
|
48
|
+
) -> Dict[str, WIDGET_TYPES]:
|
|
47
49
|
"""Builds a widget dict given a PDF form stream."""
|
|
48
50
|
|
|
49
51
|
results = {}
|
|
@@ -51,10 +53,10 @@ def build_widgets(pdf_stream: bytes) -> Dict[str, WIDGET_TYPES]:
|
|
|
51
53
|
for widgets in get_widgets_by_page(pdf_stream).values():
|
|
52
54
|
for widget in widgets:
|
|
53
55
|
key = get_widget_key(widget)
|
|
54
|
-
|
|
55
56
|
_widget = construct_widget(widget, key)
|
|
56
|
-
|
|
57
57
|
if _widget is not None:
|
|
58
|
+
_widget.full_name = get_widget_full_key(widget)
|
|
59
|
+
_widget.desc = get_widget_description(widget)
|
|
58
60
|
if isinstance(_widget, Text):
|
|
59
61
|
_widget.max_length = get_text_field_max_length(widget)
|
|
60
62
|
if _widget.max_length is not None and is_text_field_comb(widget):
|
|
@@ -74,7 +76,8 @@ def build_widgets(pdf_stream: bytes) -> Dict[str, WIDGET_TYPES]:
|
|
|
74
76
|
continue
|
|
75
77
|
|
|
76
78
|
results[key] = _widget
|
|
77
|
-
|
|
79
|
+
if _widget.full_name is not None and use_full_widget_name:
|
|
80
|
+
results[_widget.full_name] = results[key]
|
|
78
81
|
return results
|
|
79
82
|
|
|
80
83
|
|
|
@@ -192,6 +195,24 @@ def get_widget_key(widget: dict) -> Union[str, list, None]:
|
|
|
192
195
|
return result
|
|
193
196
|
|
|
194
197
|
|
|
198
|
+
def get_widget_full_key(widget: dict) -> Union[str, None]:
|
|
199
|
+
"""
|
|
200
|
+
Returns a PDF widget's full annotated key by prepending its
|
|
201
|
+
parent widget's key.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
key = get_widget_key(widget)
|
|
205
|
+
|
|
206
|
+
if (
|
|
207
|
+
Parent in widget
|
|
208
|
+
and T in widget[Parent].get_object()
|
|
209
|
+
and widget[Parent][T] != key
|
|
210
|
+
):
|
|
211
|
+
return f"{widget[Parent][T]}.{key}"
|
|
212
|
+
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
|
|
195
216
|
def get_widget_alignment(widget: dict) -> Union[str, list, None]:
|
|
196
217
|
"""Finds a PDF widget's alignment by pattern matching."""
|
|
197
218
|
|
|
@@ -225,6 +246,18 @@ def get_text_field_max_length(widget: dict) -> Union[int, None]:
|
|
|
225
246
|
return int(widget[MaxLen]) or None if MaxLen in widget else None
|
|
226
247
|
|
|
227
248
|
|
|
249
|
+
def get_widget_description(widget: dict) -> Union[str, None]:
|
|
250
|
+
"""Returns the description of the widget if presented or None."""
|
|
251
|
+
|
|
252
|
+
result = None
|
|
253
|
+
for pattern in WIDGET_DESCRIPTION_PATTERNS:
|
|
254
|
+
value = traverse_pattern(pattern, widget)
|
|
255
|
+
if value:
|
|
256
|
+
result = str(value)
|
|
257
|
+
break
|
|
258
|
+
return result
|
|
259
|
+
|
|
260
|
+
|
|
228
261
|
def check_field_flag_bit(widget: dict, bit: int) -> bool:
|
|
229
262
|
"""Checks if a bit is set in a widget's field flag."""
|
|
230
263
|
|
|
@@ -408,39 +441,41 @@ def get_paragraph_auto_wrap_length(widget_middleware: Text) -> int:
|
|
|
408
441
|
return result
|
|
409
442
|
|
|
410
443
|
|
|
411
|
-
def
|
|
444
|
+
def update_widget_keys(
|
|
412
445
|
template: bytes,
|
|
413
446
|
widgets: Dict[str, WIDGET_TYPES],
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
447
|
+
old_keys: List[str],
|
|
448
|
+
new_keys: List[str],
|
|
449
|
+
indices: List[int],
|
|
417
450
|
) -> bytes:
|
|
418
|
-
"""Updates
|
|
451
|
+
"""Updates a list of keys of widgets."""
|
|
419
452
|
# pylint: disable=R0801
|
|
420
453
|
|
|
421
454
|
pdf = PdfReader(stream_to_io(template))
|
|
422
455
|
out = PdfWriter()
|
|
423
456
|
out.append(pdf)
|
|
424
457
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
458
|
+
for i, old_key in enumerate(old_keys):
|
|
459
|
+
index = indices[i]
|
|
460
|
+
new_key = new_keys[i]
|
|
461
|
+
tracker = -1
|
|
462
|
+
for page in out.pages:
|
|
463
|
+
for annot in page.get(Annots, []): # noqa
|
|
464
|
+
annot = cast(DictionaryObject, annot.get_object())
|
|
465
|
+
key = get_widget_key(annot.get_object())
|
|
466
|
+
|
|
467
|
+
widget = widgets.get(key)
|
|
468
|
+
if widget is None:
|
|
469
|
+
continue
|
|
435
470
|
|
|
436
|
-
|
|
437
|
-
|
|
471
|
+
if old_key != key:
|
|
472
|
+
continue
|
|
438
473
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
474
|
+
tracker += 1
|
|
475
|
+
if not isinstance(widget, Radio) and tracker != index:
|
|
476
|
+
continue
|
|
442
477
|
|
|
443
|
-
|
|
478
|
+
update_annotation_name(annot, new_key)
|
|
444
479
|
|
|
445
480
|
with BytesIO() as f:
|
|
446
481
|
out.write(f)
|
|
@@ -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
|
-
|
|
21
|
+
update_widget_keys, 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
|
|
@@ -52,7 +52,7 @@ class FormWrapper:
|
|
|
52
52
|
) -> FormWrapper:
|
|
53
53
|
"""Fills a PDF form."""
|
|
54
54
|
|
|
55
|
-
widgets = build_widgets(self.stream) if self.stream else {}
|
|
55
|
+
widgets = build_widgets(self.stream, False) if self.stream else {}
|
|
56
56
|
|
|
57
57
|
for key, value in data.items():
|
|
58
58
|
if key in widgets:
|
|
@@ -79,17 +79,39 @@ class PdfWrapper(FormWrapper):
|
|
|
79
79
|
"""Constructs all attributes for the object."""
|
|
80
80
|
|
|
81
81
|
super().__init__(template)
|
|
82
|
-
self.widgets =
|
|
82
|
+
self.widgets = {}
|
|
83
|
+
self._keys_to_update = []
|
|
83
84
|
|
|
84
85
|
self.global_font = kwargs.get("global_font")
|
|
85
86
|
self.global_font_size = kwargs.get("global_font_size")
|
|
86
87
|
self.global_font_color = kwargs.get("global_font_color")
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
self.use_full_widget_name = kwargs.get("use_full_widget_name", False)
|
|
90
|
+
|
|
91
|
+
self._init_helper()
|
|
92
|
+
|
|
93
|
+
def _init_helper(self, key_to_refresh: str = None) -> None:
|
|
94
|
+
"""Updates all attributes when the state of the PDF stream changes."""
|
|
95
|
+
|
|
96
|
+
refresh_not_needed = {}
|
|
97
|
+
new_widgets = (
|
|
98
|
+
build_widgets(self.read(), self.use_full_widget_name) if self.read() else {}
|
|
99
|
+
)
|
|
100
|
+
for k, v in self.widgets.items():
|
|
101
|
+
if k in new_widgets:
|
|
102
|
+
new_widgets[k] = v
|
|
103
|
+
refresh_not_needed[k] = True
|
|
104
|
+
self.widgets = new_widgets
|
|
105
|
+
|
|
106
|
+
for key, value in self.widgets.items():
|
|
107
|
+
if (key_to_refresh and key == key_to_refresh) or (
|
|
108
|
+
key_to_refresh is None
|
|
109
|
+
and isinstance(value, Text)
|
|
110
|
+
and not refresh_not_needed.get(key)
|
|
111
|
+
):
|
|
112
|
+
value.font = self.global_font
|
|
113
|
+
value.font_size = self.global_font_size
|
|
114
|
+
value.font_color = self.global_font_color
|
|
93
115
|
|
|
94
116
|
@property
|
|
95
117
|
def sample_data(self) -> dict:
|
|
@@ -223,31 +245,48 @@ class PdfWrapper(FormWrapper):
|
|
|
223
245
|
self.stream, name, obj.non_acro_form_params
|
|
224
246
|
)
|
|
225
247
|
|
|
226
|
-
|
|
227
|
-
for k, v in self.widgets.items():
|
|
228
|
-
if k in new_widgets:
|
|
229
|
-
new_widgets[k] = v
|
|
230
|
-
self.widgets = new_widgets
|
|
248
|
+
key_to_refresh = ""
|
|
231
249
|
if widget_type in ("text", "dropdown"):
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
250
|
+
key_to_refresh = name
|
|
251
|
+
|
|
252
|
+
self._init_helper(key_to_refresh)
|
|
235
253
|
|
|
236
254
|
return self
|
|
237
255
|
|
|
238
256
|
def update_widget_key(
|
|
239
|
-
self, old_key: str, new_key: str, index: int = 0
|
|
257
|
+
self, old_key: str, new_key: str, index: int = 0, defer: bool = False
|
|
240
258
|
) -> PdfWrapper:
|
|
241
259
|
"""Updates the key of an existed widget on a PDF form."""
|
|
242
260
|
|
|
243
|
-
self.
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
261
|
+
if self.use_full_widget_name:
|
|
262
|
+
raise NotImplementedError
|
|
263
|
+
|
|
264
|
+
if defer:
|
|
265
|
+
self._keys_to_update.append((old_key, new_key, index))
|
|
266
|
+
return self
|
|
267
|
+
|
|
268
|
+
self.stream = update_widget_keys(
|
|
269
|
+
self.read(), self.widgets, [old_key], [new_key], [index]
|
|
270
|
+
)
|
|
271
|
+
self._init_helper()
|
|
272
|
+
|
|
273
|
+
return self
|
|
274
|
+
|
|
275
|
+
def commit_widget_key_updates(self) -> PdfWrapper:
|
|
276
|
+
"""Commits all deferred widget key updates on a PDF form."""
|
|
277
|
+
|
|
278
|
+
if self.use_full_widget_name:
|
|
279
|
+
raise NotImplementedError
|
|
280
|
+
|
|
281
|
+
old_keys = [each[0] for each in self._keys_to_update]
|
|
282
|
+
new_keys = [each[1] for each in self._keys_to_update]
|
|
283
|
+
indices = [each[2] for each in self._keys_to_update]
|
|
284
|
+
|
|
285
|
+
self.stream = update_widget_keys(
|
|
286
|
+
self.read(), self.widgets, old_keys, new_keys, indices
|
|
250
287
|
)
|
|
288
|
+
self._init_helper()
|
|
289
|
+
self._keys_to_update = []
|
|
251
290
|
|
|
252
291
|
return self
|
|
253
292
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: PyPDFForm
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: The Python library for PDF forms.
|
|
5
5
|
Home-page: https://github.com/chinapandaman/PyPDFForm
|
|
6
6
|
Author: Jinge Li
|
|
@@ -24,6 +24,14 @@ Requires-Dist: cryptography
|
|
|
24
24
|
Requires-Dist: pillow
|
|
25
25
|
Requires-Dist: pypdf
|
|
26
26
|
Requires-Dist: reportlab
|
|
27
|
+
Dynamic: author
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: requires-dist
|
|
33
|
+
Dynamic: requires-python
|
|
34
|
+
Dynamic: summary
|
|
27
35
|
|
|
28
36
|
<p align="center"><img src="https://github.com/chinapandaman/PyPDFForm/raw/master/logo.png"></p>
|
|
29
37
|
<p align="center">
|
|
@@ -10,11 +10,7 @@ from PyPDFForm.middleware.text import Text
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def test_base_schema_definition():
|
|
13
|
-
|
|
14
|
-
assert Widget("foo").schema_definition
|
|
15
|
-
raise AssertionError
|
|
16
|
-
except NotImplementedError:
|
|
17
|
-
pass
|
|
13
|
+
assert Widget("foo").schema_definition == {}
|
|
18
14
|
|
|
19
15
|
|
|
20
16
|
def test_fill(template_stream, pdf_samples, data_dict, request):
|
|
@@ -635,7 +631,7 @@ def test_update_radio_key(template_with_radiobutton_stream, pdf_samples, request
|
|
|
635
631
|
obj.update_widget_key("radio_3", "RADIO")
|
|
636
632
|
|
|
637
633
|
request.config.results["expected_path"] = expected_path
|
|
638
|
-
request.config.results["stream"] = obj.
|
|
634
|
+
request.config.results["stream"] = obj.preview
|
|
639
635
|
|
|
640
636
|
expected = f.read()
|
|
641
637
|
|
|
@@ -653,7 +649,7 @@ def test_update_sejda_key(sejda_template, pdf_samples, request):
|
|
|
653
649
|
obj.update_widget_key("buyer_signed_date", "BUYER_SIGNED_DATE")
|
|
654
650
|
|
|
655
651
|
request.config.results["expected_path"] = expected_path
|
|
656
|
-
request.config.results["stream"] = obj.
|
|
652
|
+
request.config.results["stream"] = obj.preview
|
|
657
653
|
|
|
658
654
|
expected = f.read()
|
|
659
655
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from PyPDFForm import PdfWrapper
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_init(sample_template_with_full_key):
|
|
9
|
+
obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
|
|
10
|
+
assert "Gain de 2 classes.0" in obj.widgets
|
|
11
|
+
assert obj.widgets["Gain de 2 classes.0"] is obj.widgets["0"]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_sample_data(sample_template_with_full_key):
|
|
15
|
+
obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
|
|
16
|
+
assert "Gain de 2 classes.0" in obj.sample_data
|
|
17
|
+
assert obj.sample_data["Gain de 2 classes.0"] == obj.sample_data["0"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_fill(sample_template_with_full_key):
|
|
21
|
+
obj_1 = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
|
|
22
|
+
obj_2 = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
|
|
23
|
+
|
|
24
|
+
assert (
|
|
25
|
+
obj_1.fill({"Gain de 2 classes.0": True}).read()
|
|
26
|
+
== obj_2.fill({"0": True}).read()
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_update_widget_key(sample_template_with_full_key):
|
|
31
|
+
obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
|
|
32
|
+
|
|
33
|
+
with pytest.raises(NotImplementedError):
|
|
34
|
+
obj.update_widget_key("0", "foo")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_commit_widget_key_updates(sample_template_with_full_key):
|
|
38
|
+
obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
|
|
39
|
+
|
|
40
|
+
with pytest.raises(NotImplementedError):
|
|
41
|
+
obj.commit_widget_key_updates()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_schema(sample_template_with_full_key):
|
|
45
|
+
obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
|
|
46
|
+
assert "Gain de 2 classes.0" in obj.schema["properties"]
|
|
47
|
+
assert (
|
|
48
|
+
obj.schema["properties"]["Gain de 2 classes.0"] == obj.schema["properties"]["0"]
|
|
49
|
+
)
|
|
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
|