PyPDFForm 5.2.3__tar.gz → 5.2.4__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.2.3 → pypdfform-5.2.4}/PKG-INFO +1 -1
  2. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/__init__.py +1 -1
  3. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/egress.py +72 -9
  4. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/utils.py +58 -1
  5. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/wrapper.py +44 -18
  6. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm.egg-info/PKG-INFO +1 -1
  7. {pypdfform-5.2.3 → pypdfform-5.2.4}/pyproject.toml +1 -1
  8. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_bulk_create_fields.py +2 -2
  9. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_create_widget.py +16 -16
  10. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_draw_elements.py +2 -2
  11. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_dropdown.py +2 -2
  12. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_functional.py +37 -13
  13. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_generate_appearance_streams.py +27 -28
  14. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_need_appearances.py +5 -6
  15. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_paragraph.py +2 -2
  16. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_signature.py +3 -3
  17. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_widget_attr_trigger.py +3 -3
  18. {pypdfform-5.2.3 → pypdfform-5.2.4}/LICENSE +0 -0
  19. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/__init__.py +0 -0
  20. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/common.py +0 -0
  21. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/create.py +0 -0
  22. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/entry.py +0 -0
  23. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/inspect.py +0 -0
  24. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/remove.py +0 -0
  25. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/root.py +0 -0
  26. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/schemas/__init__.py +0 -0
  27. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/schemas/create.py +0 -0
  28. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/schemas/update.py +0 -0
  29. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/cli/update.py +0 -0
  30. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/__init__.py +0 -0
  31. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/adapter.py +0 -0
  32. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/annotations/__init__.py +0 -0
  33. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/annotations/base.py +0 -0
  34. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/annotations/link.py +0 -0
  35. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/annotations/stamp.py +0 -0
  36. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/annotations/text.py +0 -0
  37. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/annotations/text_markup.py +0 -0
  38. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/assets/__init__.py +0 -0
  39. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/assets/bedrock.py +0 -0
  40. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/assets/blank.py +0 -0
  41. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/constants.py +0 -0
  42. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/coordinate.py +0 -0
  43. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/deprecation.py +0 -0
  44. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/filler.py +0 -0
  45. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/font.py +0 -0
  46. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/hooks.py +0 -0
  47. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/image.py +0 -0
  48. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/middleware/__init__.py +0 -0
  49. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/middleware/base.py +0 -0
  50. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/middleware/checkbox.py +0 -0
  51. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/middleware/dropdown.py +0 -0
  52. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/middleware/image.py +0 -0
  53. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/middleware/radio.py +0 -0
  54. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/middleware/signature.py +0 -0
  55. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/middleware/text.py +0 -0
  56. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/patterns.py +0 -0
  57. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/raw/__init__.py +0 -0
  58. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/raw/circle.py +0 -0
  59. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/raw/ellipse.py +0 -0
  60. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/raw/image.py +0 -0
  61. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/raw/line.py +0 -0
  62. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/raw/rect.py +0 -0
  63. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/raw/text.py +0 -0
  64. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/template.py +0 -0
  65. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/types.py +0 -0
  66. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/watermark.py +0 -0
  67. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/widgets/__init__.py +0 -0
  68. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/widgets/base.py +0 -0
  69. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/widgets/checkbox.py +0 -0
  70. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/widgets/dropdown.py +0 -0
  71. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/widgets/image.py +0 -0
  72. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/widgets/radio.py +0 -0
  73. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/widgets/signature.py +0 -0
  74. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm/lib/widgets/text.py +0 -0
  75. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm.egg-info/SOURCES.txt +0 -0
  76. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm.egg-info/dependency_links.txt +0 -0
  77. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm.egg-info/entry_points.txt +0 -0
  78. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm.egg-info/requires.txt +0 -0
  79. {pypdfform-5.2.3 → pypdfform-5.2.4}/PyPDFForm.egg-info/top_level.txt +0 -0
  80. {pypdfform-5.2.3 → pypdfform-5.2.4}/README.md +0 -0
  81. {pypdfform-5.2.3 → pypdfform-5.2.4}/setup.cfg +0 -0
  82. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_extract_middleware_attributes.py +0 -0
  83. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_fill_max_length_text_field.py +0 -0
  84. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_font_widths.py +0 -0
  85. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_js.py +0 -0
  86. {pypdfform-5.2.3 → pypdfform-5.2.4}/tests/test_use_full_widget_name.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 5.2.3
3
+ Version: 5.2.4
4
4
  Summary: The Python library & CLI for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -18,7 +18,7 @@ from Python code or from the command line.
18
18
 
19
19
  import logging
20
20
 
21
- __version__ = "5.2.3"
21
+ __version__ = "5.2.4"
22
22
 
23
23
  from .lib.annotations import Annotations
24
24
  from .lib.assets.blank import BlankPage
@@ -6,19 +6,33 @@ This module provides functionalities that prepare the final PDF for output (egre
6
6
  ensuring that it is properly formatted and ready for the end-user. This includes
7
7
  managing appearance streams (so form fields display correctly after being filled),
8
8
  handling the /NeedAppearances flag, and preserving or updating document-level
9
- properties like metadata, title, and OpenAction scripts. These functions are typically
10
- called right before the final PDF byte stream is returned by the wrapper module.
9
+ properties like metadata, title, and OpenAction scripts. It can also rebuild the
10
+ AcroForm `/Fields` array from the widget annotations present on each page. These
11
+ functions are typically called right before the final PDF byte stream is returned by
12
+ the wrapper module.
11
13
  """
12
14
 
13
15
  from functools import lru_cache
14
16
  from io import BytesIO
15
- from warnings import catch_warnings, simplefilter
17
+ from warnings import catch_warnings, filterwarnings
16
18
 
17
19
  from pikepdf import Pdf
18
20
  from pypdf import PdfReader, PdfWriter
19
- from pypdf.generic import DictionaryObject, NameObject, TextStringObject
20
-
21
- from .constants import JS, XFA, AcroForm, JavaScript, OpenAction, Root, S, Title
21
+ from pypdf.generic import ArrayObject, DictionaryObject, NameObject, TextStringObject
22
+
23
+ from .constants import (
24
+ JS,
25
+ XFA,
26
+ AcroForm,
27
+ Annots,
28
+ Fields,
29
+ JavaScript,
30
+ OpenAction,
31
+ Root,
32
+ S,
33
+ Title,
34
+ )
35
+ from .template import get_widget_key
22
36
 
23
37
 
24
38
  @lru_cache(maxsize=128)
@@ -58,12 +72,14 @@ def appearance_streams_handler(pdf: bytes, generate_appearance_streams: bool) ->
58
72
  result = f.read()
59
73
 
60
74
  if generate_appearance_streams:
61
- # TODO: remove after fixing /Annots /Fields mismatch
62
75
  with Pdf.open(BytesIO(result)) as f, catch_warnings():
63
- simplefilter("ignore")
76
+ filterwarnings(
77
+ "ignore", message=".*/AcroForm.*"
78
+ ) # handled by rebuild_acroform_fields
79
+
64
80
  f.generate_appearance_streams()
65
81
  with BytesIO() as r:
66
- f.save(r)
82
+ f.save(r, deterministic_id=True)
67
83
  r.seek(0)
68
84
  result = r.read()
69
85
 
@@ -114,3 +130,50 @@ def preserve_pdf_properties(
114
130
  writer.write(f)
115
131
  f.seek(0)
116
132
  return f.read()
133
+
134
+
135
+ def rebuild_acroform_fields(
136
+ pdf: bytes, widget_keys: set, use_full_widget_name: bool
137
+ ) -> bytes:
138
+ """
139
+ Rebuilds the AcroForm `/Fields` array from matching page annotations.
140
+
141
+ The existing `/Fields` array is replaced, creating an AcroForm dictionary
142
+ when necessary. Each page annotation is resolved to a widget key, and only
143
+ annotations whose keys are present in `widget_keys` are added to the new
144
+ array. Page annotation arrays are left unchanged. When no matching page
145
+ annotations are found, the original PDF stream is returned unchanged to
146
+ avoid an unnecessary rewrite.
147
+
148
+ Args:
149
+ pdf (bytes): The PDF stream whose AcroForm fields should be rebuilt.
150
+ widget_keys (set): Widget keys to include in the rebuilt `/Fields` array.
151
+ use_full_widget_name (bool): Whether to resolve annotations using their
152
+ full widget names, including parent names.
153
+
154
+ Returns:
155
+ bytes: The PDF stream with a rebuilt AcroForm `/Fields` array, or the
156
+ original stream when there are no matching widgets to rebuild.
157
+ """
158
+ writer = PdfWriter(BytesIO(pdf))
159
+ root = writer._root_object # type: ignore # noqa: SLF001 # # pylint: disable=W0212
160
+
161
+ if AcroForm not in root:
162
+ root[NameObject(AcroForm)] = DictionaryObject({})
163
+ root[AcroForm][NameObject(Fields)] = ArrayObject([])
164
+
165
+ needs_update = False
166
+ for page in writer.pages:
167
+ for annot in page.get(Annots, []):
168
+ key = get_widget_key(annot.get_object(), use_full_widget_name)
169
+ if key in widget_keys:
170
+ root[AcroForm][Fields].append(annot)
171
+ needs_update = True
172
+
173
+ if not needs_update:
174
+ return pdf
175
+
176
+ with BytesIO() as f:
177
+ writer.write(f)
178
+ f.seek(0)
179
+ return f.read()
@@ -21,7 +21,13 @@ from typing import Any, List
21
21
  from pypdf import PdfReader, PdfWriter
22
22
  from pypdf.generic import ArrayObject, DictionaryObject, NameObject
23
23
 
24
- from .constants import SLASH, UNIQUE_SUFFIX_LENGTH, Annots
24
+ from .constants import (
25
+ SLASH,
26
+ UNIQUE_SUFFIX_LENGTH,
27
+ VERSION_IDENTIFIER_PREFIX,
28
+ VERSION_IDENTIFIERS,
29
+ Annots,
30
+ )
25
31
 
26
32
 
27
33
  @lru_cache(maxsize=128)
@@ -329,3 +335,54 @@ def generate_unique_suffix() -> str:
329
335
  for _ in range(UNIQUE_SUFFIX_LENGTH)
330
336
  ]
331
337
  )
338
+
339
+
340
+ def get_version(pdf: bytes) -> str | None:
341
+ """
342
+ Extracts the PDF header version from a byte stream.
343
+
344
+ The stream is checked against the supported PDF header identifiers defined
345
+ in constants. The function inspects the original bytes directly so callers
346
+ can capture a document's version before handing it to tools that may rewrite
347
+ the header during output processing.
348
+
349
+ Args:
350
+ pdf (bytes): The PDF stream to inspect.
351
+
352
+ Returns:
353
+ str | None: The PDF version string, or None when the stream does not
354
+ start with a known PDF version identifier.
355
+ """
356
+
357
+ result = None
358
+ for each in VERSION_IDENTIFIERS:
359
+ if pdf.startswith(each):
360
+ result = each.replace(VERSION_IDENTIFIER_PREFIX, b"").decode()
361
+ break
362
+
363
+ return result
364
+
365
+
366
+ def set_version(pdf: bytes, old: str, new: str) -> bytes:
367
+ """
368
+ Replaces the first PDF header version marker in a byte stream.
369
+
370
+ This helper only changes the literal header marker, such as `%PDF-1.7`; it
371
+ does not validate or rewrite the document for version-specific feature
372
+ compatibility. It is used after egress rewrites so output keeps the wrapper's
373
+ cached version instead of inheriting a writer-selected version.
374
+
375
+ Args:
376
+ pdf (bytes): The PDF stream to update.
377
+ old (str): The currently present PDF version string.
378
+ new (str): The PDF version string to write into the header.
379
+
380
+ Returns:
381
+ bytes: The PDF stream with the first matching version marker replaced.
382
+ """
383
+
384
+ return pdf.replace(
385
+ VERSION_IDENTIFIER_PREFIX + bytes(old, "utf-8"),
386
+ VERSION_IDENTIFIER_PREFIX + bytes(new, "utf-8"),
387
+ 1,
388
+ )
@@ -37,9 +37,12 @@ from .adapter import (
37
37
  fp_or_f_obj_or_f_content_to_content,
38
38
  fp_or_f_obj_or_stream_to_stream,
39
39
  )
40
- from .constants import VERSION_IDENTIFIER_PREFIX, VERSION_IDENTIFIERS
41
40
  from .coordinate import generate_coordinate_grid
42
- from .egress import appearance_streams_handler, preserve_pdf_properties
41
+ from .egress import (
42
+ appearance_streams_handler,
43
+ preserve_pdf_properties,
44
+ rebuild_acroform_fields,
45
+ )
43
46
  from .filler import fill
44
47
  from .font import (
45
48
  get_all_available_fonts,
@@ -62,8 +65,10 @@ from .types import PdfArray
62
65
  from .utils import (
63
66
  generate_unique_suffix,
64
67
  get_page_streams,
68
+ get_version,
65
69
  merge_pdfs,
66
70
  remove_all_widgets,
71
+ set_version,
67
72
  )
68
73
  from .watermark import (
69
74
  copy_watermark_widgets,
@@ -144,12 +149,14 @@ class PdfWrapper:
144
149
  self._stream = fp_or_f_obj_or_stream_to_stream(template)
145
150
  self.widgets = {}
146
151
  self.title: Optional[str] = None
152
+
153
+ self._version = None
147
154
  self._metadata = (
148
155
  get_metadata(self._read()) if kwargs.get("preserve_metadata") else {}
149
156
  )
150
157
  self._on_open_javascript = None
151
158
  self._available_fonts = {} # for setting /F1
152
- self._available_fonts_loaded = False
159
+ self._available_fonts_loaded = None # for lazy loading fonts
153
160
  self._font_register_events = [] # for reregister
154
161
  self._key_update_tracker = {} # for update key preserve old key attrs
155
162
  self._keys_to_update = [] # for bulk update keys
@@ -221,8 +228,8 @@ class PdfWrapper:
221
228
  It rebuilds the widget dictionary and invalidates the lazily loaded font cache.
222
229
  """
223
230
 
224
- stream = self._read()
225
231
  self._available_fonts_loaded = False
232
+ stream = self._read()
226
233
  new_widgets = (
227
234
  build_widgets(
228
235
  stream,
@@ -363,15 +370,18 @@ class PdfWrapper:
363
370
  """
364
371
  Returns the PDF version of the underlying PDF document.
365
372
 
373
+ The version is read from the PDF header lazily and cached so egress-only
374
+ rewrites can restore the wrapper's original version even if an underlying
375
+ PDF writer emits a different default header.
376
+
366
377
  Returns:
367
378
  str | None: The PDF version as a string, or None if the version cannot be determined.
368
379
  """
369
380
 
370
- for each in VERSION_IDENTIFIERS:
371
- if self._read().startswith(each):
372
- return each.replace(VERSION_IDENTIFIER_PREFIX, b"").decode()
381
+ if self._version is None:
382
+ self._version = get_version(self._read())
373
383
 
374
- return None
384
+ return self._version
375
385
 
376
386
  @property
377
387
  def fonts(self) -> list:
@@ -452,6 +462,11 @@ class PdfWrapper:
452
462
  generating appearance streams.
453
463
  3. If `preserve_metadata`, title, or on-open JavaScript are set, it preserves
454
464
  or updates the corresponding PDF properties accordingly.
465
+ 4. Rebuilds the AcroForm `/Fields` array from page annotations for
466
+ widgets known to this wrapper, leaving the stream unchanged when no
467
+ matching widget annotations are found.
468
+ 5. Restores the wrapper's cached PDF header version after egress
469
+ processing, since PDF writers may emit their own default version.
455
470
  The wrapper's stored stream is not replaced by these final egress-only changes.
456
471
 
457
472
  Returns:
@@ -464,8 +479,15 @@ class PdfWrapper:
464
479
  result, getattr(self, "generate_appearance_streams")
465
480
  ) # cached
466
481
 
467
- if any(
468
- [getattr(self, "preserve_metadata"), self.title, self.on_open_javascript]
482
+ if (
483
+ any(
484
+ [
485
+ getattr(self, "preserve_metadata"),
486
+ self.title,
487
+ self.on_open_javascript,
488
+ ]
489
+ )
490
+ and result
469
491
  ):
470
492
  result = preserve_pdf_properties(
471
493
  result,
@@ -474,6 +496,12 @@ class PdfWrapper:
474
496
  self._metadata if getattr(self, "preserve_metadata") else None,
475
497
  )
476
498
 
499
+ if result:
500
+ result = rebuild_acroform_fields(
501
+ result, set(self.widgets.keys()), getattr(self, "use_full_widget_name")
502
+ )
503
+ if self.version:
504
+ result = set_version(result, get_version(result), self.version)
477
505
  return result
478
506
 
479
507
  def _read(self) -> bytes:
@@ -546,9 +574,9 @@ class PdfWrapper:
546
574
  """
547
575
  Changes the PDF version of the underlying document.
548
576
 
549
- The method replaces the first PDF header version marker in the current stream.
550
- It does not otherwise validate or rewrite the document for version-specific
551
- compatibility.
577
+ The method replaces the first PDF header version marker in the current stream
578
+ and updates the cached version used by later egress processing. It does not
579
+ otherwise validate or rewrite the document for version-specific compatibility.
552
580
 
553
581
  Args:
554
582
  version (str): The new PDF version string (e.g., "1.7").
@@ -557,11 +585,9 @@ class PdfWrapper:
557
585
  PdfWrapper: The `PdfWrapper` object, allowing for method chaining.
558
586
  """
559
587
 
560
- self._stream = self._read().replace(
561
- VERSION_IDENTIFIER_PREFIX + bytes(self.version, "utf-8"),
562
- VERSION_IDENTIFIER_PREFIX + bytes(version, "utf-8"),
563
- 1,
564
- )
588
+ if self.version:
589
+ self._stream = set_version(self._read(), self.version, version)
590
+ self._version = version
565
591
 
566
592
  return self
567
593
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 5.2.3
3
+ Version: 5.2.4
4
4
  Summary: The Python library & CLI for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -140,6 +140,6 @@ include = ["PyPDFForm*"]
140
140
 
141
141
  [tool.pytest.ini_options]
142
142
  markers = [
143
- "posix_only", # mainly because of zlib vs zlib-ng
143
+ "requires_zlib_over_zlib_ng", # expected PDF streams differ when Python uses zlib-ng
144
144
  "cli_test",
145
145
  ]
@@ -10,7 +10,7 @@ from PyPDFForm import BlankPage, Fields, PdfWrapper
10
10
  from PyPDFForm.lib.constants import Annots, Subtype, Widget
11
11
 
12
12
 
13
- @pytest.mark.posix_only
13
+ @pytest.mark.requires_zlib_over_zlib_ng
14
14
  def test_bulk_create_fields_stress_max(pdf_samples, request):
15
15
  expected_path = os.path.join(
16
16
  pdf_samples, "bulk_create_fields", "test_bulk_create_fields_stress_max.pdf"
@@ -86,7 +86,7 @@ def test_bulk_create_fields_stress_max(pdf_samples, request):
86
86
  assert obj.read() == expected
87
87
 
88
88
 
89
- @pytest.mark.posix_only
89
+ @pytest.mark.requires_zlib_over_zlib_ng
90
90
  def test_bulk_create_fields_stress_max_mixed(pdf_samples, request):
91
91
  expected_path = os.path.join(
92
92
  pdf_samples,
@@ -7,7 +7,7 @@ import pytest
7
7
  from PyPDFForm import Fields, PdfWrapper
8
8
 
9
9
 
10
- @pytest.mark.posix_only
10
+ @pytest.mark.requires_zlib_over_zlib_ng
11
11
  def test_create_checkbox_complex_fill(template_stream, pdf_samples, request):
12
12
  expected_path = os.path.join(
13
13
  pdf_samples, "widget", "test_create_checkbox_complex_fill.pdf"
@@ -42,7 +42,7 @@ def test_create_checkbox_complex_fill(template_stream, pdf_samples, request):
42
42
  assert obj.read() == expected
43
43
 
44
44
 
45
- @pytest.mark.posix_only
45
+ @pytest.mark.requires_zlib_over_zlib_ng
46
46
  def test_create_checkbox_check_fill(template_stream, pdf_samples, request):
47
47
  expected_path = os.path.join(
48
48
  pdf_samples, "widget", "test_create_checkbox_check_fill.pdf"
@@ -70,7 +70,7 @@ def test_create_checkbox_check_fill(template_stream, pdf_samples, request):
70
70
  assert obj.read() == expected
71
71
 
72
72
 
73
- @pytest.mark.posix_only
73
+ @pytest.mark.requires_zlib_over_zlib_ng
74
74
  def test_create_checkbox_circle_fill(template_stream, pdf_samples, request):
75
75
  expected_path = os.path.join(
76
76
  pdf_samples, "widget", "test_create_checkbox_circle_fill.pdf"
@@ -98,7 +98,7 @@ def test_create_checkbox_circle_fill(template_stream, pdf_samples, request):
98
98
  assert obj.read() == expected
99
99
 
100
100
 
101
- @pytest.mark.posix_only
101
+ @pytest.mark.requires_zlib_over_zlib_ng
102
102
  def test_create_checkbox_cross_fill(template_stream, pdf_samples, request):
103
103
  expected_path = os.path.join(
104
104
  pdf_samples, "widget", "test_create_checkbox_cross_fill.pdf"
@@ -126,7 +126,7 @@ def test_create_checkbox_cross_fill(template_stream, pdf_samples, request):
126
126
  assert obj.read() == expected
127
127
 
128
128
 
129
- @pytest.mark.posix_only
129
+ @pytest.mark.requires_zlib_over_zlib_ng
130
130
  def test_create_text_alpha_bg_color(template_stream, pdf_samples, request):
131
131
  expected_path = os.path.join(
132
132
  pdf_samples, "widget", "test_create_text_alpha_bg_color.pdf"
@@ -154,7 +154,7 @@ def test_create_text_alpha_bg_color(template_stream, pdf_samples, request):
154
154
  assert obj.read() == expected
155
155
 
156
156
 
157
- @pytest.mark.posix_only
157
+ @pytest.mark.requires_zlib_over_zlib_ng
158
158
  def test_create_text_align_center(template_stream, pdf_samples, request):
159
159
  expected_path = os.path.join(
160
160
  pdf_samples, "widget", "test_create_text_align_center.pdf"
@@ -182,7 +182,7 @@ def test_create_text_align_center(template_stream, pdf_samples, request):
182
182
  assert obj.read() == expected
183
183
 
184
184
 
185
- @pytest.mark.posix_only
185
+ @pytest.mark.requires_zlib_over_zlib_ng
186
186
  def test_create_text_multiline(template_stream, pdf_samples, request):
187
187
  expected_path = os.path.join(
188
188
  pdf_samples, "widget", "test_create_text_align_multiline.pdf"
@@ -210,7 +210,7 @@ def test_create_text_multiline(template_stream, pdf_samples, request):
210
210
  assert obj.read() == expected
211
211
 
212
212
 
213
- @pytest.mark.posix_only
213
+ @pytest.mark.requires_zlib_over_zlib_ng
214
214
  def test_create_text_complex_filled(
215
215
  template_stream, pdf_samples, sample_font_stream, request
216
216
  ):
@@ -252,7 +252,7 @@ def test_create_text_complex_filled(
252
252
  assert obj.read() == expected
253
253
 
254
254
 
255
- @pytest.mark.posix_only
255
+ @pytest.mark.requires_zlib_over_zlib_ng
256
256
  def test_create_text_comb(template_stream, pdf_samples, request):
257
257
  expected_path = os.path.join(pdf_samples, "widget", "test_create_text_comb.pdf")
258
258
  with open(expected_path, "rb+") as f:
@@ -278,7 +278,7 @@ def test_create_text_comb(template_stream, pdf_samples, request):
278
278
  assert obj.read() == expected
279
279
 
280
280
 
281
- @pytest.mark.posix_only
281
+ @pytest.mark.requires_zlib_over_zlib_ng
282
282
  def test_create_checkbox_persist_old_widgets_fill(
283
283
  template_stream, pdf_samples, request
284
284
  ):
@@ -310,7 +310,7 @@ def test_create_checkbox_persist_old_widgets_fill(
310
310
  assert obj.read() == expected
311
311
 
312
312
 
313
- @pytest.mark.posix_only
313
+ @pytest.mark.requires_zlib_over_zlib_ng
314
314
  def test_create_widget_sejda_fill_flatten_before(sejda_template, pdf_samples, request):
315
315
  expected_path = os.path.join(
316
316
  pdf_samples, "widget", "test_create_widget_sejda_fill_flatten_before.pdf"
@@ -344,7 +344,7 @@ def test_create_widget_sejda_fill_flatten_before(sejda_template, pdf_samples, re
344
344
  assert obj.read() == expected
345
345
 
346
346
 
347
- @pytest.mark.posix_only
347
+ @pytest.mark.requires_zlib_over_zlib_ng
348
348
  def test_create_widget_sejda_fill_flatten_after(sejda_template, pdf_samples, request):
349
349
  expected_path = os.path.join(
350
350
  pdf_samples, "widget", "test_create_widget_sejda_fill_flatten_after.pdf"
@@ -422,7 +422,7 @@ def test_fill_cmyk_color(pdf_samples, request):
422
422
  assert obj.read() == expected
423
423
 
424
424
 
425
- @pytest.mark.posix_only
425
+ @pytest.mark.requires_zlib_over_zlib_ng
426
426
  def test_create_radio_complex(template_stream, pdf_samples, request):
427
427
  expected_path = os.path.join(pdf_samples, "widget", "test_create_radio_complex.pdf")
428
428
  with open(expected_path, "rb+") as f:
@@ -454,7 +454,7 @@ def test_create_radio_complex(template_stream, pdf_samples, request):
454
454
  assert obj.read() == expected
455
455
 
456
456
 
457
- @pytest.mark.posix_only
457
+ @pytest.mark.requires_zlib_over_zlib_ng
458
458
  def test_create_required_fields(pdf_samples, request):
459
459
  expected_path = os.path.join(
460
460
  pdf_samples, "widget", "test_create_required_fields.pdf"
@@ -505,7 +505,7 @@ def test_create_required_fields(pdf_samples, request):
505
505
  assert obj.read() == expected
506
506
 
507
507
 
508
- @pytest.mark.posix_only
508
+ @pytest.mark.requires_zlib_over_zlib_ng
509
509
  def test_create_not_required_fields(pdf_samples, request):
510
510
  expected_path = os.path.join(
511
511
  pdf_samples, "widget", "test_create_not_required_fields.pdf"
@@ -556,7 +556,7 @@ def test_create_not_required_fields(pdf_samples, request):
556
556
  assert obj.read() == expected
557
557
 
558
558
 
559
- @pytest.mark.posix_only
559
+ @pytest.mark.requires_zlib_over_zlib_ng
560
560
  def test_create_fields_with_tooltips(pdf_samples, request):
561
561
  expected_path = os.path.join(
562
562
  pdf_samples, "widget", "test_create_fields_with_tooltips.pdf"
@@ -142,7 +142,7 @@ def test_draw_image_on_sejda_template(
142
142
  assert obj.read() == expected
143
143
 
144
144
 
145
- @pytest.mark.posix_only
145
+ @pytest.mark.requires_zlib_over_zlib_ng
146
146
  def test_draw_png_image_on_one_page(
147
147
  template_stream, image_samples, pdf_samples, request
148
148
  ):
@@ -169,7 +169,7 @@ def test_draw_png_image_on_one_page(
169
169
  assert obj.read() == expected
170
170
 
171
171
 
172
- @pytest.mark.posix_only
172
+ @pytest.mark.requires_zlib_over_zlib_ng
173
173
  def test_draw_transparent_png_image_on_one_page(
174
174
  template_stream, image_samples, pdf_samples, request
175
175
  ):
@@ -65,7 +65,7 @@ def test_dropdown_one_flatten(sample_template_with_dropdown, pdf_samples, reques
65
65
  assert obj.read() == expected
66
66
 
67
67
 
68
- @pytest.mark.posix_only
68
+ @pytest.mark.requires_zlib_over_zlib_ng
69
69
  def test_dropdown_alignment(dropdown_alignment, pdf_samples, request):
70
70
  expected_path = os.path.join(pdf_samples, "dropdown", "test_dropdown_alignment.pdf")
71
71
  with open(expected_path, "rb+") as f:
@@ -86,7 +86,7 @@ def test_dropdown_alignment(dropdown_alignment, pdf_samples, request):
86
86
  assert obj.read() == expected
87
87
 
88
88
 
89
- @pytest.mark.posix_only
89
+ @pytest.mark.requires_zlib_over_zlib_ng
90
90
  def test_dropdown_alignment_flatten_then_unflatten(
91
91
  dropdown_alignment, pdf_samples, request
92
92
  ):
@@ -5,12 +5,22 @@ from io import BytesIO
5
5
 
6
6
  import pytest
7
7
  from jsonschema import ValidationError, validate
8
+ from pypdf import PdfReader
8
9
 
9
10
  from PyPDFForm import Annotations, BlankPage, Fields, PdfArray, PdfWrapper
10
- from PyPDFForm.lib.constants import DA, UNIQUE_SUFFIX_LENGTH, T, V
11
+ from PyPDFForm.lib.constants import (
12
+ DA,
13
+ UNIQUE_SUFFIX_LENGTH,
14
+ AcroForm,
15
+ T,
16
+ V,
17
+ )
18
+ from PyPDFForm.lib.constants import (
19
+ Fields as FieldsConst,
20
+ )
11
21
  from PyPDFForm.lib.deprecation import deprecation_notice
12
22
  from PyPDFForm.lib.middleware.base import Widget
13
- from PyPDFForm.lib.template import get_widgets_by_page
23
+ from PyPDFForm.lib.template import get_widget_key, get_widgets_by_page
14
24
 
15
25
 
16
26
  def test_deprecation_warning():
@@ -95,9 +105,9 @@ def test_base_schema_definition():
95
105
  assert Widget("foo").schema_definition == {}
96
106
 
97
107
 
98
- def test_write(template_stream, pdf_samples):
108
+ def test_write(template_stream, tmp_path):
99
109
  assert PdfWrapper(template_stream).write(
100
- os.path.join(pdf_samples, "sample_template.pdf")
110
+ os.path.join(tmp_path, "sample_template.pdf")
101
111
  )
102
112
 
103
113
 
@@ -106,7 +116,7 @@ def test_write_io(template_stream):
106
116
  PdfWrapper(template_stream).write(buff)
107
117
  buff.seek(0)
108
118
 
109
- assert buff.read() == template_stream
119
+ assert buff.read()
110
120
 
111
121
 
112
122
  def test_fill_flatten_then_unflatten(template_stream, pdf_samples, data_dict, request):
@@ -135,7 +145,7 @@ def test_register_bad_fonts():
135
145
  assert "foo" not in obj.fonts
136
146
 
137
147
 
138
- @pytest.mark.posix_only
148
+ @pytest.mark.requires_zlib_over_zlib_ng
139
149
  def test_fill_with_customized_widgets(
140
150
  template_stream, pdf_samples, sample_font_stream, data_dict, request
141
151
  ):
@@ -165,7 +175,7 @@ def test_fill_with_customized_widgets(
165
175
  assert obj.read() == expected
166
176
 
167
177
 
168
- @pytest.mark.posix_only
178
+ @pytest.mark.requires_zlib_over_zlib_ng
169
179
  def test_fill_with_customized_widgets_flatten(
170
180
  template_stream, pdf_samples, sample_font_stream, data_dict, request
171
181
  ):
@@ -497,9 +507,10 @@ def test_version(pdf_samples):
497
507
 
498
508
  obj = PdfWrapper(os.path.join(pdf_samples, "versions", "unknown.pdf"))
499
509
  assert obj.version is None
510
+ assert obj.read()
500
511
 
501
512
 
502
- @pytest.mark.posix_only
513
+ @pytest.mark.requires_zlib_over_zlib_ng
503
514
  def test_fill_font_color(sample_template_with_font_colors, pdf_samples, request):
504
515
  expected_path = os.path.join(pdf_samples, "test_fill_font_color.pdf")
505
516
  with open(expected_path, "rb+") as f:
@@ -521,7 +532,7 @@ def test_fill_font_color(sample_template_with_font_colors, pdf_samples, request)
521
532
  assert obj.read() == expected
522
533
 
523
534
 
524
- @pytest.mark.posix_only
535
+ @pytest.mark.requires_zlib_over_zlib_ng
525
536
  def test_fill_complex_fonts(sample_template_with_complex_fonts, pdf_samples, request):
526
537
  expected_path = os.path.join(pdf_samples, "test_fill_complex_fonts.pdf")
527
538
  with open(expected_path, "rb+") as f:
@@ -551,7 +562,7 @@ def test_fill_complex_fonts(sample_template_with_complex_fonts, pdf_samples, req
551
562
  assert obj.read() == expected
552
563
 
553
564
 
554
- @pytest.mark.posix_only
565
+ @pytest.mark.requires_zlib_over_zlib_ng
555
566
  def test_pages_preserve_font(template_stream, pdf_samples, sample_font_stream, request):
556
567
  expected_path = os.path.join(pdf_samples, "pages", "test_pages_preserve_font.pdf")
557
568
  obj = PdfWrapper(template_stream)
@@ -703,7 +714,7 @@ def test_uncheck_checkbox(pdf_samples, request):
703
714
  assert obj.read() == expected
704
715
 
705
716
 
706
- @pytest.mark.posix_only
717
+ @pytest.mark.requires_zlib_over_zlib_ng
707
718
  def test_blank_page(pdf_samples, request):
708
719
  expected_path = os.path.join(pdf_samples, "test_blank_page.pdf")
709
720
  with open(expected_path, "rb+") as f:
@@ -718,7 +729,7 @@ def test_blank_page(pdf_samples, request):
718
729
  request.config.results["skip_regenerate"] = len(obj.read()) == len(expected)
719
730
 
720
731
 
721
- @pytest.mark.posix_only
732
+ @pytest.mark.requires_zlib_over_zlib_ng
722
733
  def test_blank_page_custom_size_multiply(pdf_samples, request):
723
734
  expected_path = os.path.join(
724
735
  pdf_samples, "test_blank_page_custom_size_multiply.pdf"
@@ -844,7 +855,7 @@ def test_remove_fields_update_widgets(template_stream):
844
855
 
845
856
 
846
857
  def test_remove_fields_no_keys_specified(template_stream):
847
- assert PdfWrapper(template_stream).remove_fields([]).read() == template_stream
858
+ assert PdfWrapper(template_stream).remove_fields([]).read()
848
859
 
849
860
 
850
861
  def test_merge(template_stream):
@@ -1102,3 +1113,16 @@ def test_rubber_stamp_annotation(template_stream, pdf_samples, request):
1102
1113
 
1103
1114
  assert len(obj.read()) == len(expected)
1104
1115
  assert obj.read() == expected
1116
+
1117
+
1118
+ def test_rebuild_acroform_fields():
1119
+ pdf = PdfWrapper(BlankPage() * 2)
1120
+
1121
+ pdf.bulk_create_fields(
1122
+ [Fields.TextField("foo", 1, 100, 100), Fields.TextField("bar", 2, 100, 200)]
1123
+ )
1124
+
1125
+ reader = PdfReader(BytesIO(pdf.read()))
1126
+
1127
+ assert get_widget_key(reader.root_object[AcroForm][FieldsConst][0], False) == "foo"
1128
+ assert get_widget_key(reader.root_object[AcroForm][FieldsConst][1], False) == "bar"
@@ -1,5 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
- # TODO: why does pikepdf randomize final streams?
3
2
 
4
3
  import os
5
4
 
@@ -24,7 +23,30 @@ def test_fill(template_stream, pdf_samples, data_dict, request):
24
23
  expected = f.read()
25
24
 
26
25
  assert len(obj.read()) == len(expected)
27
- request.config.results["skip_regenerate"] = len(obj.read()) == len(expected)
26
+ assert obj.read() == expected
27
+
28
+
29
+ def test_fill_sejda_complex(
30
+ sejda_template_complex, sejda_complex_data, pdf_samples, request
31
+ ):
32
+ expected_path = os.path.join(
33
+ pdf_samples,
34
+ "generate_appearance_streams",
35
+ "paragraph",
36
+ "sample_filled_sejda_complex.pdf",
37
+ )
38
+ with open(expected_path, "rb+") as f:
39
+ obj = PdfWrapper(sejda_template_complex, generate_appearance_streams=True).fill(
40
+ sejda_complex_data,
41
+ )
42
+
43
+ request.config.results["expected_path"] = expected_path
44
+ request.config.results["stream"] = obj.read()
45
+
46
+ expected = f.read()
47
+
48
+ assert len(obj.read()) == len(expected)
49
+ assert obj.read() == expected
28
50
 
29
51
 
30
52
  def test_dropdown_two(sample_template_with_dropdown, pdf_samples, request):
@@ -53,30 +75,7 @@ def test_dropdown_two(sample_template_with_dropdown, pdf_samples, request):
53
75
  expected = f.read()
54
76
 
55
77
  assert len(obj.read()) == len(expected)
56
- request.config.results["skip_regenerate"] = len(obj.read()) == len(expected)
57
-
58
-
59
- def test_fill_sejda_complex(
60
- sejda_template_complex, sejda_complex_data, pdf_samples, request
61
- ):
62
- expected_path = os.path.join(
63
- pdf_samples,
64
- "generate_appearance_streams",
65
- "paragraph",
66
- "sample_filled_sejda_complex.pdf",
67
- )
68
- with open(expected_path, "rb+") as f:
69
- obj = PdfWrapper(sejda_template_complex, generate_appearance_streams=True).fill(
70
- sejda_complex_data,
71
- )
72
-
73
- request.config.results["expected_path"] = expected_path
74
- request.config.results["stream"] = obj.read()
75
-
76
- expected = f.read()
77
-
78
- assert len(obj.read()) == len(expected)
79
- request.config.results["skip_regenerate"] = len(obj.read()) == len(expected)
78
+ assert obj.read() == expected
80
79
 
81
80
 
82
81
  def test_issue_613(pdf_samples, request):
@@ -100,10 +99,10 @@ def test_issue_613(pdf_samples, request):
100
99
  expected = f.read()
101
100
 
102
101
  assert len(obj.read()) == len(expected)
103
- request.config.results["skip_regenerate"] = len(obj.read()) == len(expected)
102
+ assert obj.read() == expected
104
103
 
105
104
 
106
- @pytest.mark.posix_only
105
+ @pytest.mark.requires_zlib_over_zlib_ng
107
106
  def test_sample_template_library(
108
107
  pdf_samples, image_samples, sample_font_stream, request
109
108
  ):
@@ -94,7 +94,9 @@ def run_sample_template_library_test(
94
94
 
95
95
  obj.widgets["new_text_field_widget"].font = "new_font"
96
96
  obj.widgets["new_text_field_widget"].font_color = (1, 0, 0)
97
- # TODO: why is alignment not rendered right in the appearance stream?
97
+
98
+ # Currently alignment is not respected due to qpdf limitations
99
+ # https://github.com/qpdf/qpdf/blob/503d401615a842f7c5220a3ee425f5db2f25f537/TODO.md#text-appearance-streams
98
100
  obj.widgets["new_text_field_widget"].alignment = 2
99
101
 
100
102
  obj.widgets["new_checkbox_widget"].size = 40
@@ -106,10 +108,7 @@ def run_sample_template_library_test(
106
108
  expected = f.read()
107
109
 
108
110
  assert len(obj.read()) == len(expected)
109
- if generate_appearance_streams:
110
- request.config.results["skip_regenerate"] = len(obj.read()) == len(expected)
111
- else:
112
- assert obj.read() == expected
111
+ assert obj.read() == expected
113
112
 
114
113
 
115
114
  def test_fill(template_stream, pdf_samples, data_dict, request):
@@ -199,7 +198,7 @@ def test_issue_613(pdf_samples, request):
199
198
  assert obj.read() == expected
200
199
 
201
200
 
202
- @pytest.mark.posix_only
201
+ @pytest.mark.requires_zlib_over_zlib_ng
203
202
  def test_sample_template_library(
204
203
  pdf_samples, image_samples, sample_font_stream, request
205
204
  ):
@@ -46,7 +46,7 @@ def test_fill_sejda_complex_flatten(
46
46
  assert obj.read() == expected
47
47
 
48
48
 
49
- @pytest.mark.posix_only
49
+ @pytest.mark.requires_zlib_over_zlib_ng
50
50
  def test_paragraph_complex(sample_template_paragraph_complex, pdf_samples, request):
51
51
  expected_path = os.path.join(pdf_samples, "paragraph", "test_paragraph_complex.pdf")
52
52
  with open(expected_path, "rb+") as f:
@@ -70,7 +70,7 @@ def test_paragraph_complex(sample_template_paragraph_complex, pdf_samples, reque
70
70
  assert obj.read() == expected
71
71
 
72
72
 
73
- @pytest.mark.posix_only
73
+ @pytest.mark.requires_zlib_over_zlib_ng
74
74
  def test_paragraph_max_length(
75
75
  sample_template_with_paragraph_max_length, pdf_samples, request
76
76
  ):
@@ -25,7 +25,7 @@ def test_signature_sample_value(pdf_samples):
25
25
  )
26
26
 
27
27
 
28
- @pytest.mark.posix_only
28
+ @pytest.mark.requires_zlib_over_zlib_ng
29
29
  def test_fill_signature_overlap(pdf_samples, image_samples, request):
30
30
  expected_path = os.path.join(
31
31
  pdf_samples, "signature", "test_fill_signature_overlap.pdf"
@@ -46,7 +46,7 @@ def test_fill_signature_overlap(pdf_samples, image_samples, request):
46
46
  assert obj.read() == expected
47
47
 
48
48
 
49
- @pytest.mark.posix_only
49
+ @pytest.mark.requires_zlib_over_zlib_ng
50
50
  def test_fill_small_icon(pdf_samples, image_samples, request):
51
51
  expected_path = os.path.join(pdf_samples, "signature", "test_fill_small_icon.pdf")
52
52
  with open(expected_path, "rb+") as f:
@@ -66,7 +66,7 @@ def test_fill_small_icon(pdf_samples, image_samples, request):
66
66
  assert obj.read() == expected
67
67
 
68
68
 
69
- @pytest.mark.posix_only
69
+ @pytest.mark.requires_zlib_over_zlib_ng
70
70
  def test_fill_small_icon_not_preserve_aspect_ratio(pdf_samples, image_samples, request):
71
71
  expected_path = os.path.join(
72
72
  pdf_samples, "signature", "test_fill_small_icon_not_preserve_aspect_ratio.pdf"
@@ -7,7 +7,7 @@ import pytest
7
7
  from PyPDFForm import Fields, PdfWrapper, RawElements
8
8
 
9
9
 
10
- @pytest.mark.posix_only
10
+ @pytest.mark.requires_zlib_over_zlib_ng
11
11
  def test_register_font_no_form_fields(pdf_samples, sample_font_stream, request):
12
12
  expected_path = os.path.join(
13
13
  pdf_samples, "test_widget_attr_trigger", "test_register_font_no_form_fields.pdf"
@@ -28,7 +28,7 @@ def test_register_font_no_form_fields(pdf_samples, sample_font_stream, request):
28
28
  assert obj.read() == expected
29
29
 
30
30
 
31
- @pytest.mark.posix_only
31
+ @pytest.mark.requires_zlib_over_zlib_ng
32
32
  def test_set_text_field_font_sejda(pdf_samples, font_samples, sejda_template, request):
33
33
  expected_path = os.path.join(
34
34
  pdf_samples,
@@ -219,7 +219,7 @@ def test_set_radio_size_sejda(pdf_samples, sejda_template, request):
219
219
  assert obj.read() == expected
220
220
 
221
221
 
222
- @pytest.mark.posix_only
222
+ @pytest.mark.requires_zlib_over_zlib_ng
223
223
  def test_set_dropdown_font_sejda(
224
224
  pdf_samples, dropdown_alignment_sejda, sample_font_stream, request
225
225
  ):
File without changes
File without changes
File without changes
File without changes