python-pdffiller 1.0.0__py3-none-any.whl
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.
- pdffiller/__init__.py +4 -0
- pdffiller/__main__.py +6 -0
- pdffiller/_version.py +6 -0
- pdffiller/cli/__init__.py +0 -0
- pdffiller/cli/args.py +28 -0
- pdffiller/cli/boolean_action.py +35 -0
- pdffiller/cli/cli.py +260 -0
- pdffiller/cli/command.py +291 -0
- pdffiller/cli/commands/__init__.py +0 -0
- pdffiller/cli/commands/dump_data_fields.py +75 -0
- pdffiller/cli/commands/fill_form.py +142 -0
- pdffiller/cli/exit_codes.py +10 -0
- pdffiller/cli/formatters.py +16 -0
- pdffiller/cli/once_argument.py +19 -0
- pdffiller/cli/smart_formatter.py +10 -0
- pdffiller/const.py +22 -0
- pdffiller/exceptions.py +59 -0
- pdffiller/io/__init__.py +0 -0
- pdffiller/io/colors.py +52 -0
- pdffiller/io/output.py +335 -0
- pdffiller/pdf.py +488 -0
- pdffiller/py.typed.py +0 -0
- pdffiller/typing.py +59 -0
- pdffiller/utils.py +36 -0
- pdffiller/widgets/__init__.py +0 -0
- pdffiller/widgets/base.py +107 -0
- pdffiller/widgets/checkbox.py +52 -0
- pdffiller/widgets/radio.py +37 -0
- pdffiller/widgets/text.py +82 -0
- python_pdffiller-1.0.0.dist-info/METADATA +138 -0
- python_pdffiller-1.0.0.dist-info/RECORD +36 -0
- python_pdffiller-1.0.0.dist-info/WHEEL +5 -0
- python_pdffiller-1.0.0.dist-info/entry_points.txt +2 -0
- python_pdffiller-1.0.0.dist-info/licenses/AUTHORS.rst +7 -0
- python_pdffiller-1.0.0.dist-info/licenses/COPYING +22 -0
- python_pdffiller-1.0.0.dist-info/top_level.txt +1 -0
pdffiller/io/output.py
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import traceback
|
|
4
|
+
|
|
5
|
+
from colorama import Fore, Style
|
|
6
|
+
|
|
7
|
+
from pdffiller import const
|
|
8
|
+
from pdffiller.exceptions import CommandLineError
|
|
9
|
+
from pdffiller.io.colors import color_enabled, is_terminal
|
|
10
|
+
from pdffiller.typing import Dict, Optional, Union
|
|
11
|
+
|
|
12
|
+
LEVEL_QUIET = 80 # -q
|
|
13
|
+
LEVEL_ERROR = 70 # Errors
|
|
14
|
+
LEVEL_WARNING = 60 # Warnings
|
|
15
|
+
LEVEL_NOTICE = 50 # Important messages to attract user attention.
|
|
16
|
+
LEVEL_STATUS = 40 # Default - The main interesting messages.
|
|
17
|
+
LEVEL_VERBOSE = 30 # -V Detailed informational messages.
|
|
18
|
+
LEVEL_DEBUG = 20 # -VV Closely related to internal implementation details
|
|
19
|
+
LEVEL_TRACE = 10 # -VVV Fine-grained messages with very low-level implementation details
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Color: # pylint: disable=too-few-public-methods
|
|
23
|
+
"""Wrapper around colorama colors that are undefined in importing"""
|
|
24
|
+
|
|
25
|
+
RED = Fore.RED # @UndefinedVariable
|
|
26
|
+
WHITE = Fore.WHITE # @UndefinedVariable
|
|
27
|
+
CYAN = Fore.CYAN # @UndefinedVariable
|
|
28
|
+
GREEN = Fore.GREEN # @UndefinedVariable
|
|
29
|
+
MAGENTA = Fore.MAGENTA # @UndefinedVariable
|
|
30
|
+
BLUE = Fore.BLUE # @UndefinedVariable
|
|
31
|
+
YELLOW = Fore.YELLOW # @UndefinedVariable
|
|
32
|
+
BLACK = Fore.BLACK # @UndefinedVariable
|
|
33
|
+
|
|
34
|
+
BRIGHT_RED = Style.BRIGHT + Fore.RED # @UndefinedVariable
|
|
35
|
+
BRIGHT_BLUE = Style.BRIGHT + Fore.BLUE # @UndefinedVariable
|
|
36
|
+
BRIGHT_YELLOW = Style.BRIGHT + Fore.YELLOW # @UndefinedVariable
|
|
37
|
+
BRIGHT_GREEN = Style.BRIGHT + Fore.GREEN # @UndefinedVariable
|
|
38
|
+
BRIGHT_CYAN = Style.BRIGHT + Fore.CYAN # @UndefinedVariable
|
|
39
|
+
BRIGHT_WHITE = Style.BRIGHT + Fore.WHITE # @UndefinedVariable
|
|
40
|
+
BRIGHT_MAGENTA = Style.BRIGHT + Fore.MAGENTA # @UndefinedVariable
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if os.getenv(const.ENV_PDFFILLER_COLOR_DARK):
|
|
44
|
+
Color.WHITE = Fore.BLACK
|
|
45
|
+
Color.CYAN = Fore.BLUE
|
|
46
|
+
Color.YELLOW = Fore.MAGENTA
|
|
47
|
+
Color.BRIGHT_WHITE = Fore.BLACK
|
|
48
|
+
Color.BRIGHT_CYAN = Fore.BLUE
|
|
49
|
+
Color.BRIGHT_YELLOW = Fore.MAGENTA
|
|
50
|
+
Color.BRIGHT_GREEN = Fore.GREEN
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class PdfFillerOutput:
|
|
54
|
+
"""Manage all PdfFiller output messages"""
|
|
55
|
+
|
|
56
|
+
# Singleton
|
|
57
|
+
_output_level: int = LEVEL_STATUS
|
|
58
|
+
_output_file: Optional[str] = None
|
|
59
|
+
|
|
60
|
+
def __init__(self, scope: str = "") -> None:
|
|
61
|
+
self.stream = sys.stderr
|
|
62
|
+
self._scope = scope
|
|
63
|
+
if self._output_file:
|
|
64
|
+
self.stream = open( # pylint: disable=consider-using-with
|
|
65
|
+
self._output_file, "wt", encoding="utf-8"
|
|
66
|
+
)
|
|
67
|
+
self._color: bool = color_enabled(self.stream)
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def define_log_level(cls, level_name: Optional[str] = None) -> None:
|
|
71
|
+
"""
|
|
72
|
+
Translates the verbosity level entered by a PdfFiller command.
|
|
73
|
+
If it's `None` (-V), it will be defaulted to `verbose` level.
|
|
74
|
+
|
|
75
|
+
:param level_name: `str` or `None`, where `None` is the same as `verbose`.
|
|
76
|
+
"""
|
|
77
|
+
try:
|
|
78
|
+
level = {
|
|
79
|
+
"quiet": LEVEL_QUIET, # -Vquiet 80
|
|
80
|
+
"error": LEVEL_ERROR, # -Verror 70
|
|
81
|
+
"warning": LEVEL_WARNING, # -Vwaring 60
|
|
82
|
+
"notice": LEVEL_NOTICE, # -Vnotice 50
|
|
83
|
+
"status": LEVEL_STATUS, # -Vstatus 40
|
|
84
|
+
"info": LEVEL_STATUS, # -Vstatus 40
|
|
85
|
+
None: LEVEL_VERBOSE, # -V 30
|
|
86
|
+
"verbose": LEVEL_VERBOSE, # -Vverbose 30
|
|
87
|
+
"debug": LEVEL_DEBUG, # -Vdebug 20
|
|
88
|
+
"V": LEVEL_DEBUG, # -VV 20
|
|
89
|
+
"trace": LEVEL_TRACE, # -Vtrace 10
|
|
90
|
+
"VV": LEVEL_TRACE, # -VVV 10
|
|
91
|
+
}[level_name]
|
|
92
|
+
except KeyError:
|
|
93
|
+
# pylint: disable=raise-missing-from
|
|
94
|
+
raise CommandLineError(f"Invalid argument '-V{level_name}'")
|
|
95
|
+
|
|
96
|
+
cls._output_level = level
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def define_log_output(cls, file_path: Optional[str] = None) -> None:
|
|
100
|
+
"""
|
|
101
|
+
Translates the verbosity level entered by a PdfFiller command.
|
|
102
|
+
If it's `None` (-V), it will be defaulted to `verbose` level.
|
|
103
|
+
|
|
104
|
+
:param file_path: Optional path to output log file.
|
|
105
|
+
"""
|
|
106
|
+
cls._output_file = file_path
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def level_allowed(cls, level: int) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
Determines if a level can print associated message or not.
|
|
112
|
+
"""
|
|
113
|
+
return cls._output_level <= level
|
|
114
|
+
|
|
115
|
+
@classmethod
|
|
116
|
+
def output_level(cls) -> int:
|
|
117
|
+
"""Retrieve the current output level.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
int: The current output level
|
|
121
|
+
"""
|
|
122
|
+
return cls._output_level
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def color(self) -> bool:
|
|
126
|
+
"""
|
|
127
|
+
Determines if ANSI color is enabled or not.
|
|
128
|
+
"""
|
|
129
|
+
return self._color
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def scope(self) -> str:
|
|
133
|
+
"""
|
|
134
|
+
Retrieves the current scope
|
|
135
|
+
"""
|
|
136
|
+
return self._scope
|
|
137
|
+
|
|
138
|
+
@scope.setter
|
|
139
|
+
def scope(self, out_scope: str) -> None:
|
|
140
|
+
"""
|
|
141
|
+
Defines the current scope.
|
|
142
|
+
"""
|
|
143
|
+
self._scope = out_scope
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def is_terminal(self) -> bool:
|
|
147
|
+
"""
|
|
148
|
+
Determines if a stream is interactive.
|
|
149
|
+
"""
|
|
150
|
+
return is_terminal(self.stream)
|
|
151
|
+
|
|
152
|
+
def writeln(
|
|
153
|
+
self, data: str, fore: Optional[str] = None, back: Optional[str] = None
|
|
154
|
+
) -> "PdfFillerOutput":
|
|
155
|
+
"""Writes a line including newline sequence"""
|
|
156
|
+
return self.write(data, fore, back, newline=True)
|
|
157
|
+
|
|
158
|
+
def write(
|
|
159
|
+
self,
|
|
160
|
+
data: str,
|
|
161
|
+
fore: Optional[str] = None,
|
|
162
|
+
back: Optional[str] = None,
|
|
163
|
+
newline: bool = False,
|
|
164
|
+
) -> "PdfFillerOutput":
|
|
165
|
+
"""Writes a message."""
|
|
166
|
+
if self._output_level > LEVEL_NOTICE:
|
|
167
|
+
return self
|
|
168
|
+
if self._color and (fore or back):
|
|
169
|
+
data = f"{fore or ''}{back or ''}{data}{Style.RESET_ALL}"
|
|
170
|
+
|
|
171
|
+
if newline:
|
|
172
|
+
data = f"{data}\n"
|
|
173
|
+
self.stream.write(data)
|
|
174
|
+
self.stream.flush()
|
|
175
|
+
return self
|
|
176
|
+
|
|
177
|
+
def rewrite_line(self, line: str) -> None:
|
|
178
|
+
"""Abbreviates a line and display it."""
|
|
179
|
+
tmp_color = self._color
|
|
180
|
+
self._color = False
|
|
181
|
+
total_size = 70
|
|
182
|
+
limit_size = total_size // 2 - 3
|
|
183
|
+
if len(line) > total_size:
|
|
184
|
+
line = line[0:limit_size] + " ... " + line[-limit_size:]
|
|
185
|
+
self.write(f"\r{line}{' ' * (total_size - len(line))}")
|
|
186
|
+
self.stream.flush()
|
|
187
|
+
self._color = tmp_color
|
|
188
|
+
|
|
189
|
+
def _write_message(
|
|
190
|
+
self,
|
|
191
|
+
msg: Union[str, Dict[str, str]],
|
|
192
|
+
fore: Optional[str] = None,
|
|
193
|
+
back: Optional[str] = None,
|
|
194
|
+
) -> None:
|
|
195
|
+
if isinstance(msg, dict):
|
|
196
|
+
# For traces we can receive a dict already, we try to transform then
|
|
197
|
+
# into more natural text
|
|
198
|
+
msg = ", ".join([f"{k}: {v}" for k, v in msg.items()])
|
|
199
|
+
msg = f"=> {msg}"
|
|
200
|
+
|
|
201
|
+
ret = ""
|
|
202
|
+
if self._scope:
|
|
203
|
+
if self._color:
|
|
204
|
+
ret = f"{fore or ''}{back or ''}{self.scope}:{Style.RESET_ALL} "
|
|
205
|
+
else:
|
|
206
|
+
ret = f"{self.scope}: "
|
|
207
|
+
|
|
208
|
+
if self._color:
|
|
209
|
+
ret += f"{fore or ''}{back or ''}{msg}{Style.RESET_ALL}"
|
|
210
|
+
else:
|
|
211
|
+
ret += f"{msg}"
|
|
212
|
+
|
|
213
|
+
self.stream.write(f"{ret}\n")
|
|
214
|
+
self.stream.flush()
|
|
215
|
+
|
|
216
|
+
def trace(self, msg: Union[str, Dict[str, str]]) -> "PdfFillerOutput":
|
|
217
|
+
"""
|
|
218
|
+
Prints a trace message.
|
|
219
|
+
"""
|
|
220
|
+
if self._output_level <= LEVEL_TRACE:
|
|
221
|
+
self._write_message(msg, fore=Color.BRIGHT_WHITE)
|
|
222
|
+
return self
|
|
223
|
+
|
|
224
|
+
def debug(self, msg: Union[str, Dict[str, str]]) -> "PdfFillerOutput":
|
|
225
|
+
"""
|
|
226
|
+
Prints a debug message.
|
|
227
|
+
"""
|
|
228
|
+
if self._output_level <= LEVEL_DEBUG:
|
|
229
|
+
self._write_message(msg)
|
|
230
|
+
return self
|
|
231
|
+
|
|
232
|
+
def verbose(
|
|
233
|
+
self,
|
|
234
|
+
msg: Union[str, Dict[str, str]],
|
|
235
|
+
fore: Optional[str] = None,
|
|
236
|
+
back: Optional[str] = None,
|
|
237
|
+
) -> "PdfFillerOutput":
|
|
238
|
+
"""
|
|
239
|
+
Prints a verbose message.
|
|
240
|
+
"""
|
|
241
|
+
if self._output_level <= LEVEL_VERBOSE:
|
|
242
|
+
self._write_message(msg, fore=fore, back=back)
|
|
243
|
+
return self
|
|
244
|
+
|
|
245
|
+
def info(
|
|
246
|
+
self,
|
|
247
|
+
msg: Union[str, Dict[str, str]],
|
|
248
|
+
fore: Optional[str] = None,
|
|
249
|
+
back: Optional[str] = None,
|
|
250
|
+
) -> "PdfFillerOutput":
|
|
251
|
+
"""
|
|
252
|
+
Prints a status/informative message.
|
|
253
|
+
"""
|
|
254
|
+
if self._output_level <= LEVEL_STATUS:
|
|
255
|
+
self._write_message(msg, fore=fore, back=back)
|
|
256
|
+
return self
|
|
257
|
+
|
|
258
|
+
def title(self, msg: Union[str, Dict[str, str]]) -> "PdfFillerOutput":
|
|
259
|
+
"""
|
|
260
|
+
Prints a title.
|
|
261
|
+
"""
|
|
262
|
+
if self._output_level <= LEVEL_NOTICE:
|
|
263
|
+
self._write_message(f"\n======== {msg} ========", fore=Color.BRIGHT_MAGENTA)
|
|
264
|
+
return self
|
|
265
|
+
|
|
266
|
+
def subtitle(self, msg: Union[str, Dict[str, str]]) -> "PdfFillerOutput":
|
|
267
|
+
"""
|
|
268
|
+
Prints a subtitle.
|
|
269
|
+
"""
|
|
270
|
+
if self._output_level <= LEVEL_NOTICE:
|
|
271
|
+
self._write_message(f"\n-------- {msg} --------", fore=Color.BRIGHT_MAGENTA)
|
|
272
|
+
return self
|
|
273
|
+
|
|
274
|
+
def highlight(self, msg: Union[str, Dict[str, str]]) -> "PdfFillerOutput":
|
|
275
|
+
"""
|
|
276
|
+
Prints a highlighted message.
|
|
277
|
+
"""
|
|
278
|
+
if self._output_level <= LEVEL_NOTICE:
|
|
279
|
+
self._write_message(msg, fore=Color.BRIGHT_MAGENTA)
|
|
280
|
+
return self
|
|
281
|
+
|
|
282
|
+
def success(self, msg: Union[str, Dict[str, str]]) -> "PdfFillerOutput":
|
|
283
|
+
"""
|
|
284
|
+
Prints a success message.
|
|
285
|
+
"""
|
|
286
|
+
if self._output_level <= LEVEL_NOTICE:
|
|
287
|
+
self._write_message(msg, fore=Color.BRIGHT_GREEN)
|
|
288
|
+
return self
|
|
289
|
+
|
|
290
|
+
def warning(self, msg: Union[str, Dict[str, str]]) -> "PdfFillerOutput":
|
|
291
|
+
"""
|
|
292
|
+
Prints a warning message.
|
|
293
|
+
"""
|
|
294
|
+
if self._output_level <= LEVEL_WARNING:
|
|
295
|
+
self._write_message(f"WARNING: {msg}", Color.YELLOW)
|
|
296
|
+
return self
|
|
297
|
+
|
|
298
|
+
def error(self, msg: Union[BaseException, str, Dict[str, str]]) -> "PdfFillerOutput":
|
|
299
|
+
"""
|
|
300
|
+
Prints an error message.
|
|
301
|
+
"""
|
|
302
|
+
if self._output_level <= LEVEL_ERROR:
|
|
303
|
+
if isinstance(msg, BaseException): # pragma: no cover
|
|
304
|
+
lines = traceback.format_exception(type(msg), value=msg, tb=msg.__traceback__)
|
|
305
|
+
exc_msg = ("\n".join(lines)).replace("\n", "\n ")
|
|
306
|
+
self._write_message(f"ERROR: {exc_msg}", Color.RED)
|
|
307
|
+
else:
|
|
308
|
+
self._write_message(f"ERROR: {msg}", Color.RED)
|
|
309
|
+
return self
|
|
310
|
+
|
|
311
|
+
def flush(self) -> None:
|
|
312
|
+
"""
|
|
313
|
+
Flush associated stream.
|
|
314
|
+
"""
|
|
315
|
+
self.stream.flush()
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
def cli_out_write(
|
|
319
|
+
data: Union[str, Dict[str, str]],
|
|
320
|
+
fore: Optional[str] = None,
|
|
321
|
+
back: Optional[str] = None,
|
|
322
|
+
endline: str = "\n",
|
|
323
|
+
indentation: int = 0,
|
|
324
|
+
) -> None:
|
|
325
|
+
"""
|
|
326
|
+
Output to be used by formatters to dump information to stdout
|
|
327
|
+
"""
|
|
328
|
+
fore_ = fore or ""
|
|
329
|
+
back_ = back or ""
|
|
330
|
+
if (fore or back) and color_enabled(sys.stdout):
|
|
331
|
+
data = f"{' ' * indentation}{fore_}{back_}{data}{Style.RESET_ALL}{endline}"
|
|
332
|
+
else:
|
|
333
|
+
data = f"{' ' * indentation}{data}{endline}"
|
|
334
|
+
|
|
335
|
+
sys.stdout.write(data)
|