PyPDFForm 1.4.11__tar.gz → 1.4.13__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.

Potentially problematic release.


This version of PyPDFForm might be problematic. Click here for more details.

Files changed (46) hide show
  1. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PKG-INFO +1 -1
  2. PyPDFForm-1.4.13/PyPDFForm/__init__.py +6 -0
  3. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/constants.py +9 -3
  4. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/filler.py +69 -5
  5. PyPDFForm-1.4.13/PyPDFForm/middleware/checkbox.py +55 -0
  6. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/middleware/radio.py +2 -3
  7. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/utils.py +1 -1
  8. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/wrapper.py +36 -8
  9. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm.egg-info/PKG-INFO +1 -1
  10. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm.egg-info/SOURCES.txt +4 -0
  11. PyPDFForm-1.4.13/tests/test_dropdown_simple.py +148 -0
  12. PyPDFForm-1.4.13/tests/test_fill_max_length_text_field_simple.py +92 -0
  13. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/tests/test_functional.py +60 -0
  14. PyPDFForm-1.4.13/tests/test_functional_simple.py +115 -0
  15. PyPDFForm-1.4.13/tests/test_paragraph_simple.py +137 -0
  16. PyPDFForm-1.4.11/PyPDFForm/__init__.py +0 -6
  17. PyPDFForm-1.4.11/PyPDFForm/middleware/checkbox.py +0 -31
  18. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/LICENSE +0 -0
  19. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/adapter.py +0 -0
  20. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/coordinate.py +0 -0
  21. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/font.py +0 -0
  22. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/image.py +0 -0
  23. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/middleware/__init__.py +0 -0
  24. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/middleware/base.py +0 -0
  25. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/middleware/dropdown.py +0 -0
  26. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/middleware/signature.py +0 -0
  27. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/middleware/text.py +0 -0
  28. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/patterns.py +0 -0
  29. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/template.py +0 -0
  30. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/watermark.py +0 -0
  31. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/widgets/__init__.py +0 -0
  32. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/widgets/base.py +0 -0
  33. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/widgets/checkbox.py +0 -0
  34. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm/widgets/text.py +0 -0
  35. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm.egg-info/dependency_links.txt +0 -0
  36. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm.egg-info/requires.txt +0 -0
  37. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/PyPDFForm.egg-info/top_level.txt +0 -0
  38. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/README.md +0 -0
  39. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/setup.cfg +0 -0
  40. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/setup.py +0 -0
  41. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/tests/test_create_widget.py +0 -0
  42. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/tests/test_dropdown.py +0 -0
  43. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/tests/test_fill_max_length_text_field.py +0 -0
  44. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/tests/test_paragraph.py +0 -0
  45. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/tests/test_preview.py +0 -0
  46. {PyPDFForm-1.4.11 → PyPDFForm-1.4.13}/tests/test_signature.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyPDFForm
3
- Version: 1.4.11
3
+ Version: 1.4.13
4
4
  Summary: The Python library for PDF forms.
5
5
  Home-page: https://github.com/chinapandaman/PyPDFForm
6
6
  Author: Jinge Li
@@ -0,0 +1,6 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Contains any object users might need."""
3
+
4
+ __version__ = "1.4.13"
5
+
6
+ from .wrapper import FormWrapper, PdfWrapper, PyPDFForm
@@ -26,6 +26,7 @@ WIDGET_TYPES = Union[Text, Checkbox, Radio, Dropdown, Signature]
26
26
 
27
27
  DEPRECATION_NOTICE = "{} will be deprecated soon. Use {} instead."
28
28
 
29
+ ANNOTATION_KEY = "/Annots"
29
30
  ANNOTATION_FIELD_KEY = "/T"
30
31
  ANNOTATION_RECTANGLE_KEY = "/Rect"
31
32
  SUBTYPE_KEY = "/Subtype"
@@ -34,6 +35,8 @@ WIDGET_TYPE_KEY = "/FT"
34
35
  PARENT_KEY = "/Parent"
35
36
  FIELD_FLAG_KEY = "/Ff"
36
37
  TEXT_FIELD_IDENTIFIER = "/Tx"
38
+ TEXT_VALUE_IDENTIFIER = "/V"
39
+ TEXT_VALUE_SHOW_UP_IDENTIFIER = "/AP"
37
40
  SIGNATURE_FIELD_IDENTIFIER = "/Sig"
38
41
  TEXT_FIELD_APPEARANCE_IDENTIFIER = "/DA"
39
42
  SELECTABLE_IDENTIFIER = "/Btn"
@@ -43,6 +46,7 @@ CHOICE_FIELD_IDENTIFIER = "/Ch"
43
46
  CHOICES_IDENTIFIER = "/Opt"
44
47
  BUTTON_IDENTIFIER = "/MK"
45
48
  BUTTON_STYLE_IDENTIFIER = "/CA"
49
+ SELECTED_IDENTIFIER = "/AS"
46
50
 
47
51
  # Field flag bits
48
52
  MULTILINE = 1 << 12
@@ -60,9 +64,11 @@ NEW_LINE_SYMBOL = "\n"
60
64
  DEFAULT_CHECKBOX_STYLE = "\u2713"
61
65
  DEFAULT_RADIO_STYLE = "\u25CF"
62
66
  BUTTON_STYLES = {
63
- "4": "\u2713",
64
- "5": "\u00D7",
65
- "l": "\u25CF",
67
+ "4": "\u2713", # check
68
+ "5": "\u00D7", # cross
69
+ "l": "\u25CF", # circle
66
70
  }
67
71
 
72
+ CHECKBOX_SELECT = "/Yes"
73
+
68
74
  COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO = DEFAULT_FONT_SIZE / 100
@@ -1,9 +1,15 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Contains helpers for filling a PDF form."""
3
3
 
4
- from typing import Dict
4
+ from io import BytesIO
5
+ from typing import Dict, cast
5
6
 
6
- from .constants import WIDGET_TYPES
7
+ from pypdf import PdfReader, PdfWriter
8
+ from pypdf.generic import DictionaryObject, NameObject, TextStringObject
9
+
10
+ from .constants import (ANNOTATION_KEY, CHECKBOX_SELECT, SELECTED_IDENTIFIER,
11
+ TEXT_VALUE_IDENTIFIER, TEXT_VALUE_SHOW_UP_IDENTIFIER,
12
+ WIDGET_TYPES)
7
13
  from .coordinate import (get_draw_checkbox_radio_coordinates,
8
14
  get_draw_sig_coordinates_resolutions,
9
15
  get_draw_text_coordinates,
@@ -11,10 +17,12 @@ from .coordinate import (get_draw_checkbox_radio_coordinates,
11
17
  from .font import checkbox_radio_font_size
12
18
  from .image import any_image_to_jpg
13
19
  from .middleware.checkbox import Checkbox
20
+ from .middleware.dropdown import Dropdown
14
21
  from .middleware.radio import Radio
15
22
  from .middleware.signature import Signature
23
+ from .middleware.text import Text
16
24
  from .template import get_widget_key, get_widgets_by_page
17
- from .utils import checkbox_radio_to_draw
25
+ from .utils import checkbox_radio_to_draw, stream_to_io
18
26
  from .watermark import create_watermarks_and_draw, merge_watermarks_with_pdf
19
27
 
20
28
 
@@ -44,10 +52,14 @@ def fill(
44
52
  _to_draw = x = y = None
45
53
 
46
54
  if isinstance(widgets[key], (Checkbox, Radio)):
47
- font_size = checkbox_radio_font_size(_widget)
55
+ font_size = (
56
+ checkbox_radio_font_size(_widget)
57
+ if widgets[key].size is None
58
+ else widgets[key].size
59
+ )
48
60
  _to_draw = checkbox_radio_to_draw(widgets[key], font_size)
49
61
  x, y = get_draw_checkbox_radio_coordinates(_widget, _to_draw)
50
- if isinstance(widgets[key], Checkbox) and widgets[key].value:
62
+ if type(widgets[key]) is Checkbox and widgets[key].value:
51
63
  text_needs_to_be_drawn = True
52
64
  elif isinstance(widgets[key], Radio):
53
65
  if key not in radio_button_tracker:
@@ -113,3 +125,55 @@ def fill(
113
125
  result = merge_watermarks_with_pdf(result, image_watermarks)
114
126
 
115
127
  return result
128
+
129
+
130
+ def simple_fill(
131
+ template: bytes,
132
+ widgets: Dict[str, WIDGET_TYPES],
133
+ ) -> bytes:
134
+ """Fills a PDF form in place."""
135
+
136
+ pdf = PdfReader(stream_to_io(template))
137
+ out = PdfWriter()
138
+ out.append(pdf)
139
+
140
+ radio_button_tracker = {}
141
+
142
+ for page in out.pages:
143
+ for annot in page.get(ANNOTATION_KEY, []): # noqa
144
+ annot = cast(DictionaryObject, annot.get_object())
145
+ key = get_widget_key(annot.get_object())
146
+
147
+ widget = widgets.get(key)
148
+ if widget is None:
149
+ continue
150
+
151
+ if isinstance(widget, Checkbox) and widget.value is True:
152
+ annot[NameObject(SELECTED_IDENTIFIER)] = NameObject(CHECKBOX_SELECT)
153
+ elif isinstance(widget, Radio):
154
+ if key not in radio_button_tracker:
155
+ radio_button_tracker[key] = 0
156
+ radio_button_tracker[key] += 1
157
+ if widget.value == radio_button_tracker[key] - 1:
158
+ annot[NameObject(SELECTED_IDENTIFIER)] = NameObject(
159
+ f"/{widget.value}"
160
+ )
161
+ elif isinstance(widget, Dropdown) and widget.value is not None:
162
+ annot[NameObject(TEXT_VALUE_IDENTIFIER)] = TextStringObject(
163
+ widget.choices[widget.value]
164
+ )
165
+ annot[NameObject(TEXT_VALUE_SHOW_UP_IDENTIFIER)] = TextStringObject(
166
+ widget.choices[widget.value]
167
+ )
168
+ elif isinstance(widget, Text) and widget.value:
169
+ annot[NameObject(TEXT_VALUE_IDENTIFIER)] = TextStringObject(
170
+ widget.value
171
+ )
172
+ annot[NameObject(TEXT_VALUE_SHOW_UP_IDENTIFIER)] = TextStringObject(
173
+ widget.value
174
+ )
175
+
176
+ with BytesIO() as f:
177
+ out.write(f)
178
+ f.seek(0)
179
+ return f.read()
@@ -0,0 +1,55 @@
1
+ # -*- coding: utf-8 -*-
2
+ """Contains checkbox middleware."""
3
+
4
+ from typing import Union
5
+
6
+ from .base import Widget
7
+
8
+
9
+ class Checkbox(Widget):
10
+ """A class to represent a checkbox widget."""
11
+
12
+ BUTTON_STYLE_MAPPING = {
13
+ "check": "4",
14
+ "cross": "5",
15
+ "circle": "l",
16
+ }
17
+
18
+ def __init__(
19
+ self,
20
+ name: str,
21
+ value: bool = None,
22
+ ) -> None:
23
+ """Constructs all attributes for the checkbox."""
24
+
25
+ super().__init__(name, value)
26
+
27
+ self.size = None
28
+ self._button_style = None
29
+
30
+ @property
31
+ def schema_definition(self) -> dict:
32
+ """Json schema definition of the checkbox."""
33
+
34
+ return {"type": "boolean"}
35
+
36
+ @property
37
+ def sample_value(self) -> bool:
38
+ """Sample value of the checkbox."""
39
+
40
+ return True
41
+
42
+ @property
43
+ def button_style(self) -> Union[str, None]:
44
+ """Shape of the tick for the checkbox."""
45
+
46
+ return self._button_style
47
+
48
+ @button_style.setter
49
+ def button_style(self, value) -> None:
50
+ """Converts user specified button styles to acroform values."""
51
+
52
+ if value in self.BUTTON_STYLE_MAPPING:
53
+ self._button_style = self.BUTTON_STYLE_MAPPING[value]
54
+ elif value in self.BUTTON_STYLE_MAPPING.values():
55
+ self._button_style = value
@@ -1,10 +1,10 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Contains radio middleware."""
3
3
 
4
- from .base import Widget
4
+ from .checkbox import Checkbox
5
5
 
6
6
 
7
- class Radio(Widget):
7
+ class Radio(Checkbox):
8
8
  """A class to represent a radiobutton widget."""
9
9
 
10
10
  def __init__(
@@ -16,7 +16,6 @@ class Radio(Widget):
16
16
 
17
17
  super().__init__(name, value)
18
18
 
19
- self.button_style = None
20
19
  self.number_of_options = 0
21
20
 
22
21
  @property
@@ -38,7 +38,7 @@ def checkbox_radio_to_draw(
38
38
  new_widget.font_size = font_size
39
39
  new_widget.font_color = DEFAULT_FONT_COLOR
40
40
  new_widget.value = BUTTON_STYLES.get(widget.button_style) or (
41
- DEFAULT_CHECKBOX_STYLE if isinstance(widget, Checkbox) else DEFAULT_RADIO_STYLE
41
+ DEFAULT_CHECKBOX_STYLE if type(widget) is Checkbox else DEFAULT_RADIO_STYLE
42
42
  )
43
43
 
44
44
  return new_widget
@@ -11,7 +11,7 @@ from .constants import (DEFAULT_FONT, DEFAULT_FONT_COLOR, DEFAULT_FONT_SIZE,
11
11
  DEPRECATION_NOTICE, VERSION_IDENTIFIER_PREFIX,
12
12
  VERSION_IDENTIFIERS)
13
13
  from .coordinate import generate_coordinate_grid
14
- from .filler import fill
14
+ from .filler import fill, simple_fill
15
15
  from .font import register_font
16
16
  from .image import any_image_to_jpg, rotate_image
17
17
  from .middleware.dropdown import Dropdown
@@ -26,7 +26,40 @@ from .widgets.checkbox import CheckBoxWidget
26
26
  from .widgets.text import TextWidget
27
27
 
28
28
 
29
- class PdfWrapper:
29
+ class FormWrapper:
30
+ """A simple base wrapper for just filling a PDF form."""
31
+
32
+ def __init__(
33
+ self,
34
+ template: Union[bytes, str, BinaryIO] = b"",
35
+ ) -> None:
36
+ """Constructs all attributes for the object."""
37
+
38
+ self.stream = fp_or_f_obj_or_stream_to_stream(template)
39
+
40
+ def read(self) -> bytes:
41
+ """Reads the file stream of a PDF form."""
42
+
43
+ return self.stream
44
+
45
+ def fill(
46
+ self,
47
+ data: Dict[str, Union[str, bool, int]],
48
+ ) -> FormWrapper:
49
+ """Fills a PDF form."""
50
+
51
+ widgets = build_widgets(self.stream) if self.stream else {}
52
+
53
+ for key, value in data.items():
54
+ if key in widgets:
55
+ widgets[key].value = value
56
+
57
+ self.stream = simple_fill(self.read(), widgets)
58
+
59
+ return self
60
+
61
+
62
+ class PdfWrapper(FormWrapper):
30
63
  """A class to represent a PDF form."""
31
64
 
32
65
  def __init__(
@@ -36,7 +69,7 @@ class PdfWrapper:
36
69
  ) -> None:
37
70
  """Constructs all attributes for the object."""
38
71
 
39
- self.stream = fp_or_f_obj_or_stream_to_stream(template)
72
+ super().__init__(template)
40
73
  self.widgets = build_widgets(self.stream) if self.stream else {}
41
74
 
42
75
  self.global_font = kwargs.get("global_font")
@@ -49,11 +82,6 @@ class PdfWrapper:
49
82
  each.font_size = self.global_font_size
50
83
  each.font_color = self.global_font_color
51
84
 
52
- def read(self) -> bytes:
53
- """Reads the file stream of a PDF form."""
54
-
55
- return self.stream
56
-
57
85
  @property
58
86
  def elements(self) -> dict:
59
87
  """ToDo: deprecate this."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyPDFForm
3
- Version: 1.4.11
3
+ Version: 1.4.13
4
4
  Summary: The Python library for PDF forms.
5
5
  Home-page: https://github.com/chinapandaman/PyPDFForm
6
6
  Author: Jinge Li
@@ -31,8 +31,12 @@ PyPDFForm/widgets/checkbox.py
31
31
  PyPDFForm/widgets/text.py
32
32
  tests/test_create_widget.py
33
33
  tests/test_dropdown.py
34
+ tests/test_dropdown_simple.py
34
35
  tests/test_fill_max_length_text_field.py
36
+ tests/test_fill_max_length_text_field_simple.py
35
37
  tests/test_functional.py
38
+ tests/test_functional_simple.py
36
39
  tests/test_paragraph.py
40
+ tests/test_paragraph_simple.py
37
41
  tests/test_preview.py
38
42
  tests/test_signature.py
@@ -0,0 +1,148 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import os
4
+
5
+ from PyPDFForm import FormWrapper
6
+
7
+
8
+ def test_dropdown_not_specified(sample_template_with_dropdown):
9
+ assert (
10
+ FormWrapper(sample_template_with_dropdown)
11
+ .fill(
12
+ {
13
+ "test_1": "test_1",
14
+ "test_2": "test_2",
15
+ "test_3": "test_3",
16
+ "check_1": True,
17
+ "check_2": True,
18
+ "check_3": True,
19
+ "radio_1": 1,
20
+ }
21
+ )
22
+ .read()
23
+ )
24
+
25
+
26
+ def test_dropdown_one(sample_template_with_dropdown, pdf_samples, request):
27
+ expected_path = os.path.join(pdf_samples, "simple", "dropdown", "dropdown_one.pdf")
28
+ with open(expected_path, "rb+") as f:
29
+ obj = FormWrapper(sample_template_with_dropdown).fill(
30
+ {
31
+ "test_1": "test_1",
32
+ "test_2": "test_2",
33
+ "test_3": "test_3",
34
+ "check_1": True,
35
+ "check_2": True,
36
+ "check_3": True,
37
+ "radio_1": 1,
38
+ "dropdown_1": 0,
39
+ },
40
+ )
41
+
42
+ request.config.results["expected_path"] = expected_path
43
+ request.config.results["stream"] = obj.read()
44
+
45
+ expected = f.read()
46
+
47
+ assert len(obj.read()) == len(expected)
48
+ assert obj.stream == expected
49
+
50
+
51
+ def test_dropdown_two(sample_template_with_dropdown, pdf_samples, request):
52
+ expected_path = os.path.join(pdf_samples, "simple", "dropdown", "dropdown_two.pdf")
53
+ with open(expected_path, "rb+") as f:
54
+ obj = FormWrapper(sample_template_with_dropdown).fill(
55
+ {
56
+ "test_1": "test_1",
57
+ "test_2": "test_2",
58
+ "test_3": "test_3",
59
+ "check_1": True,
60
+ "check_2": True,
61
+ "check_3": True,
62
+ "radio_1": 1,
63
+ "dropdown_1": 1,
64
+ },
65
+ )
66
+
67
+ request.config.results["expected_path"] = expected_path
68
+ request.config.results["stream"] = obj.read()
69
+
70
+ expected = f.read()
71
+
72
+ assert len(obj.read()) == len(expected)
73
+ assert obj.stream == expected
74
+
75
+
76
+ def test_dropdown_three(sample_template_with_dropdown, pdf_samples, request):
77
+ expected_path = os.path.join(
78
+ pdf_samples, "simple", "dropdown", "dropdown_three.pdf"
79
+ )
80
+ with open(expected_path, "rb+") as f:
81
+ obj = FormWrapper(sample_template_with_dropdown).fill(
82
+ {
83
+ "test_1": "test_1",
84
+ "test_2": "test_2",
85
+ "test_3": "test_3",
86
+ "check_1": True,
87
+ "check_2": True,
88
+ "check_3": True,
89
+ "radio_1": 1,
90
+ "dropdown_1": 2,
91
+ },
92
+ )
93
+
94
+ request.config.results["expected_path"] = expected_path
95
+ request.config.results["stream"] = obj.read()
96
+
97
+ expected = f.read()
98
+
99
+ assert len(obj.read()) == len(expected)
100
+ assert obj.stream == expected
101
+
102
+
103
+ def test_dropdown_four(sample_template_with_dropdown, pdf_samples, request):
104
+ expected_path = os.path.join(pdf_samples, "simple", "dropdown", "dropdown_four.pdf")
105
+ with open(expected_path, "rb+") as f:
106
+ obj = FormWrapper(sample_template_with_dropdown).fill(
107
+ {
108
+ "test_1": "test_1",
109
+ "test_2": "test_2",
110
+ "test_3": "test_3",
111
+ "check_1": True,
112
+ "check_2": True,
113
+ "check_3": True,
114
+ "radio_1": 1,
115
+ "dropdown_1": 3,
116
+ },
117
+ )
118
+
119
+ request.config.results["expected_path"] = expected_path
120
+ request.config.results["stream"] = obj.read()
121
+
122
+ expected = f.read()
123
+
124
+ assert len(obj.read()) == len(expected)
125
+ assert obj.stream == expected
126
+
127
+
128
+ def test_dropdown_alignment(dropdown_alignment, pdf_samples, request):
129
+ expected_path = os.path.join(
130
+ pdf_samples, "simple", "dropdown", "dropdown_alignment_expected.pdf"
131
+ )
132
+ with open(expected_path, "rb+") as f:
133
+ obj = FormWrapper(dropdown_alignment).fill(
134
+ {
135
+ "dropdown_left": 0,
136
+ "dropdown_center": 1,
137
+ "dropdown_right": 2,
138
+ },
139
+ )
140
+
141
+ request.config.results["expected_path"] = expected_path
142
+ request.config.results["stream"] = obj.read()
143
+
144
+ expected = f.read()
145
+
146
+ if os.name != "nt":
147
+ assert len(obj.read()) == len(expected)
148
+ assert obj.stream == expected
@@ -0,0 +1,92 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import os
4
+
5
+ from PyPDFForm import FormWrapper
6
+
7
+
8
+ def test_fill_max_length_text_field_all_chars(
9
+ sample_template_with_max_length_text_field, pdf_samples, request
10
+ ):
11
+ expected_path = os.path.join(
12
+ pdf_samples,
13
+ "simple",
14
+ "max_length_text_field_related",
15
+ "max_length_text_field_all_chars.pdf",
16
+ )
17
+ with open(expected_path, "rb+") as f:
18
+ obj = FormWrapper(sample_template_with_max_length_text_field).fill(
19
+ {
20
+ "FirstName": "John",
21
+ "MiddleName": "Joe",
22
+ "LastName": "XXXXXXXXXX",
23
+ "Awesomeness": True,
24
+ "Gender": 0,
25
+ }
26
+ )
27
+
28
+ request.config.results["expected_path"] = expected_path
29
+ request.config.results["stream"] = obj.read()
30
+
31
+ expected = f.read()
32
+
33
+ assert len(obj.stream) == len(expected)
34
+ assert obj.stream == expected
35
+
36
+
37
+ def test_fill_max_length_text_field_odd_chars(
38
+ sample_template_with_max_length_text_field, pdf_samples, request
39
+ ):
40
+ expected_path = os.path.join(
41
+ pdf_samples,
42
+ "simple",
43
+ "max_length_text_field_related",
44
+ "max_length_text_field_odd_chars.pdf",
45
+ )
46
+ with open(expected_path, "rb+") as f:
47
+ obj = FormWrapper(sample_template_with_max_length_text_field).fill(
48
+ {
49
+ "FirstName": "John",
50
+ "MiddleName": "Joe",
51
+ "LastName": "XXX",
52
+ "Awesomeness": True,
53
+ "Gender": 0,
54
+ }
55
+ )
56
+
57
+ request.config.results["expected_path"] = expected_path
58
+ request.config.results["stream"] = obj.read()
59
+
60
+ expected = f.read()
61
+
62
+ assert len(obj.stream) == len(expected)
63
+ assert obj.stream == expected
64
+
65
+
66
+ def test_fill_max_length_text_field_even_chars(
67
+ sample_template_with_max_length_text_field, pdf_samples, request
68
+ ):
69
+ expected_path = os.path.join(
70
+ pdf_samples,
71
+ "simple",
72
+ "max_length_text_field_related",
73
+ "max_length_text_field_even_chars.pdf",
74
+ )
75
+ with open(expected_path, "rb+") as f:
76
+ obj = FormWrapper(sample_template_with_max_length_text_field).fill(
77
+ {
78
+ "FirstName": "John",
79
+ "MiddleName": "Joe",
80
+ "LastName": "XXXX",
81
+ "Awesomeness": True,
82
+ "Gender": 0,
83
+ }
84
+ )
85
+
86
+ request.config.results["expected_path"] = expected_path
87
+ request.config.results["stream"] = obj.read()
88
+
89
+ expected = f.read()
90
+
91
+ assert len(obj.stream) == len(expected)
92
+ assert obj.stream == expected
@@ -550,3 +550,63 @@ def test_generate_coordinate_grid_margin_50(template_stream, pdf_samples, reques
550
550
 
551
551
  assert len(obj.read()) == len(expected)
552
552
  assert obj.stream == expected
553
+
554
+
555
+ def test_checkbox_change_size_and_button_style(template_stream, pdf_samples, request):
556
+ expected_path = os.path.join(
557
+ pdf_samples, "test_checkbox_change_size_and_button_style.pdf"
558
+ )
559
+ with open(expected_path, "rb+") as f:
560
+ obj = PdfWrapper(template_stream)
561
+ obj.widgets["check"].size = 50
562
+ obj.widgets["check"].button_style = "cross"
563
+ obj.widgets["check_2"].size = 40
564
+ obj.widgets["check_2"].button_style = "circle"
565
+ obj.widgets["check_3"].size = 60
566
+ obj.widgets["check_3"].button_style = "check"
567
+ obj = obj.fill(
568
+ {
569
+ "check": True,
570
+ "check_2": True,
571
+ "check_3": True,
572
+ },
573
+ )
574
+
575
+ request.config.results["expected_path"] = expected_path
576
+ request.config.results["stream"] = obj.read()
577
+
578
+ expected = f.read()
579
+
580
+ assert len(obj.read()) == len(expected)
581
+ assert obj.stream == expected
582
+
583
+
584
+ def test_radio_change_size_and_button_style(
585
+ template_with_radiobutton_stream, pdf_samples, request
586
+ ):
587
+ expected_path = os.path.join(
588
+ pdf_samples, "test_radio_change_size_and_button_style.pdf"
589
+ )
590
+ with open(expected_path, "rb+") as f:
591
+ obj = PdfWrapper(template_with_radiobutton_stream)
592
+ obj.widgets["radio_1"].size = 50
593
+ obj.widgets["radio_1"].button_style = "cross"
594
+ obj.widgets["radio_2"].size = 40
595
+ obj.widgets["radio_2"].button_style = "circle"
596
+ obj.widgets["radio_3"].size = 60
597
+ obj.widgets["radio_3"].button_style = "check"
598
+ obj = obj.fill(
599
+ {
600
+ "radio_1": 0,
601
+ "radio_2": 1,
602
+ "radio_3": 2,
603
+ },
604
+ )
605
+
606
+ request.config.results["expected_path"] = expected_path
607
+ request.config.results["stream"] = obj.read()
608
+
609
+ expected = f.read()
610
+
611
+ assert len(obj.read()) == len(expected)
612
+ assert obj.stream == expected
@@ -0,0 +1,115 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import os
4
+
5
+ from PyPDFForm import FormWrapper
6
+
7
+
8
+ def test_fill(template_stream, pdf_samples, data_dict, request):
9
+ expected_path = os.path.join(pdf_samples, "simple", "sample_filled.pdf")
10
+ with open(expected_path, "rb+") as f:
11
+ obj = FormWrapper(template_stream).fill(data_dict)
12
+
13
+ request.config.results["expected_path"] = expected_path
14
+ request.config.results["stream"] = obj.read()
15
+
16
+ expected = f.read()
17
+
18
+ assert len(obj.stream) == len(expected)
19
+ assert obj.stream == expected
20
+
21
+
22
+ def test_fill_radiobutton(pdf_samples, template_with_radiobutton_stream, request):
23
+ expected_path = os.path.join(pdf_samples, "simple", "sample_filled_radiobutton.pdf")
24
+ with open(expected_path, "rb+") as f:
25
+ obj = FormWrapper(template_with_radiobutton_stream).fill(
26
+ {
27
+ "radio_1": 0,
28
+ "radio_2": 1,
29
+ "radio_3": 2,
30
+ },
31
+ )
32
+
33
+ request.config.results["expected_path"] = expected_path
34
+ request.config.results["stream"] = obj.read()
35
+
36
+ expected = f.read()
37
+
38
+ assert len(obj.read()) == len(expected)
39
+ assert obj.stream == expected
40
+
41
+
42
+ def test_fill_right_aligned(
43
+ sample_template_with_right_aligned_text_field, pdf_samples, request
44
+ ):
45
+ expected_path = os.path.join(
46
+ pdf_samples, "simple", "sample_filled_right_aligned.pdf"
47
+ )
48
+ with open(expected_path, "rb+") as f:
49
+ obj = FormWrapper(sample_template_with_right_aligned_text_field).fill(
50
+ {
51
+ "name": "Hans Mustermann",
52
+ "fulladdress": "Musterstr. 12, 82903 Musterdorf, Musterland",
53
+ "advisorname": "Karl Test",
54
+ },
55
+ )
56
+
57
+ request.config.results["expected_path"] = expected_path
58
+ request.config.results["stream"] = obj.read()
59
+
60
+ expected = f.read()
61
+
62
+ assert len(obj.read()) == len(expected)
63
+ assert obj.stream == expected
64
+
65
+
66
+ def test_fill_font_color(sample_template_with_font_colors, pdf_samples, request):
67
+ expected_path = os.path.join(pdf_samples, "simple", "test_fill_font_color.pdf")
68
+ with open(expected_path, "rb+") as f:
69
+ obj = FormWrapper(sample_template_with_font_colors).fill(
70
+ {
71
+ "red_12": "red",
72
+ "green_14": "green",
73
+ "blue_16": "blue",
74
+ "mixed_auto": "mixed",
75
+ },
76
+ )
77
+
78
+ request.config.results["expected_path"] = expected_path
79
+ request.config.results["stream"] = obj.read()
80
+
81
+ expected = f.read()
82
+
83
+ if os.name != "nt":
84
+ assert len(obj.read()) == len(expected)
85
+ assert obj.stream == expected
86
+
87
+
88
+ def test_fill_complex_fonts(sample_template_with_complex_fonts, pdf_samples, request):
89
+ expected_path = os.path.join(pdf_samples, "simple", "test_fill_complex_fonts.pdf")
90
+ with open(expected_path, "rb+") as f:
91
+ obj = FormWrapper(sample_template_with_complex_fonts).fill(
92
+ {
93
+ "Courier": "Test",
94
+ "Courier-Bold": "Test",
95
+ "Courier-BoldOblique": "Test",
96
+ "Courier-Oblique": "Test",
97
+ "Helvetica": "Test",
98
+ "Helvetica-Bold": "Test",
99
+ "Helvetica-BoldOblique": "Test",
100
+ "Helvetica-Oblique": "Test",
101
+ "Times-Bold": "Test",
102
+ "Times-BoldItalic": "Test",
103
+ "Times-Italic": "Test",
104
+ "Times-Roman": "Test",
105
+ },
106
+ )
107
+
108
+ request.config.results["expected_path"] = expected_path
109
+ request.config.results["stream"] = obj.read()
110
+
111
+ expected = f.read()
112
+
113
+ if os.name != "nt":
114
+ assert len(obj.read()) == len(expected)
115
+ assert obj.stream == expected
@@ -0,0 +1,137 @@
1
+ # -*- coding: utf-8 -*-
2
+ # pylint: disable=line-too-long
3
+
4
+ import os
5
+
6
+ from PyPDFForm import FormWrapper
7
+
8
+
9
+ def test_paragraph_y_coordinate(sample_template_with_paragraph, pdf_samples, request):
10
+ expected_path = os.path.join(
11
+ pdf_samples, "simple", "paragraph", "test_paragraph_y_coordinate.pdf"
12
+ )
13
+ with open(expected_path, "rb+") as f:
14
+ obj = FormWrapper(sample_template_with_paragraph).fill(
15
+ {"paragraph_1": "test paragraph"}
16
+ )
17
+
18
+ request.config.results["expected_path"] = expected_path
19
+ request.config.results["stream"] = obj.read()
20
+
21
+ expected = f.read()
22
+
23
+ assert len(obj.read()) == len(expected)
24
+ assert obj.stream == expected
25
+
26
+
27
+ def test_paragraph_auto_wrap(sample_template_with_paragraph, pdf_samples, request):
28
+ expected_path = os.path.join(
29
+ pdf_samples, "simple", "paragraph", "test_paragraph_auto_wrap.pdf"
30
+ )
31
+ with open(expected_path, "rb+") as f:
32
+ obj = FormWrapper(sample_template_with_paragraph).fill(
33
+ {
34
+ "paragraph_1": "t xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx t"
35
+ }
36
+ )
37
+
38
+ request.config.results["expected_path"] = expected_path
39
+ request.config.results["stream"] = obj.read()
40
+
41
+ expected = f.read()
42
+
43
+ assert len(obj.read()) == len(expected)
44
+ assert obj.stream == expected
45
+
46
+
47
+ def test_paragraph_auto_font(
48
+ sample_template_with_paragraph_auto_font, pdf_samples, request
49
+ ):
50
+ expected_path = os.path.join(
51
+ pdf_samples, "simple", "paragraph", "test_paragraph_auto_font.pdf"
52
+ )
53
+ with open(expected_path, "rb+") as f:
54
+ obj = FormWrapper(sample_template_with_paragraph_auto_font).fill(
55
+ {"paragraph": "test paragraph"}
56
+ )
57
+
58
+ request.config.results["expected_path"] = expected_path
59
+ request.config.results["stream"] = obj.read()
60
+
61
+ expected = f.read()
62
+
63
+ if os.name != "nt":
64
+ assert len(obj.read()) == len(expected)
65
+ assert obj.stream == expected
66
+
67
+
68
+ def test_paragraph_auto_font_auto_wrap(
69
+ sample_template_with_paragraph_auto_font, pdf_samples, request
70
+ ):
71
+ expected_path = os.path.join(
72
+ pdf_samples, "simple", "paragraph", "test_paragraph_auto_font_auto_wrap.pdf"
73
+ )
74
+ with open(expected_path, "rb+") as f:
75
+ obj = FormWrapper(sample_template_with_paragraph_auto_font).fill(
76
+ {
77
+ "paragraph": "t xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx t"
78
+ }
79
+ )
80
+
81
+ request.config.results["expected_path"] = expected_path
82
+ request.config.results["stream"] = obj.read()
83
+
84
+ expected = f.read()
85
+
86
+ if os.name != "nt":
87
+ assert len(obj.read()) == len(expected)
88
+ assert obj.stream == expected
89
+
90
+
91
+ def test_paragraph_complex(sample_template_paragraph_complex, pdf_samples, request):
92
+ expected_path = os.path.join(
93
+ pdf_samples, "simple", "paragraph", "test_paragraph_complex.pdf"
94
+ )
95
+ with open(expected_path, "rb+") as f:
96
+ obj = FormWrapper(sample_template_paragraph_complex).fill(
97
+ {
98
+ "paragraph_font_auto_left": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
99
+ "paragraph_font_auto_right": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
100
+ "paragraph_font_auto_center": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
101
+ "paragraph_font_ten_left": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
102
+ "paragraph_font_ten_right": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
103
+ "paragraph_font_ten_center": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
104
+ }
105
+ )
106
+
107
+ request.config.results["expected_path"] = expected_path
108
+ request.config.results["stream"] = obj.read()
109
+
110
+ expected = f.read()
111
+
112
+ if os.name != "nt":
113
+ assert len(obj.read()) == len(expected)
114
+ assert obj.stream == expected
115
+
116
+
117
+ def test_paragraph_max_length(
118
+ sample_template_with_paragraph_max_length, pdf_samples, request
119
+ ):
120
+ expected_path = os.path.join(
121
+ pdf_samples, "simple", "paragraph", "test_paragraph_max_length.pdf"
122
+ )
123
+ with open(expected_path, "rb+") as f:
124
+ obj = FormWrapper(sample_template_with_paragraph_max_length).fill(
125
+ {
126
+ "paragraph": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
127
+ }
128
+ )
129
+
130
+ request.config.results["expected_path"] = expected_path
131
+ request.config.results["stream"] = obj.read()
132
+
133
+ expected = f.read()
134
+
135
+ if os.name != "nt":
136
+ assert len(obj.read()) == len(expected)
137
+ assert obj.stream == expected
@@ -1,6 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """Contains any object users might need."""
3
-
4
- __version__ = "1.4.11"
5
-
6
- from .wrapper import PdfWrapper, PyPDFForm
@@ -1,31 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """Contains checkbox middleware."""
3
-
4
- from .base import Widget
5
-
6
-
7
- class Checkbox(Widget):
8
- """A class to represent a checkbox widget."""
9
-
10
- def __init__(
11
- self,
12
- name: str,
13
- value: bool = None,
14
- ) -> None:
15
- """Constructs all attributes for the checkbox."""
16
-
17
- super().__init__(name, value)
18
-
19
- self.button_style = None
20
-
21
- @property
22
- def schema_definition(self) -> dict:
23
- """Json schema definition of the checkbox."""
24
-
25
- return {"type": "boolean"}
26
-
27
- @property
28
- def sample_value(self) -> bool:
29
- """Sample value of the checkbox."""
30
-
31
- return True
File without changes
File without changes
File without changes
File without changes
File without changes