mirror of
https://github.com/Wojtek242/pylg.git
synced 2024-12-24 23:44:38 +01:00
Release 1.3.0
This commit is contained in:
parent
6395ddd821
commit
93755c6cc3
@ -1,6 +1,14 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
1.3.0
|
||||
-----
|
||||
|
||||
- Added option to trace return value type.
|
||||
- Added options for tracing exception tracebacks.
|
||||
- Made all exception options possible to set individually for functions.
|
||||
- Added support for multi-line trace messages.
|
||||
|
||||
1.2.2
|
||||
-----
|
||||
|
||||
|
54
README.rst
54
README.rst
@ -54,10 +54,27 @@ To automatically log function entry and exit use the
|
||||
|
||||
Despite the name, this works for both functions and methods.
|
||||
|
||||
``@TraceFunction`` can take up to two optional arguments:
|
||||
``@TraceFunction`` can take up to seven optional arguments:
|
||||
|
||||
- ``trace_args`` - if ``True``, input parameters will be logged.
|
||||
- ``trace_rv`` - if ``True``, the return value will be logged.
|
||||
- ``exception_warning`` - if ``True``, PyLg will print a warning about
|
||||
every exception caught to ``stderr``.
|
||||
|
||||
- ``exception_tb_file`` - if ``True``, PyLg will write the exception
|
||||
tracebacks to the log file.
|
||||
|
||||
- ``exception_tb_stderr`` - if ``True``, PyLg will print the exception
|
||||
tracebacks to ``stderr``.
|
||||
|
||||
- ``exception_exit`` - if ``True``, PyLg will force the program to
|
||||
exit (and not just raise SystemExit) whenever an exception
|
||||
occurs. This will happen even if the exception would be handled at a
|
||||
later point.
|
||||
|
||||
- ``trace_args`` - if ``True``, PyLg will log input parameters.
|
||||
|
||||
- ``trace_rv`` - if ``True``, PyLg will log return values.
|
||||
|
||||
- ``trace_rv_type`` - if ``True``, PyLg will log return value types.
|
||||
|
||||
The default values for these arguments are set in a global settings
|
||||
file.
|
||||
@ -70,11 +87,7 @@ These arguments have to specified explicitly by name. Some examples:
|
||||
def some_fuction():
|
||||
pass
|
||||
|
||||
@TraceFunction(trace_rv = False)
|
||||
def some_fuction():
|
||||
pass
|
||||
|
||||
@TraceFunction(trace_args = False, trace_rv = False)
|
||||
@TraceFunction(trace_args = False, exception_tb_stderr = True)
|
||||
def some_fuction():
|
||||
pass
|
||||
|
||||
@ -99,13 +112,17 @@ template.
|
||||
|
||||
- ``PYLG_FILE`` (default = ``'pylg.log'``) - the log file name.
|
||||
|
||||
- ``EXCEPTION_WARNING`` (default = ``True``) - if ``True``, PyLg will
|
||||
print a warning about every exception caught to stderr.
|
||||
- ``DEFAULT_EXCEPTION_WARNING`` (default = ``True``) - the default
|
||||
setting for ``exception_warning``.
|
||||
|
||||
- ``EXCEPTION_EXIT`` (default = ``False``) - if ``True``, PyLg will
|
||||
force the program to exit (and not just raise ``SystemExit``)
|
||||
whenever an exception occurs. This will happen even if the exception
|
||||
would be handled at a later point.
|
||||
- ``DEFAULT_EXCEPTION_TB_FILE`` (default = ``True``) - the default
|
||||
setting for ``exception_tb_file``.
|
||||
|
||||
- ``DEFAULT_EXCEPTION_TB_STDERR`` (default = ``False``) - the default
|
||||
setting for ``exception_tb_stderr``.
|
||||
|
||||
- ``DEAULT_EXCEPTION_EXIT`` (default = ``False``) - the default
|
||||
setting for ``exception_exit``.
|
||||
|
||||
- ``TRACE_TIME`` (default = ``TRUE``) - enable/disable time logging.
|
||||
|
||||
@ -167,12 +184,13 @@ template.
|
||||
elements in the dictionary.
|
||||
|
||||
- ``DEFAULT_TRACE_ARGS`` (default = ``True``) - the default setting
|
||||
for ``trace_args`` which determines whether TraceFunction should
|
||||
trace function parameters on entry.
|
||||
for ``trace_args``.
|
||||
|
||||
- ``DEFAULT_TRACE_RV`` (default = ``True``) - the default setting for
|
||||
``trace_rv`` which determines whether TraceFunction should trace
|
||||
function return values on exit.
|
||||
``trace_rv``.
|
||||
|
||||
- ``DEFAULT_TRACE_RV_TYPE`` (default = ``True``) - the default setting
|
||||
for ``trace_rv_type``.
|
||||
|
||||
Under development
|
||||
-----------------
|
||||
|
@ -172,20 +172,37 @@ if PYLG_USER_FILE is not None:
|
||||
from .settings import PYLG_FILE
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# EXCEPTION_WARNING - bool
|
||||
# DEFAULT_EXCEPTION_WARNING - bool
|
||||
# -------------------------------------------------------------------------
|
||||
try:
|
||||
pylg_check_bool(EXCEPTION_WARNING, "EXCEPTION_WARNING")
|
||||
pylg_check_bool(DEFAULT_EXCEPTION_WARNING, "DEFAULT_EXCEPTION_WARNING")
|
||||
except ImportError:
|
||||
from .settings import EXCEPTION_WARNING
|
||||
from .settings import DEFAULT_EXCEPTION_WARNING
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# EXCEPTION_EXIT - bool
|
||||
# DEFAULT_EXCEPTION_TB_FILE - bool
|
||||
# -------------------------------------------------------------------------
|
||||
try:
|
||||
pylg_check_bool(EXCEPTION_EXIT, "EXCEPTION_EXIT")
|
||||
pylg_check_bool(DEFAULT_EXCEPTION_TB_FILE, "DEFAULT_EXCEPTION_TB_FILE")
|
||||
except ImportError:
|
||||
from .settings import EXCEPTION_EXIT
|
||||
from .settings import DEFAULT_EXCEPTION_TB_FILE
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# DEFAULT_EXCEPTION_TB_STDERR - bool
|
||||
# -------------------------------------------------------------------------
|
||||
try:
|
||||
pylg_check_bool(DEFAULT_EXCEPTION_TB_STDERR,
|
||||
"DEFAULT_EXCEPTION_TB_STDERR")
|
||||
except ImportError:
|
||||
from .settings import DEFAULT_EXCEPTION_TB_STDERR
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# DEFAULT_EXCEPTION_EXIT - bool
|
||||
# -------------------------------------------------------------------------
|
||||
try:
|
||||
pylg_check_bool(DEFAULT_EXCEPTION_EXIT, "DEFAULT_EXCEPTION_EXIT")
|
||||
except ImportError:
|
||||
from .settings import DEFAULT_EXCEPTION_EXIT
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# TRACE_TIME - bool
|
||||
@ -330,3 +347,9 @@ if PYLG_USER_FILE is not None:
|
||||
pylg_check_bool(DEFAULT_TRACE_RV, "DEFAULT_TRACE_RV")
|
||||
except ImportError:
|
||||
from .settings import DEFAULT_TRACE_RV
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Some final value processing.
|
||||
# -----------------------------------------------------------------------------
|
||||
if MESSAGE_WIDTH == 0:
|
||||
MESSAGE_WIDTH = float("inf")
|
||||
|
131
pylg/pylg.py
131
pylg/pylg.py
@ -16,6 +16,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from __future__ import print_function
|
||||
from datetime import datetime
|
||||
from functools import partial
|
||||
import traceback
|
||||
@ -153,8 +154,14 @@ class TraceFunction(object):
|
||||
|
||||
if args:
|
||||
|
||||
self.exception_warning = DEFAULT_EXCEPTION_WARNING
|
||||
self.exception_tb_file = DEFAULT_EXCEPTION_TB_FILE
|
||||
self.exception_tb_stderr = DEFAULT_EXCEPTION_TB_STDERR
|
||||
self.exception_exit = DEFAULT_EXCEPTION_EXIT
|
||||
|
||||
self.trace_args = DEFAULT_TRACE_ARGS
|
||||
self.trace_rv = DEFAULT_TRACE_RV
|
||||
self.trace_rv_type = DEFAULT_TRACE_RV_TYPE
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# The function init_function will verify the input.
|
||||
@ -163,31 +170,63 @@ class TraceFunction(object):
|
||||
|
||||
if kwargs:
|
||||
|
||||
exception_warning_str = 'exception_warning'
|
||||
exception_tb_file_str = 'exception_tb_file'
|
||||
exception_tb_stderr_str = 'exception_tb_stderr'
|
||||
exception_exit_str = 'exception_exit'
|
||||
|
||||
trace_args_str = 'trace_args'
|
||||
trace_rv_str = 'trace_rv'
|
||||
trace_rv_type_str = 'trace_rv_type'
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# If kwargs is non-empty, it should only contain trace_rv,
|
||||
# trace_args, or both and args should be empty. Assert all
|
||||
# this.
|
||||
# If kwargs is non-empty, args should be empty.
|
||||
# -----------------------------------------------------------------
|
||||
assert not args
|
||||
assert (len(kwargs) > 0) and (len(kwargs) <= 2)
|
||||
if len(kwargs) == 1:
|
||||
assert (trace_rv_str in kwargs) or (trace_args_str in kwargs)
|
||||
elif len(kwargs) == 2:
|
||||
assert (trace_rv_str in kwargs) and (trace_args_str in kwargs)
|
||||
|
||||
if trace_args_str in kwargs:
|
||||
try:
|
||||
self.exception_warning = kwargs[exception_warning_str]
|
||||
pylg_check_bool(self.exception_warning, "exception_warning")
|
||||
except (KeyError, ImportError):
|
||||
self.exception_warning = DEFAULT_EXCEPTION_WARNING
|
||||
|
||||
try:
|
||||
self.exception_tb_file = kwargs[exception_tb_file_str]
|
||||
pylg_check_bool(self.exception_tb_file, "exception_tb_file")
|
||||
except (KeyError, ImportError):
|
||||
self.exception_tb_file = DEFAULT_EXCEPTION_TB_FILE
|
||||
|
||||
try:
|
||||
self.exception_tb_stderr = kwargs[exception_tb_stderr_str]
|
||||
pylg_check_bool(self.exception_tb_stderr,
|
||||
"exception_tb_stderr")
|
||||
except (KeyError, ImportError):
|
||||
self.exception_tb_stderr = DEFAULT_EXCEPTION_TB_STDERR
|
||||
|
||||
try:
|
||||
self.exception_exit = kwargs[exception_exit_str]
|
||||
pylg_check_bool(self.exception_exit, "exception_exit")
|
||||
except (KeyError, ImportError):
|
||||
self.exception_exit = DEFAULT_EXCEPTION_EXIT
|
||||
|
||||
try:
|
||||
self.trace_args = kwargs[trace_args_str]
|
||||
else:
|
||||
pylg_check_bool(self.trace_args, "trace_args")
|
||||
except (KeyError, ImportError):
|
||||
self.trace_args = DEFAULT_TRACE_ARGS
|
||||
|
||||
if trace_rv_str in kwargs:
|
||||
try:
|
||||
self.trace_rv = kwargs[trace_rv_str]
|
||||
else:
|
||||
pylg_check_bool(self.trace_rv, "trace_rv")
|
||||
except (KeyError, ImportError):
|
||||
self.trace_rv = DEFAULT_TRACE_RV
|
||||
|
||||
try:
|
||||
self.trace_rv_type = kwargs[trace_rv_type_str]
|
||||
pylg_check_bool(self.trace_rv_type, "trace_rv_type")
|
||||
except (KeyError, ImportError):
|
||||
self.trace_rv_type = DEFAULT_TRACE_RV_TYPE
|
||||
|
||||
self.function = None
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
@ -249,8 +288,8 @@ class TraceFunction(object):
|
||||
except Exception as e:
|
||||
self.trace_exception(e)
|
||||
|
||||
if EXCEPTION_EXIT:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
if self.exception_exit:
|
||||
warnings.warn("Exit forced by EXCEPTION_EXIT")
|
||||
os._exit(1)
|
||||
|
||||
raise
|
||||
@ -360,6 +399,9 @@ class TraceFunction(object):
|
||||
else:
|
||||
msg += "---"
|
||||
|
||||
if self.trace_rv_type:
|
||||
msg += " (type: " + type(rv).__name__ + ")"
|
||||
|
||||
trace(msg, function=self.function)
|
||||
return
|
||||
|
||||
@ -379,9 +421,19 @@ class TraceFunction(object):
|
||||
if str(exception) is not "":
|
||||
msg += " - " + str(exception)
|
||||
|
||||
if EXCEPTION_WARNING:
|
||||
if self.exception_warning:
|
||||
warnings.warn(core_msg, RuntimeWarning)
|
||||
|
||||
if self.exception_tb_file:
|
||||
msg += "\n--- EXCEPTION ---\n"
|
||||
msg += traceback.format_exc()
|
||||
msg += "-----------------"
|
||||
|
||||
if self.exception_tb_stderr:
|
||||
print("--- EXCEPTION ---", file=sys.stderr)
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
print("-----------------", file=sys.stderr)
|
||||
|
||||
trace(msg, function=self.function)
|
||||
return
|
||||
|
||||
@ -466,26 +518,41 @@ def trace(message, function=None):
|
||||
|
||||
message = str(message)
|
||||
|
||||
if MESSAGE_WIDTH > 0:
|
||||
# ---------------------------------------------------------------------
|
||||
# Get the length of the trace line so far
|
||||
# ---------------------------------------------------------------------
|
||||
premsglen = len(msg)
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Get the length of the trace line so far
|
||||
# -----------------------------------------------------------------
|
||||
premsglen = len(msg)
|
||||
# ---------------------------------------------------------------------
|
||||
# Split into lines which will be handled separately.
|
||||
# ---------------------------------------------------------------------
|
||||
lines = message.splitlines()
|
||||
|
||||
if not lines:
|
||||
lines = [""]
|
||||
|
||||
for idx, line in enumerate(lines):
|
||||
# -----------------------------------------------------------------
|
||||
# Wrap the text.
|
||||
# -----------------------------------------------------------------
|
||||
wrapped = textwrap.wrap(message, MESSAGE_WIDTH)
|
||||
wrapped = textwrap.wrap(line, MESSAGE_WIDTH)
|
||||
|
||||
if not wrapped:
|
||||
wrapped = [""]
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# If this is the first line of the whole trace message, it
|
||||
# gets special treatment as it doesn't need whitespace in
|
||||
# front of it. Otherwise, align it with the previous line.
|
||||
# -----------------------------------------------------------------
|
||||
if idx != 0:
|
||||
msg += '{:{w}}'.format('', w=premsglen)
|
||||
|
||||
if MESSAGE_WRAP:
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Print the first line. It gets special treatment as
|
||||
# it doesn't need whitespace in front of it.
|
||||
# The first wrapped line gets special treatment as any
|
||||
# whitespace should already be prepended.
|
||||
# -------------------------------------------------------------
|
||||
msg += wrapped[0]
|
||||
|
||||
@ -493,8 +560,8 @@ def trace(message, function=None):
|
||||
# Print the remaining lines. Append whitespace to
|
||||
# align it with the first line.
|
||||
# -------------------------------------------------------------
|
||||
for line in wrapped[1:]:
|
||||
msg += '\n' + '{:{w}}'.format('', w=premsglen) + line
|
||||
for wrline in wrapped[1:]:
|
||||
msg += '\n' + '{:{w}}'.format('', w=premsglen) + wrline
|
||||
|
||||
else:
|
||||
# -------------------------------------------------------------
|
||||
@ -509,8 +576,7 @@ def trace(message, function=None):
|
||||
# ---------------------------------------------------------
|
||||
|
||||
if MESSAGE_WIDTH > 1:
|
||||
wrapped = textwrap.wrap(wrapped[0],
|
||||
MESSAGE_WIDTH - 1)
|
||||
wrapped = textwrap.wrap(wrapped[0], MESSAGE_WIDTH - 1)
|
||||
assert wrapped
|
||||
|
||||
msg += ('{m:{w}}'.format(m=wrapped[0],
|
||||
@ -528,17 +594,10 @@ def trace(message, function=None):
|
||||
# ---------------------------------------------------------
|
||||
msg += wrapped[0]
|
||||
|
||||
else:
|
||||
# -----------------------------------------------------------------
|
||||
# A MESSAGE_WIDTH of 0 denotes no limit.
|
||||
# Terminate with a newline.
|
||||
# -----------------------------------------------------------------
|
||||
assert MESSAGE_WIDTH == 0
|
||||
msg += message
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Terminate the log line with a newline.
|
||||
# -------------------------------------------------------------------------
|
||||
msg += "\n"
|
||||
msg += "\n"
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Write the data to the log file.
|
||||
|
@ -27,17 +27,30 @@ PYLG_ENABLE = True
|
||||
PYLG_FILE = 'pylg.log'
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# If True, PyLg will print a warning about every exception caught to
|
||||
# stderr.
|
||||
# The default value for 'exception_warning'. If True, PyLg will print
|
||||
# a warning about every exception caught to stderr.
|
||||
# -----------------------------------------------------------------------------
|
||||
EXCEPTION_WARNING = True
|
||||
DEFAULT_EXCEPTION_WARNING = True
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# If True, PyLg will force the program to exit (and not just raise
|
||||
# SystemExit) whenever an exception occurs. This will happen even if
|
||||
# the exception would be handled at a later point.
|
||||
# The default value for 'exception_tb_file'. If True, PyLg will write
|
||||
# the exception tracebacks to the log file.
|
||||
# -----------------------------------------------------------------------------
|
||||
EXCEPTION_EXIT = False
|
||||
DEFAULT_EXCEPTION_TB_FILE = True
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# The default value for 'exception_tb_file'. If True, PyLg will print
|
||||
# the exception tracebacks to stderr.
|
||||
# -----------------------------------------------------------------------------
|
||||
DEFAULT_EXCEPTION_TB_STDERR = False
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# The default value for 'exception_exit'. If True, PyLg will force the
|
||||
# program to exit (and not just raise SystemExit) whenever an
|
||||
# exception occurs. This will happen even if the exception would be
|
||||
# handled at a later point.
|
||||
# -----------------------------------------------------------------------------
|
||||
DEFAULT_EXCEPTION_EXIT = False
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Enable/disable time logging.
|
||||
@ -116,7 +129,9 @@ MESSAGE_WRAP = True
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# If true, truncated message lines should have the last character
|
||||
# replaced with '\'.
|
||||
# replaced with '\'. Note that this reduces MESSAGE_WIDTH by 1 for
|
||||
# truncated lines which may truncate words that would've otherwise
|
||||
# appeared in the message.
|
||||
# -----------------------------------------------------------------------------
|
||||
MESSAGE_MARK_TRUNCATION = True
|
||||
|
||||
@ -134,9 +149,19 @@ COLLAPSE_LISTS = False
|
||||
COLLAPSE_DICTS = False
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# The default settings for 'trace_args' and 'trace_rv' which determine
|
||||
# whether TraceFunction should trace function parameters on entry and
|
||||
# return values on exit.
|
||||
# The default setting for 'trace_args'. If True, PyLg will log input
|
||||
# parameters.
|
||||
# -----------------------------------------------------------------------------
|
||||
DEFAULT_TRACE_ARGS = True
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# The default setting for 'trace_rv'. If True, PyLg will log return
|
||||
# values.
|
||||
# -----------------------------------------------------------------------------
|
||||
DEFAULT_TRACE_RV = True
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# The default settings for 'trace_rv_type'. If True, PyLg will log
|
||||
# return value types.
|
||||
# -----------------------------------------------------------------------------
|
||||
DEFAULT_TRACE_RV_TYPE = False
|
||||
|
2
setup.py
2
setup.py
@ -9,7 +9,7 @@ with open(path.join(pwd, 'README.rst'), encoding='utf-8') as f:
|
||||
|
||||
setup(
|
||||
name='PyLg',
|
||||
version='1.2.2',
|
||||
version='1.3.0',
|
||||
description='Python module to facilitate and automate the process of writing runtime logs.',
|
||||
long_description=long_description,
|
||||
url='https://gitlab.wojciechkozlowski.eu/wojtek/PyLg',
|
||||
|
Loading…
Reference in New Issue
Block a user