PyPDFForm 1.5.0__tar.gz → 1.5.2__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 (49) hide show
  1. {pypdfform-1.5.0 → pypdfform-1.5.2}/PKG-INFO +10 -2
  2. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/__init__.py +1 -1
  3. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/adapter.py +1 -1
  4. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/constants.py +3 -3
  5. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/middleware/base.py +1 -0
  6. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/template.py +25 -2
  7. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/wrapper.py +30 -9
  8. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm.egg-info/PKG-INFO +10 -2
  9. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm.egg-info/SOURCES.txt +2 -1
  10. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_functional.py +16 -0
  11. pypdfform-1.5.2/tests/test_use_full_widget_name.py +49 -0
  12. {pypdfform-1.5.0 → pypdfform-1.5.2}/LICENSE +0 -0
  13. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/coordinate.py +0 -0
  14. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/filler.py +0 -0
  15. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/font.py +0 -0
  16. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/image.py +0 -0
  17. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/middleware/__init__.py +0 -0
  18. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/middleware/checkbox.py +0 -0
  19. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/middleware/dropdown.py +0 -0
  20. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/middleware/image.py +0 -0
  21. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/middleware/radio.py +0 -0
  22. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/middleware/signature.py +0 -0
  23. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/middleware/text.py +0 -0
  24. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/patterns.py +0 -0
  25. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/utils.py +0 -0
  26. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/watermark.py +0 -0
  27. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/widgets/__init__.py +0 -0
  28. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/widgets/base.py +0 -0
  29. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/widgets/checkbox.py +0 -0
  30. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/widgets/dropdown.py +0 -0
  31. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm/widgets/text.py +0 -0
  32. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm.egg-info/dependency_links.txt +0 -0
  33. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm.egg-info/requires.txt +0 -0
  34. {pypdfform-1.5.0 → pypdfform-1.5.2}/PyPDFForm.egg-info/top_level.txt +0 -0
  35. {pypdfform-1.5.0 → pypdfform-1.5.2}/README.md +0 -0
  36. {pypdfform-1.5.0 → pypdfform-1.5.2}/setup.cfg +0 -0
  37. {pypdfform-1.5.0 → pypdfform-1.5.2}/setup.py +0 -0
  38. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_adobe_mode.py +0 -0
  39. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_create_widget.py +0 -0
  40. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_dropdown.py +0 -0
  41. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_dropdown_simple.py +0 -0
  42. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_fill_max_length_text_field.py +0 -0
  43. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_fill_max_length_text_field_simple.py +0 -0
  44. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_fill_method.py +0 -0
  45. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_functional_simple.py +0 -0
  46. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_paragraph.py +0 -0
  47. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_paragraph_simple.py +0 -0
  48. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_preview.py +0 -0
  49. {pypdfform-1.5.0 → pypdfform-1.5.2}/tests/test_signature.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: PyPDFForm
3
- Version: 1.5.0
3
+ Version: 1.5.2
4
4
  Summary: The Python library for PDF forms.
5
5
  Home-page: https://github.com/chinapandaman/PyPDFForm
6
6
  Author: Jinge Li
@@ -24,6 +24,14 @@ Requires-Dist: cryptography
24
24
  Requires-Dist: pillow
25
25
  Requires-Dist: pypdf
26
26
  Requires-Dist: reportlab
27
+ Dynamic: author
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
27
35
 
28
36
  <p align="center"><img src="https://github.com/chinapandaman/PyPDFForm/raw/master/logo.png"></p>
29
37
  <p align="center">
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """Contains any object users might need."""
3
3
 
4
- __version__ = "1.5.0"
4
+ __version__ = "1.5.2"
5
5
 
6
6
  from .wrapper import FormWrapper, PdfWrapper
7
7
 
@@ -12,7 +12,7 @@ def readable(obj: Any) -> bool:
12
12
 
13
13
 
14
14
  def fp_or_f_obj_or_stream_to_stream(
15
- fp_or_f_obj_or_stream: Union[bytes, str, BinaryIO]
15
+ fp_or_f_obj_or_stream: Union[bytes, str, BinaryIO],
16
16
  ) -> bytes:
17
17
  """Converts a file path or a file object to a stream."""
18
18
 
@@ -76,11 +76,11 @@ NEW_LINE_SYMBOL = "\n"
76
76
  IMAGE_FIELD_IDENTIFIER = "event.target.buttonImportIcon();"
77
77
 
78
78
  DEFAULT_CHECKBOX_STYLE = "\u2713"
79
- DEFAULT_RADIO_STYLE = "\u25CF"
79
+ DEFAULT_RADIO_STYLE = "\u25cf"
80
80
  BUTTON_STYLES = {
81
81
  "4": "\u2713", # check
82
- "5": "\u00D7", # cross
83
- "l": "\u25CF", # circle
82
+ "5": "\u00d7", # cross
83
+ "l": "\u25cf", # circle
84
84
  }
85
85
 
86
86
  COORDINATE_GRID_FONT_SIZE_MARGIN_RATIO = DEFAULT_FONT_SIZE / 100
@@ -16,6 +16,7 @@ class Widget:
16
16
 
17
17
  super().__init__()
18
18
  self._name = name
19
+ self.full_name = None
19
20
  self._value = value
20
21
  self.desc = None
21
22
 
@@ -11,7 +11,7 @@ from pypdf.generic import DictionaryObject
11
11
  from reportlab.pdfbase.pdfmetrics import stringWidth
12
12
 
13
13
  from .constants import (COMB, DEFAULT_FONT_SIZE, MULTILINE, NEW_LINE_SYMBOL,
14
- WIDGET_TYPES, Annots, MaxLen, Rect)
14
+ WIDGET_TYPES, Annots, MaxLen, Parent, Rect, T)
15
15
  from .font import (adjust_paragraph_font_size, adjust_text_field_font_size,
16
16
  auto_detect_font, get_text_field_font_color,
17
17
  get_text_field_font_size, text_field_font_size)
@@ -43,7 +43,9 @@ def set_character_x_paddings(
43
43
  return widgets
44
44
 
45
45
 
46
- def build_widgets(pdf_stream: bytes) -> Dict[str, WIDGET_TYPES]:
46
+ def build_widgets(
47
+ pdf_stream: bytes, use_full_widget_name: bool
48
+ ) -> Dict[str, WIDGET_TYPES]:
47
49
  """Builds a widget dict given a PDF form stream."""
48
50
 
49
51
  results = {}
@@ -53,6 +55,7 @@ def build_widgets(pdf_stream: bytes) -> Dict[str, WIDGET_TYPES]:
53
55
  key = get_widget_key(widget)
54
56
  _widget = construct_widget(widget, key)
55
57
  if _widget is not None:
58
+ _widget.full_name = get_widget_full_key(widget)
56
59
  _widget.desc = get_widget_description(widget)
57
60
  if isinstance(_widget, Text):
58
61
  _widget.max_length = get_text_field_max_length(widget)
@@ -73,6 +76,8 @@ def build_widgets(pdf_stream: bytes) -> Dict[str, WIDGET_TYPES]:
73
76
  continue
74
77
 
75
78
  results[key] = _widget
79
+ if _widget.full_name is not None and use_full_widget_name:
80
+ results[_widget.full_name] = results[key]
76
81
  return results
77
82
 
78
83
 
@@ -190,6 +195,24 @@ def get_widget_key(widget: dict) -> Union[str, list, None]:
190
195
  return result
191
196
 
192
197
 
198
+ def get_widget_full_key(widget: dict) -> Union[str, None]:
199
+ """
200
+ Returns a PDF widget's full annotated key by prepending its
201
+ parent widget's key.
202
+ """
203
+
204
+ key = get_widget_key(widget)
205
+
206
+ if (
207
+ Parent in widget
208
+ and T in widget[Parent].get_object()
209
+ and widget[Parent][T] != key
210
+ ):
211
+ return f"{widget[Parent][T]}.{key}"
212
+
213
+ return None
214
+
215
+
193
216
  def get_widget_alignment(widget: dict) -> Union[str, list, None]:
194
217
  """Finds a PDF widget's alignment by pattern matching."""
195
218
 
@@ -52,7 +52,7 @@ class FormWrapper:
52
52
  ) -> FormWrapper:
53
53
  """Fills a PDF form."""
54
54
 
55
- widgets = build_widgets(self.stream) if self.stream else {}
55
+ widgets = build_widgets(self.stream, False) if self.stream else {}
56
56
 
57
57
  for key, value in data.items():
58
58
  if key in widgets:
@@ -71,6 +71,13 @@ class FormWrapper:
71
71
  class PdfWrapper(FormWrapper):
72
72
  """A class to represent a PDF form."""
73
73
 
74
+ USER_PARAMS = [
75
+ "global_font",
76
+ "global_font_size",
77
+ "global_font_color",
78
+ "use_full_widget_name",
79
+ ]
80
+
74
81
  def __init__(
75
82
  self,
76
83
  template: Union[bytes, str, BinaryIO] = b"",
@@ -82,9 +89,8 @@ class PdfWrapper(FormWrapper):
82
89
  self.widgets = {}
83
90
  self._keys_to_update = []
84
91
 
85
- self.global_font = kwargs.get("global_font")
86
- self.global_font_size = kwargs.get("global_font_size")
87
- self.global_font_color = kwargs.get("global_font_color")
92
+ for each in self.USER_PARAMS:
93
+ setattr(self, each, kwargs.get(each))
88
94
 
89
95
  self._init_helper()
90
96
 
@@ -92,7 +98,11 @@ class PdfWrapper(FormWrapper):
92
98
  """Updates all attributes when the state of the PDF stream changes."""
93
99
 
94
100
  refresh_not_needed = {}
95
- new_widgets = build_widgets(self.read()) if self.read() else {}
101
+ new_widgets = (
102
+ build_widgets(self.read(), getattr(self, "use_full_widget_name"))
103
+ if self.read()
104
+ else {}
105
+ )
96
106
  for k, v in self.widgets.items():
97
107
  if k in new_widgets:
98
108
  new_widgets[k] = v
@@ -105,9 +115,9 @@ class PdfWrapper(FormWrapper):
105
115
  and isinstance(value, Text)
106
116
  and not refresh_not_needed.get(key)
107
117
  ):
108
- value.font = self.global_font
109
- value.font_size = self.global_font_size
110
- value.font_color = self.global_font_color
118
+ value.font = getattr(self, "global_font")
119
+ value.font_size = getattr(self, "global_font_size")
120
+ value.font_color = getattr(self, "global_font_color")
111
121
 
112
122
  @property
113
123
  def sample_data(self) -> dict:
@@ -129,7 +139,12 @@ class PdfWrapper(FormWrapper):
129
139
  def pages(self) -> List[PdfWrapper]:
130
140
  """Returns a list of pdf wrapper objects where each is a page of the PDF form."""
131
141
 
132
- return [self.__class__(each) for each in get_page_streams(self.stream)]
142
+ return [
143
+ self.__class__(
144
+ each, **{param: getattr(self, param) for param in self.USER_PARAMS}
145
+ )
146
+ for each in get_page_streams(self.stream)
147
+ ]
133
148
 
134
149
  def change_version(self, version: str) -> PdfWrapper:
135
150
  """Changes the version of the PDF."""
@@ -254,6 +269,9 @@ class PdfWrapper(FormWrapper):
254
269
  ) -> PdfWrapper:
255
270
  """Updates the key of an existed widget on a PDF form."""
256
271
 
272
+ if getattr(self, "use_full_widget_name"):
273
+ raise NotImplementedError
274
+
257
275
  if defer:
258
276
  self._keys_to_update.append((old_key, new_key, index))
259
277
  return self
@@ -268,6 +286,9 @@ class PdfWrapper(FormWrapper):
268
286
  def commit_widget_key_updates(self) -> PdfWrapper:
269
287
  """Commits all deferred widget key updates on a PDF form."""
270
288
 
289
+ if getattr(self, "use_full_widget_name"):
290
+ raise NotImplementedError
291
+
271
292
  old_keys = [each[0] for each in self._keys_to_update]
272
293
  new_keys = [each[1] for each in self._keys_to_update]
273
294
  indices = [each[2] for each in self._keys_to_update]
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: PyPDFForm
3
- Version: 1.5.0
3
+ Version: 1.5.2
4
4
  Summary: The Python library for PDF forms.
5
5
  Home-page: https://github.com/chinapandaman/PyPDFForm
6
6
  Author: Jinge Li
@@ -24,6 +24,14 @@ Requires-Dist: cryptography
24
24
  Requires-Dist: pillow
25
25
  Requires-Dist: pypdf
26
26
  Requires-Dist: reportlab
27
+ Dynamic: author
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
27
35
 
28
36
  <p align="center"><img src="https://github.com/chinapandaman/PyPDFForm/raw/master/logo.png"></p>
29
37
  <p align="center">
@@ -43,4 +43,5 @@ tests/test_functional_simple.py
43
43
  tests/test_paragraph.py
44
44
  tests/test_paragraph_simple.py
45
45
  tests/test_preview.py
46
- tests/test_signature.py
46
+ tests/test_signature.py
47
+ tests/test_use_full_widget_name.py
@@ -516,6 +516,22 @@ def test_pages(template_stream, pdf_samples, request):
516
516
  assert obj.pages[0].read() == f.read()
517
517
 
518
518
 
519
+ def test_pages_inherit_attributes(template_stream):
520
+ obj = PdfWrapper(
521
+ template_stream,
522
+ global_font="Courier",
523
+ global_font_size=20,
524
+ global_font_color=(1, 0, 0),
525
+ use_full_widget_name=True,
526
+ )
527
+
528
+ for page in obj.pages:
529
+ assert getattr(page, "global_font") == "Courier"
530
+ assert getattr(page, "global_font_size") == 20
531
+ assert getattr(page, "global_font_color") == (1, 0, 0)
532
+ assert getattr(page, "use_full_widget_name")
533
+
534
+
519
535
  def test_generate_coordinate_grid(template_stream, pdf_samples, request):
520
536
  expected_path = os.path.join(pdf_samples, "test_generate_coordinate_grid.pdf")
521
537
  with open(expected_path, "rb+") as f:
@@ -0,0 +1,49 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import pytest
4
+
5
+ from PyPDFForm import PdfWrapper
6
+
7
+
8
+ def test_init(sample_template_with_full_key):
9
+ obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
10
+ assert "Gain de 2 classes.0" in obj.widgets
11
+ assert obj.widgets["Gain de 2 classes.0"] is obj.widgets["0"]
12
+
13
+
14
+ def test_sample_data(sample_template_with_full_key):
15
+ obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
16
+ assert "Gain de 2 classes.0" in obj.sample_data
17
+ assert obj.sample_data["Gain de 2 classes.0"] == obj.sample_data["0"]
18
+
19
+
20
+ def test_fill(sample_template_with_full_key):
21
+ obj_1 = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
22
+ obj_2 = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
23
+
24
+ assert (
25
+ obj_1.fill({"Gain de 2 classes.0": True}).read()
26
+ == obj_2.fill({"0": True}).read()
27
+ )
28
+
29
+
30
+ def test_update_widget_key(sample_template_with_full_key):
31
+ obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
32
+
33
+ with pytest.raises(NotImplementedError):
34
+ obj.update_widget_key("0", "foo")
35
+
36
+
37
+ def test_commit_widget_key_updates(sample_template_with_full_key):
38
+ obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
39
+
40
+ with pytest.raises(NotImplementedError):
41
+ obj.commit_widget_key_updates()
42
+
43
+
44
+ def test_schema(sample_template_with_full_key):
45
+ obj = PdfWrapper(sample_template_with_full_key, use_full_widget_name=True)
46
+ assert "Gain de 2 classes.0" in obj.schema["properties"]
47
+ assert (
48
+ obj.schema["properties"]["Gain de 2 classes.0"] == obj.schema["properties"]["0"]
49
+ )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes