pdffill 2026.6.19.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.
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: pdffill
3
+ Version: 2026.6.19.0
4
+ Summary: Command line utility to manipulate PDF fields. It can list, rename, fill-in or delete PDF fields.
5
+ Author-email: Ernesto Alfonso <erjoalgo@gmail.com>
6
+ Maintainer-email: Ernesto Alfonso <erjoalgo@gmail.com>
7
+ License-Expression: GPL-3.0-or-later
8
+ Project-URL: Homepage, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill
9
+ Project-URL: Documentation, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill/README.md
10
+ Project-URL: Repository, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill
11
+ Project-URL: Bug Tracker, https://github.com/erjoalgo/dotfiles/issues
12
+ Keywords: pdf,fields,fill
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Programming Language :: Python
15
+ Requires-Python: >=3.7
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: pypdf
18
+ Requires-Dist: fillpdf
19
+ Requires-Dist: PyMuPDF
20
+
21
+ This is a command line utility to manipulate a PDF's fields.
22
+
23
+ $ pip install pdffill
24
+
25
+ # List field names
26
+ $ pdffill input.pdf -l
27
+
28
+ # Rename some fields
29
+ $ pdffill.py input.pdf -r text_3uwum=seller text_4vpsr=buyer text_5ovhg=address
30
+
31
+ # Fill in some fields, write to a separate output file
32
+ $ pdffill.py input.pdf -o filled.pdf -f "seller=Wollam Bonnie C Estate" "buyer=John Doe" address=20235 Majestic Street, Orlando, Fl, 32833
33
+
34
+ # Delete some fields, write to a separate output file
35
+ $ pdffill.py input.pdf -o slim.pdf -d balance-to-close -d purchase-price-other-item -d purchase-price-other-item-value
36
+
37
+ # Fill in all fields with their own names, helpful for seeing where fields are on the page.
38
+ $ pdffill.py input.pdf -o debug.pdf -F
39
+
40
+ This utility doesn't handle checkboxes well, and it is recommended to use plain text fields instead.
@@ -0,0 +1,20 @@
1
+ This is a command line utility to manipulate a PDF's fields.
2
+
3
+ $ pip install pdffill
4
+
5
+ # List field names
6
+ $ pdffill input.pdf -l
7
+
8
+ # Rename some fields
9
+ $ pdffill.py input.pdf -r text_3uwum=seller text_4vpsr=buyer text_5ovhg=address
10
+
11
+ # Fill in some fields, write to a separate output file
12
+ $ pdffill.py input.pdf -o filled.pdf -f "seller=Wollam Bonnie C Estate" "buyer=John Doe" address=20235 Majestic Street, Orlando, Fl, 32833
13
+
14
+ # Delete some fields, write to a separate output file
15
+ $ pdffill.py input.pdf -o slim.pdf -d balance-to-close -d purchase-price-other-item -d purchase-price-other-item-value
16
+
17
+ # Fill in all fields with their own names, helpful for seeing where fields are on the page.
18
+ $ pdffill.py input.pdf -o debug.pdf -F
19
+
20
+ This utility doesn't handle checkboxes well, and it is recommended to use plain text fields instead.
@@ -0,0 +1,40 @@
1
+ Metadata-Version: 2.4
2
+ Name: pdffill
3
+ Version: 2026.6.19.0
4
+ Summary: Command line utility to manipulate PDF fields. It can list, rename, fill-in or delete PDF fields.
5
+ Author-email: Ernesto Alfonso <erjoalgo@gmail.com>
6
+ Maintainer-email: Ernesto Alfonso <erjoalgo@gmail.com>
7
+ License-Expression: GPL-3.0-or-later
8
+ Project-URL: Homepage, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill
9
+ Project-URL: Documentation, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill/README.md
10
+ Project-URL: Repository, https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill
11
+ Project-URL: Bug Tracker, https://github.com/erjoalgo/dotfiles/issues
12
+ Keywords: pdf,fields,fill
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Programming Language :: Python
15
+ Requires-Python: >=3.7
16
+ Description-Content-Type: text/markdown
17
+ Requires-Dist: pypdf
18
+ Requires-Dist: fillpdf
19
+ Requires-Dist: PyMuPDF
20
+
21
+ This is a command line utility to manipulate a PDF's fields.
22
+
23
+ $ pip install pdffill
24
+
25
+ # List field names
26
+ $ pdffill input.pdf -l
27
+
28
+ # Rename some fields
29
+ $ pdffill.py input.pdf -r text_3uwum=seller text_4vpsr=buyer text_5ovhg=address
30
+
31
+ # Fill in some fields, write to a separate output file
32
+ $ pdffill.py input.pdf -o filled.pdf -f "seller=Wollam Bonnie C Estate" "buyer=John Doe" address=20235 Majestic Street, Orlando, Fl, 32833
33
+
34
+ # Delete some fields, write to a separate output file
35
+ $ pdffill.py input.pdf -o slim.pdf -d balance-to-close -d purchase-price-other-item -d purchase-price-other-item-value
36
+
37
+ # Fill in all fields with their own names, helpful for seeing where fields are on the page.
38
+ $ pdffill.py input.pdf -o debug.pdf -F
39
+
40
+ This utility doesn't handle checkboxes well, and it is recommended to use plain text fields instead.
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pdffill.py
3
+ pyproject.toml
4
+ pdffill.egg-info/PKG-INFO
5
+ pdffill.egg-info/SOURCES.txt
6
+ pdffill.egg-info/dependency_links.txt
7
+ pdffill.egg-info/entry_points.txt
8
+ pdffill.egg-info/requires.txt
9
+ pdffill.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ pdffill = pdffill:main
3
+
4
+ [pdffill.pdffill]
5
+ pdffill = pdffill:pdffill
@@ -0,0 +1,3 @@
1
+ pypdf
2
+ fillpdf
3
+ PyMuPDF
@@ -0,0 +1 @@
1
+ pdffill
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """Fill, rename or list a PDF's fields."""
4
+
5
+
6
+ import argparse
7
+ import logging
8
+
9
+ from pypdf import PdfReader, PdfWriter
10
+ from pypdf.generic import NameObject, create_string_object
11
+
12
+ from fillpdf import fillpdfs
13
+
14
+ import fitz
15
+
16
+ def list_fields(input_pdf):
17
+ """List the fields in input_pdf."""
18
+ reader = PdfReader(input_pdf)
19
+ return (reader.get_fields() or {}).keys()
20
+
21
+ def rename_fields(input_pdf, output_pdf, renames):
22
+ """Rename the fields in input_pdf."""
23
+ with open(input_pdf, "rb") as fh:
24
+ writer = PdfWriter(fileobj=fh)
25
+
26
+ for page in writer.pages:
27
+ for annot in (page.get("/Annots") or []):
28
+ full_annot = annot.get_object()
29
+ if "/T" not in full_annot:
30
+ continue
31
+ current_name = full_annot["/T"]
32
+ if "checkbox" in current_name:
33
+ continue
34
+ new_name = renames.get(current_name)
35
+ if new_name:
36
+ full_annot[NameObject("/T")] = create_string_object(new_name)
37
+
38
+ for field in writer.root_object['/AcroForm']["/Fields"]:
39
+ full_field = field.get_object()
40
+ curr_name = full_field.get("/T")
41
+ if "checkbox" in curr_name:
42
+ continue
43
+ new_name = renames.get(curr_name)
44
+ if new_name:
45
+ full_field[NameObject("/T")] = create_string_object(new_name)
46
+
47
+ with open(output_pdf, "wb") as f:
48
+ writer.write(f)
49
+
50
+ def fill_pdf_pypdf(input_pdf, output_pdf, data_dict):
51
+ """Fill in the fields in input_pdf."""
52
+ with open(input_pdf, "rb") as fh:
53
+ writer = PdfWriter(fileobj = fh)
54
+
55
+ for i, page in enumerate(writer.pages):
56
+ # non_checkboxes = {k: v for k, v in data_dict.items() if "checkbox" not in k}
57
+ non_checkboxes = data_dict
58
+ logging.debug(f"on page %s{i+1}")
59
+ writer.update_page_form_field_values(
60
+ page, non_checkboxes,
61
+ auto_regenerate=False)
62
+
63
+
64
+ with open(output_pdf, "wb") as output_stream:
65
+ writer.write(output_stream)
66
+
67
+
68
+ def print_fields(input_pdf):
69
+ """Print the field names in the pdf."""
70
+ field_names = fillpdfs.get_form_fields(input_pdf)
71
+ for (name, value) in field_names.items():
72
+ print(f"{name} = {value}")
73
+
74
+
75
+ def list_to_map(arr):
76
+ """Convert a list of key=value strings into a dictionary."""
77
+ d = {}
78
+ for kv in arr:
79
+ if "=" not in kv:
80
+ logging.info("warn: skipping mapping with no = sign: %s", kv)
81
+ continue
82
+
83
+ k, v = kv.split("=")
84
+ if not v:
85
+ logging.info("warn: skipping mapping with empty value: %s", kv)
86
+ continue
87
+ d[k] = v
88
+ return d
89
+
90
+
91
+ def delete_fields(input_pdf, output_pdf, fields_to_delete):
92
+ """Delete the given fields and write to output_pdf."""
93
+ doc = fitz.open(input_pdf)
94
+ for page in doc:
95
+ # Get all interactive form widgets on the page
96
+ for widget in page.widgets():
97
+ if widget.field_name in fields_to_delete:
98
+ # 1. Get the internal object reference number
99
+ xref = widget.xref
100
+
101
+ # 2. Delete the visual widget widget from the page
102
+ page.delete_widget(widget)
103
+
104
+ # 3. Completely clear the internal object definitions
105
+ doc.update_object(xref, "<<>>")
106
+
107
+ # Save the updated PDF
108
+ doc.save(output_pdf, incremental=True,
109
+ encryption=fitz.PDF_ENCRYPT_KEEP)
110
+ doc.close()
111
+
112
+ def main():
113
+ """Main function."""
114
+ parser = argparse.ArgumentParser()
115
+ parser.add_argument("input", help="input PDF")
116
+ parser.add_argument("-o", "--output", help="output file")
117
+ parser.add_argument("-l", "--list", action="store_true",
118
+ help="""list the PDF fields""")
119
+ parser.add_argument("-r", "--rename",
120
+ help="""rename the given fields.
121
+ example: old_name1=new_name1 old_name2=new_name_2""",
122
+ nargs="+")
123
+ parser.add_argument("-f", "--fill",
124
+ help="""fill in the given fields.
125
+ example: old_name1=new_name1 old_name2=new_name_2""",
126
+ nargs="+")
127
+ parser.add_argument("-F", "--fill_all",
128
+ help="""fill in all text fields with their own field names.""",
129
+ action="store_true")
130
+ parser.add_argument("-d", "--delete", nargs="+",
131
+ help="""delete the given fields""")
132
+ parser.add_argument("-v", "--verbose", action="store_true",
133
+ help="""verbose logging""")
134
+
135
+ args= parser.parse_args()
136
+
137
+ logging.basicConfig(level=logging.DEBUG
138
+ if args.verbose else logging.INFO)
139
+
140
+ if args.list:
141
+ print_fields(args.input)
142
+
143
+ if not args.output:
144
+ logging.warning("warn: making modifications in-place")
145
+ args.output = args.input
146
+
147
+ if args.rename:
148
+ renames = list_to_map(args.rename)
149
+ assert args.output
150
+ rename_fields(args.input, args.output, renames)
151
+ print_fields(args.output)
152
+
153
+ fill_pdf_fn = fill_pdf_pypdf
154
+ if args.fill:
155
+ fills = list_to_map(args.fill)
156
+ assert args.output
157
+ fill_pdf_fn(args.input, args.output, fills)
158
+
159
+ if args.fill_all:
160
+ fields = list_fields(args.input)
161
+ fills = {name: name for name in fields}
162
+ fill_pdf_fn(args.input, args.output, fills)
163
+
164
+ if args.delete:
165
+ delete_fields(args.input, args.output, args.delete)
166
+ print_fields(args.output)
167
+
168
+ if __name__ == "__main__":
169
+ main()
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pdffill"
7
+ version = "2026.06.19.0"
8
+ dependencies = [
9
+ "pypdf",
10
+ "fillpdf",
11
+ "PyMuPDF",
12
+ ]
13
+ requires-python = ">=3.7"
14
+ authors = [
15
+ {name = "Ernesto Alfonso", email = "erjoalgo@gmail.com"},
16
+ ]
17
+ maintainers = [
18
+ {name = "Ernesto Alfonso", email = "erjoalgo@gmail.com"},
19
+ ]
20
+ description = """Command line utility to manipulate PDF fields. It can list, rename, fill-in or delete PDF fields."""
21
+
22
+ readme = "README.md"
23
+ license = "GPL-3.0-or-later"
24
+ keywords = ["pdf", "fields", "fill"]
25
+ classifiers = [
26
+ "Development Status :: 4 - Beta",
27
+ "Programming Language :: Python"
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill"
32
+ Documentation = "https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill/README.md"
33
+ Repository = "https://github.com/erjoalgo/dotfiles/tree/master/bin/pdffill"
34
+ "Bug Tracker" = "https://github.com/erjoalgo/dotfiles/issues"
35
+
36
+ [project.scripts]
37
+ pdffill = "pdffill:main"
38
+
39
+ [project.entry-points."pdffill.pdffill"]
40
+ pdffill = "pdffill:pdffill"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+