PyPDFForm 5.1.1__tar.gz → 5.2.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 (86) hide show
  1. {pypdfform-5.1.1 → pypdfform-5.2.0}/PKG-INFO +1 -3
  2. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/__init__.py +1 -1
  3. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/common.py +7 -0
  4. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/create.py +9 -5
  5. pypdfform-5.2.0/PyPDFForm/cli/remove.py +33 -0
  6. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/root.py +14 -8
  7. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/update.py +10 -3
  8. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/annotations/__init__.py +6 -2
  9. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/annotations/base.py +7 -2
  10. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/annotations/link.py +7 -2
  11. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/egress.py +1 -2
  12. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/filler.py +7 -3
  13. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/font.py +45 -11
  14. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/hooks.py +39 -7
  15. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/patterns.py +39 -6
  16. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/template.py +61 -6
  17. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/widgets/signature.py +1 -2
  18. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/wrapper.py +67 -15
  19. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm.egg-info/PKG-INFO +1 -3
  20. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm.egg-info/SOURCES.txt +1 -0
  21. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm.egg-info/requires.txt +0 -2
  22. {pypdfform-5.1.1 → pypdfform-5.2.0}/pyproject.toml +0 -2
  23. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_font_widths.py +10 -3
  24. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_functional.py +13 -0
  25. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_js.py +95 -95
  26. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_use_full_widget_name.py +8 -0
  27. {pypdfform-5.1.1 → pypdfform-5.2.0}/LICENSE +0 -0
  28. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/__init__.py +0 -0
  29. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/entry.py +0 -0
  30. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/inspect.py +0 -0
  31. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/schemas/__init__.py +0 -0
  32. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/schemas/create.py +0 -0
  33. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/cli/schemas/update.py +0 -0
  34. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/__init__.py +0 -0
  35. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/adapter.py +0 -0
  36. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/annotations/stamp.py +0 -0
  37. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/annotations/text.py +0 -0
  38. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/annotations/text_markup.py +0 -0
  39. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/assets/__init__.py +0 -0
  40. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/assets/bedrock.py +0 -0
  41. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/assets/blank.py +0 -0
  42. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/constants.py +0 -0
  43. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/coordinate.py +0 -0
  44. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/deprecation.py +0 -0
  45. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/image.py +0 -0
  46. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/middleware/__init__.py +0 -0
  47. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/middleware/base.py +0 -0
  48. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/middleware/checkbox.py +0 -0
  49. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/middleware/dropdown.py +0 -0
  50. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/middleware/image.py +0 -0
  51. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/middleware/radio.py +0 -0
  52. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/middleware/signature.py +0 -0
  53. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/middleware/text.py +0 -0
  54. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/raw/__init__.py +0 -0
  55. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/raw/circle.py +0 -0
  56. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/raw/ellipse.py +0 -0
  57. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/raw/image.py +0 -0
  58. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/raw/line.py +0 -0
  59. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/raw/rect.py +0 -0
  60. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/raw/text.py +0 -0
  61. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/types.py +0 -0
  62. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/utils.py +0 -0
  63. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/watermark.py +0 -0
  64. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/widgets/__init__.py +0 -0
  65. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/widgets/base.py +0 -0
  66. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/widgets/checkbox.py +0 -0
  67. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/widgets/dropdown.py +0 -0
  68. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/widgets/image.py +0 -0
  69. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/widgets/radio.py +0 -0
  70. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm/lib/widgets/text.py +0 -0
  71. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm.egg-info/dependency_links.txt +0 -0
  72. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm.egg-info/entry_points.txt +0 -0
  73. {pypdfform-5.1.1 → pypdfform-5.2.0}/PyPDFForm.egg-info/top_level.txt +0 -0
  74. {pypdfform-5.1.1 → pypdfform-5.2.0}/README.md +0 -0
  75. {pypdfform-5.1.1 → pypdfform-5.2.0}/setup.cfg +0 -0
  76. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_bulk_create_fields.py +0 -0
  77. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_create_widget.py +0 -0
  78. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_draw_elements.py +0 -0
  79. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_dropdown.py +0 -0
  80. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_extract_middleware_attributes.py +0 -0
  81. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_fill_max_length_text_field.py +0 -0
  82. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_generate_appearance_streams.py +0 -0
  83. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_need_appearances.py +0 -0
  84. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_paragraph.py +0 -0
  85. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_signature.py +0 -0
  86. {pypdfform-5.1.1 → pypdfform-5.2.0}/tests/test_widget_attr_trigger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 5.1.1
3
+ Version: 5.2.0
4
4
  Summary: The Python library & CLI for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -34,9 +34,7 @@ Provides-Extra: cli
34
34
  Requires-Dist: typer<1.0.0,>=0.26.1; extra == "cli"
35
35
  Requires-Dist: jsonschema<5.0.0,>=4.26.0; extra == "cli"
36
36
  Provides-Extra: dev
37
- Requires-Dist: black<27.0.0,>=26.5.1; extra == "dev"
38
37
  Requires-Dist: coverage<8.0.0,>=7.14.1; extra == "dev"
39
- Requires-Dist: isort<9.0.0,>=8.0.1; extra == "dev"
40
38
  Requires-Dist: mike<3.0.0,>=2.2.0; extra == "dev"
41
39
  Requires-Dist: mkdocs<2.0.0,>=1.6.1; extra == "dev"
42
40
  Requires-Dist: mkdocs-material<10.0.0,>=9.7.6; extra == "dev"
@@ -18,7 +18,7 @@ from Python code or from the command line.
18
18
 
19
19
  import logging
20
20
 
21
- __version__ = "5.1.1"
21
+ __version__ = "5.2.0"
22
22
 
23
23
  from .lib.annotations import Annotations
24
24
  from .lib.assets.blank import BlankPage
@@ -53,6 +53,13 @@ OPTIONAL_OUTPUT_PDF = Annotated[
53
53
  ),
54
54
  ]
55
55
  FIELD_NAME = Annotated[str, typer.Option("--field", help="Form field name.")]
56
+ FIELD_NAMES = Annotated[
57
+ list[str],
58
+ typer.Option(
59
+ "--field",
60
+ help="Form field name. Repeat this option to select multiple fields.",
61
+ ),
62
+ ]
56
63
 
57
64
 
58
65
  def json_file_option(help_text: str):
@@ -14,11 +14,15 @@ from typing import Annotated
14
14
 
15
15
  import typer
16
16
 
17
- from .. import (Annotations, BlankPage, Fields, PdfArray, PdfWrapper,
18
- RawElements)
19
- from .common import (INPUT_PDF, OPTIONAL_OUTPUT_PDF, REQUIRED_OUTPUT_PDF,
20
- cli_bad_parameter, create_elements_from_file,
21
- json_file_option)
17
+ from .. import Annotations, BlankPage, Fields, PdfArray, PdfWrapper, RawElements
18
+ from .common import (
19
+ INPUT_PDF,
20
+ OPTIONAL_OUTPUT_PDF,
21
+ REQUIRED_OUTPUT_PDF,
22
+ cli_bad_parameter,
23
+ create_elements_from_file,
24
+ json_file_option,
25
+ )
22
26
  from .schemas.create import ANNOTATION_SCHEMA, FIELD_SCHEMA, RAW_SCHEMA
23
27
 
24
28
  create_cli = typer.Typer(
@@ -0,0 +1,33 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ This module defines CLI commands for removing PDF form content.
4
+
5
+ It exposes the `remove` command group for deleting existing form fields.
6
+ Commands in this module load the target PDF, validate requested form field
7
+ names, apply the matching `PdfWrapper` operation, and write the modified PDF to
8
+ either the requested output path or the original file.
9
+ """
10
+
11
+ import typer
12
+
13
+ from .. import PdfWrapper
14
+ from .common import FIELD_NAMES, INPUT_PDF, OPTIONAL_OUTPUT_PDF, get_widget
15
+
16
+ remove_cli = typer.Typer(
17
+ context_settings={"help_option_names": ["--help", "-h"]}, no_args_is_help=True
18
+ )
19
+
20
+
21
+ @remove_cli.command(no_args_is_help=True)
22
+ def field(
23
+ ctx: typer.Context,
24
+ pdf: INPUT_PDF,
25
+ fields: FIELD_NAMES,
26
+ output: OPTIONAL_OUTPUT_PDF = None,
27
+ ) -> None:
28
+ """Remove form fields from a PDF."""
29
+ obj = PdfWrapper(str(pdf), **ctx.obj)
30
+ for field_name in fields:
31
+ get_widget(obj, field_name, "--field")
32
+
33
+ obj.remove_fields(fields).write(output or pdf)
@@ -2,16 +2,17 @@
2
2
  """
3
3
  This module defines the root command-line interface for PyPDFForm.
4
4
 
5
- It creates the Typer application, attaches the `create`, `inspect`, and `update`
6
- command groups, and exposes top-level options shared by those commands. The root
7
- callback collects global flags in the Typer context so each subcommand can
8
- initialize `PdfWrapper` with consistent settings.
5
+ It creates the Typer application, attaches the `create`, `inspect`, `update`,
6
+ and `remove` command groups, and exposes top-level options shared by those
7
+ commands. The root callback collects global flags in the Typer context so each
8
+ subcommand can initialize `PdfWrapper` with consistent settings.
9
9
 
10
10
  Commands:
11
11
  - `fill`: Fill an existing PDF form from JSON data.
12
12
  - `create`: Create PDFs, fields, annotations, raw elements, and grid views.
13
13
  - `inspect`: Print form metadata and field data as JSON.
14
14
  - `update`: Modify PDF metadata, field names, properties, geometry, and scripts.
15
+ - `remove`: Remove PDF form fields.
15
16
  """
16
17
 
17
18
  from pathlib import Path
@@ -20,10 +21,10 @@ from typing import Annotated
20
21
  import typer
21
22
 
22
23
  from .. import PdfWrapper, Widgets, __version__
23
- from .common import (INPUT_PDF, OPTIONAL_OUTPUT_PDF, json_file_option,
24
- load_json_file)
24
+ from .common import INPUT_PDF, OPTIONAL_OUTPUT_PDF, json_file_option, load_json_file
25
25
  from .create import create_cli
26
26
  from .inspect import inspect_cli
27
+ from .remove import remove_cli
27
28
  from .update import update_cli
28
29
 
29
30
  cli_app = typer.Typer(
@@ -44,6 +45,11 @@ cli_app.add_typer(
44
45
  name="update",
45
46
  help="Update PDF metadata, fields, and scripts.",
46
47
  )
48
+ cli_app.add_typer(
49
+ remove_cli,
50
+ name="remove",
51
+ help="Remove PDF form content.",
52
+ )
47
53
 
48
54
 
49
55
  def version_callback(value: bool) -> None:
@@ -68,7 +74,7 @@ def version_callback(value: bool) -> None:
68
74
 
69
75
  @cli_app.callback(
70
76
  invoke_without_command=True,
71
- help="Create, fill, inspect, and update PDF forms.",
77
+ help="Work with PDF forms from the command line.",
72
78
  )
73
79
  def main(
74
80
  ctx: typer.Context,
@@ -111,7 +117,7 @@ def main(
111
117
  ),
112
118
  ] = False,
113
119
  ) -> None:
114
- """Create, fill, inspect, and update PDF forms."""
120
+ """Work with PDF forms from the command line."""
115
121
  ctx.obj = {
116
122
  "need_appearances": need_appearances,
117
123
  "generate_appearance_streams": generate_appearance_streams,
@@ -17,9 +17,16 @@ import typer
17
17
 
18
18
  from .. import PdfWrapper
19
19
  from ..lib.constants import PdfVersion
20
- from .common import (FIELD_NAME, INPUT_PDF, OPTIONAL_OUTPUT_PDF,
21
- cli_bad_parameter, get_widget, handle_font_registration,
22
- json_file_option, load_json_file)
20
+ from .common import (
21
+ FIELD_NAME,
22
+ INPUT_PDF,
23
+ OPTIONAL_OUTPUT_PDF,
24
+ cli_bad_parameter,
25
+ get_widget,
26
+ handle_font_registration,
27
+ json_file_option,
28
+ load_json_file,
29
+ )
23
30
  from .schemas.update import FIELD_SCHEMA, RENAME_SCHEMA
24
31
 
25
32
  update_cli = typer.Typer(
@@ -14,8 +14,12 @@ from dataclasses import dataclass
14
14
  from .link import LinkAnnotation
15
15
  from .stamp import RubberStampAnnotation
16
16
  from .text import TextAnnotation
17
- from .text_markup import (HighlightAnnotation, SquigglyAnnotation,
18
- StrikeOutAnnotation, UnderlineAnnotation)
17
+ from .text_markup import (
18
+ HighlightAnnotation,
19
+ SquigglyAnnotation,
20
+ StrikeOutAnnotation,
21
+ UnderlineAnnotation,
22
+ )
19
23
 
20
24
  AnnotationTypes = (
21
25
  TextAnnotation
@@ -11,8 +11,13 @@ Classes:
11
11
 
12
12
  from dataclasses import dataclass
13
13
 
14
- from pypdf.generic import (ArrayObject, DictionaryObject, FloatObject,
15
- NameObject, TextStringObject)
14
+ from pypdf.generic import (
15
+ ArrayObject,
16
+ DictionaryObject,
17
+ FloatObject,
18
+ NameObject,
19
+ TextStringObject,
20
+ )
16
21
 
17
22
  from ..constants import Annot, Contents, Rect, Subtype, Type
18
23
 
@@ -12,8 +12,13 @@ Classes:
12
12
  from dataclasses import dataclass
13
13
  from typing import Optional
14
14
 
15
- from pypdf.generic import (ArrayObject, DictionaryObject, NameObject,
16
- NumberObject, TextStringObject)
15
+ from pypdf.generic import (
16
+ ArrayObject,
17
+ DictionaryObject,
18
+ NameObject,
19
+ NumberObject,
20
+ TextStringObject,
21
+ )
17
22
 
18
23
  from ..constants import A, S
19
24
  from .base import Annotation
@@ -17,8 +17,7 @@ from pikepdf import Pdf
17
17
  from pypdf import PdfReader, PdfWriter
18
18
  from pypdf.generic import DictionaryObject, NameObject, TextStringObject
19
19
 
20
- from .constants import (JS, XFA, AcroForm, JavaScript, OpenAction, Root, S,
21
- Title)
20
+ from .constants import JS, XFA, AcroForm, JavaScript, OpenAction, Root, S, Title
22
21
 
23
22
 
24
23
  @lru_cache
@@ -24,9 +24,13 @@ from .middleware.image import Image
24
24
  from .middleware.radio import Radio
25
25
  from .middleware.signature import Signature
26
26
  from .middleware.text import Text
27
- from .patterns import (get_widget_key, update_checkbox_value,
28
- update_dropdown_value, update_radio_value,
29
- update_text_value)
27
+ from .patterns import (
28
+ get_widget_key,
29
+ update_checkbox_value,
30
+ update_dropdown_value,
31
+ update_radio_value,
32
+ update_text_value,
33
+ )
30
34
  from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
31
35
 
32
36
 
@@ -16,20 +16,52 @@ from zlib import compress
16
16
 
17
17
  from fontTools.ttLib import TTFont as FT_TTFont
18
18
  from pypdf import PdfReader, PdfWriter
19
- from pypdf.generic import (ArrayObject, DictionaryObject, FloatObject,
20
- NameObject, NumberObject, StreamObject)
19
+ from pypdf.generic import (
20
+ ArrayObject,
21
+ DictionaryObject,
22
+ FloatObject,
23
+ NameObject,
24
+ NumberObject,
25
+ StreamObject,
26
+ )
21
27
  from reportlab.pdfbase.pdfmetrics import _fonts
22
28
  from reportlab.pdfbase.ttfonts import TTFError, TTFont
23
29
 
24
30
  from .assets.blank import BlankPage
25
- from .constants import (DEFAULT_ASSUMED_GLYPH_WIDTH, DR, EM_TO_PDF_FACTOR,
26
- ENCODING_TABLE_SIZE, FIRST_CHAR_CODE, FONT_NAME_PREFIX,
27
- LAST_CHAR_CODE, AcroForm, BaseFont, Encoding, Fields,
28
- Filter, FirstChar, FlateDecode, Font, FontCmap,
29
- FontDescriptor, FontFile2, FontHead, FontHmtx,
30
- FontName, FontNotdef, LastChar, Length, Length1,
31
- MissingWidth, Resources, Subtype, TrueType, Type,
32
- Widths, WinAnsiEncoding)
31
+ from .constants import (
32
+ DEFAULT_ASSUMED_GLYPH_WIDTH,
33
+ DR,
34
+ EM_TO_PDF_FACTOR,
35
+ ENCODING_TABLE_SIZE,
36
+ FIRST_CHAR_CODE,
37
+ FONT_NAME_PREFIX,
38
+ LAST_CHAR_CODE,
39
+ AcroForm,
40
+ BaseFont,
41
+ Encoding,
42
+ Fields,
43
+ Filter,
44
+ FirstChar,
45
+ FlateDecode,
46
+ Font,
47
+ FontCmap,
48
+ FontDescriptor,
49
+ FontFile2,
50
+ FontHead,
51
+ FontHmtx,
52
+ FontName,
53
+ FontNotdef,
54
+ LastChar,
55
+ Length,
56
+ Length1,
57
+ MissingWidth,
58
+ Resources,
59
+ Subtype,
60
+ TrueType,
61
+ Type,
62
+ Widths,
63
+ WinAnsiEncoding,
64
+ )
33
65
  from .raw.text import RawText
34
66
  from .watermark import create_watermarks_and_draw
35
67
 
@@ -287,7 +319,9 @@ def register_font_acroform(
287
319
  font_dict_ref = writer._add_object(font_dict) # type: ignore # noqa: SLF001 # # pylint: disable=W0212
288
320
 
289
321
  if AcroForm not in writer._root_object: # type: ignore # noqa: SLF001 # # pylint: disable=W0212
290
- writer._root_object[NameObject(AcroForm)] = DictionaryObject({NameObject(Fields): ArrayObject([])}) # type: ignore # noqa: SLF001 # # pylint: disable=W0212
322
+ writer._root_object[NameObject(AcroForm)] = DictionaryObject( # type: ignore # noqa: SLF001 # pylint: disable=W0212
323
+ {NameObject(Fields): ArrayObject([])}
324
+ )
291
325
  acroform = writer._root_object[AcroForm] # type: ignore # noqa: SLF001 # # pylint: disable=W0212
292
326
 
293
327
  if DR not in acroform:
@@ -14,15 +14,47 @@ from io import BytesIO
14
14
  from typing import TextIO, cast
15
15
 
16
16
  from pypdf import PdfReader, PdfWriter
17
- from pypdf.generic import (ArrayObject, DictionaryObject, FloatObject,
18
- NameObject, NumberObject, TextStringObject)
17
+ from pypdf.generic import (
18
+ ArrayObject,
19
+ DictionaryObject,
20
+ FloatObject,
21
+ NameObject,
22
+ NumberObject,
23
+ TextStringObject,
24
+ )
19
25
 
20
26
  from .adapter import fp_or_f_obj_or_f_content_to_content
21
- from .constants import (AA, COMB, DA, FONT_COLOR_IDENTIFIER,
22
- FONT_SIZE_IDENTIFIER, HIDDEN, JS, MULTILINE, READ_ONLY,
23
- REQUIRED, TU, Action, Annots, Bl, D, E, F, Ff, Fo,
24
- JavaScript, MaxLen, Opt, Parent, Q, Rect, S, Type, U,
25
- X)
27
+ from .constants import (
28
+ AA,
29
+ COMB,
30
+ DA,
31
+ FONT_COLOR_IDENTIFIER,
32
+ FONT_SIZE_IDENTIFIER,
33
+ HIDDEN,
34
+ JS,
35
+ MULTILINE,
36
+ READ_ONLY,
37
+ REQUIRED,
38
+ TU,
39
+ Action,
40
+ Annots,
41
+ Bl,
42
+ D,
43
+ E,
44
+ F,
45
+ Ff,
46
+ Fo,
47
+ JavaScript,
48
+ MaxLen,
49
+ Opt,
50
+ Parent,
51
+ Q,
52
+ Rect,
53
+ S,
54
+ Type,
55
+ U,
56
+ X,
57
+ )
26
58
  from .patterns import get_widget_key
27
59
 
28
60
 
@@ -10,12 +10,45 @@ for updating these widgets.
10
10
 
11
11
  from typing import Tuple
12
12
 
13
- from pypdf.generic import (ArrayObject, DictionaryObject, NameObject,
14
- NumberObject, TextStringObject)
15
-
16
- from .constants import (AP, AS, DV, FT, HIDDEN, IMAGE_FIELD_IDENTIFIER, JS,
17
- SLASH, TU, A, Btn, Ch, F, Ff, I, MaxLen, N, Off, Opt,
18
- Parent, Q, Rect, Sig, Subtype, T, Tx, V, Widget, Yes)
13
+ from pypdf.generic import (
14
+ ArrayObject,
15
+ DictionaryObject,
16
+ NameObject,
17
+ NumberObject,
18
+ TextStringObject,
19
+ )
20
+
21
+ from .constants import (
22
+ AP,
23
+ AS,
24
+ DV,
25
+ FT,
26
+ HIDDEN,
27
+ IMAGE_FIELD_IDENTIFIER,
28
+ JS,
29
+ SLASH,
30
+ TU,
31
+ A,
32
+ Btn,
33
+ Ch,
34
+ F,
35
+ Ff,
36
+ I,
37
+ MaxLen,
38
+ N,
39
+ Off,
40
+ Opt,
41
+ Parent,
42
+ Q,
43
+ Rect,
44
+ Sig,
45
+ Subtype,
46
+ T,
47
+ Tx,
48
+ V,
49
+ Widget,
50
+ Yes,
51
+ )
19
52
  from .middleware.checkbox import Checkbox
20
53
  from .middleware.dropdown import Dropdown
21
54
  from .middleware.image import Image
@@ -22,12 +22,22 @@ from .middleware.checkbox import Checkbox
22
22
  from .middleware.dropdown import Dropdown
23
23
  from .middleware.radio import Radio
24
24
  from .middleware.text import Text
25
- from .patterns import (WIDGET_DESCRIPTION_PATTERNS, WIDGET_TYPE_PATTERNS,
26
- check_field_flag, get_checkbox_value,
27
- get_dropdown_choices, get_dropdown_value,
28
- get_field_hidden, get_field_rect, get_radio_value,
29
- get_text_field_alignment, get_text_field_max_length,
30
- get_text_value, get_widget_key, update_annotation_name)
25
+ from .patterns import (
26
+ WIDGET_DESCRIPTION_PATTERNS,
27
+ WIDGET_TYPE_PATTERNS,
28
+ check_field_flag,
29
+ get_checkbox_value,
30
+ get_dropdown_choices,
31
+ get_dropdown_value,
32
+ get_field_hidden,
33
+ get_field_rect,
34
+ get_radio_value,
35
+ get_text_field_alignment,
36
+ get_text_field_max_length,
37
+ get_text_value,
38
+ get_widget_key,
39
+ update_annotation_name,
40
+ )
31
41
  from .utils import extract_widget_property, find_pattern_match
32
42
 
33
43
 
@@ -366,6 +376,51 @@ def create_annotations(
366
376
  return f.read()
367
377
 
368
378
 
379
+ def remove_widgets_by_keys(
380
+ pdf: bytes, keys: List[str], use_full_widget_name: bool = False
381
+ ) -> bytes:
382
+ """
383
+ Removes specific widgets from a PDF by their keys.
384
+
385
+ This function removes any widget annotation whose key matches one of the
386
+ provided keys. If no keys are provided, the original PDF stream is returned
387
+ unchanged.
388
+
389
+ Args:
390
+ pdf (bytes): The PDF stream to remove widgets from.
391
+ keys (List[str]): A list of widget keys to remove.
392
+ use_full_widget_name (bool): Whether to match widgets by their full
393
+ names, including parent names.
394
+
395
+ Returns:
396
+ bytes: The updated PDF stream with the matching widgets removed.
397
+ """
398
+ if not keys:
399
+ return pdf
400
+
401
+ writer = PdfWriter(BytesIO(pdf))
402
+
403
+ for page in writer.pages:
404
+ needs_update = False
405
+ page_annots = ArrayObject([])
406
+
407
+ for annot in page.get(Annots, []):
408
+ annot = cast(DictionaryObject, annot.get_object())
409
+ key = get_widget_key(annot.get_object(), use_full_widget_name)
410
+ if key not in keys:
411
+ page_annots.append(annot)
412
+ else:
413
+ needs_update = True
414
+
415
+ if needs_update:
416
+ page[NameObject(Annots)] = page_annots
417
+
418
+ with BytesIO() as f:
419
+ writer.write(f)
420
+ f.seek(0)
421
+ return f.read()
422
+
423
+
369
424
  def update_widget_keys(
370
425
  template: bytes,
371
426
  widgets: Dict[str, WIDGET_TYPES],
@@ -19,8 +19,7 @@ from io import BytesIO
19
19
  from typing import List, Optional, Type
20
20
 
21
21
  from pypdf import PdfReader, PdfWriter
22
- from pypdf.generic import (ArrayObject, FloatObject, NameObject,
23
- TextStringObject)
22
+ from pypdf.generic import ArrayObject, FloatObject, NameObject, TextStringObject
24
23
  from reportlab.pdfgen.canvas import Canvas
25
24
 
26
25
  from ..assets.bedrock import BEDROCK_PDF
@@ -22,30 +22,61 @@ from collections import defaultdict
22
22
  from dataclasses import asdict
23
23
  from functools import cached_property
24
24
  from os import PathLike
25
- from typing import (TYPE_CHECKING, BinaryIO, Dict, Optional, Sequence, TextIO,
26
- Tuple)
27
-
28
- from .adapter import (fp_or_f_obj_or_f_content_to_content,
29
- fp_or_f_obj_or_stream_to_stream)
25
+ from typing import (
26
+ TYPE_CHECKING,
27
+ BinaryIO,
28
+ Dict,
29
+ List,
30
+ Optional,
31
+ Sequence,
32
+ TextIO,
33
+ Tuple,
34
+ )
35
+
36
+ from .adapter import (
37
+ fp_or_f_obj_or_f_content_to_content,
38
+ fp_or_f_obj_or_stream_to_stream,
39
+ )
30
40
  from .constants import VERSION_IDENTIFIER_PREFIX, VERSION_IDENTIFIERS
31
41
  from .coordinate import generate_coordinate_grid
32
42
  from .egress import appearance_streams_handler, preserve_pdf_properties
33
43
  from .filler import fill
34
- from .font import (get_all_available_fonts, register_font_acroform,
35
- temporary_font_registration, validate_font)
44
+ from .font import (
45
+ get_all_available_fonts,
46
+ register_font_acroform,
47
+ temporary_font_registration,
48
+ validate_font,
49
+ )
36
50
  from .hooks import trigger_widget_hooks
37
51
  from .middleware.dropdown import Dropdown
38
52
  from .middleware.signature import Signature
39
53
  from .middleware.text import Text
40
- from .template import (build_widgets, create_annotations, get_metadata,
41
- update_widget_keys)
54
+ from .template import (
55
+ build_widgets,
56
+ create_annotations,
57
+ get_metadata,
58
+ remove_widgets_by_keys,
59
+ update_widget_keys,
60
+ )
42
61
  from .types import PdfArray
43
- from .utils import (generate_unique_suffix, get_page_streams, merge_pdfs,
44
- remove_all_widgets)
45
- from .watermark import (copy_watermark_widgets, create_watermarks_and_draw,
46
- merge_watermarks_with_pdf)
47
- from .widgets import (CheckBoxField, DropdownField, ImageField, RadioGroup,
48
- SignatureField)
62
+ from .utils import (
63
+ generate_unique_suffix,
64
+ get_page_streams,
65
+ merge_pdfs,
66
+ remove_all_widgets,
67
+ )
68
+ from .watermark import (
69
+ copy_watermark_widgets,
70
+ create_watermarks_and_draw,
71
+ merge_watermarks_with_pdf,
72
+ )
73
+ from .widgets import (
74
+ CheckBoxField,
75
+ DropdownField,
76
+ ImageField,
77
+ RadioGroup,
78
+ SignatureField,
79
+ )
49
80
 
50
81
  if TYPE_CHECKING:
51
82
  from .annotations import AnnotationTypes
@@ -665,6 +696,27 @@ class PdfWrapper:
665
696
 
666
697
  return self
667
698
 
699
+ def remove_fields(self, keys: List[str]) -> PdfWrapper:
700
+ """
701
+ Removes form fields from the PDF by their keys.
702
+
703
+ This method removes any fields whose keys are included in `keys` and
704
+ refreshes the wrapper's widget metadata after the PDF stream is updated.
705
+
706
+ Args:
707
+ keys (List[str]): A list of form field keys to remove.
708
+
709
+ Returns:
710
+ PdfWrapper: The `PdfWrapper` object, allowing for method chaining.
711
+ """
712
+
713
+ self._stream = remove_widgets_by_keys(
714
+ self._read(), keys, getattr(self, "use_full_widget_name")
715
+ )
716
+ self._init_helper()
717
+
718
+ return self
719
+
668
720
  def update_widget_key(
669
721
  self, old_key: str, new_key: str, index: int = 0
670
722
  ) -> PdfWrapper:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 5.1.1
3
+ Version: 5.2.0
4
4
  Summary: The Python library & CLI for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -34,9 +34,7 @@ Provides-Extra: cli
34
34
  Requires-Dist: typer<1.0.0,>=0.26.1; extra == "cli"
35
35
  Requires-Dist: jsonschema<5.0.0,>=4.26.0; extra == "cli"
36
36
  Provides-Extra: dev
37
- Requires-Dist: black<27.0.0,>=26.5.1; extra == "dev"
38
37
  Requires-Dist: coverage<8.0.0,>=7.14.1; extra == "dev"
39
- Requires-Dist: isort<9.0.0,>=8.0.1; extra == "dev"
40
38
  Requires-Dist: mike<3.0.0,>=2.2.0; extra == "dev"
41
39
  Requires-Dist: mkdocs<2.0.0,>=1.6.1; extra == "dev"
42
40
  Requires-Dist: mkdocs-material<10.0.0,>=9.7.6; extra == "dev"
@@ -13,6 +13,7 @@ PyPDFForm/cli/common.py
13
13
  PyPDFForm/cli/create.py
14
14
  PyPDFForm/cli/entry.py
15
15
  PyPDFForm/cli/inspect.py
16
+ PyPDFForm/cli/remove.py
16
17
  PyPDFForm/cli/root.py
17
18
  PyPDFForm/cli/update.py
18
19
  PyPDFForm/cli/schemas/__init__.py
@@ -10,9 +10,7 @@ typer<1.0.0,>=0.26.1
10
10
  jsonschema<5.0.0,>=4.26.0
11
11
 
12
12
  [dev]
13
- black<27.0.0,>=26.5.1
14
13
  coverage<8.0.0,>=7.14.1
15
- isort<9.0.0,>=8.0.1
16
14
  mike<3.0.0,>=2.2.0
17
15
  mkdocs<2.0.0,>=1.6.1
18
16
  mkdocs-material<10.0.0,>=9.7.6
@@ -45,9 +45,7 @@ Documentation = "https://chinapandaman.github.io/PyPDFForm/"
45
45
  # update `CLI_DEPENDENCIES` in `PyPDFForm/cli/entry.py` when changing cli dependencies
46
46
  cli = ["typer>=0.26.1,<1.0.0", "jsonschema>=4.26.0,<5.0.0"]
47
47
  dev = [
48
- "black>=26.5.1,<27.0.0",
49
48
  "coverage>=7.14.1,<8.0.0",
50
- "isort>=8.0.1,<9.0.0",
51
49
  "mike>=2.2.0,<3.0.0",
52
50
  "mkdocs>=1.6.1,<2.0.0",
53
51
  "mkdocs-material>=9.7.6,<10.0.0",
@@ -13,9 +13,16 @@ from fontTools.ttLib import TTLibError
13
13
  from pypdf import PdfWriter
14
14
 
15
15
  from PyPDFForm import PdfWrapper
16
- from PyPDFForm.lib.constants import (DEFAULT_ASSUMED_GLYPH_WIDTH, DR,
17
- ENCODING_TABLE_SIZE, AcroForm, Font,
18
- FontDescriptor, MissingWidth, Widths)
16
+ from PyPDFForm.lib.constants import (
17
+ DEFAULT_ASSUMED_GLYPH_WIDTH,
18
+ DR,
19
+ ENCODING_TABLE_SIZE,
20
+ AcroForm,
21
+ Font,
22
+ FontDescriptor,
23
+ MissingWidth,
24
+ Widths,
25
+ )
19
26
  from PyPDFForm.lib.font import compute_font_glyph_widths
20
27
 
21
28
 
@@ -834,6 +834,19 @@ def test_hidden_sejda(sejda_template, pdf_samples, request):
834
834
  assert obj.read() == expected
835
835
 
836
836
 
837
+ def test_remove_fields_update_widgets(template_stream):
838
+ obj = PdfWrapper(template_stream)
839
+ obj.remove_fields(["test", "test_2", "check_2"])
840
+
841
+ assert "test" not in obj.widgets
842
+ assert "test_2" not in obj.widgets
843
+ assert "check_2" not in obj.widgets
844
+
845
+
846
+ def test_remove_fields_no_keys_specified(template_stream):
847
+ assert PdfWrapper(template_stream).remove_fields([]).read() == template_stream
848
+
849
+
837
850
  def test_merge(template_stream):
838
851
  pdf_list = PdfArray()
839
852
  for i in range(20):
@@ -44,25 +44,25 @@ def test_text_field_scripts(template_stream, pdf_samples, request):
44
44
  expected_path = os.path.join(pdf_samples, "js", "test_text_field_scripts.pdf")
45
45
  with open(expected_path, "rb+") as f:
46
46
  pdf = PdfWrapper(template_stream)
47
- pdf.widgets["test"].on_hovered_over_javascript = (
48
- 'this.getField("test").value = "hoverover";'
49
- )
50
- pdf.widgets["test"].on_hovered_off_javascript = (
51
- 'this.getField("test").value = "hoveroff";'
52
- )
53
- pdf.widgets["test"].on_mouse_pressed_javascript = (
54
- 'this.getField("test").value = "pressed";'
55
- )
56
- pdf.widgets["test"].on_mouse_released_javascript = (
57
- 'this.getField("test").value = "released";'
58
- )
59
-
60
- pdf.widgets["test_2"].on_focused_javascript = (
61
- 'this.getField("test_2").value = "focused";'
62
- )
63
- pdf.widgets["test_2"].on_blurred_javascript = (
64
- 'this.getField("test_2").value = "defocused";'
65
- )
47
+ pdf.widgets[
48
+ "test"
49
+ ].on_hovered_over_javascript = 'this.getField("test").value = "hoverover";'
50
+ pdf.widgets[
51
+ "test"
52
+ ].on_hovered_off_javascript = 'this.getField("test").value = "hoveroff";'
53
+ pdf.widgets[
54
+ "test"
55
+ ].on_mouse_pressed_javascript = 'this.getField("test").value = "pressed";'
56
+ pdf.widgets[
57
+ "test"
58
+ ].on_mouse_released_javascript = 'this.getField("test").value = "released";'
59
+
60
+ pdf.widgets[
61
+ "test_2"
62
+ ].on_focused_javascript = 'this.getField("test_2").value = "focused";'
63
+ pdf.widgets[
64
+ "test_2"
65
+ ].on_blurred_javascript = 'this.getField("test_2").value = "defocused";'
66
66
 
67
67
  request.config.results["expected_path"] = expected_path
68
68
  request.config.results["stream"] = pdf.read()
@@ -77,25 +77,25 @@ def test_checkbox_scripts(template_stream, pdf_samples, request):
77
77
  expected_path = os.path.join(pdf_samples, "js", "test_checkbox_scripts.pdf")
78
78
  with open(expected_path, "rb+") as f:
79
79
  pdf = PdfWrapper(template_stream)
80
- pdf.widgets["check"].on_hovered_over_javascript = (
81
- 'this.getField("test").value = "hoverover";'
82
- )
83
- pdf.widgets["check"].on_hovered_off_javascript = (
84
- 'this.getField("test").value = "hoveroff";'
85
- )
86
- pdf.widgets["check"].on_mouse_pressed_javascript = (
87
- 'this.getField("test").value = "pressed";'
88
- )
89
- pdf.widgets["check"].on_mouse_released_javascript = (
90
- 'this.getField("test").value = "released";'
91
- )
92
-
93
- pdf.widgets["check_2"].on_focused_javascript = (
94
- 'this.getField("test_2").value = "focused";'
95
- )
96
- pdf.widgets["check_2"].on_blurred_javascript = (
97
- 'this.getField("test_2").value = "defocused";'
98
- )
80
+ pdf.widgets[
81
+ "check"
82
+ ].on_hovered_over_javascript = 'this.getField("test").value = "hoverover";'
83
+ pdf.widgets[
84
+ "check"
85
+ ].on_hovered_off_javascript = 'this.getField("test").value = "hoveroff";'
86
+ pdf.widgets[
87
+ "check"
88
+ ].on_mouse_pressed_javascript = 'this.getField("test").value = "pressed";'
89
+ pdf.widgets[
90
+ "check"
91
+ ].on_mouse_released_javascript = 'this.getField("test").value = "released";'
92
+
93
+ pdf.widgets[
94
+ "check_2"
95
+ ].on_focused_javascript = 'this.getField("test_2").value = "focused";'
96
+ pdf.widgets[
97
+ "check_2"
98
+ ].on_blurred_javascript = 'this.getField("test_2").value = "defocused";'
99
99
 
100
100
  request.config.results["expected_path"] = expected_path
101
101
  request.config.results["stream"] = pdf.read()
@@ -110,25 +110,25 @@ def test_radio_scripts(template_with_radiobutton_stream, pdf_samples, request):
110
110
  expected_path = os.path.join(pdf_samples, "js", "test_radio_scripts.pdf")
111
111
  with open(expected_path, "rb+") as f:
112
112
  pdf = PdfWrapper(template_with_radiobutton_stream)
113
- pdf.widgets["radio_1"].on_hovered_over_javascript = (
114
- 'this.getField("test").value = "hoverover";'
115
- )
116
- pdf.widgets["radio_1"].on_hovered_off_javascript = (
117
- 'this.getField("test").value = "hoveroff";'
118
- )
119
- pdf.widgets["radio_1"].on_mouse_pressed_javascript = (
120
- 'this.getField("test").value = "pressed";'
121
- )
122
- pdf.widgets["radio_1"].on_mouse_released_javascript = (
123
- 'this.getField("test").value = "released";'
124
- )
125
-
126
- pdf.widgets["radio_2"].on_focused_javascript = (
127
- 'this.getField("test_2").value = "focused";'
128
- )
129
- pdf.widgets["radio_2"].on_blurred_javascript = (
130
- 'this.getField("test_2").value = "defocused";'
131
- )
113
+ pdf.widgets[
114
+ "radio_1"
115
+ ].on_hovered_over_javascript = 'this.getField("test").value = "hoverover";'
116
+ pdf.widgets[
117
+ "radio_1"
118
+ ].on_hovered_off_javascript = 'this.getField("test").value = "hoveroff";'
119
+ pdf.widgets[
120
+ "radio_1"
121
+ ].on_mouse_pressed_javascript = 'this.getField("test").value = "pressed";'
122
+ pdf.widgets[
123
+ "radio_1"
124
+ ].on_mouse_released_javascript = 'this.getField("test").value = "released";'
125
+
126
+ pdf.widgets[
127
+ "radio_2"
128
+ ].on_focused_javascript = 'this.getField("test_2").value = "focused";'
129
+ pdf.widgets[
130
+ "radio_2"
131
+ ].on_blurred_javascript = 'this.getField("test_2").value = "defocused";'
132
132
 
133
133
  request.config.results["expected_path"] = expected_path
134
134
  request.config.results["stream"] = pdf.read()
@@ -143,25 +143,25 @@ def test_dropdown_scripts(sample_template_with_dropdown, pdf_samples, request):
143
143
  expected_path = os.path.join(pdf_samples, "js", "test_dropdown_scripts.pdf")
144
144
  with open(expected_path, "rb+") as f:
145
145
  pdf = PdfWrapper(sample_template_with_dropdown)
146
- pdf.widgets["dropdown_1"].on_hovered_over_javascript = (
147
- 'this.getField("test_1").value = "hoverover";'
148
- )
149
- pdf.widgets["dropdown_1"].on_hovered_off_javascript = (
150
- 'this.getField("test_1").value = "hoveroff";'
151
- )
152
- pdf.widgets["dropdown_1"].on_mouse_pressed_javascript = (
153
- 'this.getField("test_1").value = "pressed";'
154
- )
155
- pdf.widgets["dropdown_1"].on_mouse_released_javascript = (
156
- 'this.getField("test_1").value = "released";'
157
- )
158
-
159
- pdf.widgets["dropdown_1"].on_focused_javascript = (
160
- 'this.getField("test_2").value = "focused";'
161
- )
162
- pdf.widgets["dropdown_1"].on_blurred_javascript = (
163
- 'this.getField("test_2").value = "defocused";'
164
- )
146
+ pdf.widgets[
147
+ "dropdown_1"
148
+ ].on_hovered_over_javascript = 'this.getField("test_1").value = "hoverover";'
149
+ pdf.widgets[
150
+ "dropdown_1"
151
+ ].on_hovered_off_javascript = 'this.getField("test_1").value = "hoveroff";'
152
+ pdf.widgets[
153
+ "dropdown_1"
154
+ ].on_mouse_pressed_javascript = 'this.getField("test_1").value = "pressed";'
155
+ pdf.widgets[
156
+ "dropdown_1"
157
+ ].on_mouse_released_javascript = 'this.getField("test_1").value = "released";'
158
+
159
+ pdf.widgets[
160
+ "dropdown_1"
161
+ ].on_focused_javascript = 'this.getField("test_2").value = "focused";'
162
+ pdf.widgets[
163
+ "dropdown_1"
164
+ ].on_blurred_javascript = 'this.getField("test_2").value = "defocused";'
165
165
 
166
166
  request.config.results["expected_path"] = expected_path
167
167
  request.config.results["stream"] = pdf.read()
@@ -176,25 +176,25 @@ def test_image_scripts(sample_template_with_image_field, pdf_samples, request):
176
176
  expected_path = os.path.join(pdf_samples, "js", "test_image_scripts.pdf")
177
177
  with open(expected_path, "rb+") as f:
178
178
  pdf = PdfWrapper(sample_template_with_image_field)
179
- pdf.widgets["image_1"].on_hovered_over_javascript = (
180
- 'this.getField("test").value = "hoverover";'
181
- )
182
- pdf.widgets["image_1"].on_hovered_off_javascript = (
183
- 'this.getField("test").value = "hoveroff";'
184
- )
185
- pdf.widgets["image_1"].on_mouse_pressed_javascript = (
186
- 'this.getField("test").value = "pressed";'
187
- )
188
- pdf.widgets["image_1"].on_mouse_released_javascript = (
189
- 'this.getField("test").value = "released";'
190
- )
191
-
192
- pdf.widgets["image_1"].on_focused_javascript = (
193
- 'this.getField("test_2").value = "focused";'
194
- )
195
- pdf.widgets["image_1"].on_blurred_javascript = (
196
- 'this.getField("test_2").value = "defocused";'
197
- )
179
+ pdf.widgets[
180
+ "image_1"
181
+ ].on_hovered_over_javascript = 'this.getField("test").value = "hoverover";'
182
+ pdf.widgets[
183
+ "image_1"
184
+ ].on_hovered_off_javascript = 'this.getField("test").value = "hoveroff";'
185
+ pdf.widgets[
186
+ "image_1"
187
+ ].on_mouse_pressed_javascript = 'this.getField("test").value = "pressed";'
188
+ pdf.widgets[
189
+ "image_1"
190
+ ].on_mouse_released_javascript = 'this.getField("test").value = "released";'
191
+
192
+ pdf.widgets[
193
+ "image_1"
194
+ ].on_focused_javascript = 'this.getField("test_2").value = "focused";'
195
+ pdf.widgets[
196
+ "image_1"
197
+ ].on_blurred_javascript = 'this.getField("test_2").value = "defocused";'
198
198
 
199
199
  request.config.results["expected_path"] = expected_path
200
200
  request.config.results["stream"] = pdf.read()
@@ -45,3 +45,11 @@ def test_schema(sample_template_with_full_key):
45
45
  obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
46
46
  assert "Gain de 2 classes.0" in obj.schema["properties"]
47
47
  assert "0" not in obj.schema
48
+
49
+
50
+ def test_remove_fields(sample_template_with_full_key):
51
+ obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
52
+ obj.remove_fields(["Gain de 2 classes.0"])
53
+
54
+ assert "Gain de 2 classes.0" not in obj.widgets
55
+ assert "0" not in obj.widgets
File without changes
File without changes
File without changes