PyPDFForm 4.5.2__tar.gz → 4.6.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. {pypdfform-4.5.2 → pypdfform-4.6.0}/PKG-INFO +1 -1
  2. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/__init__.py +1 -1
  3. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/annotations/__init__.py +17 -2
  4. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/annotations/base.py +14 -0
  5. pypdfform-4.6.0/PyPDFForm/annotations/link.py +57 -0
  6. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/annotations/text.py +18 -6
  7. pypdfform-4.6.0/PyPDFForm/annotations/text_markup.py +82 -0
  8. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/raw/__init__.py +1 -1
  9. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/template.py +1 -4
  10. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/widgets/__init__.py +1 -1
  11. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm.egg-info/PKG-INFO +1 -1
  12. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm.egg-info/SOURCES.txt +2 -0
  13. {pypdfform-4.5.2 → pypdfform-4.6.0}/pyproject.toml +1 -0
  14. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_functional.py +12 -0
  15. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_generate_appearance_streams.py +8 -93
  16. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_need_appearances.py +119 -88
  17. {pypdfform-4.5.2 → pypdfform-4.6.0}/LICENSE +0 -0
  18. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/adapter.py +0 -0
  19. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/ap.py +0 -0
  20. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/assets/__init__.py +0 -0
  21. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/assets/bedrock.py +0 -0
  22. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/assets/blank.py +0 -0
  23. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/constants.py +0 -0
  24. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/coordinate.py +0 -0
  25. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/deprecation.py +0 -0
  26. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/filler.py +0 -0
  27. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/font.py +0 -0
  28. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/hooks.py +0 -0
  29. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/image.py +0 -0
  30. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/middleware/__init__.py +0 -0
  31. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/middleware/base.py +0 -0
  32. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/middleware/checkbox.py +0 -0
  33. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/middleware/dropdown.py +0 -0
  34. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/middleware/image.py +0 -0
  35. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/middleware/radio.py +0 -0
  36. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/middleware/signature.py +0 -0
  37. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/middleware/text.py +0 -0
  38. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/patterns.py +0 -0
  39. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/raw/circle.py +0 -0
  40. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/raw/ellipse.py +0 -0
  41. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/raw/image.py +0 -0
  42. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/raw/line.py +0 -0
  43. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/raw/rect.py +0 -0
  44. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/raw/text.py +0 -0
  45. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/types.py +0 -0
  46. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/utils.py +0 -0
  47. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/watermark.py +0 -0
  48. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/widgets/base.py +0 -0
  49. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/widgets/checkbox.py +0 -0
  50. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/widgets/dropdown.py +0 -0
  51. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/widgets/image.py +0 -0
  52. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/widgets/radio.py +0 -0
  53. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/widgets/signature.py +0 -0
  54. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/widgets/text.py +0 -0
  55. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm/wrapper.py +0 -0
  56. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm.egg-info/dependency_links.txt +0 -0
  57. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm.egg-info/requires.txt +0 -0
  58. {pypdfform-4.5.2 → pypdfform-4.6.0}/PyPDFForm.egg-info/top_level.txt +0 -0
  59. {pypdfform-4.5.2 → pypdfform-4.6.0}/README.md +0 -0
  60. {pypdfform-4.5.2 → pypdfform-4.6.0}/setup.cfg +0 -0
  61. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_bulk_create_fields.py +0 -0
  62. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_create_widget.py +0 -0
  63. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_draw_elements.py +0 -0
  64. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_dropdown.py +0 -0
  65. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_extract_middleware_attributes.py +0 -0
  66. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_fill_max_length_text_field.py +0 -0
  67. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_font_widths.py +0 -0
  68. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_js.py +0 -0
  69. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_paragraph.py +0 -0
  70. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_signature.py +0 -0
  71. {pypdfform-4.5.2 → pypdfform-4.6.0}/tests/test_use_full_widget_name.py +0 -0
  72. {pypdfform-4.5.2 → pypdfform-4.6.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: 4.5.2
3
+ Version: 4.6.0
4
4
  Summary: The Python library for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -20,7 +20,7 @@ The library supports various PDF form features, including:
20
20
  PyPDFForm aims to simplify PDF form manipulation, making it accessible to developers of all skill levels.
21
21
  """
22
22
 
23
- __version__ = "4.5.2"
23
+ __version__ = "4.6.0"
24
24
 
25
25
  from .annotations import Annotations
26
26
  from .assets.blank import BlankPage
@@ -2,7 +2,7 @@
2
2
  """
3
3
  The `annotations` package provides classes representing various types of PDF annotations.
4
4
 
5
- It defines `AnnotationTypes` as a Union of all supported annotation types, allowing for
5
+ It defines `AnnotationTypes` as a collection of all supported annotation types, allowing for
6
6
  flexible type hinting when working with different annotation configurations.
7
7
 
8
8
  Classes within this package encapsulate the properties and behaviors of individual
@@ -11,9 +11,19 @@ annotations, facilitating their creation and manipulation within PDF documents.
11
11
 
12
12
  from dataclasses import dataclass
13
13
 
14
+ from .link import LinkAnnotation
14
15
  from .text import TextAnnotation
16
+ from .text_markup import (HighlightAnnotation, SquigglyAnnotation,
17
+ StrikeOutAnnotation, UnderlineAnnotation)
15
18
 
16
- AnnotationTypes = TextAnnotation
19
+ AnnotationTypes = (
20
+ TextAnnotation
21
+ | LinkAnnotation
22
+ | HighlightAnnotation
23
+ | UnderlineAnnotation
24
+ | SquigglyAnnotation
25
+ | StrikeOutAnnotation
26
+ )
17
27
 
18
28
 
19
29
  @dataclass
@@ -26,3 +36,8 @@ class Annotations:
26
36
  """
27
37
 
28
38
  TextAnnotation = TextAnnotation
39
+ LinkAnnotation = LinkAnnotation
40
+ HighlightAnnotation = HighlightAnnotation
41
+ UnderlineAnnotation = UnderlineAnnotation
42
+ SquigglyAnnotation = SquigglyAnnotation
43
+ StrikeOutAnnotation = StrikeOutAnnotation
@@ -36,3 +36,17 @@ class Annotation:
36
36
  width: float = 20
37
37
  height: float = 20
38
38
  contents: str = ""
39
+
40
+ def get_specific_properties(self) -> dict:
41
+ """
42
+ Gets properties specific to the annotation type.
43
+
44
+ This method should be implemented by subclasses to return a dictionary
45
+ containing PDF properties and their values that are unique to that
46
+ specific type of annotation. These properties are used when creating
47
+ the annotation's entry in the PDF document.
48
+
49
+ Returns:
50
+ dict: A dictionary of PDF properties specific to the annotation type.
51
+ """
52
+ raise NotImplementedError
@@ -0,0 +1,57 @@
1
+ # -*- coding: utf-8 -*-
2
+ # TODO: finish other features
3
+ """
4
+ This module defines the class for link annotations in PyPDFForm.
5
+
6
+ It provides a structure for representing and interacting with PDF link
7
+ annotations, which allow users to click and navigate to a URI.
8
+
9
+ Classes:
10
+ - `LinkAnnotation`: A dataclass representing the properties of a PDF link annotation.
11
+ """
12
+
13
+ from dataclasses import dataclass
14
+ from typing import Optional
15
+
16
+ from pypdf.generic import DictionaryObject, NameObject, TextStringObject
17
+
18
+ from ..constants import A, S
19
+ from .base import Annotation
20
+
21
+
22
+ @dataclass
23
+ class LinkAnnotation(Annotation):
24
+ """
25
+ A dataclass representing the properties of a PDF link annotation.
26
+
27
+ This class extends the `Annotation` base class to specifically handle
28
+ link annotations, including the target URI.
29
+
30
+ Attributes:
31
+ uri (str): The URI that the link annotation points to. Defaults to None.
32
+ """
33
+
34
+ _annotation_type: str = "/Link"
35
+
36
+ uri: Optional[str] = None
37
+
38
+ def get_specific_properties(self) -> dict:
39
+ """
40
+ Gets properties specific to the link annotation type.
41
+
42
+ This method returns a dictionary containing PDF properties and their
43
+ values that are unique to a link annotation, perforated with the URI action.
44
+
45
+ Returns:
46
+ dict: A dictionary of PDF properties specific to the link annotation.
47
+ """
48
+ result = {}
49
+ if self.uri is not None:
50
+ result[NameObject(A)] = DictionaryObject(
51
+ {
52
+ NameObject(S): NameObject("/URI"),
53
+ NameObject("/URI"): TextStringObject(self.uri),
54
+ }
55
+ )
56
+
57
+ return result
@@ -27,8 +27,6 @@ class TextAnnotation(Annotation):
27
27
 
28
28
  Attributes:
29
29
  _annotation_type (str): The PDF internal type of the annotation, which is "/Text".
30
- _additional_properties (tuple): A tuple defining how specific attributes are mapped
31
- to PDF dictionary keys for the annotation.
32
30
  note_icon (str): The identifier for a "Note" icon.
33
31
  comment_icon (str): The identifier for a "Comment" icon.
34
32
  help_icon (str): The identifier for a "Help" icon.
@@ -39,10 +37,6 @@ class TextAnnotation(Annotation):
39
37
  """
40
38
 
41
39
  _annotation_type: str = "/Text"
42
- _additional_properties: tuple = (
43
- (NameObject(T), (TextStringObject, "title")),
44
- (NameObject("/Name"), (NameObject, "icon")),
45
- )
46
40
 
47
41
  note_icon: str = "/Note"
48
42
  comment_icon: str = "/Comment"
@@ -52,3 +46,21 @@ class TextAnnotation(Annotation):
52
46
 
53
47
  title: Optional[str] = None
54
48
  icon: Optional[str] = None
49
+
50
+ def get_specific_properties(self) -> dict:
51
+ """
52
+ Gets properties specific to the text annotation.
53
+
54
+ This method includes the title (author) and the icon name for the
55
+ text annotation if they are provided.
56
+
57
+ Returns:
58
+ dict: A dictionary of PDF properties specific to the text annotation.
59
+ """
60
+ result = {}
61
+ if self.title is not None:
62
+ result[NameObject(T)] = TextStringObject(self.title)
63
+ if self.icon is not None:
64
+ result[NameObject("/Name")] = NameObject(self.icon)
65
+
66
+ return result
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ This module defines the `TextMarkupAnnotation` class and its subclasses,
4
+ which are used to represent text markup annotations in a PDF document.
5
+
6
+ Classes:
7
+ - `TextMarkupAnnotation`: Base class for all text markup annotations.
8
+ - `HighlightAnnotation`: Represents a highlight annotation.
9
+ - `UnderlineAnnotation`: Represents an underline annotation.
10
+ - `SquigglyAnnotation`: Represents a squiggly (curly) underline annotation.
11
+ - `StrikeOutAnnotation`: Represents a strikeout annotation.
12
+ """
13
+
14
+ from dataclasses import dataclass
15
+
16
+ from pypdf.generic import ArrayObject, FloatObject, NameObject
17
+
18
+ from .base import Annotation
19
+
20
+
21
+ @dataclass
22
+ class TextMarkupAnnotation(Annotation):
23
+ """
24
+ Base dataclass for all text markup annotations.
25
+
26
+ Text markup annotations appear as marks on the text of a document,
27
+ such as highlights, underlines, etc. They are defined by a set of
28
+ quadrilateral points (QuadPoints) that encompass the text being marked.
29
+ """
30
+
31
+ def get_specific_properties(self) -> dict:
32
+ """
33
+ Gets properties specific to the text markup annotation.
34
+
35
+ This method calculates the `QuadPoints` for the markup based on the
36
+ annotation's position and dimensions.
37
+
38
+ Returns:
39
+ dict: A dictionary containing the `/QuadPoints` property.
40
+ """
41
+ return {
42
+ NameObject("/QuadPoints"): ArrayObject(
43
+ [
44
+ FloatObject(self.x),
45
+ FloatObject(self.y),
46
+ FloatObject(self.x + self.width),
47
+ FloatObject(self.y),
48
+ FloatObject(self.x),
49
+ FloatObject(self.y + self.height),
50
+ FloatObject(self.x + self.width),
51
+ FloatObject(self.y + self.height),
52
+ ]
53
+ )
54
+ }
55
+
56
+
57
+ @dataclass
58
+ class HighlightAnnotation(TextMarkupAnnotation):
59
+ """Represents a highlight annotation."""
60
+
61
+ _annotation_type: str = "/Highlight"
62
+
63
+
64
+ @dataclass
65
+ class UnderlineAnnotation(TextMarkupAnnotation):
66
+ """Represents an underline annotation."""
67
+
68
+ _annotation_type: str = "/Underline"
69
+
70
+
71
+ @dataclass
72
+ class SquigglyAnnotation(TextMarkupAnnotation):
73
+ """Represents a squiggly (curly) underline annotation."""
74
+
75
+ _annotation_type: str = "/Squiggly"
76
+
77
+
78
+ @dataclass
79
+ class StrikeOutAnnotation(TextMarkupAnnotation):
80
+ """Represents a strikeout annotation."""
81
+
82
+ _annotation_type: str = "/StrikeOut"
@@ -3,7 +3,7 @@
3
3
  The `raw` package provides classes representing raw drawable elements
4
4
  (like text and images) that can be rendered directly onto a PDF document.
5
5
 
6
- It defines `RawTypes` as a Union of all supported raw element types, used for
6
+ It defines `RawTypes` as a collection of all supported raw element types, used for
7
7
  type hinting in methods that handle drawing onto the PDF.
8
8
  """
9
9
 
@@ -358,10 +358,7 @@ def _create_annotation_object(annotation: AnnotationTypes) -> DictionaryObject:
358
358
  NameObject(Contents): TextStringObject(annotation.contents),
359
359
  }
360
360
  )
361
- for k, v in getattr(annotation, "_additional_properties", ()):
362
- val = getattr(annotation, v[1])
363
- if val is not None:
364
- annot[k] = v[0](val)
361
+ annot.update(**annotation.get_specific_properties())
365
362
  return annot
366
363
 
367
364
 
@@ -2,7 +2,7 @@
2
2
  """
3
3
  The `widgets` package provides a collection of classes representing various types of PDF form fields (widgets).
4
4
 
5
- It defines `FieldTypes` as a Union of all supported field types, allowing for flexible
5
+ It defines `FieldTypes` as a collection of all supported field types, allowing for flexible
6
6
  type hinting when working with different widget configurations.
7
7
 
8
8
  Classes within this package encapsulate the properties and behaviors of individual
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 4.5.2
3
+ Version: 4.6.0
4
4
  Summary: The Python library for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -24,7 +24,9 @@ PyPDFForm.egg-info/requires.txt
24
24
  PyPDFForm.egg-info/top_level.txt
25
25
  PyPDFForm/annotations/__init__.py
26
26
  PyPDFForm/annotations/base.py
27
+ PyPDFForm/annotations/link.py
27
28
  PyPDFForm/annotations/text.py
29
+ PyPDFForm/annotations/text_markup.py
28
30
  PyPDFForm/assets/__init__.py
29
31
  PyPDFForm/assets/bedrock.py
30
32
  PyPDFForm/assets/blank.py
@@ -105,6 +105,7 @@ select = [
105
105
  "TCH",
106
106
  "YTT",
107
107
  "W",
108
+ "UP007",
108
109
  ]
109
110
  ignore = ["B009", "E501", "N999", "Q000", "TC006", "N816"]
110
111
 
@@ -7,6 +7,7 @@ import pytest
7
7
  from jsonschema import ValidationError, validate
8
8
 
9
9
  from PyPDFForm import Annotations, BlankPage, Fields, PdfArray, PdfWrapper
10
+ from PyPDFForm.annotations.base import Annotation
10
11
  from PyPDFForm.constants import DA, UNIQUE_SUFFIX_LENGTH, T, V
11
12
  from PyPDFForm.deprecation import deprecation_notice
12
13
  from PyPDFForm.middleware.base import Widget
@@ -788,6 +789,17 @@ def test_merge(template_stream):
788
789
  assert field[V] == f"test_3_{int(page / 3 - 0.5)}"
789
790
 
790
791
 
792
+ def test_base_annotation_get_specific_properties_not_implemented():
793
+ annotation = Annotation(1, 100, 100)
794
+ try:
795
+ annotation.get_specific_properties()
796
+ pytest.fail(
797
+ reason="base annotation shouldn't have get_specific_properties implemented."
798
+ )
799
+ except NotImplementedError:
800
+ pass
801
+
802
+
791
803
  def test_annotate(template_stream, pdf_samples, request):
792
804
  expected_path = os.path.join(pdf_samples, "test_annotate.pdf")
793
805
  with open(expected_path, "rb+") as f:
@@ -5,7 +5,8 @@ import os
5
5
 
6
6
  import pytest
7
7
 
8
- from PyPDFForm import Fields, PdfWrapper
8
+ from PyPDFForm import PdfWrapper
9
+ from tests.test_need_appearances import run_sample_template_library_test
9
10
 
10
11
 
11
12
  def test_fill(template_stream, pdf_samples, data_dict, request):
@@ -106,96 +107,10 @@ def test_issue_613(pdf_samples, request):
106
107
  def test_sample_template_library(
107
108
  pdf_samples, image_samples, sample_font_stream, request
108
109
  ):
109
- expected_path = os.path.join(
110
- pdf_samples, "generate_appearance_streams", "test_sample_template_library.pdf"
110
+ run_sample_template_library_test(
111
+ pdf_samples,
112
+ image_samples,
113
+ sample_font_stream,
114
+ request,
115
+ generate_appearance_streams=True,
111
116
  )
112
-
113
- with open(expected_path, "rb+") as f:
114
- obj = (
115
- PdfWrapper(
116
- os.path.join(pdf_samples, "dummy.pdf"), generate_appearance_streams=True
117
- )
118
- .register_font("new_font", sample_font_stream)
119
- .create_field(
120
- Fields.TextField(
121
- name="new_text_field_widget",
122
- page_number=1,
123
- x=60,
124
- y=710,
125
- )
126
- )
127
- .create_field(
128
- Fields.CheckBoxField(
129
- name="new_checkbox_widget",
130
- page_number=1,
131
- x=100,
132
- y=600,
133
- )
134
- )
135
- .create_field(
136
- Fields.RadioGroup(
137
- name="new_radio_group",
138
- page_number=1,
139
- x=[50, 100, 150],
140
- y=[50, 100, 150],
141
- )
142
- )
143
- .create_field(
144
- Fields.DropdownField(
145
- name="new_dropdown_widget",
146
- page_number=1,
147
- x=300,
148
- y=710,
149
- options=[
150
- "foo",
151
- "bar",
152
- "foobar",
153
- ],
154
- font="new_font",
155
- )
156
- )
157
- .create_field(
158
- Fields.ImageField(
159
- name="new_image_widget",
160
- page_number=1,
161
- x=300,
162
- y=200,
163
- )
164
- )
165
- .create_field(
166
- Fields.SignatureField(
167
- name="new_signature_wiget",
168
- page_number=1,
169
- x=300,
170
- y=400,
171
- )
172
- )
173
- .fill(
174
- {
175
- "new_text_field_widget": "test text",
176
- "new_checkbox_widget": True,
177
- "new_radio_group": 1,
178
- "new_dropdown_widget": "barfoo",
179
- "new_image_widget": os.path.join(image_samples, "sample_image.jpg"),
180
- "new_signature_wiget": os.path.join(
181
- image_samples, "sample_signature.png"
182
- ),
183
- },
184
- )
185
- )
186
-
187
- obj.widgets["new_text_field_widget"].font = "new_font"
188
- obj.widgets["new_text_field_widget"].font_color = (1, 0, 0)
189
- obj.widgets["new_text_field_widget"].alignment = (
190
- 2 # TODO: why is alignment not rendered right in the appearance stream?
191
- )
192
- obj.widgets["new_checkbox_widget"].size = 40
193
- obj.widgets["new_radio_group"].size = 50
194
-
195
- request.config.results["expected_path"] = expected_path
196
- request.config.results["stream"] = obj.read()
197
-
198
- expected = f.read()
199
-
200
- assert len(obj.read()) == len(expected)
201
- request.config.results["skip_regenerate"] = len(obj.read()) == len(expected)
@@ -7,6 +7,119 @@ import pytest
7
7
  from PyPDFForm import Fields, PdfWrapper
8
8
 
9
9
 
10
+ def run_sample_template_library_test(
11
+ pdf_samples,
12
+ image_samples,
13
+ sample_font_stream,
14
+ request,
15
+ generate_appearance_streams=False,
16
+ need_appearances=False,
17
+ ):
18
+ subdir = (
19
+ "generate_appearance_streams"
20
+ if generate_appearance_streams
21
+ else "need_appearances"
22
+ )
23
+ expected_path = os.path.join(
24
+ pdf_samples, subdir, "test_sample_template_library.pdf"
25
+ )
26
+
27
+ with open(expected_path, "rb+") as f:
28
+ obj = (
29
+ PdfWrapper(
30
+ os.path.join(pdf_samples, "dummy.pdf"),
31
+ generate_appearance_streams=generate_appearance_streams,
32
+ need_appearances=need_appearances,
33
+ )
34
+ .register_font("new_font", sample_font_stream)
35
+ .create_field(
36
+ Fields.TextField(
37
+ name="new_text_field_widget",
38
+ page_number=1,
39
+ x=60,
40
+ y=710,
41
+ )
42
+ )
43
+ .create_field(
44
+ Fields.CheckBoxField(
45
+ name="new_checkbox_widget",
46
+ page_number=1,
47
+ x=100,
48
+ y=600,
49
+ )
50
+ )
51
+ .create_field(
52
+ Fields.RadioGroup(
53
+ name="new_radio_group",
54
+ page_number=1,
55
+ x=[50, 100, 150],
56
+ y=[50, 100, 150],
57
+ )
58
+ )
59
+ .create_field(
60
+ Fields.DropdownField(
61
+ name="new_dropdown_widget",
62
+ page_number=1,
63
+ x=300,
64
+ y=710,
65
+ options=[
66
+ "foo",
67
+ "bar",
68
+ "foobar",
69
+ ],
70
+ font="new_font",
71
+ )
72
+ )
73
+ .create_field(
74
+ Fields.ImageField(
75
+ name="new_image_widget",
76
+ page_number=1,
77
+ x=300,
78
+ y=200,
79
+ )
80
+ )
81
+ .create_field(
82
+ Fields.SignatureField(
83
+ name="new_signature_wiget",
84
+ page_number=1,
85
+ x=300,
86
+ y=400,
87
+ )
88
+ )
89
+ .fill(
90
+ {
91
+ "new_text_field_widget": "test text",
92
+ "new_checkbox_widget": True,
93
+ "new_radio_group": 1,
94
+ "new_dropdown_widget": "barfoo",
95
+ "new_image_widget": os.path.join(image_samples, "sample_image.jpg"),
96
+ "new_signature_wiget": os.path.join(
97
+ image_samples, "sample_signature.png"
98
+ ),
99
+ },
100
+ )
101
+ )
102
+
103
+ obj.widgets["new_text_field_widget"].font = "new_font"
104
+ obj.widgets["new_text_field_widget"].font_color = (1, 0, 0)
105
+ # TODO: why is alignment not rendered right in the appearance stream?
106
+ obj.widgets["new_text_field_widget"].alignment = 2
107
+
108
+ obj.widgets["new_checkbox_widget"].size = 40
109
+ obj.widgets["new_radio_group"].size = 50
110
+
111
+ request.config.results["expected_path"] = expected_path
112
+ request.config.results["stream"] = obj.read()
113
+
114
+ expected = f.read()
115
+
116
+ assert len(obj.read()) == len(expected)
117
+ if generate_appearance_streams:
118
+ request.config.results["skip_regenerate"] = len(obj.read()) == len(expected)
119
+ else:
120
+ assert obj.read() == expected
121
+
122
+
10
123
  def test_fill(template_stream, pdf_samples, data_dict, request):
11
124
  expected_path = os.path.join(pdf_samples, "need_appearances", "sample_filled.pdf")
12
125
  with open(expected_path, "rb+") as f:
@@ -98,92 +211,10 @@ def test_issue_613(pdf_samples, request):
98
211
  def test_sample_template_library(
99
212
  pdf_samples, image_samples, sample_font_stream, request
100
213
  ):
101
- expected_path = os.path.join(
102
- pdf_samples, "need_appearances", "test_sample_template_library.pdf"
214
+ run_sample_template_library_test(
215
+ pdf_samples,
216
+ image_samples,
217
+ sample_font_stream,
218
+ request,
219
+ need_appearances=True,
103
220
  )
104
-
105
- with open(expected_path, "rb+") as f:
106
- obj = (
107
- PdfWrapper(os.path.join(pdf_samples, "dummy.pdf"), need_appearances=True)
108
- .register_font("new_font", sample_font_stream)
109
- .create_field(
110
- Fields.TextField(
111
- name="new_text_field_widget",
112
- page_number=1,
113
- x=60,
114
- y=710,
115
- )
116
- )
117
- .create_field(
118
- Fields.CheckBoxField(
119
- name="new_checkbox_widget",
120
- page_number=1,
121
- x=100,
122
- y=600,
123
- )
124
- )
125
- .create_field(
126
- Fields.RadioGroup(
127
- name="new_radio_group",
128
- page_number=1,
129
- x=[50, 100, 150],
130
- y=[50, 100, 150],
131
- )
132
- )
133
- .create_field(
134
- Fields.DropdownField(
135
- name="new_dropdown_widget",
136
- page_number=1,
137
- x=300,
138
- y=710,
139
- options=[
140
- "foo",
141
- "bar",
142
- "foobar",
143
- ],
144
- font="new_font",
145
- )
146
- )
147
- .create_field(
148
- Fields.ImageField(
149
- name="new_image_widget",
150
- page_number=1,
151
- x=300,
152
- y=200,
153
- )
154
- )
155
- .create_field(
156
- Fields.SignatureField(
157
- name="new_signature_wiget",
158
- page_number=1,
159
- x=300,
160
- y=400,
161
- )
162
- )
163
- .fill(
164
- {
165
- "new_text_field_widget": "test text",
166
- "new_checkbox_widget": True,
167
- "new_radio_group": 1,
168
- "new_dropdown_widget": "barfoo",
169
- "new_image_widget": os.path.join(image_samples, "sample_image.jpg"),
170
- "new_signature_wiget": os.path.join(
171
- image_samples, "sample_signature.png"
172
- ),
173
- },
174
- )
175
- )
176
-
177
- obj.widgets["new_text_field_widget"].font = "new_font"
178
- obj.widgets["new_text_field_widget"].font_color = (1, 0, 0)
179
- obj.widgets["new_text_field_widget"].alignment = 2
180
- obj.widgets["new_checkbox_widget"].size = 40
181
- obj.widgets["new_radio_group"].size = 50
182
-
183
- request.config.results["expected_path"] = expected_path
184
- request.config.results["stream"] = obj.read()
185
-
186
- expected = f.read()
187
-
188
- assert len(obj.read()) == len(expected)
189
- assert obj.read() == expected
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes