PyPDFForm 2.0.0__py3-none-any.whl → 2.1.0__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.

@@ -1,5 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains signature middleware."""
2
+ """Provides middleware for PDF signature field widgets.
3
+
4
+ This module contains the Signature class which handles:
5
+ - Signature image processing
6
+ - Aspect ratio preservation
7
+ - File path resolution
8
+ - PDF form field integration
9
+ """
3
10
 
4
11
  from os.path import expanduser
5
12
  from typing import BinaryIO, Union
@@ -9,34 +16,70 @@ from .base import Widget
9
16
 
10
17
 
11
18
  class Signature(Widget):
12
- """A class to represent a signature field widget."""
19
+ """Middleware for PDF signature field widgets.
20
+
21
+ Handles all aspects of signature field processing including:
22
+ - Signature image handling
23
+ - Aspect ratio control
24
+ - File path resolution
25
+ - PDF form field integration
26
+
27
+ Inherits from Widget base class and extends it with signature-specific features.
28
+ """
13
29
 
14
30
  preserve_aspect_ratio = True
31
+ """Whether to preserve the original image's aspect ratio when scaling."""
15
32
 
16
33
  def __init__(
17
34
  self,
18
35
  name: str,
19
36
  value: Union[bytes, str, BinaryIO] = None,
20
37
  ) -> None:
21
- """Constructs all attributes for the signature field."""
38
+ """Initializes a new signature field widget.
39
+
40
+ Args:
41
+ name: Field name/key for the signature
42
+ value: Signature image as bytes, file path, or file object (default: None)
43
+ """
22
44
 
23
45
  super().__init__(name, value)
24
46
 
25
47
  @property
26
48
  def schema_definition(self) -> dict:
27
- """Json schema definition of the signature field."""
49
+ """Generates a JSON schema definition for the signature field.
50
+
51
+ Returns:
52
+ dict: Schema properties including:
53
+ - type: string (file path)
54
+ - description (if available from base class)
55
+ """
28
56
 
29
57
  return {"type": "string"}
30
58
 
31
59
  @property
32
60
  def sample_value(self) -> str:
33
- """Sample value of the signature field."""
61
+ """Generates a sample value for the signature field.
62
+
63
+ Returns a default sample image path from the user's Downloads folder.
64
+
65
+ Returns:
66
+ str: Path to sample image file
67
+ """
34
68
 
35
69
  return expanduser("~/Downloads/sample_image.jpg")
36
70
 
37
71
  @property
38
72
  def stream(self) -> Union[bytes, None]:
39
- """Converts the value of the signature field image to a stream."""
73
+ """Converts the signature image to a byte stream.
74
+
75
+ Handles conversion of:
76
+ - Raw image bytes
77
+ - File paths
78
+ - File-like objects
79
+
80
+ Returns:
81
+ Union[bytes, None]: Image data as bytes, or None if no value set
82
+ """
40
83
 
41
84
  return (
42
85
  fp_or_f_obj_or_stream_to_stream(self.value)
@@ -1,5 +1,13 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains text middleware."""
2
+ """Provides middleware for PDF text field widgets.
3
+
4
+ This module contains the Text class which handles:
5
+ - Text field value management
6
+ - Font properties (family, size, color)
7
+ - Text wrapping and formatting
8
+ - Comb field (fixed character spacing) support
9
+ - Preview mode for form field visualization
10
+ """
3
11
 
4
12
  from typing import Any
5
13
 
@@ -7,14 +15,29 @@ from .base import Widget
7
15
 
8
16
 
9
17
  class Text(Widget):
10
- """A class to represent a text field widget."""
18
+ """Middleware for PDF text field widgets.
19
+
20
+ Handles all aspects of text field processing including:
21
+ - Value conversion and validation
22
+ - Font styling and formatting
23
+ - Multiline text wrapping
24
+ - Comb field character spacing
25
+ - Preview mode rendering
26
+
27
+ Inherits from Widget base class and extends it with text-specific features.
28
+ """
11
29
 
12
30
  def __init__(
13
31
  self,
14
32
  name: str,
15
33
  value: str = None,
16
34
  ) -> None:
17
- """Constructs all attributes for the text field."""
35
+ """Initializes a new text field widget.
36
+
37
+ Args:
38
+ name: Field name/key for the text field
39
+ value: Initial text value (default: None)
40
+ """
18
41
 
19
42
  super().__init__(name, value)
20
43
 
@@ -31,7 +54,13 @@ class Text(Widget):
31
54
 
32
55
  @property
33
56
  def value(self) -> Any:
34
- """Value to fill for the text field."""
57
+ """Gets the text field's current value with type conversion.
58
+
59
+ Converts numeric values to strings automatically.
60
+
61
+ Returns:
62
+ Any: The text value as a string (converted if numeric)
63
+ """
35
64
 
36
65
  if isinstance(self._value, (int, float)):
37
66
  return str(self._value)
@@ -40,13 +69,26 @@ class Text(Widget):
40
69
 
41
70
  @value.setter
42
71
  def value(self, value: str) -> None:
43
- """Sets value to fill for the text field."""
72
+ """Sets the text field's value.
73
+
74
+ Args:
75
+ value: New text value (will be converted to string if numeric)
76
+ """
44
77
 
45
78
  self._value = value
46
79
 
47
80
  @property
48
81
  def schema_definition(self) -> dict:
49
- """Json schema definition of the text field."""
82
+ """Generates a JSON schema definition for the text field.
83
+
84
+ Includes:
85
+ - Type constraint (string)
86
+ - Max length if specified
87
+ - Any inherited schema properties
88
+
89
+ Returns:
90
+ dict: Complete JSON schema definition
91
+ """
50
92
 
51
93
  result = {"type": "string"}
52
94
 
@@ -57,7 +99,13 @@ class Text(Widget):
57
99
 
58
100
  @property
59
101
  def sample_value(self) -> str:
60
- """Sample value of the text field."""
102
+ """Generates a sample value demonstrating the text field's capacity.
103
+
104
+ Uses the field name as the sample value, truncated to max_length if specified.
105
+
106
+ Returns:
107
+ str: Sample text value for demonstration purposes
108
+ """
61
109
 
62
110
  return (
63
111
  self.name[: self.max_length] if self.max_length is not None else self.name
PyPDFForm/patterns.py CHANGED
@@ -1,5 +1,19 @@
1
1
  # -*- coding: utf-8 -*-
2
- """Contains patterns used for identifying properties of widgets."""
2
+ """Pattern matching utilities for PDF form widgets.
3
+
4
+ This module provides:
5
+ - Pattern definitions for identifying widget types and properties
6
+ - Functions for updating widget states and appearances
7
+ - Support for common PDF form operations like flattening fields
8
+
9
+ Patterns are used throughout PyPDFForm to:
10
+ - Classify widget types (text, checkbox, radio, etc.)
11
+ - Extract widget properties (alignment, colors, flags)
12
+ - Modify widget states (values, appearances, flags)
13
+
14
+ The module also contains utility functions for common PDF form operations
15
+ like updating field values and flattening form fields.
16
+ """
3
17
 
4
18
  from pypdf.generic import (DictionaryObject, NameObject, NumberObject,
5
19
  TextStringObject)
@@ -24,10 +38,23 @@ WIDGET_TYPE_PATTERNS = [
24
38
  ({FT: Sig},),
25
39
  Signature,
26
40
  ),
41
+ (
42
+ ({Parent: {FT: Sig}},),
43
+ Signature,
44
+ ),
27
45
  (
28
46
  ({FT: Tx},),
29
47
  Text,
30
48
  ),
49
+ (
50
+ # reportlab creation pattern
51
+ (
52
+ {FT: Btn},
53
+ {Parent: {FT: Btn}},
54
+ {AS: (Yes, Off)},
55
+ ),
56
+ Radio,
57
+ ),
31
58
  (
32
59
  (
33
60
  {FT: Btn},
@@ -111,7 +138,16 @@ BORDER_DASH_ARRAY_PATTERNS = [{BS: {D: True}}]
111
138
 
112
139
 
113
140
  def simple_update_checkbox_value(annot: DictionaryObject, check: bool = False) -> None:
114
- """Patterns to update values for checkbox annotations."""
141
+ """Update checkbox annotation values based on check state.
142
+
143
+ Modifies the appearance state (AS) and value (V) of a checkbox annotation
144
+ to reflect the desired checked/unchecked state. Uses the annotation's
145
+ appearance dictionary (AP/N) to determine valid states.
146
+
147
+ Args:
148
+ annot: PDF annotation dictionary to modify
149
+ check: Whether the checkbox should be checked (True) or unchecked (False)
150
+ """
115
151
 
116
152
  for each in annot[AP][N]: # noqa
117
153
  if (check and str(each) != Off) or (not check and str(each) == Off):
@@ -121,7 +157,15 @@ def simple_update_checkbox_value(annot: DictionaryObject, check: bool = False) -
121
157
 
122
158
 
123
159
  def simple_update_radio_value(annot: DictionaryObject) -> None:
124
- """Patterns to update values for radio annotations."""
160
+ """Update radio button annotation values to selected state.
161
+
162
+ Modifies the appearance state (AS) of a radio button annotation and updates
163
+ the parent's value (V) to reflect the selected state. Uses the annotation's
164
+ appearance dictionary (AP/N) to determine valid states.
165
+
166
+ Args:
167
+ annot: PDF radio button annotation dictionary to modify
168
+ """
125
169
 
126
170
  for each in annot[AP][N]: # noqa
127
171
  if str(each) != Off:
@@ -131,7 +175,16 @@ def simple_update_radio_value(annot: DictionaryObject) -> None:
131
175
 
132
176
 
133
177
  def simple_update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> None:
134
- """Patterns to update values for dropdown annotations."""
178
+ """Update dropdown annotation values based on widget selection.
179
+
180
+ Modifies the value (V) and appearance (AP) of a dropdown annotation to
181
+ reflect the currently selected choice from the widget. Handles both
182
+ standalone dropdowns and those with parent annotations.
183
+
184
+ Args:
185
+ annot: PDF dropdown annotation dictionary to modify
186
+ widget: Dropdown widget containing the selected value
187
+ """
135
188
 
136
189
  if Parent in annot and T not in annot:
137
190
  annot[NameObject(Parent)][NameObject(V)] = TextStringObject( # noqa
@@ -144,7 +197,16 @@ def simple_update_dropdown_value(annot: DictionaryObject, widget: Dropdown) -> N
144
197
 
145
198
 
146
199
  def simple_update_text_value(annot: DictionaryObject, widget: Text) -> None:
147
- """Patterns to update values for text annotations."""
200
+ """Update text field annotation values based on widget content.
201
+
202
+ Modifies the value (V) and appearance (AP) of a text field annotation to
203
+ reflect the current value from the text widget. Handles both standalone
204
+ text fields and those with parent annotations.
205
+
206
+ Args:
207
+ annot: PDF text field annotation dictionary to modify
208
+ widget: Text widget containing the value to set
209
+ """
148
210
 
149
211
  if Parent in annot and T not in annot:
150
212
  annot[NameObject(Parent)][NameObject(V)] = TextStringObject( # noqa
@@ -157,7 +219,15 @@ def simple_update_text_value(annot: DictionaryObject, widget: Text) -> None:
157
219
 
158
220
 
159
221
  def simple_flatten_radio(annot: DictionaryObject) -> None:
160
- """Patterns to flatten checkbox annotations."""
222
+ """Flatten radio button annotation by making it read-only.
223
+
224
+ Modifies the field flags (Ff) of a radio button's parent annotation
225
+ to set the read-only flag, effectively flattening the field and
226
+ preventing further user interaction.
227
+
228
+ Args:
229
+ annot: PDF radio button annotation dictionary to flatten
230
+ """
161
231
 
162
232
  annot[NameObject(Parent)][NameObject(Ff)] = NumberObject( # noqa
163
233
  int(annot[NameObject(Parent)].get(NameObject(Ff), 0)) | READ_ONLY # noqa
@@ -165,7 +235,15 @@ def simple_flatten_radio(annot: DictionaryObject) -> None:
165
235
 
166
236
 
167
237
  def simple_flatten_generic(annot: DictionaryObject) -> None:
168
- """Patterns to flatten generic annotations."""
238
+ """Flatten generic annotation by making it read-only.
239
+
240
+ Modifies the field flags (Ff) of an annotation to set the read-only flag,
241
+ effectively flattening the field and preventing further user interaction.
242
+ Handles both standalone annotations and those with parent annotations.
243
+
244
+ Args:
245
+ annot: PDF annotation dictionary to flatten
246
+ """
169
247
 
170
248
  if Parent in annot and Ff not in annot:
171
249
  annot[NameObject(Parent)][NameObject(Ff)] = NumberObject( # noqa
@@ -178,7 +256,15 @@ def simple_flatten_generic(annot: DictionaryObject) -> None:
178
256
 
179
257
 
180
258
  def update_annotation_name(annot: DictionaryObject, val: str) -> None:
181
- """Patterns to update the name of an annotation."""
259
+ """Update the name/title of a PDF annotation.
260
+
261
+ Modifies the title (T) field of an annotation to set a new name.
262
+ Handles both standalone annotations and those with parent annotations.
263
+
264
+ Args:
265
+ annot: PDF annotation dictionary to modify
266
+ val: New name/title to set for the annotation
267
+ """
182
268
 
183
269
  if Parent in annot and T not in annot:
184
270
  annot[NameObject(Parent)][NameObject(T)] = TextStringObject(val) # noqa
@@ -187,13 +273,29 @@ def update_annotation_name(annot: DictionaryObject, val: str) -> None:
187
273
 
188
274
 
189
275
  def update_created_text_field_alignment(annot: DictionaryObject, val: int) -> None:
190
- """Patterns to update text alignment for text annotations created by the library."""
276
+ """Update text alignment for created text field annotations.
277
+
278
+ Modifies the alignment (Q) field of a text field annotation created
279
+ by the library to set the specified text alignment.
280
+
281
+ Args:
282
+ annot: PDF text field annotation dictionary to modify
283
+ val: Alignment value to set (typically 0=left, 1=center, 2=right)
284
+ """
191
285
 
192
286
  annot[NameObject(Q)] = NumberObject(val)
193
287
 
194
288
 
195
289
  def update_created_text_field_multiline(annot: DictionaryObject, val: bool) -> None:
196
- """Patterns to update to multiline for text annotations created by the library."""
290
+ """Update multiline flag for created text field annotations.
291
+
292
+ Modifies the field flags (Ff) of a text field annotation created by
293
+ the library to set or clear the multiline flag based on the input value.
294
+
295
+ Args:
296
+ annot: PDF text field annotation dictionary to modify
297
+ val: Whether to enable multiline (True) or disable (False)
298
+ """
197
299
 
198
300
  if val:
199
301
  annot[NameObject(Ff)] = NumberObject(