python-pdffiller 1.0.0__tar.gz → 1.1.0__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.
Files changed (72) hide show
  1. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/PKG-INFO +1 -1
  2. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/_version.py +1 -1
  3. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/commands/fill_form.py +3 -3
  4. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/pdf.py +42 -198
  5. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/widgets/base.py +28 -1
  6. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/widgets/checkbox.py +3 -1
  7. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/widgets/text.py +3 -1
  8. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pyproject.toml +1 -1
  9. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/python_pdffiller.egg-info/PKG-INFO +1 -1
  10. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/AUTHORS.rst +0 -0
  11. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/CHANGELOG.md +0 -0
  12. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/COPYING +0 -0
  13. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/MANIFEST.in +0 -0
  14. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/README.rst +0 -0
  15. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/Makefile +0 -0
  16. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/make.bat +0 -0
  17. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/__init__.py +0 -0
  18. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/_static/rtd_literal_block.css +0 -0
  19. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/_static/rtd_theme_overrides.css +0 -0
  20. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/_static/terminal_output.css +0 -0
  21. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/changelog.md +0 -0
  22. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/cli-commands.rst +0 -0
  23. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/cli-usage.rst +0 -0
  24. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/commands/dump_data_fields.rst +0 -0
  25. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/commands/fill_form.rst +0 -0
  26. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/conf.py +0 -0
  27. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/contributing.rst +0 -0
  28. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/docs/source/index.rst +0 -0
  29. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/__init__.py +0 -0
  30. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/__main__.py +0 -0
  31. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/__init__.py +0 -0
  32. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/args.py +0 -0
  33. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/boolean_action.py +0 -0
  34. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/cli.py +0 -0
  35. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/command.py +0 -0
  36. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/commands/__init__.py +0 -0
  37. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/commands/dump_data_fields.py +0 -0
  38. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/exit_codes.py +0 -0
  39. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/formatters.py +0 -0
  40. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/once_argument.py +0 -0
  41. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/cli/smart_formatter.py +0 -0
  42. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/const.py +0 -0
  43. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/exceptions.py +0 -0
  44. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/io/__init__.py +0 -0
  45. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/io/colors.py +0 -0
  46. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/io/output.py +0 -0
  47. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/py.typed.py +0 -0
  48. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/typing.py +0 -0
  49. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/utils.py +0 -0
  50. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/widgets/__init__.py +0 -0
  51. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/pdffiller/widgets/radio.py +0 -0
  52. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/python_pdffiller.egg-info/SOURCES.txt +0 -0
  53. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/python_pdffiller.egg-info/dependency_links.txt +0 -0
  54. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/python_pdffiller.egg-info/entry_points.txt +0 -0
  55. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/python_pdffiller.egg-info/requires.txt +0 -0
  56. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/python_pdffiller.egg-info/top_level.txt +0 -0
  57. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/requirements-dev.txt +0 -0
  58. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/requirements-doc.txt +0 -0
  59. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/requirements-lint.txt +0 -0
  60. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/requirements-test.txt +0 -0
  61. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/requirements.txt +0 -0
  62. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/setup.cfg +0 -0
  63. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/setup.py +0 -0
  64. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tests/__init__.py +0 -0
  65. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tests/conftest.py +0 -0
  66. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tests/data/empty.pdf +0 -0
  67. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tests/data/input.pdf +0 -0
  68. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tests/unit/__init__.py +0 -0
  69. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tests/unit/test_form_field.py +0 -0
  70. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tests/unit/test_formatters.py +0 -0
  71. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tests/unit/test_setup.py +0 -0
  72. {python_pdffiller-1.0.0 → python_pdffiller-1.1.0}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-pdffiller
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Interact with PDF by inspecting or filling it
5
5
  Author-email: Jacques Raphanel <jraphanel@sismic.fr>
6
6
  License-Expression: MIT
@@ -3,4 +3,4 @@ __copyright__ = "Copyright 2025 SISMIC"
3
3
  __email__ = "jraphanel@sismic.fr"
4
4
  __license__ = "MIT"
5
5
  __title__ = "pdffiller"
6
- __version__ = "1.0.0"
6
+ __version__ = "1.1.0"
@@ -17,7 +17,7 @@ from pdffiller.exceptions import (
17
17
  )
18
18
  from pdffiller.io.output import PdfFillerOutput
19
19
  from pdffiller.pdf import Pdf
20
- from pdffiller.typing import Any, Dict, Union
20
+ from pdffiller.typing import Any, Dict
21
21
 
22
22
  from ..exit_codes import ERROR_ENCOUNTERED
23
23
 
@@ -94,7 +94,7 @@ def fill_form(parser: PdfFillerArgumentParser, *args: Any) -> Any:
94
94
  if not opts.data and not opts.input_data:
95
95
  raise CommandLineError("no data file path given")
96
96
 
97
- input_data: Dict[str, Union[str, int, float, bool]] = {}
97
+ input_data: Dict[str, str] = {}
98
98
  if opts.input_data:
99
99
  try:
100
100
  input_data = json.loads(opts.input_data)
@@ -132,7 +132,7 @@ def fill_form(parser: PdfFillerArgumentParser, *args: Any) -> Any:
132
132
  input_data = input_dict
133
133
 
134
134
  try:
135
- pdf = Pdf(opts.file)
135
+ pdf = Pdf()
136
136
  pdf.fill(opts.file, opts.output, input_data, opts.flatten)
137
137
  except PdfFillerException as exp:
138
138
  output.error(str(exp))
@@ -14,25 +14,19 @@ from collections import OrderedDict
14
14
 
15
15
  from pypdf import PdfReader, PdfWriter
16
16
  from pypdf.errors import PyPdfError
17
- from pypdf.generic import (
18
- ArrayObject,
19
- DictionaryObject,
20
- NameObject,
21
- NumberObject,
22
- TextStringObject,
23
- )
17
+ from pypdf.generic import ArrayObject, DictionaryObject, NameObject
24
18
 
25
19
  from pdffiller.io.output import PdfFillerOutput
26
20
 
27
21
  from .typing import (
28
22
  Any,
29
- Callable,
30
23
  cast,
31
24
  Dict,
32
25
  List,
33
26
  Optional,
34
27
  PathLike,
35
28
  StrByteType,
29
+ Tuple,
36
30
  Type,
37
31
  Union,
38
32
  )
@@ -179,7 +173,9 @@ class Pdf:
179
173
  elif widget_type in ["list", "combo"] and value:
180
174
  choices = [each[1:] for each in widget[PdfAttributes.Opt]]
181
175
  if key not in loaded_widgets:
182
- new_widget = self.TYPE_TO_OBJECT[widget_type](key, i, value)
176
+ new_widget = self.TYPE_TO_OBJECT[widget_type](
177
+ key, i, value, self.is_readonly(widget_type, widget.get_object())
178
+ )
183
179
  if choices and isinstance(new_widget, CheckBoxWidget):
184
180
  new_widget.choices = choices
185
181
  elif isinstance(new_widget, TextWidget):
@@ -224,7 +220,7 @@ class Pdf:
224
220
  self,
225
221
  input_file: StrByteType,
226
222
  output_file: PathLike,
227
- data: Dict[str, Union[str, int, float, bool]],
223
+ data: Dict[str, str],
228
224
  flatten: bool = True,
229
225
  ) -> "Pdf":
230
226
  """
@@ -244,68 +240,23 @@ class Pdf:
244
240
  Returns:
245
241
  Pdf: The `Pdf` object, allowing for method chaining.
246
242
  """
247
- for key, value in data.items():
248
- if key in self.widgets:
249
- self.widgets[key].value = value
250
-
251
243
  reader = PdfReader(input_file)
252
- if self.adobe_mode:
253
- if (
254
- PdfAttributes.AcroForm in cast(Any, reader.trailer[PdfAttributes.Root])
255
- and PdfAttributes.XFA
256
- in cast(Any, reader.trailer[PdfAttributes.Root])[PdfAttributes.AcroForm]
257
- ):
258
- del cast(Any, reader.trailer[PdfAttributes.Root])[PdfAttributes.AcroForm][
259
- PdfAttributes.XFA
260
- ]
261
-
262
- writer = PdfWriter(reader)
263
- if self.adobe_mode:
264
- writer.set_need_appearances_writer()
265
244
 
266
- fillers: Dict[str, Callable[[DictionaryObject, Any], None]] = {
267
- "checkbox": self._fill_checkbox,
268
- "text": self._fill_text,
269
- "radio": self._fill_radio,
270
- }
245
+ self._init_helper(input_file)
246
+ fields: Dict[str, Union[str, List[str], Tuple[str, str, float]]] = {}
271
247
 
272
- output = PdfFillerOutput()
273
- for page in writer.pages:
274
- widgets: Optional[ArrayObject] = page.annotations
275
- if not widgets:
276
- continue
277
- for widget in widgets:
278
- if (
279
- PdfAttributes.Subtype not in widget
280
- or widget[PdfAttributes.Subtype] != PdfAttributes.Widget
281
- ):
282
- continue
248
+ for name, value in data.items():
249
+ widget = self.widgets.get(name)
250
+ fields[name] = value
251
+ if isinstance(widget, CheckBoxWidget):
252
+ if value and value[0] != "/":
253
+ fields[name] = "/" + value
283
254
 
284
- annotation = cast(DictionaryObject, widget.get_object())
285
- if PdfAttributes.T not in widget:
286
- widget = widget[PdfAttributes.Parent]
287
- widget_key: Optional[str] = self._get_widget_name(widget)
288
- if not widget_key or widget_key not in self.widgets:
289
- continue
290
-
291
- widget_type: Optional[str] = self._get_field_type(widget)
292
- if not widget_type:
293
- continue
294
-
295
- if widget_type != "radio":
296
- self.flatten_generic(annotation, flatten)
297
- else:
298
- self.flatten_radio(annotation, flatten)
299
-
300
- if widget_key not in data or widget_type not in fillers:
301
- continue
302
-
303
- current_widget = self.widgets[widget_key]
304
- if current_widget.value is None:
305
- continue
306
-
307
- output.debug(f"Filling {current_widget.name} with {current_widget.value}")
308
- fillers[widget_type](annotation, current_widget)
255
+ writer = PdfWriter(reader)
256
+ writer.update_page_form_field_values(None, fields, auto_regenerate=False, flatten=flatten)
257
+ if flatten:
258
+ writer.remove_annotations(None)
259
+ writer.compress_identical_objects(remove_identicals=True, remove_orphans=True)
309
260
 
310
261
  with open(output_file, "wb") as f:
311
262
  writer.write(f)
@@ -346,143 +297,36 @@ class Pdf:
346
297
  return None
347
298
 
348
299
  @staticmethod
349
- def _fill_text(annotation: DictionaryObject, widget: TextWidget) -> None:
350
- """
351
- Updates the value of a text annotation, setting the text content.
352
-
353
- This function modifies the value (V) and appearance (AP) of the text
354
- annotation to reflect the new text content.
355
-
356
- Args:
357
- annotation (DictionaryObject): The text annotation dictionary.
358
- widget (TextWidget): The Text widget object containing the text value.
359
- """
360
- if PdfAttributes.Parent in annotation and PdfAttributes.T not in annotation:
361
- annotation[NameObject(PdfAttributes.Parent)] = TextStringObject(widget.value)
362
- annotation[NameObject(PdfAttributes.AP)] = TextStringObject(widget.value)
363
- else:
364
- annotation[NameObject(PdfAttributes.V)] = TextStringObject(widget.value)
365
- annotation[NameObject(PdfAttributes.AP)] = TextStringObject(widget.value)
366
-
367
- @staticmethod
368
- def _fill_checkbox(annotation: DictionaryObject, widget: CheckBoxWidget) -> None:
369
- value: Union[bool, str, None] = widget.value
370
- if value is None:
371
- value = False
372
- if not isinstance(value, bool):
373
- annotation[NameObject(PdfAttributes.AS)] = NameObject("/" + widget.value)
374
- annotation[NameObject(PdfAttributes.V)] = NameObject("/" + widget.value)
375
- return
376
-
377
- for each in cast(Any, annotation[PdfAttributes.AP])[PdfAttributes.N]:
378
- if (value and str(each) != PdfAttributes.Off) or (
379
- not value and str(each) == PdfAttributes.Off
380
- ):
381
- annotation[NameObject(PdfAttributes.AS)] = NameObject(each)
382
- annotation[NameObject(PdfAttributes.V)] = NameObject(each)
383
- return
384
-
385
- if PdfAttributes.V in annotation:
386
- del annotation[PdfAttributes.V]
387
- if PdfAttributes.AS in annotation:
388
- del annotation[PdfAttributes.AS]
389
-
390
- @staticmethod
391
- def _fill_radio(annotation: DictionaryObject, widget: RadioWidget) -> None:
392
-
393
- for each in (
394
- cast(Any, annotation[PdfAttributes.Kids])
395
- if PdfAttributes.T in annotation
396
- else cast(Any, annotation[PdfAttributes.Parent])[PdfAttributes.Kids]
397
- ):
398
- # determine the export value of each kid
399
- keys = each[PdfAttributes.AP][PdfAttributes.N].keys()
400
- if PdfAttributes.Off in keys:
401
- keys.remove(PdfAttributes.Off)
402
- export = list(keys)[0] or None
403
-
404
- if f"/{widget.value}" == export:
405
- annotation[NameObject(PdfAttributes.AS)] = NameObject(export)
406
- cast(Any, annotation[NameObject(PdfAttributes.Parent)])[
407
- NameObject(PdfAttributes.V)
408
- ] = NameObject(export)
409
- else:
410
- annotation[NameObject(PdfAttributes.AS)] = NameObject(PdfAttributes.Off)
411
-
412
- @staticmethod
413
- def flatten_radio(annot: DictionaryObject, val: bool) -> None:
300
+ def is_readonly(widget_type: str, annot: DictionaryObject) -> bool:
414
301
  """
415
- Flattens a radio button annotation by setting or unsetting the ReadOnly flag,
416
- making it non-editable or editable based on the `val` parameter.
302
+ Determines whether readonly flag is set or not.
417
303
 
418
- This function modifies the Ff (flags) entry in the radio button's annotation
419
- dictionary or its parent dictionary if `Parent` exists in `annot`, to set or
420
- unset the ReadOnly flag, preventing or allowing the user from changing the
421
- selected option.
304
+ This function evaluates if readonly is activating by checking Ff (flags) entry
305
+ in the annotation dictionary.
422
306
 
423
307
  Args:
424
- annot (DictionaryObject): The radio button annotation dictionary.
425
- val (bool): True to flatten (make read-only), False to unflatten (make editable).
308
+ widget_type (str): The widget type
309
+ annot (DictionaryObject): The annotation dictionary.
310
+ Returns:
311
+ True if read-only is set, else False
426
312
  """
427
- if PdfAttributes.Parent in annot:
428
- cast(Any, annot[NameObject(PdfAttributes.Parent)])[NameObject(PdfAttributes.Ff)] = (
429
- NumberObject(
430
- (
431
- int(
432
- cast(Any, annot[NameObject(PdfAttributes.Parent)]).get(
433
- NameObject(PdfAttributes.Ff), 0
434
- )
313
+ if widget_type == "radio":
314
+ if PdfAttributes.Parent in annot:
315
+ return (
316
+ int(
317
+ cast(Any, annot[NameObject(PdfAttributes.Parent)]).get(
318
+ NameObject(PdfAttributes.Ff), 0
435
319
  )
436
- | PdfAttributes.READ_ONLY
437
- if val
438
- else int(
439
- cast(Any, annot[NameObject(PdfAttributes.Parent)]).get(
440
- NameObject(PdfAttributes.Ff), 0
441
- )
442
- )
443
- & ~PdfAttributes.READ_ONLY
444
320
  )
321
+ & PdfAttributes.READ_ONLY
322
+ == PdfAttributes.READ_ONLY
445
323
  )
324
+ return (
325
+ int(annot.get(NameObject(PdfAttributes.Ff), 0)) & PdfAttributes.READ_ONLY
326
+ == PdfAttributes.READ_ONLY
446
327
  )
447
- else:
448
- annot[NameObject(PdfAttributes.Ff)] = NumberObject(
449
- (
450
- int(annot.get(NameObject(PdfAttributes.Ff), 0)) | PdfAttributes.READ_ONLY
451
- if val
452
- else int(annot.get(NameObject(PdfAttributes.Ff), 0)) & ~PdfAttributes.READ_ONLY
453
- )
454
- )
455
-
456
- @staticmethod
457
- def flatten_generic(annot: DictionaryObject, val: bool) -> None:
458
- """
459
- Flattens a generic annotation by setting or unsetting the ReadOnly flag,
460
- making it non-editable or editable based on the `val` parameter.
461
328
 
462
- This function modifies the Ff (flags) entry in the annotation dictionary to
463
- set or unset the ReadOnly flag, preventing or allowing the user from
464
- interacting with the form field.
465
-
466
- Args:
467
- annot (DictionaryObject): The annotation dictionary.
468
- val (bool): True to flatten (make read-only), False to unflatten (make editable).
469
- """
470
- if PdfAttributes.Parent in annot and PdfAttributes.Ff not in annot:
471
- cast(Any, annot[NameObject(PdfAttributes.Parent)])[NameObject(PdfAttributes.Ff)] = (
472
- NumberObject(
473
- (
474
- int(annot.get(NameObject(PdfAttributes.Ff), 0)) | PdfAttributes.READ_ONLY
475
- if val
476
- else int(annot.get(NameObject(PdfAttributes.Ff), 0))
477
- & ~PdfAttributes.READ_ONLY
478
- )
479
- )
480
- )
481
- else:
482
- annot[NameObject(PdfAttributes.Ff)] = NumberObject(
483
- (
484
- int(annot.get(NameObject(PdfAttributes.Ff), 0)) | PdfAttributes.READ_ONLY
485
- if val
486
- else int(annot.get(NameObject(PdfAttributes.Ff), 0)) & ~PdfAttributes.READ_ONLY
487
- )
488
- )
329
+ return (
330
+ int(annot.get(NameObject(PdfAttributes.Ff), 0)) & PdfAttributes.READ_ONLY
331
+ == PdfAttributes.READ_ONLY
332
+ )
@@ -20,7 +20,9 @@ class Widget:
20
20
  as name, value, and schema definition.
21
21
  """
22
22
 
23
- def __init__(self, name: str, page_number: int, value: Optional[Any] = None) -> None:
23
+ def __init__(
24
+ self, name: str, page_number: int, value: Optional[Any] = None, readonly: bool = False
25
+ ) -> None:
24
26
  """
25
27
  Initialize a new widget.
26
28
 
@@ -28,11 +30,13 @@ class Widget:
28
30
  name (str): The name of the widget.
29
31
  page_number (int): The associated page index
30
32
  value (Any): The initial value of the widget. Defaults to None.
33
+ readonly (bool): True if readonly is set, else False.
31
34
  """
32
35
  super().__init__()
33
36
  self._name: str = name
34
37
  self.page_number: int = page_number
35
38
  self._value: Optional[Any] = value
39
+ self._readonly: bool = readonly
36
40
  self._description: Optional[str] = None
37
41
 
38
42
  @property
@@ -65,6 +69,26 @@ class Widget:
65
69
  """
66
70
  self._value = value
67
71
 
72
+ @property
73
+ def readonly(self) -> bool:
74
+ """
75
+ Determine whether readonly mode is set or not.
76
+
77
+ Returns:
78
+ bool: True if readonly mode is set, else False.
79
+ """
80
+ return self._readonly
81
+
82
+ @readonly.setter
83
+ def readonly(self, readonly: bool) -> None:
84
+ """
85
+ Specify if the readonly mode is set
86
+
87
+ Args:
88
+ readonly (bool): True if readonly mode is set, else False.
89
+ """
90
+ self._readonly = readonly
91
+
68
92
  @property
69
93
  def description(self) -> Optional[str]:
70
94
  """
@@ -101,6 +125,9 @@ class Widget:
101
125
  if self._value:
102
126
  result["FieldValue"] = self._value
103
127
 
128
+ if self._readonly:
129
+ result["Readonly"] = self._readonly
130
+
104
131
  if self._description is not None:
105
132
  result["Description"] = self._description
106
133
 
@@ -24,6 +24,7 @@ class CheckBoxWidget(Widget):
24
24
  name: str,
25
25
  page_number: int,
26
26
  value: Optional[str] = None,
27
+ readonly: bool = False,
27
28
  choices: Optional[List[str]] = None,
28
29
  ) -> None:
29
30
  """
@@ -33,9 +34,10 @@ class CheckBoxWidget(Widget):
33
34
  name (str): The name of the checkbox.
34
35
  page_number (int): The associated page index
35
36
  value (str): The initial value of the checkbox. Defaults to None.
37
+ readonly (bool): True if readonly is set, else False.
36
38
  choices: The list of available choices. Defaults to None.
37
39
  """
38
- super().__init__(name, page_number, value)
40
+ super().__init__(name, page_number, value, readonly)
39
41
  self.choices: Optional[List[str]] = choices
40
42
 
41
43
  @property
@@ -25,6 +25,7 @@ class TextWidget(Widget):
25
25
  name: str,
26
26
  page_number: int,
27
27
  value: Optional[str] = None,
28
+ readonly: bool = False,
28
29
  max_length: Optional[int] = None,
29
30
  ) -> None:
30
31
  """
@@ -34,9 +35,10 @@ class TextWidget(Widget):
34
35
  name (str): The name of the checkbox.
35
36
  page_number (int): The associated page index
36
37
  value (str): The initial value of the checkbox. Defaults to None.
38
+ readonly (bool): True if readonly is set, else False.
37
39
  max_length (int): The maximum length of the text field. Defaults to None.
38
40
  """
39
- super().__init__(name, page_number, value)
41
+ super().__init__(name, page_number, value, readonly)
40
42
  self.max_length: Optional[int] = max_length
41
43
 
42
44
  @property
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-pdffiller"
7
- version = "1.0.0"
7
+ version = "1.1.0"
8
8
  description="Interact with PDF by inspecting or filling it"
9
9
  requires-python = ">=3.9"
10
10
  license ="MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-pdffiller
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Interact with PDF by inspecting or filling it
5
5
  Author-email: Jacques Raphanel <jraphanel@sismic.fr>
6
6
  License-Expression: MIT