PyPDFForm 4.8.1__tar.gz → 4.8.3__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.
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PKG-INFO +7 -7
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/__init__.py +1 -1
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/cli/common.py +66 -5
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/cli/create.py +40 -4
- pypdfform-4.8.3/PyPDFForm/cli/entry.py +37 -0
- pypdfform-4.8.1/PyPDFForm/cli/__init__.py → pypdfform-4.8.3/PyPDFForm/cli/root.py +28 -10
- pypdfform-4.8.3/PyPDFForm/cli/schemas/create.py +525 -0
- pypdfform-4.8.3/PyPDFForm/cli/schemas/update.py +74 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/cli/update.py +19 -9
- pypdfform-4.8.3/PyPDFForm/lib/__init__.py +0 -0
- pypdfform-4.8.3/PyPDFForm/lib/assets/__init__.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/middleware/dropdown.py +8 -3
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/wrapper.py +1 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm.egg-info/PKG-INFO +7 -7
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm.egg-info/SOURCES.txt +5 -0
- pypdfform-4.8.3/PyPDFForm.egg-info/entry_points.txt +2 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm.egg-info/requires.txt +6 -6
- {pypdfform-4.8.1 → pypdfform-4.8.3}/pyproject.toml +6 -7
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_dropdown.py +3 -1
- pypdfform-4.8.1/PyPDFForm.egg-info/entry_points.txt +0 -2
- {pypdfform-4.8.1 → pypdfform-4.8.3}/LICENSE +0 -0
- {pypdfform-4.8.1/PyPDFForm/lib → pypdfform-4.8.3/PyPDFForm/cli}/__init__.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/cli/inspect.py +0 -0
- {pypdfform-4.8.1/PyPDFForm/lib/assets → pypdfform-4.8.3/PyPDFForm/cli/schemas}/__init__.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/adapter.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/annotations/__init__.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/annotations/base.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/annotations/link.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/annotations/stamp.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/annotations/text.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/annotations/text_markup.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/assets/bedrock.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/assets/blank.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/constants.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/coordinate.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/deprecation.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/egress.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/filler.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/font.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/hooks.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/image.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/middleware/__init__.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/middleware/base.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/middleware/checkbox.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/middleware/image.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/middleware/radio.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/middleware/signature.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/middleware/text.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/patterns.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/raw/__init__.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/raw/circle.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/raw/ellipse.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/raw/image.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/raw/line.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/raw/rect.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/raw/text.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/template.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/types.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/utils.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/watermark.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/widgets/__init__.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/widgets/base.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/widgets/checkbox.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/widgets/dropdown.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/widgets/image.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/widgets/radio.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/widgets/signature.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm/lib/widgets/text.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm.egg-info/dependency_links.txt +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/PyPDFForm.egg-info/top_level.txt +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/README.md +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/setup.cfg +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_bulk_create_fields.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_create_widget.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_draw_elements.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_extract_middleware_attributes.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_fill_max_length_text_field.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_font_widths.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_functional.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_generate_appearance_streams.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_js.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_need_appearances.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_paragraph.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_signature.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/tests/test_use_full_widget_name.py +0 -0
- {pypdfform-4.8.1 → pypdfform-4.8.3}/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.8.
|
|
3
|
+
Version: 4.8.3
|
|
4
4
|
Summary: The Python library for PDF forms.
|
|
5
5
|
Author: Jinge Li
|
|
6
6
|
License-Expression: MIT
|
|
@@ -20,19 +20,19 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
20
20
|
Requires-Python: >=3.10
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: cryptography<
|
|
23
|
+
Requires-Dist: cryptography<48.0.0,>=47.0.0
|
|
24
24
|
Requires-Dist: fonttools<5.0.0,>=4.62.1
|
|
25
|
-
Requires-Dist: pikepdf<11.0.0,>=10.5.
|
|
25
|
+
Requires-Dist: pikepdf<11.0.0,>=10.5.1
|
|
26
26
|
Requires-Dist: pillow<13.0.0,>=12.2.0
|
|
27
27
|
Requires-Dist: pypdf<7.0.0,>=6.10.1
|
|
28
28
|
Requires-Dist: reportlab<5.0.0,>=4.4.6
|
|
29
29
|
Provides-Extra: cli
|
|
30
|
-
Requires-Dist: typer<1.0.0,>=0.
|
|
30
|
+
Requires-Dist: typer<1.0.0,>=0.25.0; extra == "cli"
|
|
31
|
+
Requires-Dist: jsonschema<5.0.0,>=4.26.0; extra == "cli"
|
|
31
32
|
Provides-Extra: dev
|
|
32
33
|
Requires-Dist: black<27.0.0,>=26.3.1; extra == "dev"
|
|
33
|
-
Requires-Dist: coverage<8.0.0,>=7.
|
|
34
|
+
Requires-Dist: coverage<8.0.0,>=7.13.5; extra == "dev"
|
|
34
35
|
Requires-Dist: isort<9.0.0,>=8.0.1; extra == "dev"
|
|
35
|
-
Requires-Dist: jsonschema<5.0.0,>=4.26.0; extra == "dev"
|
|
36
36
|
Requires-Dist: mike<3.0.0,>=2.1.3; extra == "dev"
|
|
37
37
|
Requires-Dist: mkdocs<2.0.0,>=1.6.1; extra == "dev"
|
|
38
38
|
Requires-Dist: mkdocs-material<10.0.0,>=9.7.6; extra == "dev"
|
|
@@ -41,7 +41,7 @@ Requires-Dist: pylint<5.0.0,>=4.0.5; extra == "dev"
|
|
|
41
41
|
Requires-Dist: pyright<2.0.0,>=1.1.407; extra == "dev"
|
|
42
42
|
Requires-Dist: pytest<10.0.0,>=9.0.3; extra == "dev"
|
|
43
43
|
Requires-Dist: requests<3.0.0,>=2.33.1; extra == "dev"
|
|
44
|
-
Requires-Dist: ruff<1.0.0,>=0.
|
|
44
|
+
Requires-Dist: ruff<1.0.0,>=0.15.12; extra == "dev"
|
|
45
45
|
Dynamic: license-file
|
|
46
46
|
|
|
47
47
|
<p align="center"><img src="https://github.com/chinapandaman/PyPDFForm/raw/master/docs/img/logo.png"></p>
|
|
@@ -9,9 +9,10 @@ into the objects expected by `PdfWrapper` methods.
|
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Annotated, NoReturn
|
|
12
|
+
from typing import Annotated, Any, NoReturn
|
|
13
13
|
|
|
14
14
|
import typer
|
|
15
|
+
from jsonschema import ValidationError, validate
|
|
15
16
|
|
|
16
17
|
from .. import PdfWrapper
|
|
17
18
|
from ..lib.middleware.base import Widget
|
|
@@ -79,7 +80,7 @@ def json_file_option(help_text: str):
|
|
|
79
80
|
def cli_bad_parameter(
|
|
80
81
|
message: str,
|
|
81
82
|
param_hint: str,
|
|
82
|
-
cause: BaseException,
|
|
83
|
+
cause: BaseException | None = None,
|
|
83
84
|
) -> NoReturn:
|
|
84
85
|
"""
|
|
85
86
|
Raises a Typer input error with a stable CLI message.
|
|
@@ -87,14 +88,71 @@ def cli_bad_parameter(
|
|
|
87
88
|
Args:
|
|
88
89
|
message (str): Error message to display to the CLI user.
|
|
89
90
|
param_hint (str): CLI parameter associated with the error.
|
|
90
|
-
cause (BaseException): Original exception that caused the CLI
|
|
91
|
+
cause (BaseException, optional): Original exception that caused the CLI
|
|
92
|
+
error. Defaults to None.
|
|
91
93
|
|
|
92
94
|
Raises:
|
|
93
95
|
typer.BadParameter: Raised with the provided message and parameter hint.
|
|
94
96
|
"""
|
|
97
|
+
if cause is None:
|
|
98
|
+
raise typer.BadParameter(message, param_hint=param_hint)
|
|
99
|
+
|
|
95
100
|
raise typer.BadParameter(message, param_hint=param_hint) from cause
|
|
96
101
|
|
|
97
102
|
|
|
103
|
+
def _validation_error_path(exc: ValidationError) -> str:
|
|
104
|
+
"""
|
|
105
|
+
Builds a dotted JSON path for a validation error.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
exc (ValidationError): The JSON schema validation error.
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
str: Dotted path for the failing instance location.
|
|
112
|
+
"""
|
|
113
|
+
return ".".join(str(each) for each in exc.absolute_path)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def load_json_file(data: Path, schema: dict, param_hint: str) -> Any:
|
|
117
|
+
"""
|
|
118
|
+
Loads a JSON CLI input file and validates it against a schema.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
data (Path): JSON file path.
|
|
122
|
+
schema (dict): JSON schema to validate against.
|
|
123
|
+
param_hint (str): CLI parameter associated with the JSON file.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Any: Parsed and validated JSON input.
|
|
127
|
+
|
|
128
|
+
Raises:
|
|
129
|
+
typer.BadParameter: Raised when the file cannot be loaded or validation
|
|
130
|
+
fails.
|
|
131
|
+
"""
|
|
132
|
+
try:
|
|
133
|
+
with open(data, "r", encoding="utf-8") as f:
|
|
134
|
+
input_data = json.load(f)
|
|
135
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
136
|
+
cli_bad_parameter(
|
|
137
|
+
f"Invalid JSON file: {exc}",
|
|
138
|
+
param_hint=param_hint,
|
|
139
|
+
cause=exc,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
validate(instance=input_data, schema=schema)
|
|
144
|
+
except ValidationError as exc:
|
|
145
|
+
error_path = _validation_error_path(exc)
|
|
146
|
+
location = f" at {error_path}" if error_path else ""
|
|
147
|
+
cli_bad_parameter(
|
|
148
|
+
f"Invalid JSON file{location}: {exc.message}",
|
|
149
|
+
param_hint=param_hint,
|
|
150
|
+
cause=exc,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
return input_data
|
|
154
|
+
|
|
155
|
+
|
|
98
156
|
def get_widget(wrapper: PdfWrapper, field: str, param_hint: str) -> Widget:
|
|
99
157
|
"""
|
|
100
158
|
Look up a widget and report missing names as CLI input errors.
|
|
@@ -150,8 +208,10 @@ def create_elements_from_file(
|
|
|
150
208
|
pdf: Path,
|
|
151
209
|
data: Path,
|
|
152
210
|
element_map: dict,
|
|
211
|
+
schema: dict,
|
|
153
212
|
method_name: str,
|
|
154
213
|
ctx: typer.Context,
|
|
214
|
+
param_hint: str,
|
|
155
215
|
output: Path | None = None,
|
|
156
216
|
) -> None:
|
|
157
217
|
"""
|
|
@@ -169,16 +229,17 @@ def create_elements_from_file(
|
|
|
169
229
|
definitions.
|
|
170
230
|
element_map (dict): Mapping from JSON group names to element classes or
|
|
171
231
|
callables used to construct each object.
|
|
232
|
+
schema (dict): JSON schema used to validate the grouped definitions.
|
|
172
233
|
method_name (str): Name of the `PdfWrapper` method that accepts the
|
|
173
234
|
constructed elements, such as `bulk_create_fields`, `draw`, or
|
|
174
235
|
`annotate`.
|
|
175
236
|
ctx (typer.Context): Typer context containing global wrapper options in
|
|
176
237
|
`ctx.obj`.
|
|
238
|
+
param_hint (str): CLI parameter associated with the JSON file.
|
|
177
239
|
output (Path, optional): Path where the modified PDF should be saved. If
|
|
178
240
|
omitted, the input PDF is overwritten. Defaults to None.
|
|
179
241
|
"""
|
|
180
|
-
|
|
181
|
-
input_data = json.load(f)
|
|
242
|
+
input_data = load_json_file(data, schema, param_hint)
|
|
182
243
|
|
|
183
244
|
obj = PdfWrapper(str(pdf), **ctx.obj)
|
|
184
245
|
ungrouped_input = []
|
|
@@ -17,7 +17,9 @@ import typer
|
|
|
17
17
|
from .. import (Annotations, BlankPage, Fields, PdfArray, PdfWrapper,
|
|
18
18
|
RawElements)
|
|
19
19
|
from .common import (INPUT_PDF, OPTIONAL_OUTPUT_PDF, REQUIRED_OUTPUT_PDF,
|
|
20
|
-
create_elements_from_file,
|
|
20
|
+
cli_bad_parameter, create_elements_from_file,
|
|
21
|
+
json_file_option)
|
|
22
|
+
from .schemas.create import ANNOTATION_SCHEMA, FIELD_SCHEMA, RAW_SCHEMA
|
|
21
23
|
|
|
22
24
|
create_cli = typer.Typer(
|
|
23
25
|
context_settings={"help_option_names": ["--help", "-h"]}, no_args_is_help=True
|
|
@@ -93,6 +95,13 @@ def extract(
|
|
|
93
95
|
] = None,
|
|
94
96
|
) -> None:
|
|
95
97
|
"""Extract pages from an existing PDF."""
|
|
98
|
+
if start is not None and end is not None and start > end:
|
|
99
|
+
message = "End page must be greater than or equal to start page."
|
|
100
|
+
cli_bad_parameter(
|
|
101
|
+
message,
|
|
102
|
+
param_hint="--end",
|
|
103
|
+
)
|
|
104
|
+
|
|
96
105
|
PdfWrapper(str(pdf), **ctx.obj).pages[slice((start or 1) - 1, end)].write(output)
|
|
97
106
|
|
|
98
107
|
|
|
@@ -132,7 +141,16 @@ def field(
|
|
|
132
141
|
"image": Fields.ImageField,
|
|
133
142
|
"signature": Fields.SignatureField,
|
|
134
143
|
}
|
|
135
|
-
create_elements_from_file(
|
|
144
|
+
create_elements_from_file(
|
|
145
|
+
pdf=pdf,
|
|
146
|
+
data=data,
|
|
147
|
+
element_map=field_map,
|
|
148
|
+
schema=FIELD_SCHEMA,
|
|
149
|
+
method_name="bulk_create_fields",
|
|
150
|
+
ctx=ctx,
|
|
151
|
+
param_hint="--file",
|
|
152
|
+
output=output,
|
|
153
|
+
)
|
|
136
154
|
|
|
137
155
|
|
|
138
156
|
@create_cli.command(no_args_is_help=True)
|
|
@@ -151,7 +169,16 @@ def raw(
|
|
|
151
169
|
"circle": RawElements.RawCircle,
|
|
152
170
|
"ellipse": RawElements.RawEllipse,
|
|
153
171
|
}
|
|
154
|
-
create_elements_from_file(
|
|
172
|
+
create_elements_from_file(
|
|
173
|
+
pdf=pdf,
|
|
174
|
+
data=data,
|
|
175
|
+
element_map=raw_element_map,
|
|
176
|
+
schema=RAW_SCHEMA,
|
|
177
|
+
method_name="draw",
|
|
178
|
+
ctx=ctx,
|
|
179
|
+
param_hint="--file",
|
|
180
|
+
output=output,
|
|
181
|
+
)
|
|
155
182
|
|
|
156
183
|
|
|
157
184
|
@create_cli.command(no_args_is_help=True)
|
|
@@ -171,7 +198,16 @@ def annotation(
|
|
|
171
198
|
"strikeout": Annotations.StrikeOutAnnotation,
|
|
172
199
|
"stamp": Annotations.RubberStampAnnotation,
|
|
173
200
|
}
|
|
174
|
-
create_elements_from_file(
|
|
201
|
+
create_elements_from_file(
|
|
202
|
+
pdf=pdf,
|
|
203
|
+
data=data,
|
|
204
|
+
element_map=annotation_map,
|
|
205
|
+
schema=ANNOTATION_SCHEMA,
|
|
206
|
+
method_name="annotate",
|
|
207
|
+
ctx=ctx,
|
|
208
|
+
param_hint="--file",
|
|
209
|
+
output=output,
|
|
210
|
+
)
|
|
175
211
|
|
|
176
212
|
|
|
177
213
|
@create_cli.command(no_args_is_help=True)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Console script entry point for the optional PyPDFForm CLI.
|
|
4
|
+
|
|
5
|
+
The CLI implementation depends on the optional ``cli`` extra. This lightweight
|
|
6
|
+
wrapper lets the ``pypdfform`` command fail with installation guidance instead
|
|
7
|
+
of an import traceback when those optional dependencies are absent.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import importlib
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
CLI_DEPENDENCIES = {"jsonschema", "typer"}
|
|
14
|
+
CLI_INSTALL_HINT = "pip install 'PyPDFForm[cli]'"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main() -> None:
|
|
18
|
+
"""
|
|
19
|
+
Run the PyPDFForm CLI.
|
|
20
|
+
|
|
21
|
+
Raises:
|
|
22
|
+
SystemExit: Raised with exit code 1 when optional CLI dependencies are
|
|
23
|
+
missing.
|
|
24
|
+
"""
|
|
25
|
+
try:
|
|
26
|
+
cli_module = importlib.import_module("PyPDFForm.cli.root")
|
|
27
|
+
except ModuleNotFoundError as exc:
|
|
28
|
+
if exc.name in CLI_DEPENDENCIES:
|
|
29
|
+
print(
|
|
30
|
+
"PyPDFForm CLI dependencies are not installed. "
|
|
31
|
+
f"Install them with: {CLI_INSTALL_HINT}",
|
|
32
|
+
file=sys.stderr,
|
|
33
|
+
)
|
|
34
|
+
raise SystemExit(1) from None
|
|
35
|
+
raise
|
|
36
|
+
|
|
37
|
+
getattr(cli_module, "cli_app")()
|
|
@@ -14,14 +14,14 @@ Commands:
|
|
|
14
14
|
- `update`: Modify PDF metadata, field names, properties, geometry, and scripts.
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
-
import json
|
|
18
17
|
from pathlib import Path
|
|
19
18
|
from typing import Annotated
|
|
20
19
|
|
|
21
20
|
import typer
|
|
22
21
|
|
|
23
22
|
from .. import PdfWrapper, Widgets, __version__
|
|
24
|
-
from .common import INPUT_PDF, OPTIONAL_OUTPUT_PDF, json_file_option
|
|
23
|
+
from .common import (INPUT_PDF, OPTIONAL_OUTPUT_PDF, json_file_option,
|
|
24
|
+
load_json_file)
|
|
25
25
|
from .create import create_cli
|
|
26
26
|
from .inspect import inspect_cli
|
|
27
27
|
from .update import update_cli
|
|
@@ -132,18 +132,36 @@ def fill(
|
|
|
132
132
|
] = None,
|
|
133
133
|
) -> None:
|
|
134
134
|
"""Fill a PDF form with JSON data."""
|
|
135
|
-
with open(data, "r", encoding="utf-8") as f:
|
|
136
|
-
input_data = json.load(f)
|
|
137
|
-
|
|
138
135
|
obj = PdfWrapper(str(pdf), **ctx.obj)
|
|
136
|
+
|
|
137
|
+
schema = obj.schema
|
|
138
|
+
for key, widget in obj.widgets.items():
|
|
139
|
+
if isinstance(widget, (Widgets.Image, Widgets.Signature)):
|
|
140
|
+
schema["properties"][key] = {
|
|
141
|
+
"anyOf": [
|
|
142
|
+
schema["properties"][key],
|
|
143
|
+
{
|
|
144
|
+
"type": "object",
|
|
145
|
+
"properties": {
|
|
146
|
+
"path": {"type": "string"},
|
|
147
|
+
"preserve_aspect_ratio": {"type": "boolean"},
|
|
148
|
+
},
|
|
149
|
+
"required": ["path"],
|
|
150
|
+
"additionalProperties": False,
|
|
151
|
+
},
|
|
152
|
+
]
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
input_data = load_json_file(data, schema, "--file")
|
|
139
156
|
for k, each in obj.widgets.items():
|
|
140
|
-
if
|
|
141
|
-
|
|
157
|
+
if (
|
|
158
|
+
k in input_data
|
|
159
|
+
and isinstance(each, (Widgets.Image, Widgets.Signature))
|
|
160
|
+
and isinstance(input_data[k], dict)
|
|
161
|
+
):
|
|
162
|
+
each.preserve_aspect_ratio = input_data[k].get(
|
|
142
163
|
"preserve_aspect_ratio", each.preserve_aspect_ratio
|
|
143
164
|
)
|
|
144
165
|
input_data[k] = input_data[k]["path"]
|
|
145
166
|
|
|
146
167
|
obj.fill(input_data, flatten=flatten).write(output or pdf)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
__all__ = ["cli_app"]
|