PyPDFForm 2.2.7__py3-none-any.whl → 2.3.1__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
@@ -5,7 +5,7 @@ This package provides tools for filling PDF forms, drawing text and images,
5
5
  and manipulating PDF form elements programmatically.
6
6
  """
7
7
 
8
- __version__ = "2.2.7"
8
+ __version__ = "2.3.1"
9
9
 
10
10
  from .wrapper import FormWrapper, PdfWrapper
11
11
 
PyPDFForm/filler.py CHANGED
@@ -333,10 +333,8 @@ def enable_adobe_mode(reader: PdfReader, writer: PdfWriter, adobe_mode: bool) ->
333
333
  writer.root_object.update(
334
334
  {NameObject(AcroForm): IndirectObject(len(writer.root_object), 0, writer)}
335
335
  )
336
- writer.root_object[AcroForm][NameObject(NeedAppearances)] = BooleanObject( # noqa
337
- True
338
- )
339
- writer.root_object[AcroForm][NameObject(Fields)] = ArrayObject() # noqa
336
+ writer.root_object[AcroForm][NameObject(NeedAppearances)] = BooleanObject(True)
337
+ writer.root_object[AcroForm][NameObject(Fields)] = ArrayObject()
340
338
 
341
339
 
342
340
  def simple_fill(
@@ -370,7 +368,7 @@ def simple_fill(
370
368
  radio_button_tracker = {}
371
369
 
372
370
  for page in out.pages:
373
- for annot in page.get(Annots, []): # noqa
371
+ for annot in page.get(Annots, []):
374
372
  annot = cast(DictionaryObject, annot.get_object())
375
373
  key = extract_widget_property(
376
374
  annot.get_object(), WIDGET_KEY_PATTERNS, None, str
PyPDFForm/patterns.py CHANGED
@@ -149,7 +149,7 @@ def simple_update_checkbox_value(annot: DictionaryObject, check: bool = False) -
149
149
  check: Whether the checkbox should be checked (True) or unchecked (False)
150
150
  """
151
151
 
152
- for each in annot[AP][N]: # noqa
152
+ for each in annot[AP][N]:
153
153
  if (check and str(each) != Off) or (not check and str(each) == Off):
154
154
  annot[NameObject(AS)] = NameObject(each)
155
155
  annot[NameObject(V)] = NameObject(each)
@@ -169,12 +169,12 @@ def simple_update_radio_value(annot: DictionaryObject) -> None:
169
169
  """
170
170
 
171
171
  if Opt in annot[Parent]:
172
- del annot[Parent][Opt] # noqa
172
+ del annot[Parent][Opt]
173
173
 
174
- for each in annot[AP][N]: # noqa
174
+ for each in annot[AP][N]:
175
175
  if str(each) != Off:
176
176
  annot[NameObject(AS)] = NameObject(each)
177
- annot[NameObject(Parent)][NameObject(V)] = NameObject(each) # noqa
177
+ annot[NameObject(Parent)][NameObject(V)] = NameObject(each)
178
178
  break
179
179
 
180
180
 
@@ -191,7 +191,7 @@ def simple_update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> N
191
191
  """
192
192
 
193
193
  if Parent in annot and T not in annot:
194
- annot[NameObject(Parent)][NameObject(V)] = TextStringObject( # noqa
194
+ annot[NameObject(Parent)][NameObject(V)] = TextStringObject(
195
195
  widget.choices[widget.value]
196
196
  )
197
197
  annot[NameObject(AP)] = TextStringObject(widget.choices[widget.value])
@@ -214,9 +214,7 @@ def simple_update_text_value(annot: DictionaryObject, widget: Text) -> None:
214
214
  """
215
215
 
216
216
  if Parent in annot and T not in annot:
217
- annot[NameObject(Parent)][NameObject(V)] = TextStringObject( # noqa
218
- widget.value
219
- )
217
+ annot[NameObject(Parent)][NameObject(V)] = TextStringObject(widget.value)
220
218
  annot[NameObject(AP)] = TextStringObject(widget.value)
221
219
  else:
222
220
  annot[NameObject(V)] = TextStringObject(widget.value)
@@ -234,8 +232,8 @@ def simple_flatten_radio(annot: DictionaryObject) -> None:
234
232
  annot: PDF radio button annotation dictionary to flatten
235
233
  """
236
234
 
237
- annot[NameObject(Parent)][NameObject(Ff)] = NumberObject( # noqa
238
- int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY # noqa
235
+ annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
236
+ int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY
239
237
  )
240
238
 
241
239
 
@@ -251,12 +249,12 @@ def simple_flatten_generic(annot: DictionaryObject) -> None:
251
249
  """
252
250
 
253
251
  if Parent in annot and Ff not in annot:
254
- annot[NameObject(Parent)][NameObject(Ff)] = NumberObject( # noqa
255
- int(annot.get(NameObject(Ff), 0)) | READ_ONLY # noqa
252
+ annot[NameObject(Parent)][NameObject(Ff)] = NumberObject(
253
+ int(annot.get(NameObject(Ff), 0)) | READ_ONLY
256
254
  )
257
255
  else:
258
256
  annot[NameObject(Ff)] = NumberObject(
259
- int(annot.get(NameObject(Ff), 0)) | READ_ONLY # noqa
257
+ int(annot.get(NameObject(Ff), 0)) | READ_ONLY
260
258
  )
261
259
 
262
260
 
@@ -272,9 +270,9 @@ def update_annotation_name(annot: DictionaryObject, val: str) -> None:
272
270
  """
273
271
 
274
272
  if Parent in annot and T not in annot:
275
- annot[NameObject(Parent)][NameObject(T)] = TextStringObject(val) # noqa
273
+ annot[NameObject(Parent)][NameObject(T)] = TextStringObject(val)
276
274
  else:
277
- annot[NameObject(T)] = TextStringObject(val) # noqa
275
+ annot[NameObject(T)] = TextStringObject(val)
278
276
 
279
277
 
280
278
  def update_created_text_field_alignment(annot: DictionaryObject, val: int) -> None:
@@ -303,9 +301,7 @@ def update_created_text_field_multiline(annot: DictionaryObject, val: bool) -> N
303
301
  """
304
302
 
305
303
  if val:
306
- annot[NameObject(Ff)] = NumberObject(
307
- int(annot[NameObject(Ff)]) | MULTILINE # noqa
308
- )
304
+ annot[NameObject(Ff)] = NumberObject(int(annot[NameObject(Ff)]) | MULTILINE)
309
305
 
310
306
 
311
307
  NON_ACRO_FORM_PARAM_TO_FUNC = {
PyPDFForm/template.py CHANGED
@@ -39,21 +39,30 @@ from .utils import (extract_widget_property, find_pattern_match, handle_color,
39
39
 
40
40
 
41
41
  def set_character_x_paddings(
42
- pdf_stream: bytes, widgets: Dict[str, WIDGET_TYPES]
42
+ pdf_stream: bytes,
43
+ widgets: Dict[str, WIDGET_TYPES],
44
+ use_full_widget_name: bool,
43
45
  ) -> Dict[str, WIDGET_TYPES]:
44
- """Calculates and sets character spacing for comb text fields.
46
+ """Calculates and sets character spacing for comb text fields in PDF forms.
47
+
48
+ This function processes each widget in the PDF form and calculates the horizontal spacing
49
+ between characters for comb text fields (fixed-width text fields). The spacing is stored
50
+ in the widget's character_paddings property.
45
51
 
46
52
  Args:
47
- pdf_stream: PDF form as bytes
48
- widgets: Dictionary of widget middleware objects
53
+ pdf_stream (bytes): PDF form as bytes
54
+ widgets (Dict[str, WIDGET_TYPES]): Dictionary of widget middleware objects
55
+ use_full_widget_name (bool): Whether to use full widget names including parent names
49
56
 
50
57
  Returns:
51
- Dict[str, WIDGET_TYPES]: Updated widgets with character paddings
58
+ Dict[str, WIDGET_TYPES]: Updated widget dictionary with character paddings set for comb fields
52
59
  """
53
60
 
54
61
  for _widgets in get_widgets_by_page(pdf_stream).values():
55
62
  for widget in _widgets:
56
63
  key = extract_widget_property(widget, WIDGET_KEY_PATTERNS, None, str)
64
+ if use_full_widget_name:
65
+ key = get_widget_full_key(widget)
57
66
  _widget = widgets[key]
58
67
 
59
68
  if isinstance(_widget, Text) and _widget.comb is True:
@@ -166,23 +175,35 @@ def dropdown_to_text(dropdown: Dropdown) -> Text:
166
175
  def update_text_field_attributes(
167
176
  template_stream: bytes,
168
177
  widgets: Dict[str, WIDGET_TYPES],
178
+ use_full_widget_name: bool,
169
179
  ) -> None:
170
- """Updates text field properties based on PDF template settings.
180
+ """Update text field properties in a PDF form template.
171
181
 
172
- Handles:
173
- - Font detection and sizing
174
- - Color properties
175
- - Paragraph wrapping
176
- - Auto font size adjustment
182
+ Processes text field widgets in the template to update their visual attributes including:
183
+ - Font properties (family, size, color)
184
+ - Text alignment and wrapping behavior
185
+ - Auto-sizing of text to fit within field bounds
186
+ - Multi-line text field formatting
177
187
 
178
188
  Args:
179
- template_stream: PDF form as bytes
180
- widgets: Dictionary of widget middleware objects
189
+ template_stream: Raw bytes of the PDF template containing form fields
190
+ widgets: Dictionary mapping field names to widget objects to update
191
+ use_full_widget_name: If True, uses full hierarchical widget names including parent keys.
192
+ When False (default), uses simple field names.
193
+
194
+ Returns:
195
+ None: Modifies widget objects in-place
196
+
197
+ Note:
198
+ This function modifies the widget objects in-place and does not return anything.
199
+ Changes include font properties, text alignment, and auto-wrapping settings.
181
200
  """
182
201
 
183
202
  for _widgets in get_widgets_by_page(template_stream).values():
184
203
  for _widget in _widgets:
185
204
  key = extract_widget_property(_widget, WIDGET_KEY_PATTERNS, None, str)
205
+ if use_full_widget_name:
206
+ key = get_widget_full_key(_widget)
186
207
 
187
208
  if isinstance(widgets[key], Text):
188
209
  should_adjust_font_size = False
@@ -569,7 +590,7 @@ def update_widget_keys(
569
590
  new_key = new_keys[i]
570
591
  tracker = -1
571
592
  for page in out.pages:
572
- for annot in page.get(Annots, []): # noqa
593
+ for annot in page.get(Annots, []):
573
594
  annot = cast(DictionaryObject, annot.get_object())
574
595
  key = extract_widget_property(
575
596
  annot.get_object(), WIDGET_KEY_PATTERNS, None, str
PyPDFForm/watermark.py CHANGED
@@ -380,7 +380,7 @@ def copy_watermark_widgets(
380
380
  watermark_file = PdfReader(stream_to_io(watermark))
381
381
  for j, page in enumerate(watermark_file.pages):
382
382
  widgets_to_copy_pdf[j] = []
383
- for annot in page.get(Annots, []): # noqa
383
+ for annot in page.get(Annots, []):
384
384
  key = extract_widget_property(
385
385
  annot.get_object(), WIDGET_KEY_PATTERNS, None, str
386
386
  )
@@ -393,7 +393,7 @@ def copy_watermark_widgets(
393
393
  for i, page in enumerate(out.pages):
394
394
  if i in widgets_to_copy:
395
395
  page[NameObject(Annots)] = (
396
- (page[NameObject(Annots)] + ArrayObject(widgets_to_copy[i])) # noqa
396
+ (page[NameObject(Annots)] + ArrayObject(widgets_to_copy[i]))
397
397
  if Annots in page
398
398
  else ArrayObject(widgets_to_copy[i])
399
399
  )
PyPDFForm/widgets/base.py CHANGED
@@ -83,7 +83,7 @@ class Widget:
83
83
  )
84
84
  self.acro_form_params[param] = value
85
85
  elif user_input in self.NONE_DEFAULTS:
86
- self.acro_form_params[param] = None # noqa
86
+ self.acro_form_params[param] = None
87
87
 
88
88
  for each in self.ALLOWED_NON_ACRO_FORM_PARAMS:
89
89
  if each in kwargs:
@@ -154,7 +154,7 @@ def handle_non_acro_form_params(pdf: bytes, key: str, params: list) -> bytes:
154
154
  out.append(pdf_file)
155
155
 
156
156
  for page in out.pages:
157
- for annot in page.get(Annots, []): # noqa
157
+ for annot in page.get(Annots, []):
158
158
  annot = cast(DictionaryObject, annot.get_object())
159
159
  _key = extract_widget_property(
160
160
  annot.get_object(), WIDGET_KEY_PATTERNS, None, str
@@ -101,12 +101,12 @@ class SignatureWidget:
101
101
 
102
102
  input_pdf = PdfReader(stream_to_io(stream))
103
103
  page_count = len(input_pdf.pages)
104
- pdf = PdfReader(stream_to_io(BEDROCK_PDF)) # noqa
104
+ pdf = PdfReader(stream_to_io(BEDROCK_PDF))
105
105
  out = PdfWriter()
106
106
  out.append(pdf)
107
107
 
108
108
  for page in out.pages:
109
- for annot in page.get(Annots, []): # noqa
109
+ for annot in page.get(Annots, []):
110
110
  key = extract_widget_property(
111
111
  annot.get_object(), WIDGET_KEY_PATTERNS, None, str
112
112
  )
PyPDFForm/wrapper.py CHANGED
@@ -432,9 +432,13 @@ class PdfWrapper(FormWrapper):
432
432
  if isinstance(value, Dropdown):
433
433
  self.widgets[key] = dropdown_to_text(value)
434
434
 
435
- update_text_field_attributes(self.stream, self.widgets)
435
+ update_text_field_attributes(
436
+ self.stream, self.widgets, getattr(self, "use_full_widget_name")
437
+ )
436
438
  if self.read():
437
- self.widgets = set_character_x_paddings(self.stream, self.widgets)
439
+ self.widgets = set_character_x_paddings(
440
+ self.stream, self.widgets, getattr(self, "use_full_widget_name")
441
+ )
438
442
 
439
443
  self.stream = remove_all_widgets(
440
444
  fill(self.stream, self.widgets, getattr(self, "use_full_widget_name"))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 2.2.7
3
+ Version: 2.3.1
4
4
  Summary: The Python library for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -49,15 +49,6 @@ Dynamic: license-file
49
49
  <a href="https://pypistats.org/packages/pypdfform"><img src="https://img.shields.io/pypi/dm/pypdfform?logo=pypi&logoColor=white&label=downloads&labelColor=black&color=blue&style=for-the-badge"></a>
50
50
  </p>
51
51
 
52
- ## Important Announcements
53
-
54
- Hello fellow Python developers! With the release of v2.0.0, there are some important changes I'm making to the library:
55
-
56
- * Since I started developing the library, versioning releases has been quite unorthodox, and there isn't any convention I followed. Starting with v2.0.0, PyPDFForm will version releases following the conventions defined by [Semantic Versioning](https://semver.org/).
57
- * PyPDFForm now renders PDF form widgets! Ever since its ancestral stage, the library has only been able to render the data you filled into a PDF form. Now if you fill a PDF form using `PdfWrapper`, the result will render the whole widget instead of just the value that got filled. If you would like to disable this behavior, please refer to the docs [here](https://chinapandaman.github.io/PyPDFForm/fill/#disable-rendering-widgets).
58
-
59
- Happy hacking!
60
-
61
52
  ## Introduction
62
53
 
63
54
  PyPDFForm is a free and open source pure-Python 3 library for PDF form processing. It contains the essential
@@ -1,15 +1,15 @@
1
- PyPDFForm/__init__.py,sha256=r3unIF6eX0bQ9fRotGNv_5feWcA35-AiSA4k9gF3BR8,328
1
+ PyPDFForm/__init__.py,sha256=QFQO1-GsB4IwC8FPcYzd75pdkWM3pHKwuFVmhGWbmGE,328
2
2
  PyPDFForm/adapter.py,sha256=_5fP5UR-NzjDDayJmBRO36DgbnbUzNbjZtHZtPvSM14,1909
3
3
  PyPDFForm/constants.py,sha256=3ed0j11cWd9Uo4s-XvZwwJojPSz8aqdmZgaEishWjqE,2342
4
4
  PyPDFForm/coordinate.py,sha256=gQI7z-GsdCO33Qny5kXLBs6Y2TW5KO_mJ2in64fvXcg,16412
5
- PyPDFForm/filler.py,sha256=f8xgMBTCVWpwQm56ojhLXOo6A_R7oQCooSLUD5qZICA,14253
5
+ PyPDFForm/filler.py,sha256=HrvgRrAjai9TFOr-bQBH9dlwmEGQsNZgKpOEFfDsXtg,14215
6
6
  PyPDFForm/font.py,sha256=eRbDyQFhXUkHzyZvCtru9Ypg_ukfbBAnSM5xNzPb5ss,7280
7
7
  PyPDFForm/image.py,sha256=aYk7BC-AHiqt73durGIQ3e6gE5Ggbdr8jmkCUaQdsk8,1627
8
- PyPDFForm/patterns.py,sha256=Zv80gZswYFlFuo6eXL1j8bMyckavXPuw55D8IzcvIW0,9472
9
- PyPDFForm/template.py,sha256=WFU6KnGWJ06lQ1GdjdYxmfToL2ash_c9g4z2yiWGebo,18889
8
+ PyPDFForm/patterns.py,sha256=VH7cgAFHLKEUIfE1yIlifIJ9mc0Eb2Kqo-krk34HGOY,9316
9
+ PyPDFForm/template.py,sha256=geZUB8a_otsHa5Q7dO0JH9md1WFodE7Dl_alBhqiU18,20128
10
10
  PyPDFForm/utils.py,sha256=QxJSG96FHGch863UdBPT8DdTKN9gVzQzA2ezifTm7z4,8575
11
- PyPDFForm/watermark.py,sha256=Ni6Y2-DSaAaxqXtCSTrmDOMO0XW7-u3Hucr6J4njtG8,12475
12
- PyPDFForm/wrapper.py,sha256=-Yp8mnehn2Ho-5O5v7cojHcoBotjeWhi_qM9NAIpTDk,25544
11
+ PyPDFForm/watermark.py,sha256=Zmx4orMrQRMoOWGYo4bvVhxptMXFnCM4RshagTp8LFY,12459
12
+ PyPDFForm/wrapper.py,sha256=hBgSkHq0VjzY5VDdT_XHmHt6yr2LPq6hXqBy-LcJCdc,25674
13
13
  PyPDFForm/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  PyPDFForm/middleware/base.py,sha256=d4z7M7pm80176cC4H85m3ZRWzAu_Fm1HkwQkmSSi-WE,2832
15
15
  PyPDFForm/middleware/checkbox.py,sha256=gRGhFySPoIpKBseoiOTS3WggoBBik12dXbZ-LJKzIwM,2611
@@ -19,16 +19,16 @@ PyPDFForm/middleware/radio.py,sha256=M4yqHYzHj0jvOGbjYdqeYnNAlYhTF-h47qxqrjXDOoU
19
19
  PyPDFForm/middleware/signature.py,sha256=0gexCQwHCEOrjrgvUXeJJCGo2plfSEbXlykPJJCqpfA,2380
20
20
  PyPDFForm/middleware/text.py,sha256=eAxeVwboPPlnDT4aaOi7UpQ_xPmnlzkIbUOtRm1VMd0,2944
21
21
  PyPDFForm/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- PyPDFForm/widgets/base.py,sha256=Rv4_fxpq-qDFFGLVGUlbxNmhllNEIhU_P5m0kJFFYiM,5418
22
+ PyPDFForm/widgets/base.py,sha256=cVJzGuZTWE7sWTKlEV4Keh8AGglpQ-i379hEiSHvU18,5402
23
23
  PyPDFForm/widgets/bedrock.py,sha256=j6beU04kaQzpAIFZHI5VJLaDT5RVAAa6LzkU1luJpN8,137660
24
24
  PyPDFForm/widgets/checkbox.py,sha256=_1I5yh1211RgRUyWzd3NNYpI9JchqJNSJWaZAhl2uOo,1248
25
25
  PyPDFForm/widgets/dropdown.py,sha256=zszIT5MI6ggBRUEn7oGBKK0pKmDC9LQw3RnqaKG8ocQ,1764
26
26
  PyPDFForm/widgets/image.py,sha256=6y8Ysmk49USr_qWOXD6KGL6cch516cUIlrxoj0pJy9Q,797
27
27
  PyPDFForm/widgets/radio.py,sha256=ipadJyHbgftDUvjGk15kapzgHPN3HjdF_iB_7amXR6o,2737
28
- PyPDFForm/widgets/signature.py,sha256=EndajR-SQWDZyVfbvDoz5Bjuer5KbURjFlRGqxeXYeY,5115
28
+ PyPDFForm/widgets/signature.py,sha256=8z1sOOgcvhQtLXZ5TeTd59oVtkNGTrgQtZRfuaOWR8w,5099
29
29
  PyPDFForm/widgets/text.py,sha256=HP2cPEUAzK5QL3kDfMz7gQcC3svCpmYuyFItBjlrBpI,1233
30
- pypdfform-2.2.7.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
31
- pypdfform-2.2.7.dist-info/METADATA,sha256=AGsBkSQv4d11UOfNlrnDn8oHBU8KouKIjgJQSTlZiyM,5605
32
- pypdfform-2.2.7.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
33
- pypdfform-2.2.7.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
34
- pypdfform-2.2.7.dist-info/RECORD,,
30
+ pypdfform-2.3.1.dist-info/licenses/LICENSE,sha256=43awmYkI6opyTpg19me731iO1WfXZwViqb67oWtCsFY,1065
31
+ pypdfform-2.3.1.dist-info/METADATA,sha256=MBMmjVXvBQatGn-eY-XdmefJPLRZiG0JdAkTju-U_kw,4738
32
+ pypdfform-2.3.1.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
33
+ pypdfform-2.3.1.dist-info/top_level.txt,sha256=GQQKuWqPUjT9YZqwK95NlAQzxjwoQrsxQ8ureM8lWOY,10
34
+ pypdfform-2.3.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.3.1)
2
+ Generator: setuptools (80.4.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5