PyPDFForm 5.2.5__tar.gz → 5.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PKG-INFO +2 -1
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/__init__.py +1 -1
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/common.py +43 -25
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/create.py +24 -15
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/entry.py +1 -1
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/root.py +10 -8
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/update.py +21 -18
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm.egg-info/PKG-INFO +2 -1
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm.egg-info/requires.txt +1 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/pyproject.toml +5 -1
- {pypdfform-5.2.5 → pypdfform-5.3.0}/LICENSE +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/__init__.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/inspect.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/remove.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/schemas/__init__.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/schemas/create.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/cli/schemas/update.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/__init__.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/adapter.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/annotations/__init__.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/annotations/base.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/annotations/link.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/annotations/stamp.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/annotations/text.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/annotations/text_markup.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/assets/__init__.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/assets/bedrock.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/assets/blank.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/constants.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/coordinate.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/deprecation.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/egress.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/filler.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/font.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/hooks.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/image.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/middleware/__init__.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/middleware/base.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/middleware/checkbox.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/middleware/dropdown.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/middleware/image.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/middleware/radio.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/middleware/signature.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/middleware/text.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/patterns.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/raw/__init__.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/raw/circle.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/raw/ellipse.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/raw/image.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/raw/line.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/raw/rect.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/raw/text.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/template.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/types.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/utils.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/watermark.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/widgets/__init__.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/widgets/base.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/widgets/checkbox.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/widgets/dropdown.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/widgets/image.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/widgets/radio.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/widgets/signature.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/widgets/text.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm/lib/wrapper.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm.egg-info/SOURCES.txt +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm.egg-info/dependency_links.txt +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm.egg-info/entry_points.txt +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/PyPDFForm.egg-info/top_level.txt +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/README.md +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/setup.cfg +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_bulk_create_fields.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_create_widget.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_draw_elements.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_dropdown.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_extract_middleware_attributes.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_fill_max_length_text_field.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_font_widths.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_functional.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_generate_appearance_streams.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_js.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_need_appearances.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_paragraph.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_signature.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_use_full_widget_name.py +0 -0
- {pypdfform-5.2.5 → pypdfform-5.3.0}/tests/test_widget_attr_trigger.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyPDFForm
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.3.0
|
|
4
4
|
Summary: The Python library & CLI for PDF forms.
|
|
5
5
|
Author: Jinge Li
|
|
6
6
|
License-Expression: MIT
|
|
@@ -33,6 +33,7 @@ Requires-Dist: reportlab<6.0.0,>=4.5.1
|
|
|
33
33
|
Provides-Extra: cli
|
|
34
34
|
Requires-Dist: typer<1.0.0,>=0.26.1; extra == "cli"
|
|
35
35
|
Requires-Dist: jsonschema<5.0.0,>=4.26.0; extra == "cli"
|
|
36
|
+
Requires-Dist: PyYAML<7.0.0,>=6.0.3; extra == "cli"
|
|
36
37
|
Provides-Extra: dev
|
|
37
38
|
Requires-Dist: coverage<8.0.0,>=7.14.1; extra == "dev"
|
|
38
39
|
Requires-Dist: mike<3.0.0,>=2.2.0; extra == "dev"
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"""
|
|
3
3
|
This module provides shared helpers for PyPDFForm CLI commands.
|
|
4
4
|
|
|
5
|
-
It contains utilities for loading
|
|
6
|
-
once per command invocation, and converting grouped
|
|
5
|
+
It contains utilities for loading structured command input, registering custom
|
|
6
|
+
fonts once per command invocation, and converting grouped element definitions
|
|
7
7
|
into the objects expected by `PdfWrapper` methods.
|
|
8
8
|
"""
|
|
9
9
|
|
|
@@ -12,6 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
from typing import Annotated, Any, NoReturn
|
|
13
13
|
|
|
14
14
|
import typer
|
|
15
|
+
import yaml
|
|
15
16
|
from jsonschema import ValidationError, validate
|
|
16
17
|
|
|
17
18
|
from .. import PdfWrapper
|
|
@@ -62,15 +63,15 @@ FIELD_NAMES = Annotated[
|
|
|
62
63
|
]
|
|
63
64
|
|
|
64
65
|
|
|
65
|
-
def
|
|
66
|
+
def data_file_option(help_text: str):
|
|
66
67
|
"""
|
|
67
|
-
Creates the common validated
|
|
68
|
+
Creates the common validated structured data file option.
|
|
68
69
|
|
|
69
70
|
Args:
|
|
70
71
|
help_text (str): Help text to display for the option.
|
|
71
72
|
|
|
72
73
|
Returns:
|
|
73
|
-
typer.Option: A configured `--file` / `-f` option for
|
|
74
|
+
typer.Option: A configured `--file` / `-f` option for file input.
|
|
74
75
|
"""
|
|
75
76
|
return typer.Option(
|
|
76
77
|
"--file",
|
|
@@ -109,7 +110,7 @@ def cli_bad_parameter(
|
|
|
109
110
|
|
|
110
111
|
def _validation_error_path(exc: ValidationError) -> str:
|
|
111
112
|
"""
|
|
112
|
-
Builds a dotted
|
|
113
|
+
Builds a dotted input data path for a validation error.
|
|
113
114
|
|
|
114
115
|
Args:
|
|
115
116
|
exc (ValidationError): The JSON schema validation error.
|
|
@@ -120,28 +121,45 @@ def _validation_error_path(exc: ValidationError) -> str:
|
|
|
120
121
|
return ".".join(str(each) for each in exc.absolute_path)
|
|
121
122
|
|
|
122
123
|
|
|
123
|
-
def
|
|
124
|
+
def _input_file_kind(data: Path) -> str:
|
|
124
125
|
"""
|
|
125
|
-
|
|
126
|
+
Gets the structured data format to use for a CLI input file.
|
|
126
127
|
|
|
127
128
|
Args:
|
|
128
|
-
data (Path):
|
|
129
|
+
data (Path): Input file path.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
str: The upper-case format name for user-facing messages.
|
|
133
|
+
"""
|
|
134
|
+
if data.suffix.lower() in {".yaml", ".yml"}:
|
|
135
|
+
return "YAML"
|
|
136
|
+
|
|
137
|
+
return "JSON"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def load_data_file(data: Path, schema: dict, param_hint: str) -> Any:
|
|
141
|
+
"""
|
|
142
|
+
Loads a YAML or JSON CLI input file and validates it against a schema.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
data (Path): YAML or JSON file path.
|
|
129
146
|
schema (dict): JSON schema to validate against.
|
|
130
|
-
param_hint (str): CLI parameter associated with the
|
|
147
|
+
param_hint (str): CLI parameter associated with the input file.
|
|
131
148
|
|
|
132
149
|
Returns:
|
|
133
|
-
Any: Parsed and validated
|
|
150
|
+
Any: Parsed and validated input data.
|
|
134
151
|
|
|
135
152
|
Raises:
|
|
136
153
|
typer.BadParameter: Raised when the file cannot be loaded or validation
|
|
137
154
|
fails.
|
|
138
155
|
"""
|
|
156
|
+
input_kind = _input_file_kind(data)
|
|
139
157
|
try:
|
|
140
158
|
with open(data, "r", encoding="utf-8") as f:
|
|
141
|
-
input_data = json.load(f)
|
|
142
|
-
except (OSError, json.JSONDecodeError) as exc:
|
|
159
|
+
input_data = yaml.safe_load(f) if input_kind == "YAML" else json.load(f)
|
|
160
|
+
except (OSError, json.JSONDecodeError, yaml.YAMLError) as exc:
|
|
143
161
|
cli_bad_parameter(
|
|
144
|
-
f"Invalid
|
|
162
|
+
f"Invalid {input_kind} file: {exc}",
|
|
145
163
|
param_hint=param_hint,
|
|
146
164
|
cause=exc,
|
|
147
165
|
)
|
|
@@ -152,7 +170,7 @@ def load_json_file(data: Path, schema: dict, param_hint: str) -> Any:
|
|
|
152
170
|
error_path = _validation_error_path(exc)
|
|
153
171
|
location = f" at {error_path}" if error_path else ""
|
|
154
172
|
cli_bad_parameter(
|
|
155
|
-
f"Invalid
|
|
173
|
+
f"Invalid {input_kind} file{location}: {exc.message}",
|
|
156
174
|
param_hint=param_hint,
|
|
157
175
|
cause=exc,
|
|
158
176
|
)
|
|
@@ -191,15 +209,15 @@ def handle_font_registration(
|
|
|
191
209
|
"""
|
|
192
210
|
Registers a custom font referenced by CLI input.
|
|
193
211
|
|
|
194
|
-
CLI
|
|
212
|
+
CLI input files may provide a file path in a `font` parameter. This helper
|
|
195
213
|
registers each unique font path on the supplied `PdfWrapper` once, assigns
|
|
196
214
|
it a generated internal font name, and mutates `params["font"]` to that
|
|
197
215
|
registered name so downstream field or element constructors can use it.
|
|
198
216
|
|
|
199
217
|
Args:
|
|
200
218
|
obj (PdfWrapper): The wrapper for the PDF currently being modified.
|
|
201
|
-
params (dict): The element or widget parameters loaded from
|
|
202
|
-
dictionary is mutated when it contains a `font` key.
|
|
219
|
+
params (dict): The element or widget parameters loaded from the input
|
|
220
|
+
file. This dictionary is mutated when it contains a `font` key.
|
|
203
221
|
registered_font (dict): Mapping of source font paths to generated
|
|
204
222
|
`PdfWrapper` font names for the current command invocation.
|
|
205
223
|
"""
|
|
@@ -222,9 +240,9 @@ def create_elements_from_file(
|
|
|
222
240
|
output: Path | None = None,
|
|
223
241
|
) -> None:
|
|
224
242
|
"""
|
|
225
|
-
Creates PDF elements from grouped
|
|
243
|
+
Creates PDF elements from grouped file definitions.
|
|
226
244
|
|
|
227
|
-
The input
|
|
245
|
+
The input data is expected to group element definitions by type, such as
|
|
228
246
|
`text`, `image`, or `highlight`. Each group key is resolved through
|
|
229
247
|
`element_map`, each item is constructed after optional font registration,
|
|
230
248
|
and the resulting objects are passed to `method_name` on `PdfWrapper`.
|
|
@@ -232,21 +250,21 @@ def create_elements_from_file(
|
|
|
232
250
|
|
|
233
251
|
Args:
|
|
234
252
|
pdf (Path): The path to the input PDF file.
|
|
235
|
-
data (Path): The path to the
|
|
253
|
+
data (Path): The path to the input file containing grouped element
|
|
236
254
|
definitions.
|
|
237
|
-
element_map (dict): Mapping from
|
|
238
|
-
callables used to construct each object.
|
|
255
|
+
element_map (dict): Mapping from input group names to element classes
|
|
256
|
+
or callables used to construct each object.
|
|
239
257
|
schema (dict): JSON schema used to validate the grouped definitions.
|
|
240
258
|
method_name (str): Name of the `PdfWrapper` method that accepts the
|
|
241
259
|
constructed elements, such as `bulk_create_fields`, `draw`, or
|
|
242
260
|
`annotate`.
|
|
243
261
|
ctx (typer.Context): Typer context containing global wrapper options in
|
|
244
262
|
`ctx.obj`.
|
|
245
|
-
param_hint (str): CLI parameter associated with the
|
|
263
|
+
param_hint (str): CLI parameter associated with the input file.
|
|
246
264
|
output (Path, optional): Path where the modified PDF should be saved. If
|
|
247
265
|
omitted, the input PDF is overwritten. Defaults to None.
|
|
248
266
|
"""
|
|
249
|
-
input_data =
|
|
267
|
+
input_data = load_data_file(data, schema, param_hint)
|
|
250
268
|
|
|
251
269
|
obj = PdfWrapper(str(pdf), **ctx.obj)
|
|
252
270
|
ungrouped_input = []
|
|
@@ -4,8 +4,8 @@ This module defines CLI commands for creating PDF files and PDF content.
|
|
|
4
4
|
|
|
5
5
|
It exposes the `create` command group for blank PDFs, extracted page ranges,
|
|
6
6
|
merged PDFs, form fields, raw drawn elements, annotations, and coordinate grid
|
|
7
|
-
views. Commands in this module translate command-line arguments or grouped
|
|
8
|
-
input into `PdfWrapper`, `BlankPage`, `Fields`, `RawElements`, and
|
|
7
|
+
views. Commands in this module translate command-line arguments or grouped
|
|
8
|
+
YAML/JSON input into `PdfWrapper`, `BlankPage`, `Fields`, `RawElements`, and
|
|
9
9
|
`Annotations` operations.
|
|
10
10
|
"""
|
|
11
11
|
|
|
@@ -21,7 +21,7 @@ from .common import (
|
|
|
21
21
|
REQUIRED_OUTPUT_PDF,
|
|
22
22
|
cli_bad_parameter,
|
|
23
23
|
create_elements_from_file,
|
|
24
|
-
|
|
24
|
+
data_file_option,
|
|
25
25
|
)
|
|
26
26
|
from .schemas.create import ANNOTATION_SCHEMA, FIELD_SCHEMA, RAW_SCHEMA
|
|
27
27
|
|
|
@@ -194,13 +194,15 @@ def merge(
|
|
|
194
194
|
def field(
|
|
195
195
|
ctx: typer.Context,
|
|
196
196
|
pdf: INPUT_PDF,
|
|
197
|
-
data: Annotated[
|
|
197
|
+
data: Annotated[
|
|
198
|
+
Path, data_file_option("YAML or JSON file with form field definitions.")
|
|
199
|
+
],
|
|
198
200
|
output: OPTIONAL_OUTPUT_PDF = None,
|
|
199
201
|
) -> None:
|
|
200
202
|
"""
|
|
201
|
-
Add form fields described by grouped JSON definitions.
|
|
203
|
+
Add form fields described by grouped YAML or JSON definitions.
|
|
202
204
|
|
|
203
|
-
The command maps
|
|
205
|
+
The command maps input groups such as `text`, `check`, and `signature` to
|
|
204
206
|
PyPDFForm field classes, validates the input file against the CLI field
|
|
205
207
|
schema, creates the corresponding field objects, and calls
|
|
206
208
|
`PdfWrapper.bulk_create_fields` before writing the modified PDF.
|
|
@@ -209,7 +211,8 @@ def field(
|
|
|
209
211
|
ctx (typer.Context): Typer context containing global `PdfWrapper`
|
|
210
212
|
options in `ctx.obj`.
|
|
211
213
|
pdf (Path): Input PDF path.
|
|
212
|
-
data (Path): JSON file containing grouped form field
|
|
214
|
+
data (Path): YAML or JSON file containing grouped form field
|
|
215
|
+
definitions.
|
|
213
216
|
output (Path, optional): Output PDF path. If omitted, the input PDF is
|
|
214
217
|
overwritten. Defaults to None.
|
|
215
218
|
"""
|
|
@@ -240,13 +243,15 @@ def field(
|
|
|
240
243
|
def raw(
|
|
241
244
|
ctx: typer.Context,
|
|
242
245
|
pdf: INPUT_PDF,
|
|
243
|
-
data: Annotated[
|
|
246
|
+
data: Annotated[
|
|
247
|
+
Path, data_file_option("YAML or JSON file with raw element definitions.")
|
|
248
|
+
],
|
|
244
249
|
output: OPTIONAL_OUTPUT_PDF = None,
|
|
245
250
|
) -> None:
|
|
246
251
|
"""
|
|
247
|
-
Draw raw elements described by grouped JSON definitions.
|
|
252
|
+
Draw raw elements described by grouped YAML or JSON definitions.
|
|
248
253
|
|
|
249
|
-
The command maps
|
|
254
|
+
The command maps input groups such as `text`, `image`, and `rectangle` to
|
|
250
255
|
raw element classes, validates the input file against the CLI raw element
|
|
251
256
|
schema, creates the corresponding drawable objects, and calls
|
|
252
257
|
`PdfWrapper.draw` before writing the modified PDF.
|
|
@@ -255,7 +260,8 @@ def raw(
|
|
|
255
260
|
ctx (typer.Context): Typer context containing global `PdfWrapper`
|
|
256
261
|
options in `ctx.obj`.
|
|
257
262
|
pdf (Path): Input PDF path.
|
|
258
|
-
data (Path): JSON file containing grouped raw element
|
|
263
|
+
data (Path): YAML or JSON file containing grouped raw element
|
|
264
|
+
definitions.
|
|
259
265
|
output (Path, optional): Output PDF path. If omitted, the input PDF is
|
|
260
266
|
overwritten. Defaults to None.
|
|
261
267
|
"""
|
|
@@ -286,13 +292,15 @@ def raw(
|
|
|
286
292
|
def annotation(
|
|
287
293
|
ctx: typer.Context,
|
|
288
294
|
pdf: INPUT_PDF,
|
|
289
|
-
data: Annotated[
|
|
295
|
+
data: Annotated[
|
|
296
|
+
Path, data_file_option("YAML or JSON file with annotation definitions.")
|
|
297
|
+
],
|
|
290
298
|
output: OPTIONAL_OUTPUT_PDF = None,
|
|
291
299
|
) -> None:
|
|
292
300
|
"""
|
|
293
|
-
Add annotations described by grouped JSON definitions.
|
|
301
|
+
Add annotations described by grouped YAML or JSON definitions.
|
|
294
302
|
|
|
295
|
-
The command maps
|
|
303
|
+
The command maps input groups such as `text`, `link`, and `highlight` to
|
|
296
304
|
annotation classes, validates the input file against the CLI annotation
|
|
297
305
|
schema, creates the corresponding annotation objects, and calls
|
|
298
306
|
`PdfWrapper.annotate` before writing the modified PDF.
|
|
@@ -301,7 +309,8 @@ def annotation(
|
|
|
301
309
|
ctx (typer.Context): Typer context containing global `PdfWrapper`
|
|
302
310
|
options in `ctx.obj`.
|
|
303
311
|
pdf (Path): Input PDF path.
|
|
304
|
-
data (Path): JSON file containing grouped annotation
|
|
312
|
+
data (Path): YAML or JSON file containing grouped annotation
|
|
313
|
+
definitions.
|
|
305
314
|
output (Path, optional): Output PDF path. If omitted, the input PDF is
|
|
306
315
|
overwritten. Defaults to None.
|
|
307
316
|
"""
|
|
@@ -10,7 +10,7 @@ of an import traceback when those optional dependencies are absent.
|
|
|
10
10
|
import importlib
|
|
11
11
|
import sys
|
|
12
12
|
|
|
13
|
-
CLI_DEPENDENCIES = {"jsonschema", "typer"}
|
|
13
|
+
CLI_DEPENDENCIES = {"jsonschema", "typer", "yaml"}
|
|
14
14
|
CLI_INSTALL_HINT = 'pipx install "PyPDFForm[cli]"'
|
|
15
15
|
CLI_ENV_INSTALL_HINT = "pip install 'PyPDFForm[cli]'"
|
|
16
16
|
|
|
@@ -8,7 +8,7 @@ commands. The root callback collects global flags in the Typer context so each
|
|
|
8
8
|
subcommand can initialize `PdfWrapper` with consistent settings.
|
|
9
9
|
|
|
10
10
|
Commands:
|
|
11
|
-
- `fill`: Fill an existing PDF form from JSON data.
|
|
11
|
+
- `fill`: Fill an existing PDF form from YAML or JSON data.
|
|
12
12
|
- `create`: Create PDFs, fields, annotations, raw elements, and grid views.
|
|
13
13
|
- `inspect`: Print form metadata and field data as JSON.
|
|
14
14
|
- `update`: Modify PDF metadata, field names, properties, geometry, and scripts.
|
|
@@ -21,7 +21,7 @@ from typing import Annotated
|
|
|
21
21
|
import typer
|
|
22
22
|
|
|
23
23
|
from .. import PdfWrapper, Widgets, __version__
|
|
24
|
-
from .common import INPUT_PDF, OPTIONAL_OUTPUT_PDF,
|
|
24
|
+
from .common import INPUT_PDF, OPTIONAL_OUTPUT_PDF, data_file_option, load_data_file
|
|
25
25
|
from .create import create_cli
|
|
26
26
|
from .inspect import inspect_cli
|
|
27
27
|
from .remove import remove_cli
|
|
@@ -145,12 +145,14 @@ def main(
|
|
|
145
145
|
|
|
146
146
|
@cli_app.command(
|
|
147
147
|
no_args_is_help=True,
|
|
148
|
-
help="Fill a PDF form with JSON data.",
|
|
148
|
+
help="Fill a PDF form with YAML or JSON data.",
|
|
149
149
|
)
|
|
150
150
|
def fill(
|
|
151
151
|
ctx: typer.Context,
|
|
152
152
|
pdf: INPUT_PDF,
|
|
153
|
-
data: Annotated[
|
|
153
|
+
data: Annotated[
|
|
154
|
+
Path, data_file_option("YAML or JSON file with form field values.")
|
|
155
|
+
],
|
|
154
156
|
output: OPTIONAL_OUTPUT_PDF = None,
|
|
155
157
|
flatten: Annotated[
|
|
156
158
|
bool,
|
|
@@ -158,11 +160,11 @@ def fill(
|
|
|
158
160
|
] = None,
|
|
159
161
|
) -> None:
|
|
160
162
|
"""
|
|
161
|
-
Fill an existing PDF form from a validated JSON file.
|
|
163
|
+
Fill an existing PDF form from a validated YAML or JSON file.
|
|
162
164
|
|
|
163
165
|
The command loads the input PDF with the global options stored by the root
|
|
164
166
|
callback, expands the generated schema so image and signature widgets can
|
|
165
|
-
accept path objects, validates the
|
|
167
|
+
accept path objects, validates the input file, normalizes image and
|
|
166
168
|
signature values, and writes the filled PDF to the requested output path or
|
|
167
169
|
back to the input file.
|
|
168
170
|
|
|
@@ -170,7 +172,7 @@ def fill(
|
|
|
170
172
|
ctx (typer.Context): Typer context containing global `PdfWrapper`
|
|
171
173
|
options in `ctx.obj`.
|
|
172
174
|
pdf (Path): Input PDF form path.
|
|
173
|
-
data (Path): JSON file containing form field values.
|
|
175
|
+
data (Path): YAML or JSON file containing form field values.
|
|
174
176
|
output (Path, optional): Output PDF path. If omitted, the input PDF is
|
|
175
177
|
overwritten. Defaults to None.
|
|
176
178
|
flatten (bool, optional): Whether to flatten form fields after filling.
|
|
@@ -196,7 +198,7 @@ def fill(
|
|
|
196
198
|
]
|
|
197
199
|
}
|
|
198
200
|
|
|
199
|
-
input_data =
|
|
201
|
+
input_data = load_data_file(data, schema, "--file")
|
|
200
202
|
for k, each in obj.widgets.items():
|
|
201
203
|
if (
|
|
202
204
|
k in input_data
|
|
@@ -5,8 +5,8 @@ This module defines CLI commands for updating existing PDF files.
|
|
|
5
5
|
It exposes the `update` command group for metadata changes, PDF version
|
|
6
6
|
changes, field bounds edits, field renames, field property updates, and
|
|
7
7
|
document-level JavaScript actions. Commands in this module load command-line or
|
|
8
|
-
JSON input, apply the matching `PdfWrapper` operation, and write the
|
|
9
|
-
PDF to either the requested output path or the original file.
|
|
8
|
+
YAML/JSON input, apply the matching `PdfWrapper` operation, and write the
|
|
9
|
+
modified PDF to either the requested output path or the original file.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from enum import Enum
|
|
@@ -22,10 +22,10 @@ from .common import (
|
|
|
22
22
|
INPUT_PDF,
|
|
23
23
|
OPTIONAL_OUTPUT_PDF,
|
|
24
24
|
cli_bad_parameter,
|
|
25
|
+
data_file_option,
|
|
25
26
|
get_widget,
|
|
26
27
|
handle_font_registration,
|
|
27
|
-
|
|
28
|
-
load_json_file,
|
|
28
|
+
load_data_file,
|
|
29
29
|
)
|
|
30
30
|
from .schemas.update import FIELD_SCHEMA, RENAME_SCHEMA
|
|
31
31
|
|
|
@@ -186,18 +186,20 @@ def bounds(
|
|
|
186
186
|
|
|
187
187
|
@update_cli.command(
|
|
188
188
|
no_args_is_help=True,
|
|
189
|
-
help="Rename form fields from JSON.",
|
|
189
|
+
help="Rename form fields from YAML or JSON.",
|
|
190
190
|
)
|
|
191
191
|
def rename(
|
|
192
192
|
ctx: typer.Context,
|
|
193
193
|
pdf: INPUT_PDF,
|
|
194
|
-
data: Annotated[
|
|
194
|
+
data: Annotated[
|
|
195
|
+
Path, data_file_option("YAML or JSON file with form field renames.")
|
|
196
|
+
],
|
|
195
197
|
output: OPTIONAL_OUTPUT_PDF = None,
|
|
196
198
|
) -> None:
|
|
197
199
|
"""
|
|
198
|
-
Rename form fields using a validated JSON mapping file.
|
|
200
|
+
Rename form fields using a validated YAML or JSON mapping file.
|
|
199
201
|
|
|
200
|
-
The command rejects full widget name mode, validates the
|
|
202
|
+
The command rejects full widget name mode, validates the input file against
|
|
201
203
|
the rename schema, resolves each existing field, queues the requested key
|
|
202
204
|
updates on the `PdfWrapper`, commits the rename operations, and writes the
|
|
203
205
|
modified PDF to the requested output path or back to the input file.
|
|
@@ -206,13 +208,14 @@ def rename(
|
|
|
206
208
|
ctx (typer.Context): Typer context containing global `PdfWrapper`
|
|
207
209
|
options in `ctx.obj`.
|
|
208
210
|
pdf (Path): Input PDF path.
|
|
209
|
-
data (Path): JSON file containing form field rename
|
|
211
|
+
data (Path): YAML or JSON file containing form field rename
|
|
212
|
+
definitions.
|
|
210
213
|
output (Path, optional): Output PDF path. If omitted, the input PDF is
|
|
211
214
|
overwritten. Defaults to None.
|
|
212
215
|
|
|
213
216
|
Raises:
|
|
214
217
|
typer.BadParameter: Raised when full widget name mode is enabled, the
|
|
215
|
-
|
|
218
|
+
input file is invalid, or a requested field does not exist.
|
|
216
219
|
"""
|
|
217
220
|
if ctx.obj.get("use_full_widget_name"):
|
|
218
221
|
cli_bad_parameter(
|
|
@@ -221,7 +224,7 @@ def rename(
|
|
|
221
224
|
param_hint="--use-full-widget-name",
|
|
222
225
|
)
|
|
223
226
|
|
|
224
|
-
input_data =
|
|
227
|
+
input_data = load_data_file(data, RENAME_SCHEMA, "--file")
|
|
225
228
|
|
|
226
229
|
obj = PdfWrapper(str(pdf), **ctx.obj)
|
|
227
230
|
for item in input_data:
|
|
@@ -234,20 +237,20 @@ def rename(
|
|
|
234
237
|
|
|
235
238
|
@update_cli.command(
|
|
236
239
|
no_args_is_help=True,
|
|
237
|
-
help="Update form field properties from JSON.",
|
|
240
|
+
help="Update form field properties from YAML or JSON.",
|
|
238
241
|
)
|
|
239
242
|
def field(
|
|
240
243
|
ctx: typer.Context,
|
|
241
244
|
pdf: INPUT_PDF,
|
|
242
245
|
data: Annotated[
|
|
243
|
-
Path,
|
|
246
|
+
Path, data_file_option("YAML or JSON file with form field property updates.")
|
|
244
247
|
],
|
|
245
248
|
output: OPTIONAL_OUTPUT_PDF = None,
|
|
246
249
|
) -> None:
|
|
247
250
|
"""
|
|
248
|
-
Update form field properties from a validated JSON file.
|
|
251
|
+
Update form field properties from a validated YAML or JSON file.
|
|
249
252
|
|
|
250
|
-
The command validates the
|
|
253
|
+
The command validates the input file against the field update schema, loads
|
|
251
254
|
the PDF with the global CLI options stored in `ctx.obj`, resolves each
|
|
252
255
|
field name, registers any referenced fonts once per invocation, assigns the
|
|
253
256
|
requested widget properties, and writes the modified PDF to the requested
|
|
@@ -257,15 +260,15 @@ def field(
|
|
|
257
260
|
ctx (typer.Context): Typer context containing global `PdfWrapper`
|
|
258
261
|
options in `ctx.obj`.
|
|
259
262
|
pdf (Path): Input PDF path.
|
|
260
|
-
data (Path): JSON file containing form field property updates.
|
|
263
|
+
data (Path): YAML or JSON file containing form field property updates.
|
|
261
264
|
output (Path, optional): Output PDF path. If omitted, the input PDF is
|
|
262
265
|
overwritten. Defaults to None.
|
|
263
266
|
|
|
264
267
|
Raises:
|
|
265
|
-
typer.BadParameter: Raised when the
|
|
268
|
+
typer.BadParameter: Raised when the input file is invalid or a requested
|
|
266
269
|
field does not exist.
|
|
267
270
|
"""
|
|
268
|
-
input_data =
|
|
271
|
+
input_data = load_data_file(data, FIELD_SCHEMA, "--file")
|
|
269
272
|
|
|
270
273
|
obj = PdfWrapper(str(pdf), **ctx.obj)
|
|
271
274
|
registered_font = {}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyPDFForm
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.3.0
|
|
4
4
|
Summary: The Python library & CLI for PDF forms.
|
|
5
5
|
Author: Jinge Li
|
|
6
6
|
License-Expression: MIT
|
|
@@ -33,6 +33,7 @@ Requires-Dist: reportlab<6.0.0,>=4.5.1
|
|
|
33
33
|
Provides-Extra: cli
|
|
34
34
|
Requires-Dist: typer<1.0.0,>=0.26.1; extra == "cli"
|
|
35
35
|
Requires-Dist: jsonschema<5.0.0,>=4.26.0; extra == "cli"
|
|
36
|
+
Requires-Dist: PyYAML<7.0.0,>=6.0.3; extra == "cli"
|
|
36
37
|
Provides-Extra: dev
|
|
37
38
|
Requires-Dist: coverage<8.0.0,>=7.14.1; extra == "dev"
|
|
38
39
|
Requires-Dist: mike<3.0.0,>=2.2.0; extra == "dev"
|
|
@@ -43,7 +43,11 @@ Documentation = "https://chinapandaman.github.io/PyPDFForm/"
|
|
|
43
43
|
|
|
44
44
|
[project.optional-dependencies]
|
|
45
45
|
# update `CLI_DEPENDENCIES` in `PyPDFForm/cli/entry.py` when changing cli dependencies
|
|
46
|
-
cli = [
|
|
46
|
+
cli = [
|
|
47
|
+
"typer>=0.26.1,<1.0.0",
|
|
48
|
+
"jsonschema>=4.26.0,<5.0.0",
|
|
49
|
+
"PyYAML>=6.0.3,<7.0.0",
|
|
50
|
+
]
|
|
47
51
|
dev = [
|
|
48
52
|
"coverage>=7.14.1,<8.0.0",
|
|
49
53
|
"mike>=2.2.0,<3.0.0",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|