PyPDFForm 3.1.0__py3-none-any.whl → 3.1.2__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 PyPDFForm might be problematic. Click here for more details.

PyPDFForm/__init__.py CHANGED
@@ -20,7 +20,7 @@ The library supports various PDF form features, including:
20
20
  PyPDFForm aims to simplify PDF form manipulation, making it accessible to developers of all skill levels.
21
21
  """
22
22
 
23
- __version__ = "3.1.0"
23
+ __version__ = "3.1.2"
24
24
 
25
25
  from .middleware.text import Text # exposing for setting global font attrs
26
26
  from .wrapper import PdfWrapper
PyPDFForm/constants.py CHANGED
@@ -105,3 +105,5 @@ IMAGE_FIELD_IDENTIFIER = "event.target.buttonImportIcon();"
105
105
 
106
106
  COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO = DEFAULT_FONT_SIZE / 100
107
107
  UNIQUE_SUFFIX_LENGTH = 20
108
+
109
+ SLASH = "/"
PyPDFForm/patterns.py CHANGED
@@ -8,11 +8,13 @@ properties in the PDF's annotation dictionary. It also provides utility function
8
8
  for updating these widgets.
9
9
  """
10
10
 
11
+ from typing import Union
12
+
11
13
  from pypdf.generic import (ArrayObject, DictionaryObject, NameObject,
12
14
  NumberObject, TextStringObject)
13
15
 
14
- from .constants import (AP, AS, DV, FT, IMAGE_FIELD_IDENTIFIER, JS, TU, A, Btn,
15
- Ch, I, N, Off, Opt, Parent, Sig, T, Tx, V, Yes)
16
+ from .constants import (AP, AS, DV, FT, IMAGE_FIELD_IDENTIFIER, JS, SLASH, TU,
17
+ A, Btn, Ch, I, N, Off, Opt, Parent, Sig, T, Tx, V, Yes)
16
18
  from .middleware.checkbox import Checkbox
17
19
  from .middleware.dropdown import Dropdown
18
20
  from .middleware.image import Image
@@ -42,7 +44,7 @@ WIDGET_TYPE_PATTERNS = [
42
44
  (
43
45
  {FT: Btn},
44
46
  {Parent: {FT: Btn}},
45
- {AS: (Yes, Off)},
47
+ {AS: (Yes, Off, SLASH)},
46
48
  ),
47
49
  Radio,
48
50
  ),
@@ -76,7 +78,7 @@ WIDGET_TYPE_PATTERNS = [
76
78
  (
77
79
  (
78
80
  {Parent: {FT: Btn}},
79
- {AS: (Yes, Off)},
81
+ {AS: (Yes, Off, SLASH)},
80
82
  ),
81
83
  Radio,
82
84
  ),
@@ -113,6 +115,23 @@ def update_checkbox_value(annot: DictionaryObject, check: bool = False) -> None:
113
115
  break
114
116
 
115
117
 
118
+ def get_checkbox_value(annot: DictionaryObject) -> Union[bool, None]:
119
+ """
120
+ Retrieves the boolean value of a checkbox annotation.
121
+
122
+ This function checks the value (V) of the checkbox annotation. If the value
123
+ is not 'Off', it means the checkbox is checked, and True is returned.
124
+ Otherwise, if the value is 'Off' or not present, None is returned.
125
+
126
+ Args:
127
+ annot (DictionaryObject): The checkbox annotation dictionary.
128
+
129
+ Returns:
130
+ Union[bool, None]: True if the checkbox is checked, None otherwise.
131
+ """
132
+ return True if annot.get(V, Off) != Off else None
133
+
134
+
116
135
  def update_radio_value(annot: DictionaryObject) -> None:
117
136
  """
118
137
  Updates the value of a radio button annotation, selecting it.
@@ -133,6 +152,28 @@ def update_radio_value(annot: DictionaryObject) -> None:
133
152
  break
134
153
 
135
154
 
155
+ def get_radio_value(annot: DictionaryObject) -> bool:
156
+ """
157
+ Retrieves the boolean value of a radio button annotation.
158
+
159
+ This function iterates through the appearance states (AP) of the radio button
160
+ annotation. If the value (V) of the parent dictionary matches any of these
161
+ appearance states, it means the radio button is selected, and True is returned.
162
+ Otherwise, False is returned.
163
+
164
+ Args:
165
+ annot (DictionaryObject): The radio button annotation dictionary.
166
+
167
+ Returns:
168
+ bool: True if the radio button is selected, False otherwise.
169
+ """
170
+ for each in annot.get(AP, {}).get(N, []):
171
+ if annot.get(Parent, {}).get(V) == each:
172
+ return True
173
+
174
+ return False
175
+
176
+
136
177
  def update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
137
178
  """
138
179
  Updates the value of a dropdown annotation, selecting an option from the list.
@@ -157,6 +198,29 @@ def update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
157
198
  annot[NameObject(I)] = ArrayObject([NumberObject(widget.value)])
158
199
 
159
200
 
201
+ def get_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
202
+ """
203
+ Retrieves the selected value of a dropdown annotation and updates the widget.
204
+
205
+ This function determines the current value of the dropdown, considering
206
+ whether it's a child annotation or a top-level one. It then iterates
207
+ through the widget's choices to find a match and sets the widget's
208
+ value to the index of the matched choice.
209
+
210
+ Args:
211
+ annot (DictionaryObject): The dropdown annotation dictionary.
212
+ widget (Dropdown): The Dropdown widget object to update with the retrieved value.
213
+ """
214
+ if Parent in annot and T not in annot:
215
+ to_compare = annot.get(Parent, {}).get(V)
216
+ else:
217
+ to_compare = annot.get(V)
218
+
219
+ for i, each in enumerate(widget.choices):
220
+ if each == to_compare:
221
+ widget.value = i or None # set None when 0
222
+
223
+
160
224
  def update_text_value(annot: DictionaryObject, widget: Text) -> None:
161
225
  """
162
226
  Updates the value of a text annotation, setting the text content.
@@ -176,6 +240,24 @@ def update_text_value(annot: DictionaryObject, widget: Text) -> None:
176
240
  annot[NameObject(AP)] = TextStringObject(widget.value)
177
241
 
178
242
 
243
+ def get_text_value(annot: DictionaryObject, widget: Text) -> None:
244
+ """
245
+ Retrieves the text value of a text annotation and updates the widget.
246
+
247
+ This function determines the current text value of the annotation, considering
248
+ whether it's a child annotation or a top-level one, and then sets the
249
+ widget's value accordingly.
250
+
251
+ Args:
252
+ annot (DictionaryObject): The text annotation dictionary.
253
+ widget (Text): The Text widget object to update with the retrieved value.
254
+ """
255
+ if Parent in annot and T not in annot:
256
+ widget.value = annot[Parent].get(V)
257
+ else:
258
+ widget.value = annot.get(V)
259
+
260
+
179
261
  def update_annotation_name(annot: DictionaryObject, val: str) -> None:
180
262
  """
181
263
  Updates the name of an annotation, setting the T (title) entry.
PyPDFForm/template.py CHANGED
@@ -16,12 +16,14 @@ from pypdf import PdfReader, PdfWriter
16
16
  from pypdf.generic import DictionaryObject
17
17
 
18
18
  from .constants import WIDGET_TYPES, Annots, MaxLen, Parent, T
19
+ from .middleware.checkbox import Checkbox
19
20
  from .middleware.dropdown import Dropdown
20
21
  from .middleware.radio import Radio
21
22
  from .middleware.text import Text
22
23
  from .patterns import (DROPDOWN_CHOICE_PATTERNS, WIDGET_DESCRIPTION_PATTERNS,
23
24
  WIDGET_KEY_PATTERNS, WIDGET_TYPE_PATTERNS,
24
- update_annotation_name)
25
+ get_checkbox_value, get_dropdown_value, get_radio_value,
26
+ get_text_value, update_annotation_name)
25
27
  from .utils import extract_widget_property, find_pattern_match, stream_to_io
26
28
 
27
29
 
@@ -61,11 +63,16 @@ def build_widgets(
61
63
  if isinstance(_widget, Text):
62
64
  # mostly for schema for now
63
65
  _widget.max_length = get_text_field_max_length(widget)
66
+ get_text_value(widget, _widget)
67
+
68
+ if type(_widget) is Checkbox:
69
+ _widget.value = get_checkbox_value(widget)
64
70
 
65
71
  if isinstance(_widget, Dropdown):
66
72
  # actually used for filling value
67
73
  # doesn't trigger hook
68
74
  _widget.__dict__["choices"] = get_dropdown_choices(widget)
75
+ get_dropdown_value(widget, _widget)
69
76
 
70
77
  if isinstance(_widget, Radio):
71
78
  if key not in results:
@@ -73,6 +80,9 @@ def build_widgets(
73
80
 
74
81
  # for schema
75
82
  results[key].number_of_options += 1
83
+
84
+ if get_radio_value(widget):
85
+ results[key].value = results[key].number_of_options - 1
76
86
  continue
77
87
 
78
88
  results[key] = _widget
PyPDFForm/utils.py CHANGED
@@ -23,7 +23,7 @@ from typing import Any, BinaryIO, List, Union
23
23
  from pypdf import PdfReader, PdfWriter
24
24
  from pypdf.generic import ArrayObject, DictionaryObject, NameObject
25
25
 
26
- from .constants import UNIQUE_SUFFIX_LENGTH, XFA, AcroForm, Annots, Root
26
+ from .constants import SLASH, UNIQUE_SUFFIX_LENGTH, XFA, AcroForm, Annots, Root
27
27
 
28
28
 
29
29
  @lru_cache
@@ -220,6 +220,8 @@ def find_pattern_match(pattern: dict, widget: Union[dict, DictionaryObject]) ->
220
220
  else:
221
221
  if isinstance(pattern[key], tuple):
222
222
  result = value in pattern[key]
223
+ if not result and SLASH in pattern[key] and value.startswith(SLASH):
224
+ result = True
223
225
  else:
224
226
  result = pattern[key] == value
225
227
  if result:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 3.1.0
3
+ Version: 3.1.2
4
4
  Summary: The Python library for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -1,14 +1,14 @@
1
- PyPDFForm/__init__.py,sha256=R4BorFo4mdXpjdpfUiO6kvJpowukDOHSiRpfHBV2jYs,925
1
+ PyPDFForm/__init__.py,sha256=6b0B0-Gyc70MQiyWMVmuvBagVeL07jurO3U1j3TQdNs,925
2
2
  PyPDFForm/adapter.py,sha256=8E_PZlXU1ALWez_pWF_U52cynzowK_NQFYzMJoH9VUk,2428
3
- PyPDFForm/constants.py,sha256=WQjBvYTryj5gxxeXECPgHplXXXmqHNeVbgmhvlLDCpA,2443
3
+ PyPDFForm/constants.py,sha256=LW_YGzzirel8hxoqWylzo-eE1KvofKWG_p7SGd4ovpA,2456
4
4
  PyPDFForm/coordinate.py,sha256=VMVkqa-VAGJSGVvetZwOxeMzIgQtQdvtn_DI_qSecCE,3876
5
5
  PyPDFForm/filler.py,sha256=KwStL6YzrNBcDd919ig83MnAxopi8Vnz3QNJzN_CjNM,7272
6
6
  PyPDFForm/font.py,sha256=EZSAHnkzaBo96p9XJrQDMcEhjh5BZ8p7WwFC3SbKRMM,8828
7
7
  PyPDFForm/hooks.py,sha256=A8p67ubWvCvzRt346Q7BjOvbi4_NXBcynXmq6fJTadY,11679
8
8
  PyPDFForm/image.py,sha256=CAC69jEfSbWbyNJcjLhjWVSNJuFh7frMI70eaiFayHw,3823
9
- PyPDFForm/patterns.py,sha256=xuKAqGf07f3WFXwASnrmcS073pSEcR9lQMqLppjkQ2E,5829
10
- PyPDFForm/template.py,sha256=aGhwezcynmwCEck1SUNlQvgfupn-plV9mV2FF2RNn_M,9188
11
- PyPDFForm/utils.py,sha256=RX2mOP2uCIcN_JcTalCdYKhnYtyYc8dUIqg1wP_7MJA,10867
9
+ PyPDFForm/patterns.py,sha256=RiQKqsOMrB9u4KWj5Kv6GUmcuGI77xMvdOcOcHy_9qE,8717
10
+ PyPDFForm/template.py,sha256=lKkja_8Sx6vun1tOklSpdNT1pdelhfVl10kX-G4sLlA,9673
11
+ PyPDFForm/utils.py,sha256=hLSVUG6qnE0iTMB-yPNQQIhmm3R69X7fcnbCTDvSUQs,11001
12
12
  PyPDFForm/watermark.py,sha256=9p1tjaIqicXngTNai_iOEkCoXRYnR66azB4s7wNsZUw,9349
13
13
  PyPDFForm/wrapper.py,sha256=Ysd1mkvE5OfDkjUI6mNFIt16-JUKwj2ifbp1MioWPUo,25257
14
14
  PyPDFForm/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -28,8 +28,8 @@ PyPDFForm/widgets/image.py,sha256=aSD-3MEZFIRL7HYVuO6Os8irfSUOLHA_rHGkqcEIPPA,85
28
28
  PyPDFForm/widgets/radio.py,sha256=nWSQQp06kRISO7Q7FVFeB3PXYvMOSc0SMhRs1bHTxeQ,2261
29
29
  PyPDFForm/widgets/signature.py,sha256=EqIRIuKSQEg8LJZ_Mu859eEvs0dwO-mzkMNuhHG1Vsg,4034
30
30
  PyPDFForm/widgets/text.py,sha256=gtheE6_w0vQPRJJ9oj_l9FaMDEGnPtvVR6_axsrmxKI,1540
31
- pypdfform-3.1.0.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
32
- pypdfform-3.1.0.dist-info/METADATA,sha256=-vHzFtOdPxAwCjPm98xvD424mC3Yc0KttyMir2HvPjE,4587
33
- pypdfform-3.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
- pypdfform-3.1.0.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
35
- pypdfform-3.1.0.dist-info/RECORD,,
31
+ pypdfform-3.1.2.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
32
+ pypdfform-3.1.2.dist-info/METADATA,sha256=mDwVIYsMYDjn2mGkdAt0a6SVEwhxZqOzgh_cIVQc8RE,4587
33
+ pypdfform-3.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ pypdfform-3.1.2.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
35
+ pypdfform-3.1.2.dist-info/RECORD,,