legion
Python module contains miscellaneous functions and constants for the
maintenance scripts of my private system. It is shared in this public repository
just in case its code may be of help for other programmers.
The current API (symbols and functions) follows.
-
Module constants:
DESKTOP_PATH
Path of user'sDesktop
directory.PROGRAM_PATH
Path of the currently executing script.PROGRAM_NAME
User friendly name of the currently executing script.DEFAULT_CREDENTIALS_FILE
Filename used by default byget_credentials()
for user credentials.TIMESTAMP_FORMAT
time.strftime()
compatible format specification for timestamps.ARROW_L
Left pointing arrow character for pretty-printing program output.ARROW_R
Right pointing arrow character for pretty-printing program output.ERROR_MARKER
Marker string prepended to error messages.UTF8
Normalized name forUTF-8
encoding.
-
WFKStatuses
Available forwin32
platform, only, they are the possible return values forwait_for_keypress()
, implemented for now as anIntEnum
:WFKStatuses.NO_WIN32
Do not wait for keypress, nowin32
platform.WFKStatuses.NO_CONSOLE_ATTACHED
Do not wait for keypress, no console attached.WFKStatuses.NO_CONSOLE_TITLE
Do not wait for keypress, no console title.WFKStatuses.NO_TRANSIENT_FROZEN
Do not wait for keypress, no transient console with frozen executable.WFKStatuses.NO_TRANSIENT_PYTHON
Do not wait for keypress, no transient console withPython
script.WFKStatuses.WAIT_FOR_KEYPRESS
Wait for keypress.
-
logger
Default per-application logger instance. Its public interface is identical tologging.Logger
objects but it also includes indentation support and a simple configuration system by adding the following methods:set_indent(level: int) -> None
Set the logger indentation level tolevel
. Negative values are ignored and zero is used instead.indent() -> None
Increment current logger indentation level.dedent() -> None
Decrement current logger indentation level.config(
debugfile: str|Path|None = None,
logfile: str|Path|None = None,
console: bool = True
) -> None
Configure logger.
With the default configuration ALL logging messages are sent to
debugfile
with a timestamp and some debugging information; those messages with severity oflogging.INFO
or higher are sent tologfile
, also timestamped.In addition to that, and if
console
isTrue
(the default), messages with a severity oflogging.INFO
(and only those) are sent to the standard output stream, and messages with a severity oflogging.WARNING
or higher are sent to the standard error stream, without a timestamp in both cases.If
debugfile
orlogfile
areNone
(the default), then the corresponding files are not created and no logging message will go there. In this case, ifconsole
isFalse
, NO LOGGING OUTPUT WILL BE PRODUCED AT ALL.
-
error(
message: str,
details: str = ''
) -> None
Preprocess and log errormessage
, optionally includingdetails
.A header/marker is prepended to the
message
, and a visual separator is prepended to thedetails
. Both themessage
and thedetails
are indented.Finally, everything is logged using
logging.error()
. -
excepthook(
exc_type: type[BaseException],
exc_value: BaseException,
exc_traceback: TracebackType | None
) -> None
Log information about unhandled exceptions using the provided exceptiontype
,value
and associatedtraceback
.For
KeyboardInterrupt
exceptions, no logging is performed, the default exception hook is used instead.For
OSError
exceptions, a different message is logged, including particularOSError
information, and notraceback
is logged.For any other unhandled exception, a generic message is logged together with the
traceback
, if available.Finally, depending on the platform, some kind of modal dialog is shown so the end user does not miss the error.
Intended to be used as default exception hook (
sys.excepthook
). -
munge_oserror(
exception: OSError
) -> tuple[str, str, str, str, str]
Process theexception
object forOSError
exceptions (and its subclasses), and return a tuple containing the processed information.First item is the actual
OSError
subclass which was raised, as a string.Second item is the
errno
andwinerror
codes, separated by a slash if both are present. If no error codes exist in theexception
object, this item is replaced by an informative placeholder.The third item is the error message, starting with an uppercase letter and ending in a period. If it does not exist, it will be an empty string.
Final two items are the filenames involved in the
exception
. Depending on the actualexception
, there may be zero, one or two filenames involved. If some of the filenames is not present in theexception
object, it will still be in the tuple but it's value will beNone
. -
prettyprint_oserror(
reason: str,
exc: OSError
) -> None
Print a very simpleOSError
message using thereason
andexception
information. -
timestamp() -> str
Produce a timestamp string from current local date and time. -
run(
command: Sequence[str],
**subprocess_args: Any
) -> subprocess.CompletedProcess[str]
Runcommand
, usingsubprocess_args
as arguments. This is just a helper forsubprocess.run()
to make such calls more convenient by providing a set of defaults for the arguments.For that reason, the keyword arguments accepted in
subprocess_args
and the return value for this function are the exact same ones accepted and returned by thesubprocess.run()
function itself. -
Deprecated
setup_logging(debugfile=None, logfile=None, console=True)
Set up logging system, disabling all existing loggers.With the current configuration ALL logging messages are sent to
debugfile
andlogging.INFO
messages are sent tologfile
, timestamped.In addition to that, and if
console
isTrue
(the default), alllogging.INFO
messages are sent to the console too, but without a timestamp.If
debugfile
orlogfile
areNone
, the corresponding files are not created and no logging message will go there. In this case, if console isFalse
, NO LOGGING OUTPUT WILL BE PRODUCED AT ALL. -
Deprecated
logging.indent(level=None)
Iflevel
is provided, set the current logging indentation level to that number, meaning that logging messages will be prepended with that many copies of the current logging indentation character.If
level
is not provided or isNone
, the current logging indentation level is increased in 1 copy of the current logging indentation character. -
Deprecated
logging.dedent(level=None)
Iflevel
is provided, set the current logging indentation level to that number, meaning that logging messages will be prepended with that many copies of the current logging indentation character.If
level
is not provided or isNone
, the current logging indentation level is decreased in 1 copy of the current logging indentation character. -
wait_for_keypress() -> WFKStatuses
Wait for a keypress to continue ifsys.stdout
is a real console AND the console is transient.For
win32
platform only. -
get_credentials(
credentials_path: Path = _Config.CREDENTIALS_FILE
) -> dict[str, Any] | None
Get credentials for current user, from the file atcredentials_path
.If
credentials_path
if not provided as argument, a default path is used.No matter the actual syntax of the file, which may change in the future, the credentials are returned as a simple two-levels dictionary. The first level are the different sections, intended to group credentials. The second level are the credentials themselves. They are accessed by credential identifier and returned as strings.
If credentials file cannot be read or has syntax problems,
None
is returned.
- Both
sys.stdout
andsys.stderr
are automatically reconfigured into UTF-8 mode. - Very basic logging configuration is performed even when
logger.setup()
is not called: all logging messages will be handled and sent to console with a default format (currently, just the logging message, without any context), and all default logging handlers are removed from the root logger after closing them. No indentation of logging messages is possible. - A new logging class is set up by the logger, with indentation support, so
ALL new loggers created by the application importing this module will have
that new class (not exposed on purpose). This can be changed at any time by
the application by calling
logging.setLoggerClass()
with the desired class. - The provided exception hook is registered at
sys.excepthook
. The previously registered one is still accessible atsys.__excepthook__
if needed. - Under
win32
, anatexit
handler is registered which waits for a keypress when the program exits if it is running on a transient console. - If the module is run rather than imported, it prints some demos. Currently, a timestamp and the names and values of all constants which are valid in all platforms.