mirror of
https://github.com/Wojtek242/pylg.git
synced 2024-11-23 16:15:25 +01:00
Convert settings.py to settings.yml
This commit is contained in:
parent
da5a114bc1
commit
20e0c3219c
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
dist
|
dist
|
||||||
PyLg.egg-info
|
PyLg.egg-info
|
||||||
*.log
|
*.log
|
||||||
|
.coverage
|
||||||
|
@ -1,24 +1,8 @@
|
|||||||
# -----------------------------------------------------------------------------
|
"""PyLg: facilitate and automate the process of writing runtime logs.
|
||||||
# PyLg: module to facilitate and automate the process of writing runtime logs.
|
|
||||||
# Copyright (C) 2017 Wojciech Kozlowski <wk@wojciechkozlowski.eu>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
from .load_settings import PYLG_ENABLE
|
"""
|
||||||
|
|
||||||
if PYLG_ENABLE:
|
from pylg.pylg import TraceFunction, trace
|
||||||
from .pylg import TraceFunction, trace
|
|
||||||
else:
|
assert TraceFunction
|
||||||
from .dummy import TraceFunctionDummy as TraceFunction, trace
|
assert trace
|
||||||
|
@ -1,355 +0,0 @@
|
|||||||
# -----------------------------------------------------------------------------
|
|
||||||
# PyLg: module to facilitate and automate the process of writing runtime logs.
|
|
||||||
# Copyright (C) 2017 Wojciech Kozlowski <wk@wojciechkozlowski.eu>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
import warnings
|
|
||||||
import inspect
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Import all the defaults first.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
from .settings import *
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# The filename of the user settings. It will be set once it can be
|
|
||||||
# determined after loading the module.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
PYLG_USER_FILE = None
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Attempt to load the module pylg_settings module. If successful, set
|
|
||||||
# PYLG_USER_FILE to the module's path. By attempting an import rather
|
|
||||||
# than checking if a file exists, we can handle the case of the user
|
|
||||||
# having the settings file elsewhere in their path.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# We import the module itself to be able to determine its source
|
|
||||||
# file before we import all the settings.
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
import pylg_settings
|
|
||||||
from pylg_settings import *
|
|
||||||
PYLG_USER_FILE = inspect.getsourcefile(pylg_settings)
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# The user settings don't exist. We assume the user is happy with
|
|
||||||
# the defaults.
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
pass
|
|
||||||
|
|
||||||
except (NameError, SyntaxError):
|
|
||||||
|
|
||||||
warnings.warn("There was a problem importing user settings")
|
|
||||||
|
|
||||||
sys.stderr.write("\n")
|
|
||||||
traceback.print_exc(file=sys.stderr)
|
|
||||||
sys.stderr.write("\n")
|
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Utility functions for sanity checking user settings. They raise an
|
|
||||||
# ImportError if something is wrong.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
def pylg_check_bool(value, name):
|
|
||||||
|
|
||||||
if not isinstance(value, bool):
|
|
||||||
|
|
||||||
warning_msg = ("Invalid type for " + name + " in " +
|
|
||||||
PYLG_USER_FILE +
|
|
||||||
" - should be bool, is type " +
|
|
||||||
type(value).__name__)
|
|
||||||
|
|
||||||
warnings.warn(warning_msg)
|
|
||||||
|
|
||||||
raise ImportError
|
|
||||||
|
|
||||||
|
|
||||||
def pylg_check_string(value, name):
|
|
||||||
|
|
||||||
if not isinstance(value, str):
|
|
||||||
|
|
||||||
warning_msg = ("Invalid type for " + name + " in " +
|
|
||||||
PYLG_USER_FILE +
|
|
||||||
" - should be a string, is type " +
|
|
||||||
type(value).__name__)
|
|
||||||
|
|
||||||
warnings.warn(warning_msg)
|
|
||||||
|
|
||||||
raise ImportError
|
|
||||||
|
|
||||||
|
|
||||||
def pylg_check_int(value, name):
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# We check for bool as well as bools are an instance of int, but
|
|
||||||
# we don't want to let that go through.
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
if not isinstance(value, int) or isinstance(value, bool):
|
|
||||||
|
|
||||||
warning_msg = ("Invalid type for " + name + " in " +
|
|
||||||
PYLG_USER_FILE +
|
|
||||||
" - should be int, is " +
|
|
||||||
type(value).__name__)
|
|
||||||
|
|
||||||
warnings.warn(warning_msg)
|
|
||||||
|
|
||||||
raise ImportError
|
|
||||||
|
|
||||||
|
|
||||||
def pylg_check_nonneg_int(value, name):
|
|
||||||
|
|
||||||
pylg_check_int(value, name)
|
|
||||||
|
|
||||||
if value < 0:
|
|
||||||
|
|
||||||
warning_msg = ("Invalid value for " + name + " in " +
|
|
||||||
PYLG_USER_FILE +
|
|
||||||
" - should be non-negative, is " +
|
|
||||||
str(value))
|
|
||||||
|
|
||||||
warnings.warn(warning_msg)
|
|
||||||
|
|
||||||
raise ImportError
|
|
||||||
|
|
||||||
|
|
||||||
def pylg_check_pos_int(value, name):
|
|
||||||
|
|
||||||
pylg_check_int(value, name)
|
|
||||||
|
|
||||||
if value <= 0:
|
|
||||||
|
|
||||||
warning_msg = ("Invalid value for " + name + " in " +
|
|
||||||
PYLG_USER_FILE +
|
|
||||||
" - should be positive, is " +
|
|
||||||
str(value))
|
|
||||||
|
|
||||||
warnings.warn(warning_msg)
|
|
||||||
|
|
||||||
raise ImportError
|
|
||||||
|
|
||||||
|
|
||||||
if PYLG_USER_FILE is not None:
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# If PYLG_USER_FILE is set, we have successfully imported user
|
|
||||||
# settings. Nowe, we need to sanity check them. If anything is
|
|
||||||
# wrong we reset the value to its default. At this stage a single
|
|
||||||
# error should not affect any other settings.
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# PYLG_ENABLE - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(PYLG_ENABLE, "PYLG_ENABLE")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import PYLG_ENABLE
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# PYLG_FILE - string
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_string(PYLG_FILE, "PYLG_FILE")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import PYLG_FILE
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# DEFAULT_EXCEPTION_WARNING - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(DEFAULT_EXCEPTION_WARNING, "DEFAULT_EXCEPTION_WARNING")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import DEFAULT_EXCEPTION_WARNING
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# DEFAULT_EXCEPTION_TB_FILE - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(DEFAULT_EXCEPTION_TB_FILE, "DEFAULT_EXCEPTION_TB_FILE")
|
|
||||||
except ImportError:
|
|
||||||
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
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(TRACE_TIME, "TRACE_TIME")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import TRACE_TIME
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# TIME_FORMAT - string
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_string(TIME_FORMAT, "TIME_FORMAT")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import TIME_FORMAT
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# TRACE_FILENAME - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(TRACE_FILENAME, "TRACE_FILENAME")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import TRACE_FILENAME
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# FILENAME_COLUMN_WIDTH - non-negative integer
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_pos_int(FILENAME_COLUMN_WIDTH, "FILENAME_COLUMN_WIDTH")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import FILENAME_COLUMN_WIDTH
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# TRACE_LINENO - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(TRACE_LINENO, "TRACE_LINENO")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import TRACE_LINENO
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# LINENO_WIDTH - non-negative integer
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_nonneg_int(LINENO_WIDTH, "LINENO_WIDTH")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import LINENO_WIDTH
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# TRACE_FUNCTION - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(TRACE_FUNCTION, "TRACE_FUNCTION")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import TRACE_FUNCTION
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# FUNCTION_COLUMN_WIDTH - non-negative integer
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_pos_int(FUNCTION_COLUMN_WIDTH, "FUNCTION_COLUMN_WIDTH")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import FUNCTION_COLUMN_WIDTH
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# CLASS_NAME_RESOLUTION - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(CLASS_NAME_RESOLUTION, "CLASS_NAME_RESOLUTION")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import CLASS_NAME_RESOLUTION
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# TRACE_MESSAGE - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(TRACE_MESSAGE, "TRACE_MESSAGE")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import TRACE_MESSAGE
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# MESSAGE_WIDTH - non-negative integer - note 0 denotes unlimited
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_nonneg_int(MESSAGE_WIDTH, "MESSAGE_WIDTH")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import MESSAGE_WIDTH
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# MESSAGE_WRAP - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(MESSAGE_WRAP, "MESSAGE_WRAP")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import MESSAGE_WRAP
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# MESSAGE_MARK_TRUNCATION - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(MESSAGE_MARK_TRUNCATION, "MESSAGE_MARK_TRUNCATION")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import MESSAGE_MARK_TRUNCATION
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# TRACE_SELF - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(TRACE_SELF, "TRACE_SELF")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import TRACE_SELF
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# COLLAPSE_LISTS - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(COLLAPSE_LISTS, "COLLAPSE_LISTS")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import COLLAPSE_LISTS
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# COLLAPSE_DICTS - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(COLLAPSE_DICTS, "COLLAPSE_DICTS")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import COLLAPSE_DICTS
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# DEFAULT_TRACE_ARGS - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
pylg_check_bool(DEFAULT_TRACE_ARGS, "DEFAULT_TRACE_ARGS")
|
|
||||||
except ImportError:
|
|
||||||
from .settings import DEFAULT_TRACE_ARGS
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
# DEFAULT_TRACE_RV - bool
|
|
||||||
# -------------------------------------------------------------------------
|
|
||||||
try:
|
|
||||||
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")
|
|
537
pylg/pylg.py
537
pylg/pylg.py
@ -1,24 +1,8 @@
|
|||||||
# -----------------------------------------------------------------------------
|
"""PyLg: facilitate and automate the process of writing runtime logs."""
|
||||||
# PyLg: module to facilitate and automate the process of writing runtime logs.
|
|
||||||
# Copyright (C) 2017 Wojciech Kozlowski <wk@wojciechkozlowski.eu>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from typing import Optional
|
||||||
import traceback
|
import traceback
|
||||||
import warnings
|
import warnings
|
||||||
import textwrap
|
import textwrap
|
||||||
@ -26,103 +10,156 @@ import inspect
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
from pylg.settings import _pylg_check_bool
|
||||||
# Load settings.
|
import pylg.settings
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
from .load_settings import *
|
|
||||||
|
|
||||||
|
|
||||||
class ClassNameStack(object):
|
class ClassNameStack:
|
||||||
|
"""Stack for the class names of the currently executing functions.
|
||||||
|
|
||||||
|
The class name of the last traced function that was called will be on top
|
||||||
|
of the stack. It is removed after it finishes executing.
|
||||||
|
|
||||||
""" A class to keep a global stack of the class names of the
|
|
||||||
functions that are currently executing. The class name of the
|
|
||||||
last traced function that was called will be on top of the
|
|
||||||
stack. It is removed after it finishes executing.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
stack = []
|
stack = []
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def insert(classname):
|
def disable(cls) -> None:
|
||||||
if CLASS_NAME_RESOLUTION:
|
"""Disable the stack.
|
||||||
ClassNameStack.stack.append(classname)
|
|
||||||
|
|
||||||
@staticmethod
|
This is achieved by rendering all functions no-ops.
|
||||||
def pop():
|
|
||||||
if CLASS_NAME_RESOLUTION and ClassNameStack.stack:
|
|
||||||
ClassNameStack.stack.pop()
|
|
||||||
|
|
||||||
@staticmethod
|
WARNING: This is an irreversible operation.
|
||||||
def get():
|
|
||||||
if CLASS_NAME_RESOLUTION and ClassNameStack.stack:
|
|
||||||
return ClassNameStack.stack[-1]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class PyLg(object):
|
|
||||||
|
|
||||||
""" Class to handle the log file.
|
|
||||||
"""
|
"""
|
||||||
|
cls.insert = lambda _classname: None
|
||||||
|
cls.pop = lambda: None
|
||||||
|
cls.get = lambda: None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def insert(cls, classname: str) -> None:
|
||||||
|
"""Insert an entry.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
classname : str
|
||||||
|
The class name to insert.
|
||||||
|
|
||||||
|
"""
|
||||||
|
cls.stack.append(classname)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def pop(cls) -> str:
|
||||||
|
"""str: Return top-most entry and remove it."""
|
||||||
|
return cls.stack.pop() if cls.stack else None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def peek(cls) -> str:
|
||||||
|
"""str: Return the top-most entry without removing it."""
|
||||||
|
return ClassNameStack.stack[-1] if cls.stack else None
|
||||||
|
|
||||||
|
|
||||||
|
class PyLg:
|
||||||
|
"""Class to handle the log file."""
|
||||||
|
|
||||||
wfile = None
|
wfile = None
|
||||||
filename = PYLG_FILE
|
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def set_filename(new_filename):
|
def configure(cls, user_settings_path: Optional[str] = None) -> None:
|
||||||
|
"""PyLg initialisation.
|
||||||
|
|
||||||
""" Change the file name of the log file. The change will be
|
Parameters
|
||||||
rejected if the log file is already open.
|
----------
|
||||||
|
user_settings_path : Optional[str]
|
||||||
|
Path to the user settings file.
|
||||||
|
|
||||||
:param str new_filename: The new file name for the log file.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if PyLg.wfile is None:
|
# ---------------------------------------------------------------------
|
||||||
PyLg.filename = new_filename
|
# Load the settings.
|
||||||
else:
|
# ---------------------------------------------------------------------
|
||||||
warnings.warn("PyLg wfile is open - cannot change filename")
|
settings = pylg.settings.load(user_settings_path)
|
||||||
|
|
||||||
@staticmethod
|
# ---------------------------------------------------------------------
|
||||||
def write(string):
|
# Local variables for settings to avoid dictionary access which is only
|
||||||
|
# O(1) on average. Admittedly the size of the settings dict is not
|
||||||
|
# large, but these accesses will be frequent.
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
cls.pylg_enable = settings["pylg_enable"]
|
||||||
|
cls.pylg_file = settings["pylg_file"]
|
||||||
|
cls.default_exception_warning = settings["default_exception_warning"]
|
||||||
|
cls.default_exception_tb_file = settings["default_exception_tb_file"]
|
||||||
|
cls.default_exception_tb_stderr = \
|
||||||
|
settings["default_exception_tb_stderr"]
|
||||||
|
cls.default_exception_exit = settings["default_exception_exit"]
|
||||||
|
cls.trace_time = settings["trace_time"]
|
||||||
|
cls.time_format = settings["time_format"]
|
||||||
|
cls.trace_filename = settings["trace_filename"]
|
||||||
|
cls.filename_column_width = settings["filename_column_width"]
|
||||||
|
cls.trace_lineno = settings["trace_lineno"]
|
||||||
|
cls.lineno_width = settings["lineno_width"]
|
||||||
|
cls.trace_function = settings["trace_function"]
|
||||||
|
cls.function_column_width = settings["function_column_width"]
|
||||||
|
cls.class_name_resolution = settings["class_name_resolution"]
|
||||||
|
cls.trace_message = settings["trace_message"]
|
||||||
|
cls.message_width = settings["message_width"]
|
||||||
|
cls.message_wrap = settings["message_wrap"]
|
||||||
|
cls.message_mark_truncation = settings["message_mark_truncation"]
|
||||||
|
cls.trace_self = settings["trace_self"]
|
||||||
|
cls.collapse_lists = settings["collapse_lists"]
|
||||||
|
cls.collapse_dicts = settings["collapse_dicts"]
|
||||||
|
cls.default_trace_args = settings["default_trace_args"]
|
||||||
|
cls.default_trace_rv = settings["default_trace_rv"]
|
||||||
|
cls.default_trace_rv_type = settings["default_trace_rv_type"]
|
||||||
|
|
||||||
""" Write to the log file. A new log file is opened and
|
if not cls.class_name_resolution:
|
||||||
initialised if it has not been opened yet.
|
ClassNameStack.disable()
|
||||||
|
|
||||||
|
cls.wfile = open(cls.pylg_file, "w")
|
||||||
|
cls.wfile.write(
|
||||||
|
"=== Log initialised at {} ===\n\n".format(datetime.now())
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def write(cls, string: str):
|
||||||
|
"""Write to the log file.
|
||||||
|
|
||||||
|
A new log file is opened and initialised if it has not been opened yet.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
string : str
|
||||||
|
The string to be written to the log file.
|
||||||
|
|
||||||
:param str string: The string to be written to the log file.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if PyLg.wfile is None:
|
cls.wfile.write(string)
|
||||||
PyLg.wfile = open(PyLg.filename, "w")
|
cls.wfile.flush()
|
||||||
PyLg.wfile.write("=== Log initialised at " +
|
|
||||||
str(datetime.now()) + " ===\n\n")
|
|
||||||
|
|
||||||
PyLg.wfile.write(string)
|
@classmethod
|
||||||
PyLg.wfile.flush()
|
def close(cls):
|
||||||
|
"""Close the log file."""
|
||||||
|
|
||||||
@staticmethod
|
if cls.wfile is not None:
|
||||||
def close():
|
cls.wfile.close()
|
||||||
|
cls.wfile = None
|
||||||
""" Close the log file.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if PyLg.wfile is not None:
|
|
||||||
PyLg.wfile.close()
|
|
||||||
PyLg.wfile = None
|
|
||||||
else:
|
else:
|
||||||
warnings.warn("PyLg wfile is not open - nothing to close")
|
warnings.warn("PyLg wfile is not open - nothing to close")
|
||||||
|
|
||||||
|
|
||||||
class TraceFunction(object):
|
# pylint: disable=too-many-instance-attributes
|
||||||
|
class TraceFunction:
|
||||||
|
"""Decorator to trace entry and exit from functions.
|
||||||
|
|
||||||
|
Used by appending @TraceFunction on top of the definition of the function
|
||||||
|
to trace.
|
||||||
|
|
||||||
""" Class that serves as a decorator to trace entry and exit from
|
|
||||||
functions. Used by appending @TraceFunction on top of the
|
|
||||||
definition of the function to trace.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class TraceFunctionStruct(object):
|
# pylint: disable=too-few-public-methods
|
||||||
|
class TraceFunctionStruct:
|
||||||
""" Internal object to handle traced function properties.
|
"""Internal object to handle traced function properties."""
|
||||||
"""
|
|
||||||
|
|
||||||
function = None
|
function = None
|
||||||
varnames = None
|
varnames = None
|
||||||
@ -134,19 +171,10 @@ class TraceFunction(object):
|
|||||||
functionname = None
|
functionname = None
|
||||||
|
|
||||||
def __get__(self, obj, objtype):
|
def __get__(self, obj, objtype):
|
||||||
|
"""Support for instance functions."""
|
||||||
""" Support for instance functions.
|
|
||||||
"""
|
|
||||||
|
|
||||||
return partial(self.__call__, obj)
|
return partial(self.__call__, obj)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
""" Constructor for TraceFunction. Note that the behaviour is
|
|
||||||
different depending on whether TraceFunction is passed any
|
|
||||||
parameters. For details see __call__ in this class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# Make sure this decorator is never called with no arguments.
|
# Make sure this decorator is never called with no arguments.
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
@ -154,14 +182,14 @@ class TraceFunction(object):
|
|||||||
|
|
||||||
if args:
|
if args:
|
||||||
|
|
||||||
self.exception_warning = DEFAULT_EXCEPTION_WARNING
|
self._exception_warning = PyLg.default_exception_warning
|
||||||
self.exception_tb_file = DEFAULT_EXCEPTION_TB_FILE
|
self._exception_tb_file = PyLg.default_exception_tb_file
|
||||||
self.exception_tb_stderr = DEFAULT_EXCEPTION_TB_STDERR
|
self._exception_tb_stderr = PyLg.default_exception_tb_stderr
|
||||||
self.exception_exit = DEFAULT_EXCEPTION_EXIT
|
self._exception_exit = PyLg.default_exception_exit
|
||||||
|
|
||||||
self.trace_args = DEFAULT_TRACE_ARGS
|
self._trace_args = PyLg.default_trace_args
|
||||||
self.trace_rv = DEFAULT_TRACE_RV
|
self._trace_rv = PyLg.default_trace_rv
|
||||||
self.trace_rv_type = DEFAULT_TRACE_RV_TYPE
|
self._trace_rv_type = PyLg.default_trace_rv_type
|
||||||
|
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
# The function init_function will verify the input.
|
# The function init_function will verify the input.
|
||||||
@ -170,6 +198,11 @@ class TraceFunction(object):
|
|||||||
|
|
||||||
if kwargs:
|
if kwargs:
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
# If kwargs is non-empty, args should be empty.
|
||||||
|
# -----------------------------------------------------------------
|
||||||
|
assert not args
|
||||||
|
|
||||||
exception_warning_str = 'exception_warning'
|
exception_warning_str = 'exception_warning'
|
||||||
exception_tb_file_str = 'exception_tb_file'
|
exception_tb_file_str = 'exception_tb_file'
|
||||||
exception_tb_stderr_str = 'exception_tb_stderr'
|
exception_tb_stderr_str = 'exception_tb_stderr'
|
||||||
@ -179,70 +212,47 @@ class TraceFunction(object):
|
|||||||
trace_rv_str = 'trace_rv'
|
trace_rv_str = 'trace_rv'
|
||||||
trace_rv_type_str = 'trace_rv_type'
|
trace_rv_type_str = 'trace_rv_type'
|
||||||
|
|
||||||
# -----------------------------------------------------------------
|
kwopts = {}
|
||||||
# If kwargs is non-empty, args should be empty.
|
for option, default in [
|
||||||
# -----------------------------------------------------------------
|
(exception_warning_str, PyLg.default_exception_warning),
|
||||||
assert not args
|
(exception_tb_file_str, PyLg.default_exception_tb_file),
|
||||||
|
(exception_tb_stderr_str,
|
||||||
|
PyLg.default_exception_tb_stderr),
|
||||||
|
(exception_exit_str, PyLg.default_exception_exit),
|
||||||
|
(trace_args_str, PyLg.default_trace_args),
|
||||||
|
(trace_rv_str, PyLg.default_trace_rv),
|
||||||
|
(trace_rv_type_str, PyLg.default_trace_rv_type),
|
||||||
|
]:
|
||||||
|
|
||||||
try:
|
kwopts[option] = kwargs.get(option, default)
|
||||||
self.exception_warning = kwargs[exception_warning_str]
|
if not _pylg_check_bool(kwopts[option]):
|
||||||
pylg_check_bool(self.exception_warning, "exception_warning")
|
raise ValueError(
|
||||||
except (KeyError, ImportError):
|
"Invalid type for {} - should be bool, is type {}"
|
||||||
self.exception_warning = DEFAULT_EXCEPTION_WARNING
|
.format(option, type(kwopts[option]).__name__)
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
self._exception_warning = kwopts[exception_warning_str]
|
||||||
self.exception_tb_file = kwargs[exception_tb_file_str]
|
self._exception_tb_file = kwopts[exception_tb_file_str]
|
||||||
pylg_check_bool(self.exception_tb_file, "exception_tb_file")
|
self._exception_tb_stderr = kwopts[exception_tb_stderr_str]
|
||||||
except (KeyError, ImportError):
|
self._exception_exit = kwopts[exception_exit_str]
|
||||||
self.exception_tb_file = DEFAULT_EXCEPTION_TB_FILE
|
|
||||||
|
|
||||||
try:
|
self._trace_args = kwopts[trace_args_str]
|
||||||
self.exception_tb_stderr = kwargs[exception_tb_stderr_str]
|
self._trace_rv = kwopts[trace_rv_str]
|
||||||
pylg_check_bool(self.exception_tb_stderr,
|
self._trace_rv_type = kwopts[trace_rv_type_str]
|
||||||
"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]
|
|
||||||
pylg_check_bool(self.trace_args, "trace_args")
|
|
||||||
except (KeyError, ImportError):
|
|
||||||
self.trace_args = DEFAULT_TRACE_ARGS
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.trace_rv = kwargs[trace_rv_str]
|
|
||||||
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
|
self.function = None
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
|
"""Wrapper that is called when a call to a decorated function is made.
|
||||||
|
|
||||||
""" The actual wrapper that is called when a call to a
|
It also handles extra initialisation when parameters are passed to
|
||||||
decorated function is made. It also handles extra
|
|
||||||
initialisation when parameters are passed to
|
|
||||||
TraceFunction.
|
TraceFunction.
|
||||||
|
|
||||||
:return: The return value of the decorated function.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# __call__ has to behave differently depending on whether the
|
# __call__ has to behave differently depending on whether the decorator
|
||||||
# decorator has been given any parameters. The reason for this
|
# has been given any parameters. The reason for this is as follows:
|
||||||
# is as follows:
|
|
||||||
#
|
#
|
||||||
# @TraceFunction
|
# @TraceFunction
|
||||||
# decorated_function
|
# decorated_function
|
||||||
@ -254,25 +264,24 @@ class TraceFunction(object):
|
|||||||
#
|
#
|
||||||
# translates to TraceFunction(*args, **kwargs)(decorated_function)
|
# translates to TraceFunction(*args, **kwargs)(decorated_function)
|
||||||
#
|
#
|
||||||
# In both cases, the result should be a callable object which
|
# In both cases, the result should be a callable object which will be
|
||||||
# will be called whenever the decorated function is called. In
|
# called whenever the decorated function is called. In the first case,
|
||||||
# the first case, the callable object is an instance of
|
# the callable object is an instance of TraceFunction, in the latter
|
||||||
# TraceFunction, in the latter case the return value of
|
# case the return value of TraceFunction.__call__ is the callable
|
||||||
# TraceFunction.__call__ is the callable object.
|
# object.
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
|
|
||||||
if self.function is None:
|
if self.function is None:
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
# If the decorator has been passed a parameter, __init__
|
# If the decorator has been passed a parameter, __init__ will not
|
||||||
# will not define self.function and __call__ will be
|
# define self.function and __call__ will be called immediately
|
||||||
# called immediately after __init__ with the decorated
|
# after __init__ with the decorated function as the only parameter.
|
||||||
# function as the only parameter. Therefore, this __call__
|
# Therefore, this __call__ function has to return the callable
|
||||||
# function has to return the callable object that is meant
|
# object that is meant to be called every time the decorated
|
||||||
# to be called every time the decorated function is
|
# function is called. Here, self is returned in order to return the
|
||||||
# called. Here, self is returned in order to return the
|
# object as the callable handle for the decorated function. This if
|
||||||
# object as the callable handle for the decorated
|
# block should be hit only once at most and only during
|
||||||
# function. This if block should be hit only once at most
|
# initialisation.
|
||||||
# and only during initialisation.
|
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
self.init_function(*args, **kwargs)
|
self.init_function(*args, **kwargs)
|
||||||
return self
|
return self
|
||||||
@ -285,11 +294,13 @@ class TraceFunction(object):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
rv = self.function.function(*args, **kwargs)
|
rv = self.function.function(*args, **kwargs)
|
||||||
except Exception as e:
|
except Exception as exc:
|
||||||
self.trace_exception(e)
|
self.trace_exception(exc)
|
||||||
|
|
||||||
if self.exception_exit:
|
if self._exception_exit:
|
||||||
warnings.warn("Exit forced by EXCEPTION_EXIT")
|
warnings.warn("Exit forced by EXCEPTION_EXIT")
|
||||||
|
|
||||||
|
# pylint: disable=protected-access
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
|
|
||||||
raise
|
raise
|
||||||
@ -300,17 +311,13 @@ class TraceFunction(object):
|
|||||||
return rv
|
return rv
|
||||||
|
|
||||||
def init_function(self, *args, **kwargs):
|
def init_function(self, *args, **kwargs):
|
||||||
|
"""Initialise the TraceFunctionStruct kept by the decorator."""
|
||||||
""" Function to initialise the TraceFunctionStruct kept by the
|
|
||||||
decorator.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# This function should only ever be called with one parameter
|
# This function should only ever be called with one parameter - the
|
||||||
# - the function to be decorated. These checks are done here,
|
# function to be decorated. These checks are done here, rather than by
|
||||||
# rather than by the caller, as anything that calls this
|
# the caller, as anything that calls this function should also have
|
||||||
# function should also have been called with the decorated
|
# been called with the decorated function as its only parameter.
|
||||||
# function as its only parameter.
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
assert not kwargs
|
assert not kwargs
|
||||||
assert len(args) == 1
|
assert len(args) == 1
|
||||||
@ -329,8 +336,8 @@ class TraceFunction(object):
|
|||||||
argspec.defaults))
|
argspec.defaults))
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# init_function is called from either __init__ or __call__ and
|
# init_function is called from either __init__ or __call__ and we want
|
||||||
# we want the frame before that.
|
# the frame before that.
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
frames_back = 2
|
frames_back = 2
|
||||||
caller_frame = inspect.stack()[frames_back]
|
caller_frame = inspect.stack()[frames_back]
|
||||||
@ -341,10 +348,11 @@ class TraceFunction(object):
|
|||||||
self.function.functionname = self.function.function.__name__
|
self.function.functionname = self.function.function.__name__
|
||||||
|
|
||||||
def trace_entry(self, *args, **kwargs):
|
def trace_entry(self, *args, **kwargs):
|
||||||
|
"""Handle function entry.
|
||||||
|
|
||||||
|
This function collects all the function arguments and constructs a
|
||||||
|
message to pass to trace.
|
||||||
|
|
||||||
""" Called on function entry. This function collects all the
|
|
||||||
function arguments and constructs a message to pass to
|
|
||||||
trace.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
@ -355,23 +363,22 @@ class TraceFunction(object):
|
|||||||
msg += ": "
|
msg += ": "
|
||||||
|
|
||||||
n_args = len(args)
|
n_args = len(args)
|
||||||
if self.trace_args:
|
if self._trace_args:
|
||||||
for arg in range(n_args):
|
for arg in range(n_args):
|
||||||
|
|
||||||
if not TRACE_SELF and \
|
if not PyLg.trace_self and \
|
||||||
self.function.varnames[arg] == "self":
|
self.function.varnames[arg] == "self":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
msg += (self.function.varnames[arg] + " = " +
|
msg += "{} = {}, ".format(
|
||||||
self.get_value_string(args[arg]) + ", ")
|
self.function.varnames[arg],
|
||||||
|
self.get_value_string(args[arg])
|
||||||
|
)
|
||||||
|
|
||||||
for name in self.function.varnames[n_args:]:
|
for name in self.function.varnames[n_args:]:
|
||||||
msg += name + " = "
|
msg += "{} = {}, ".format(
|
||||||
if name in kwargs:
|
name, kwargs.get(name, self.function.defaults[name])
|
||||||
value = kwargs[name]
|
)
|
||||||
else:
|
|
||||||
value = self.function.defaults[name]
|
|
||||||
msg += self.get_value_string(value) + ", "
|
|
||||||
|
|
||||||
msg = msg[:-2]
|
msg = msg[:-2]
|
||||||
|
|
||||||
@ -381,11 +388,10 @@ class TraceFunction(object):
|
|||||||
trace(msg, function=self.function)
|
trace(msg, function=self.function)
|
||||||
|
|
||||||
def trace_exit(self, rv=None):
|
def trace_exit(self, rv=None):
|
||||||
|
"""Handle function exit.
|
||||||
|
|
||||||
""" Called on function exit to log the fact that a function has
|
Log the fact that a function has finished executing.
|
||||||
finished executing.
|
|
||||||
|
|
||||||
:param rv: The return value of the traced function.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
@ -394,22 +400,19 @@ class TraceFunction(object):
|
|||||||
msg = "<- EXIT "
|
msg = "<- EXIT "
|
||||||
if rv is not None:
|
if rv is not None:
|
||||||
msg += ": "
|
msg += ": "
|
||||||
if self.trace_rv:
|
if self._trace_rv:
|
||||||
msg += self.get_value_string(rv)
|
msg += self.get_value_string(rv)
|
||||||
else:
|
else:
|
||||||
msg += "---"
|
msg += "---"
|
||||||
|
|
||||||
if self.trace_rv_type:
|
if self._trace_rv_type:
|
||||||
msg += " (type: " + type(rv).__name__ + ")"
|
msg += " (type: {})".format(type(rv).__name__)
|
||||||
|
|
||||||
trace(msg, function=self.function)
|
trace(msg, function=self.function)
|
||||||
return
|
|
||||||
|
|
||||||
def trace_exception(self, exception):
|
def trace_exception(self, exception):
|
||||||
|
|
||||||
"""Called when a function terminated due to an exception.
|
"""Called when a function terminated due to an exception.
|
||||||
|
|
||||||
:param exception: The raised exception.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
@ -418,58 +421,55 @@ class TraceFunction(object):
|
|||||||
core_msg = type(exception).__name__ + " RAISED"
|
core_msg = type(exception).__name__ + " RAISED"
|
||||||
msg = "<- EXIT : " + core_msg
|
msg = "<- EXIT : " + core_msg
|
||||||
|
|
||||||
if str(exception) is not "":
|
if str(exception) != "":
|
||||||
msg += " - " + str(exception)
|
msg += " - " + str(exception)
|
||||||
|
|
||||||
if self.exception_warning:
|
if self._exception_warning:
|
||||||
warnings.warn(core_msg, RuntimeWarning)
|
warnings.warn(core_msg, RuntimeWarning)
|
||||||
|
|
||||||
if self.exception_tb_file:
|
if self._exception_tb_file:
|
||||||
msg += "\n--- EXCEPTION ---\n"
|
msg += "\n--- EXCEPTION ---\n"
|
||||||
msg += traceback.format_exc()
|
msg += traceback.format_exc()
|
||||||
msg += "-----------------"
|
msg += "-----------------"
|
||||||
|
|
||||||
if self.exception_tb_stderr:
|
if self._exception_tb_stderr:
|
||||||
print("--- EXCEPTION ---", file=sys.stderr)
|
print("--- EXCEPTION ---", file=sys.stderr)
|
||||||
traceback.print_exc(file=sys.stderr)
|
traceback.print_exc(file=sys.stderr)
|
||||||
print("-----------------", file=sys.stderr)
|
print("-----------------", file=sys.stderr)
|
||||||
|
|
||||||
trace(msg, function=self.function)
|
trace(msg, function=self.function)
|
||||||
return
|
|
||||||
|
|
||||||
def get_value_string(self, value):
|
@staticmethod
|
||||||
|
def get_value_string(value):
|
||||||
|
"""Convert value to a string for the log."""
|
||||||
|
|
||||||
""" Convert value to a string for the log.
|
if isinstance(value, list) and PyLg.collapse_lists:
|
||||||
"""
|
return "[ len={} ]".format(len(value))
|
||||||
|
|
||||||
if isinstance(value, list) and COLLAPSE_LISTS:
|
if isinstance(value, dict) and PyLg.collapse_dicts:
|
||||||
return self.collapse_list(value)
|
return "{{ len={} }}".format(len(value))
|
||||||
elif isinstance(value, dict) and COLLAPSE_DICTS:
|
|
||||||
return self.collapse_dict(value)
|
|
||||||
else:
|
|
||||||
return str(value)
|
|
||||||
|
|
||||||
def collapse_list(self, ll):
|
return "{}".format(value)
|
||||||
return "[ len=" + str(len(ll)) + " ]"
|
|
||||||
|
|
||||||
def collapse_dict(self, dd):
|
|
||||||
return "{ len=" + str(len(dd)) + " }"
|
|
||||||
|
|
||||||
|
|
||||||
def trace(message, function=None):
|
def trace(message, function=None):
|
||||||
|
"""Write message to the log file.
|
||||||
|
|
||||||
""" Writes message to the log file. It will also log the time,
|
It will also log the time, filename, line number and function name.
|
||||||
filename, line number and function name.
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
message : str
|
||||||
|
The log message.
|
||||||
|
function : Optional[TraceFunctionStruct]
|
||||||
|
A TraceFunctionStruct object if called from within TraceFunction.
|
||||||
|
|
||||||
:param str message: The log message.
|
|
||||||
:param function: A TraceFunctionStruct object if called from within
|
|
||||||
TraceFunction.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if function is None:
|
if function is None:
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# If there is no function object, we need to work out
|
# If there is no function object, we need to work out where the trace
|
||||||
# where the trace call was made from.
|
# call was made from.
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
frames_back = 1
|
frames_back = 1
|
||||||
caller_frame = inspect.stack()[frames_back]
|
caller_frame = inspect.stack()[frames_back]
|
||||||
@ -484,37 +484,40 @@ def trace(message, function=None):
|
|||||||
functionname = function.functionname
|
functionname = function.functionname
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# If CLASS_NAME_RESOLUTION is enabled, the top element of the
|
# If _CLASS_NAME_RESOLUTION is enabled, the top element of the stack should
|
||||||
# stack should be the class name of the function from which this
|
# be the class name of the function from which this trace call is made.
|
||||||
# trace call is made. This cannot be policed so the user must make
|
# This cannot be policed so the user must make sure this is the case by
|
||||||
# sure this is the case by ensuring that trace is only called
|
# ensuring that trace is only called outside of any function or from within
|
||||||
# outside of any function or from within functions that have the
|
# functions that have the @TraceFunction decorator.
|
||||||
# @TraceFunction decorator.
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
classname = ClassNameStack.get()
|
classname = ClassNameStack.get()
|
||||||
if classname is not None and classname != "<module>":
|
if classname is not None and classname != "<module>":
|
||||||
functionname = classname + "." + functionname
|
functionname = "{}.{}".format(classname, functionname)
|
||||||
|
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
# Generate the string based on the settings.
|
# Generate the string based on the settings.
|
||||||
# -------------------------------------------------------------------------
|
# -------------------------------------------------------------------------
|
||||||
msg = ""
|
msg = ""
|
||||||
|
|
||||||
if TRACE_TIME:
|
if PyLg.trace_time:
|
||||||
msg += datetime.now().strftime(TIME_FORMAT) + " "
|
msg += datetime.now().strftime(PyLg.time_format) + " "
|
||||||
|
|
||||||
if TRACE_FILENAME:
|
if PyLg.trace_filename:
|
||||||
msg += '{filename:{w}.{w}} '.format(filename=filename,
|
msg += "{filename:{w}.{w}} ".format(
|
||||||
w=FILENAME_COLUMN_WIDTH)
|
filename=filename,
|
||||||
|
w=PyLg.filename_column_width
|
||||||
|
)
|
||||||
|
|
||||||
if TRACE_LINENO:
|
if PyLg.trace_lineno:
|
||||||
msg += '{lineno:0{w}}: '.format(lineno=lineno, w=LINENO_WIDTH)
|
msg += "{lineno:0{w}}: ".format(lineno=lineno, w=PyLg.lineno_width)
|
||||||
|
|
||||||
if TRACE_FUNCTION:
|
if PyLg.trace_function:
|
||||||
msg += '{function:{w}.{w}} '.format(function=functionname,
|
msg += "{function:{w}.{w}} ".format(
|
||||||
w=FUNCTION_COLUMN_WIDTH)
|
function=functionname,
|
||||||
|
w=PyLg.function_column_width
|
||||||
|
)
|
||||||
|
|
||||||
if TRACE_MESSAGE:
|
if PyLg.trace_message:
|
||||||
|
|
||||||
message = str(message)
|
message = str(message)
|
||||||
|
|
||||||
@ -535,20 +538,20 @@ def trace(message, function=None):
|
|||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
# Wrap the text.
|
# Wrap the text.
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
wrapped = textwrap.wrap(line, MESSAGE_WIDTH)
|
wrapped = textwrap.wrap(line, PyLg.message_width)
|
||||||
|
|
||||||
if not wrapped:
|
if not wrapped:
|
||||||
wrapped = [""]
|
wrapped = [""]
|
||||||
|
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
# If this is the first line of the whole trace message, it
|
# If this is the first line of the whole trace message, it gets
|
||||||
# gets special treatment as it doesn't need whitespace in
|
# special treatment as it doesn't need whitespace in front of it.
|
||||||
# front of it. Otherwise, align it with the previous line.
|
# Otherwise, align it with the previous line.
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
if idx != 0:
|
if idx != 0:
|
||||||
msg += '{:{w}}'.format('', w=premsglen)
|
msg += "{:{w}}".format("", w=premsglen)
|
||||||
|
|
||||||
if MESSAGE_WRAP:
|
if PyLg.message_wrap:
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
# The first wrapped line gets special treatment as any
|
# The first wrapped line gets special treatment as any
|
||||||
@ -557,34 +560,38 @@ def trace(message, function=None):
|
|||||||
msg += wrapped[0]
|
msg += wrapped[0]
|
||||||
|
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
# Print the remaining lines. Append whitespace to
|
# Print the remaining lines. Append whitespace to align it with
|
||||||
# align it with the first line.
|
# the first line.
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
for wrline in wrapped[1:]:
|
for wrline in wrapped[1:]:
|
||||||
msg += '\n' + '{:{w}}'.format('', w=premsglen) + wrline
|
msg += "\n{:{w}}".format('', w=premsglen) + wrline
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
# The message is not being wrapped.
|
# The message is not being wrapped.
|
||||||
# -------------------------------------------------------------
|
# -------------------------------------------------------------
|
||||||
|
|
||||||
if MESSAGE_MARK_TRUNCATION and wrapped[1:]:
|
if PyLg.message_mark_truncation and wrapped[1:]:
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# We want to mark truncated lines so we need to
|
# We want to mark truncated lines so we need to determine
|
||||||
# determine if the line is being truncated. If it
|
# if the line is being truncated. If it is we replace the
|
||||||
# is we replace the last character with '\'.
|
# last character with '\'.
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
if MESSAGE_WIDTH > 1:
|
if PyLg.message_width > 1:
|
||||||
wrapped = textwrap.wrap(wrapped[0], MESSAGE_WIDTH - 1)
|
wrapped = textwrap.wrap(
|
||||||
|
wrapped[0],
|
||||||
|
PyLg.message_width - 1
|
||||||
|
)
|
||||||
assert wrapped
|
assert wrapped
|
||||||
|
|
||||||
msg += ('{m:{w}}'.format(m=wrapped[0],
|
msg += "{m:{w}}\\".format(
|
||||||
w=MESSAGE_WIDTH - 1) +
|
m=wrapped[0],
|
||||||
'\\')
|
w=PyLg.message_width - 1,
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
assert MESSAGE_WIDTH == 1
|
assert PyLg.message_width == 1
|
||||||
msg += '\\'
|
msg += '\\'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
305
pylg/settings.py
305
pylg/settings.py
@ -1,167 +1,162 @@
|
|||||||
# -----------------------------------------------------------------------------
|
"""Handlers for PyLg settings."""
|
||||||
# PyLg: module to facilitate and automate the process of writing runtime logs.
|
|
||||||
# Copyright (C) 2017 Wojciech Kozlowski <wk@wojciechkozlowski.eu>
|
from typing import Optional
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
import os
|
||||||
# it under the terms of the GNU General Public License as published by
|
import yaml
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
_USER_FILE_NAME = "pylg_settings.yml"
|
||||||
#
|
_PYLG_FILE_NAME = "settings.yml"
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
_BOOL_OPTIONS = set([
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
"pylg_enable",
|
||||||
# GNU General Public License for more details.
|
"default_exception_warning",
|
||||||
#
|
"default_exception_tb_file",
|
||||||
# You should have received a copy of the GNU General Public License
|
"default_exception_tb_stderr",
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
"default_exception_exit",
|
||||||
# -----------------------------------------------------------------------------
|
"trace_time",
|
||||||
|
"trace_filename",
|
||||||
|
"trace_lineno",
|
||||||
|
"trace_function",
|
||||||
|
"class_name_resolution",
|
||||||
|
"trace_message",
|
||||||
|
"message_wrap",
|
||||||
|
"message_mark_truncation",
|
||||||
|
"trace_self",
|
||||||
|
"collapse_lists",
|
||||||
|
"collapse_dicts",
|
||||||
|
"default_trace_args",
|
||||||
|
"default_trace_rv",
|
||||||
|
"default_trace_rv_type",
|
||||||
|
])
|
||||||
|
|
||||||
|
_STRING_OPTIONS = set([
|
||||||
|
"pylg_file",
|
||||||
|
"time_format",
|
||||||
|
])
|
||||||
|
|
||||||
|
_POS_INT_OPTIONS = set([
|
||||||
|
"filename_column_width",
|
||||||
|
"function_column_width",
|
||||||
|
])
|
||||||
|
|
||||||
|
_NONNEG_OPTIONS = set([
|
||||||
|
"lineno_width",
|
||||||
|
"message_width",
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
def load(user_settings_path: Optional[str] = None) -> dict:
|
||||||
|
"""Load PyLg settings from file.
|
||||||
|
|
||||||
|
If a user provides a settings file, it will be used. Otherwise, PyLg's
|
||||||
|
default settings will be read in.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Load the default settings.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
default_settings_path = os.path.join(
|
||||||
|
os.path.dirname(os.path.realpath(__file__)), _PYLG_FILE_NAME
|
||||||
|
)
|
||||||
|
|
||||||
|
with open(default_settings_path, 'r') as settings_file:
|
||||||
|
default_settings = yaml.full_load(settings_file)
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Load the user settings.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
user_settings = {}
|
||||||
|
if user_settings_path is not None:
|
||||||
|
with open(user_settings_path, 'r') as settings_file:
|
||||||
|
user_settings = yaml.full_load(settings_file)
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Merge the two settings preferring user values over defaults.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
settings = {**default_settings, **user_settings}
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Verify the input.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
for option in settings.keys():
|
||||||
|
source_file = (user_settings_path
|
||||||
|
if option in user_settings
|
||||||
|
else default_settings_path)
|
||||||
|
option_type = type(settings[option]).__name__
|
||||||
|
option_value = settings[option]
|
||||||
|
|
||||||
|
if option in _BOOL_OPTIONS:
|
||||||
|
if not _pylg_check_bool(option_value):
|
||||||
|
raise ImportError(
|
||||||
|
"Invalid type for {} in {} - should be bool, is type {}"
|
||||||
|
.format(option, source_file, option_type)
|
||||||
|
)
|
||||||
|
|
||||||
|
elif option in _STRING_OPTIONS:
|
||||||
|
if not _pylg_check_string(option_value):
|
||||||
|
raise ImportError(
|
||||||
|
"Invalid type for {} in {} - should be str, is type {}"
|
||||||
|
.format(option, source_file, option_type)
|
||||||
|
)
|
||||||
|
|
||||||
|
elif option in _POS_INT_OPTIONS:
|
||||||
|
if not _pylg_check_pos_int(option_value):
|
||||||
|
raise ImportError(
|
||||||
|
"Invalid type/value for {} in {} - "
|
||||||
|
"should be positive int, is {}"
|
||||||
|
.format(option, source_file, option_value)
|
||||||
|
)
|
||||||
|
|
||||||
|
elif option in _NONNEG_OPTIONS:
|
||||||
|
if not _pylg_check_nonneg_int(option_value):
|
||||||
|
raise ImportError(
|
||||||
|
"Invalid type/value for {} in {} - "
|
||||||
|
"should be non-negative int, is {}"
|
||||||
|
.format(option, source_file, option_value)
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise ImportError("Unrecognised option in {}: {}"
|
||||||
|
.format(source_file, option))
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
# Some final value processing.
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
if settings["message_width"] == 0:
|
||||||
|
settings["message_width"] = float("inf")
|
||||||
|
|
||||||
|
return settings
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Enable/disable PyLg.
|
# Utility functions for sanity checking user settings.
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
PYLG_ENABLE = True
|
def _pylg_check_bool(value) -> bool:
|
||||||
|
return isinstance(value, bool)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# The log file name.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
PYLG_FILE = 'pylg.log'
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
def _pylg_check_string(value) -> bool:
|
||||||
# The default value for 'exception_warning'. If True, PyLg will print
|
return isinstance(value, str)
|
||||||
# a warning about every exception caught to stderr.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
DEFAULT_EXCEPTION_WARNING = True
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# The default value for 'exception_tb_file'. If True, PyLg will write
|
|
||||||
# the exception tracebacks to the log file.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
DEFAULT_EXCEPTION_TB_FILE = True
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
def _pylg_check_int(value) -> bool:
|
||||||
# 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
|
# We check for bool as well as bools are an instance of int, but we don't
|
||||||
# program to exit (and not just raise SystemExit) whenever an
|
# want to let that go through.
|
||||||
# exception occurs. This will happen even if the exception would be
|
# -------------------------------------------------------------------------
|
||||||
# handled at a later point.
|
return isinstance(value, int) and not isinstance(value, bool)
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
DEFAULT_EXCEPTION_EXIT = False
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Enable/disable time logging.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
TRACE_TIME = True
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
def _pylg_check_nonneg_int(value):
|
||||||
# Formatting for the time trace. For a full list of options, see
|
return _pylg_check_int(value) and value >= 0
|
||||||
# https://docs.python.org/2/library/datetime.html#strftime-strptime-behavior.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
TIME_FORMAT = "%Y-%m-%d %H:%M:%S.%f"
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Enable/disable file name logging.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
TRACE_FILENAME = True
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
def _pylg_check_pos_int(value):
|
||||||
# The column width for the file name. If a name is too long, it will
|
return _pylg_check_int(value) and value > 0
|
||||||
# be truncated.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
FILENAME_COLUMN_WIDTH = 20
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Enable/disable the logging of the line number from which the trace
|
|
||||||
# call was made. For entry and exit messages this logs the line in
|
|
||||||
# which the decorator is placed (which should be directly above the
|
|
||||||
# function itself).
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
TRACE_LINENO = True
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# The minimum number of digits to use to print the line number. If the
|
|
||||||
# number is too long, more digits will be used.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
LINENO_WIDTH = 4
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Enable/disable the logging of the function name from which the trace
|
|
||||||
# call was made. Entry/exit logs refer to the function they enter into
|
|
||||||
# and exit from.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
TRACE_FUNCTION = True
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# The column width for the function name. If a name is too long, it
|
|
||||||
# will be truncated.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
FUNCTION_COLUMN_WIDTH = 32
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Enable/disable class name resolution. Function names will be printed
|
|
||||||
# with their class names.
|
|
||||||
#
|
|
||||||
# IMPORTANT: If this setting is enabled, the trace function should
|
|
||||||
# ONLY be called from within functions that have the @TraceFunction
|
|
||||||
# decorator OR outside of any function.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
CLASS_NAME_RESOLUTION = False
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Enable/disable message logging.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
TRACE_MESSAGE = True
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# The column width for the message. A width of zero means unlimited.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
MESSAGE_WIDTH = 0
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# If True, PyLg will wrap the message to fit within the column
|
|
||||||
# width. Otherwise, the message will be truncated.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
MESSAGE_WRAP = True
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# If true, truncated message lines should have the last character
|
|
||||||
# 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
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Enable/disable logging of the 'self' function argument.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
TRACE_SELF = False
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# If True lists/dictionaries will be collapsed to '[ len=x ]' and '{
|
|
||||||
# len=x }' respectively, where x denotes the number of elements in the
|
|
||||||
# collection.
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
COLLAPSE_LISTS = False
|
|
||||||
COLLAPSE_DICTS = False
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# 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
|
|
||||||
|
143
pylg/settings.yml
Normal file
143
pylg/settings.yml
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Enable/disable PyLg.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
pylg_enable: True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# The log file name.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
pylg_file: 'pylg.log'
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# The default value for 'exception_warning'. If True, PyLg will print a warning
|
||||||
|
# about every exception caught to stderr.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
default_exception_warning: True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# The default value for 'exception_tb_file'. If True, PyLg will write the
|
||||||
|
# exception tracebacks to the log file.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
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.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
trace_time: True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Formatting for the time trace. For a full list of options, see
|
||||||
|
# https://docs.python.org/2/library/datetime.html#strftime-strptime-behavior.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
time_format: "%Y-%m-%d %H:%M:%S.%f"
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Enable/disable file name logging.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
trace_filename: True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# The column width for the file name. If a name is too long, it will be
|
||||||
|
# truncated.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
filename_column_width: 20
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Enable/disable the logging of the line number from which the trace call was
|
||||||
|
# made. For entry and exit messages this logs the line in which the decorator
|
||||||
|
# is placed (which should be directly above the function itself).
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
trace_lineno: True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# The minimum number of digits to use to print the line number. If the number
|
||||||
|
# is too long, more digits will be used.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
lineno_width: 4
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Enable/disable the logging of the function name from which the trace call was
|
||||||
|
# made. Entry/exit logs refer to the function they enter into and exit from.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
trace_function: True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# The column width for the function name. If a name is too long, it will be
|
||||||
|
# truncated.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
function_column_width: 32
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Enable/disable class name resolution. Function names will be printed with
|
||||||
|
# their class names.
|
||||||
|
#
|
||||||
|
# IMPORTANT: If this setting is enabled, the trace function should ONLY be
|
||||||
|
# called from within functions that have the @TraceFunction decorator OR
|
||||||
|
# outside of any function.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
class_name_resolution: False
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Enable/disable message logging.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
trace_message: True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# The column width for the message. A width of zero means unlimited.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
message_width: 0
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# If True, PyLg will wrap the message to fit within the column width.
|
||||||
|
# Otherwise, the message will be truncated.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
message_wrap: True
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# If true, truncated message lines should have the last character 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
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# Enable/disable logging of the 'self' function argument.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
trace_self: False
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# If True lists/dictionaries will be collapsed to '[ len=x ]' and '{ len=x }'
|
||||||
|
# respectively, where x denotes the number of elements in the collection.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
collapse_lists: False
|
||||||
|
collapse_dicts: False
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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
|
63
pylg/settings_to_yml.py
Normal file
63
pylg/settings_to_yml.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
"""Convert old-style settings.py to new-style settings.yml."""
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
import sys
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
|
||||||
|
def convert(source, destination):
|
||||||
|
"""Convert source python settings file to destination yml file.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
source : str
|
||||||
|
File name of the old-style Python settings file.
|
||||||
|
destination: str
|
||||||
|
File name for the new-style YAML settings file.
|
||||||
|
|
||||||
|
"""
|
||||||
|
with open(source, 'r') as src, open(destination, 'w') as dst:
|
||||||
|
for line in src:
|
||||||
|
if not line.lstrip().startswith('#') and '=' in line:
|
||||||
|
key, val = line.split('=')
|
||||||
|
key = key.strip().lower()
|
||||||
|
val = val.strip()
|
||||||
|
dst.write("{}: {}\n".format(key, val))
|
||||||
|
else:
|
||||||
|
dst.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def settings_to_yml():
|
||||||
|
"""Convert user settings file from old-style python to new-style YAML."""
|
||||||
|
|
||||||
|
settings_py = "pylg_settings.py"
|
||||||
|
|
||||||
|
root_dir = path.dirname(sys.modules['__main__'].__file__)
|
||||||
|
settings_py_path = path.join(root_dir, settings_py)
|
||||||
|
if path.isfile(settings_py_path):
|
||||||
|
warnings.warn(
|
||||||
|
"Deprecated {} found".format(settings_py),
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
|
||||||
|
settings_yml = "{}.yml".format(settings_py[:-3])
|
||||||
|
settings_yml_path = path.join(root_dir, settings_yml)
|
||||||
|
if path.isfile(settings_yml_path):
|
||||||
|
warnings.warn(
|
||||||
|
"Could not convert {py} to {yml}, {yml} already exists. "
|
||||||
|
"If this is the converted settings file, delete {py} to get "
|
||||||
|
"rid of this warning."
|
||||||
|
.format(py=settings_py, yml=settings_yml),
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
warnings.warn(
|
||||||
|
"Converting {} to {}".format(settings_py, settings_yml),
|
||||||
|
DeprecationWarning,
|
||||||
|
)
|
||||||
|
convert(settings_py_path, settings_yml_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
settings_to_yml()
|
0
pylg/tests/__init__.py
Normal file
0
pylg/tests/__init__.py
Normal file
5
pylg/tests/test_pylg.py
Normal file
5
pylg/tests/test_pylg.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from pylg import TraceFunction, trace
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def test_load():
|
||||||
|
print(sys.modules['__main__'].__file__)
|
571
pylintrc
Normal file
571
pylintrc
Normal file
@ -0,0 +1,571 @@
|
|||||||
|
[MASTER]
|
||||||
|
|
||||||
|
# A comma-separated list of package or module names from where C extensions may
|
||||||
|
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||||
|
# run arbitrary code.
|
||||||
|
extension-pkg-whitelist=
|
||||||
|
|
||||||
|
# Add files or directories to the blacklist. They should be base names, not
|
||||||
|
# paths.
|
||||||
|
ignore=CVS
|
||||||
|
|
||||||
|
# Add files or directories matching the regex patterns to the blacklist. The
|
||||||
|
# regex matches against base names, not paths.
|
||||||
|
ignore-patterns=
|
||||||
|
|
||||||
|
# Python code to execute, usually for sys.path manipulation such as
|
||||||
|
# pygtk.require().
|
||||||
|
#init-hook=
|
||||||
|
|
||||||
|
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
|
||||||
|
# number of processors available to use.
|
||||||
|
jobs=1
|
||||||
|
|
||||||
|
# Control the amount of potential inferred values when inferring a single
|
||||||
|
# object. This can help the performance when dealing with large functions or
|
||||||
|
# complex, nested conditions.
|
||||||
|
limit-inference-results=100
|
||||||
|
|
||||||
|
# List of plugins (as comma separated values of python modules names) to load,
|
||||||
|
# usually to register additional checkers.
|
||||||
|
load-plugins=
|
||||||
|
|
||||||
|
# Pickle collected data for later comparisons.
|
||||||
|
persistent=yes
|
||||||
|
|
||||||
|
# Specify a configuration file.
|
||||||
|
#rcfile=
|
||||||
|
|
||||||
|
# When enabled, pylint would attempt to guess common misconfiguration and emit
|
||||||
|
# user-friendly hints instead of false-positive error messages.
|
||||||
|
suggestion-mode=yes
|
||||||
|
|
||||||
|
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||||
|
# active Python interpreter and may run arbitrary code.
|
||||||
|
unsafe-load-any-extension=no
|
||||||
|
|
||||||
|
|
||||||
|
[MESSAGES CONTROL]
|
||||||
|
|
||||||
|
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||||
|
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
|
||||||
|
confidence=
|
||||||
|
|
||||||
|
# Disable the message, report, category or checker with the given id(s). You
|
||||||
|
# can either give multiple identifiers separated by comma (,) or put this
|
||||||
|
# option multiple times (only on the command line, not in the configuration
|
||||||
|
# file where it should appear only once). You can also use "--disable=all" to
|
||||||
|
# disable everything first and then reenable specific checks. For example, if
|
||||||
|
# you want to run only the similarities checker, you can use "--disable=all
|
||||||
|
# --enable=similarities". If you want to run only the classes checker, but have
|
||||||
|
# no Warning level messages displayed, use "--disable=all --enable=classes
|
||||||
|
# --disable=W".
|
||||||
|
disable=print-statement,
|
||||||
|
parameter-unpacking,
|
||||||
|
unpacking-in-except,
|
||||||
|
old-raise-syntax,
|
||||||
|
backtick,
|
||||||
|
long-suffix,
|
||||||
|
old-ne-operator,
|
||||||
|
old-octal-literal,
|
||||||
|
import-star-module-level,
|
||||||
|
non-ascii-bytes-literal,
|
||||||
|
raw-checker-failed,
|
||||||
|
bad-inline-option,
|
||||||
|
locally-disabled,
|
||||||
|
file-ignored,
|
||||||
|
suppressed-message,
|
||||||
|
useless-suppression,
|
||||||
|
deprecated-pragma,
|
||||||
|
use-symbolic-message-instead,
|
||||||
|
apply-builtin,
|
||||||
|
basestring-builtin,
|
||||||
|
buffer-builtin,
|
||||||
|
cmp-builtin,
|
||||||
|
coerce-builtin,
|
||||||
|
execfile-builtin,
|
||||||
|
file-builtin,
|
||||||
|
long-builtin,
|
||||||
|
raw_input-builtin,
|
||||||
|
reduce-builtin,
|
||||||
|
standarderror-builtin,
|
||||||
|
unicode-builtin,
|
||||||
|
xrange-builtin,
|
||||||
|
coerce-method,
|
||||||
|
delslice-method,
|
||||||
|
getslice-method,
|
||||||
|
setslice-method,
|
||||||
|
no-absolute-import,
|
||||||
|
old-division,
|
||||||
|
dict-iter-method,
|
||||||
|
dict-view-method,
|
||||||
|
next-method-called,
|
||||||
|
metaclass-assignment,
|
||||||
|
indexing-exception,
|
||||||
|
raising-string,
|
||||||
|
reload-builtin,
|
||||||
|
oct-method,
|
||||||
|
hex-method,
|
||||||
|
nonzero-method,
|
||||||
|
cmp-method,
|
||||||
|
input-builtin,
|
||||||
|
round-builtin,
|
||||||
|
intern-builtin,
|
||||||
|
unichr-builtin,
|
||||||
|
map-builtin-not-iterating,
|
||||||
|
zip-builtin-not-iterating,
|
||||||
|
range-builtin-not-iterating,
|
||||||
|
filter-builtin-not-iterating,
|
||||||
|
using-cmp-argument,
|
||||||
|
eq-without-hash,
|
||||||
|
div-method,
|
||||||
|
idiv-method,
|
||||||
|
rdiv-method,
|
||||||
|
exception-message-attribute,
|
||||||
|
invalid-str-codec,
|
||||||
|
sys-max-int,
|
||||||
|
bad-python3-import,
|
||||||
|
deprecated-string-function,
|
||||||
|
deprecated-str-translate-call,
|
||||||
|
deprecated-itertools-function,
|
||||||
|
deprecated-types-field,
|
||||||
|
next-method-defined,
|
||||||
|
dict-items-not-iterating,
|
||||||
|
dict-keys-not-iterating,
|
||||||
|
dict-values-not-iterating,
|
||||||
|
deprecated-operator-function,
|
||||||
|
deprecated-urllib-function,
|
||||||
|
xreadlines-attribute,
|
||||||
|
deprecated-sys-function,
|
||||||
|
exception-escape,
|
||||||
|
comprehension-escape
|
||||||
|
|
||||||
|
# Enable the message, report, category or checker with the given id(s). You can
|
||||||
|
# either give multiple identifier separated by comma (,) or put this option
|
||||||
|
# multiple time (only on the command line, not in the configuration file where
|
||||||
|
# it should appear only once). See also the "--disable" option for examples.
|
||||||
|
enable=c-extension-no-member
|
||||||
|
|
||||||
|
|
||||||
|
[REPORTS]
|
||||||
|
|
||||||
|
# Python expression which should return a note less than 10 (10 is the highest
|
||||||
|
# note). You have access to the variables errors warning, statement which
|
||||||
|
# respectively contain the number of errors / warnings messages and the total
|
||||||
|
# number of statements analyzed. This is used by the global evaluation report
|
||||||
|
# (RP0004).
|
||||||
|
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||||
|
|
||||||
|
# Template used to display messages. This is a python new-style format string
|
||||||
|
# used to format the message information. See doc for all details.
|
||||||
|
#msg-template=
|
||||||
|
|
||||||
|
# Set the output format. Available formats are text, parseable, colorized, json
|
||||||
|
# and msvs (visual studio). You can also give a reporter class, e.g.
|
||||||
|
# mypackage.mymodule.MyReporterClass.
|
||||||
|
output-format=text
|
||||||
|
|
||||||
|
# Tells whether to display a full report or only the messages.
|
||||||
|
reports=no
|
||||||
|
|
||||||
|
# Activate the evaluation score.
|
||||||
|
score=yes
|
||||||
|
|
||||||
|
|
||||||
|
[REFACTORING]
|
||||||
|
|
||||||
|
# Maximum number of nested blocks for function / method body
|
||||||
|
max-nested-blocks=5
|
||||||
|
|
||||||
|
# Complete name of functions that never returns. When checking for
|
||||||
|
# inconsistent-return-statements if a never returning function is called then
|
||||||
|
# it will be considered as an explicit return statement and no message will be
|
||||||
|
# printed.
|
||||||
|
never-returning-functions=sys.exit
|
||||||
|
|
||||||
|
|
||||||
|
[TYPECHECK]
|
||||||
|
|
||||||
|
# List of decorators that produce context managers, such as
|
||||||
|
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||||
|
# produce valid context managers.
|
||||||
|
contextmanager-decorators=contextlib.contextmanager
|
||||||
|
|
||||||
|
# List of members which are set dynamically and missed by pylint inference
|
||||||
|
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||||
|
# expressions are accepted.
|
||||||
|
generated-members=
|
||||||
|
|
||||||
|
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||||
|
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||||
|
ignore-mixin-members=yes
|
||||||
|
|
||||||
|
# Tells whether to warn about missing members when the owner of the attribute
|
||||||
|
# is inferred to be None.
|
||||||
|
ignore-none=yes
|
||||||
|
|
||||||
|
# This flag controls whether pylint should warn about no-member and similar
|
||||||
|
# checks whenever an opaque object is returned when inferring. The inference
|
||||||
|
# can return multiple potential results while evaluating a Python object, but
|
||||||
|
# some branches might not be evaluated, which results in partial inference. In
|
||||||
|
# that case, it might be useful to still emit no-member and other checks for
|
||||||
|
# the rest of the inferred objects.
|
||||||
|
ignore-on-opaque-inference=yes
|
||||||
|
|
||||||
|
# List of class names for which member attributes should not be checked (useful
|
||||||
|
# for classes with dynamically set attributes). This supports the use of
|
||||||
|
# qualified names.
|
||||||
|
ignored-classes=optparse.Values,thread._local,_thread._local
|
||||||
|
|
||||||
|
# List of module names for which member attributes should not be checked
|
||||||
|
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||||
|
# and thus existing member attributes cannot be deduced by static analysis. It
|
||||||
|
# supports qualified module names, as well as Unix pattern matching.
|
||||||
|
ignored-modules=
|
||||||
|
|
||||||
|
# Show a hint with possible names when a member name was not found. The aspect
|
||||||
|
# of finding the hint is based on edit distance.
|
||||||
|
missing-member-hint=yes
|
||||||
|
|
||||||
|
# The minimum edit distance a name should have in order to be considered a
|
||||||
|
# similar match for a missing member name.
|
||||||
|
missing-member-hint-distance=1
|
||||||
|
|
||||||
|
# The total number of similar names that should be taken in consideration when
|
||||||
|
# showing a hint for a missing member.
|
||||||
|
missing-member-max-choices=1
|
||||||
|
|
||||||
|
|
||||||
|
[BASIC]
|
||||||
|
|
||||||
|
# Naming style matching correct argument names.
|
||||||
|
argument-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct argument names. Overrides argument-
|
||||||
|
# naming-style.
|
||||||
|
#argument-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct attribute names.
|
||||||
|
attr-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct attribute names. Overrides attr-naming-
|
||||||
|
# style.
|
||||||
|
#attr-rgx=
|
||||||
|
|
||||||
|
# Bad variable names which should always be refused, separated by a comma.
|
||||||
|
bad-names=foo,
|
||||||
|
bar,
|
||||||
|
baz,
|
||||||
|
toto,
|
||||||
|
tutu,
|
||||||
|
tata
|
||||||
|
|
||||||
|
# Naming style matching correct class attribute names.
|
||||||
|
class-attribute-naming-style=any
|
||||||
|
|
||||||
|
# Regular expression matching correct class attribute names. Overrides class-
|
||||||
|
# attribute-naming-style.
|
||||||
|
#class-attribute-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct class names.
|
||||||
|
class-naming-style=PascalCase
|
||||||
|
|
||||||
|
# Regular expression matching correct class names. Overrides class-naming-
|
||||||
|
# style.
|
||||||
|
#class-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct constant names.
|
||||||
|
const-naming-style=UPPER_CASE
|
||||||
|
|
||||||
|
# Regular expression matching correct constant names. Overrides const-naming-
|
||||||
|
# style.
|
||||||
|
#const-rgx=
|
||||||
|
|
||||||
|
# Minimum line length for functions/classes that require docstrings, shorter
|
||||||
|
# ones are exempt.
|
||||||
|
docstring-min-length=-1
|
||||||
|
|
||||||
|
# Naming style matching correct function names.
|
||||||
|
function-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct function names. Overrides function-
|
||||||
|
# naming-style.
|
||||||
|
#function-rgx=
|
||||||
|
|
||||||
|
# Good variable names which should always be accepted, separated by a comma.
|
||||||
|
good-names=i,
|
||||||
|
j,
|
||||||
|
k,
|
||||||
|
ex,
|
||||||
|
Run,
|
||||||
|
rv,
|
||||||
|
_
|
||||||
|
|
||||||
|
# Include a hint for the correct naming format with invalid-name.
|
||||||
|
include-naming-hint=no
|
||||||
|
|
||||||
|
# Naming style matching correct inline iteration names.
|
||||||
|
inlinevar-naming-style=any
|
||||||
|
|
||||||
|
# Regular expression matching correct inline iteration names. Overrides
|
||||||
|
# inlinevar-naming-style.
|
||||||
|
#inlinevar-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct method names.
|
||||||
|
method-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct method names. Overrides method-naming-
|
||||||
|
# style.
|
||||||
|
#method-rgx=
|
||||||
|
|
||||||
|
# Naming style matching correct module names.
|
||||||
|
module-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct module names. Overrides module-naming-
|
||||||
|
# style.
|
||||||
|
#module-rgx=
|
||||||
|
|
||||||
|
# Colon-delimited sets of names that determine each other's naming style when
|
||||||
|
# the name regexes allow several styles.
|
||||||
|
name-group=
|
||||||
|
|
||||||
|
# Regular expression which should only match function or class names that do
|
||||||
|
# not require a docstring.
|
||||||
|
no-docstring-rgx=^_
|
||||||
|
|
||||||
|
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||||
|
# to this list to register other decorators that produce valid properties.
|
||||||
|
# These decorators are taken in consideration only for invalid-name.
|
||||||
|
property-classes=abc.abstractproperty
|
||||||
|
|
||||||
|
# Naming style matching correct variable names.
|
||||||
|
variable-naming-style=snake_case
|
||||||
|
|
||||||
|
# Regular expression matching correct variable names. Overrides variable-
|
||||||
|
# naming-style.
|
||||||
|
#variable-rgx=
|
||||||
|
|
||||||
|
|
||||||
|
[FORMAT]
|
||||||
|
|
||||||
|
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||||
|
expected-line-ending-format=
|
||||||
|
|
||||||
|
# Regexp for a line that is allowed to be longer than the limit.
|
||||||
|
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||||
|
|
||||||
|
# Number of spaces of indent required inside a hanging or continued line.
|
||||||
|
indent-after-paren=4
|
||||||
|
|
||||||
|
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||||
|
# tab).
|
||||||
|
indent-string=' '
|
||||||
|
|
||||||
|
# Maximum number of characters on a single line.
|
||||||
|
max-line-length=100
|
||||||
|
|
||||||
|
# Maximum number of lines in a module.
|
||||||
|
max-module-lines=1000
|
||||||
|
|
||||||
|
# List of optional constructs for which whitespace checking is disabled. `dict-
|
||||||
|
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
|
||||||
|
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
|
||||||
|
# `empty-line` allows space-only lines.
|
||||||
|
no-space-check=trailing-comma,
|
||||||
|
dict-separator
|
||||||
|
|
||||||
|
# Allow the body of a class to be on the same line as the declaration if body
|
||||||
|
# contains single statement.
|
||||||
|
single-line-class-stmt=no
|
||||||
|
|
||||||
|
# Allow the body of an if to be on the same line as the test if there is no
|
||||||
|
# else.
|
||||||
|
single-line-if-stmt=no
|
||||||
|
|
||||||
|
|
||||||
|
[SIMILARITIES]
|
||||||
|
|
||||||
|
# Ignore comments when computing similarities.
|
||||||
|
ignore-comments=yes
|
||||||
|
|
||||||
|
# Ignore docstrings when computing similarities.
|
||||||
|
ignore-docstrings=yes
|
||||||
|
|
||||||
|
# Ignore imports when computing similarities.
|
||||||
|
ignore-imports=no
|
||||||
|
|
||||||
|
# Minimum lines number of a similarity.
|
||||||
|
min-similarity-lines=4
|
||||||
|
|
||||||
|
|
||||||
|
[MISCELLANEOUS]
|
||||||
|
|
||||||
|
# List of note tags to take in consideration, separated by a comma.
|
||||||
|
notes=FIXME,
|
||||||
|
XXX,
|
||||||
|
TODO
|
||||||
|
|
||||||
|
|
||||||
|
[STRING]
|
||||||
|
|
||||||
|
# This flag controls whether the implicit-str-concat-in-sequence should
|
||||||
|
# generate a warning on implicit string concatenation in sequences defined over
|
||||||
|
# several lines.
|
||||||
|
check-str-concat-over-line-jumps=no
|
||||||
|
|
||||||
|
|
||||||
|
[SPELLING]
|
||||||
|
|
||||||
|
# Limits count of emitted suggestions for spelling mistakes.
|
||||||
|
max-spelling-suggestions=4
|
||||||
|
|
||||||
|
# Spelling dictionary name. Available dictionaries: en_GB (myspell), en_US
|
||||||
|
# (myspell)..
|
||||||
|
spelling-dict=
|
||||||
|
|
||||||
|
# List of comma separated words that should not be checked.
|
||||||
|
spelling-ignore-words=
|
||||||
|
|
||||||
|
# A path to a file that contains private dictionary; one word per line.
|
||||||
|
spelling-private-dict-file=
|
||||||
|
|
||||||
|
# Tells whether to store unknown words to indicated private dictionary in
|
||||||
|
# --spelling-private-dict-file option instead of raising a message.
|
||||||
|
spelling-store-unknown-words=no
|
||||||
|
|
||||||
|
|
||||||
|
[VARIABLES]
|
||||||
|
|
||||||
|
# List of additional names supposed to be defined in builtins. Remember that
|
||||||
|
# you should avoid defining new builtins when possible.
|
||||||
|
additional-builtins=
|
||||||
|
|
||||||
|
# Tells whether unused global variables should be treated as a violation.
|
||||||
|
allow-global-unused-variables=yes
|
||||||
|
|
||||||
|
# List of strings which can identify a callback function by name. A callback
|
||||||
|
# name must start or end with one of those strings.
|
||||||
|
callbacks=cb_,
|
||||||
|
_cb
|
||||||
|
|
||||||
|
# A regular expression matching the name of dummy variables (i.e. expected to
|
||||||
|
# not be used).
|
||||||
|
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||||
|
|
||||||
|
# Argument names that match this expression will be ignored. Default to name
|
||||||
|
# with leading underscore.
|
||||||
|
ignored-argument-names=_.*|^ignored_|^unused_
|
||||||
|
|
||||||
|
# Tells whether we should check for unused import in __init__ files.
|
||||||
|
init-import=no
|
||||||
|
|
||||||
|
# List of qualified module names which can have objects that can redefine
|
||||||
|
# builtins.
|
||||||
|
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
|
||||||
|
|
||||||
|
|
||||||
|
[LOGGING]
|
||||||
|
|
||||||
|
# Format style used to check logging format string. `old` means using %
|
||||||
|
# formatting, while `new` is for `{}` formatting.
|
||||||
|
logging-format-style=old
|
||||||
|
|
||||||
|
# Logging modules to check that the string format arguments are in logging
|
||||||
|
# function parameter format.
|
||||||
|
logging-modules=logging
|
||||||
|
|
||||||
|
|
||||||
|
[CLASSES]
|
||||||
|
|
||||||
|
# List of method names used to declare (i.e. assign) instance attributes.
|
||||||
|
defining-attr-methods=__init__,
|
||||||
|
__new__,
|
||||||
|
setUp
|
||||||
|
|
||||||
|
# List of member names, which should be excluded from the protected access
|
||||||
|
# warning.
|
||||||
|
exclude-protected=_asdict,
|
||||||
|
_fields,
|
||||||
|
_replace,
|
||||||
|
_source,
|
||||||
|
_make
|
||||||
|
|
||||||
|
# List of valid names for the first argument in a class method.
|
||||||
|
valid-classmethod-first-arg=cls
|
||||||
|
|
||||||
|
# List of valid names for the first argument in a metaclass class method.
|
||||||
|
valid-metaclass-classmethod-first-arg=cls
|
||||||
|
|
||||||
|
|
||||||
|
[DESIGN]
|
||||||
|
|
||||||
|
# Maximum number of arguments for function / method.
|
||||||
|
max-args=5
|
||||||
|
|
||||||
|
# Maximum number of attributes for a class (see R0902).
|
||||||
|
max-attributes=7
|
||||||
|
|
||||||
|
# Maximum number of boolean expressions in an if statement.
|
||||||
|
max-bool-expr=5
|
||||||
|
|
||||||
|
# Maximum number of branch for function / method body.
|
||||||
|
max-branches=12
|
||||||
|
|
||||||
|
# Maximum number of locals for function / method body.
|
||||||
|
max-locals=15
|
||||||
|
|
||||||
|
# Maximum number of parents for a class (see R0901).
|
||||||
|
max-parents=7
|
||||||
|
|
||||||
|
# Maximum number of public methods for a class (see R0904).
|
||||||
|
max-public-methods=20
|
||||||
|
|
||||||
|
# Maximum number of return / yield for function / method body.
|
||||||
|
max-returns=6
|
||||||
|
|
||||||
|
# Maximum number of statements in function / method body.
|
||||||
|
max-statements=50
|
||||||
|
|
||||||
|
# Minimum number of public methods for a class (see R0903).
|
||||||
|
min-public-methods=2
|
||||||
|
|
||||||
|
|
||||||
|
[IMPORTS]
|
||||||
|
|
||||||
|
# Allow wildcard imports from modules that define __all__.
|
||||||
|
allow-wildcard-with-all=no
|
||||||
|
|
||||||
|
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||||
|
# 3 compatible code, which means that the block might have code that exists
|
||||||
|
# only in one or another interpreter, leading to false positives when analysed.
|
||||||
|
analyse-fallback-blocks=no
|
||||||
|
|
||||||
|
# Deprecated modules which should not be used, separated by a comma.
|
||||||
|
deprecated-modules=optparse,tkinter.tix
|
||||||
|
|
||||||
|
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||||
|
# not be disabled).
|
||||||
|
ext-import-graph=
|
||||||
|
|
||||||
|
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||||
|
# given file (report RP0402 must not be disabled).
|
||||||
|
import-graph=
|
||||||
|
|
||||||
|
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||||
|
# not be disabled).
|
||||||
|
int-import-graph=
|
||||||
|
|
||||||
|
# Force import order to recognize a module as part of the standard
|
||||||
|
# compatibility libraries.
|
||||||
|
known-standard-library=
|
||||||
|
|
||||||
|
# Force import order to recognize a module as part of a third party library.
|
||||||
|
known-third-party=enchant
|
||||||
|
|
||||||
|
|
||||||
|
[EXCEPTIONS]
|
||||||
|
|
||||||
|
# Exceptions that will emit a warning when being caught. Defaults to
|
||||||
|
# "BaseException, Exception".
|
||||||
|
overgeneral-exceptions=BaseException,
|
||||||
|
Exception
|
34
setup.py
34
setup.py
@ -1,26 +1,44 @@
|
|||||||
from setuptools import setup, find_packages
|
"""PyLg setup file."""
|
||||||
from codecs import open
|
|
||||||
|
from codecs import open as codecs_open
|
||||||
from os import path
|
from os import path
|
||||||
|
|
||||||
pwd = path.abspath(path.dirname(__file__))
|
from setuptools import setup
|
||||||
|
|
||||||
with open(path.join(pwd, 'README.rst'), encoding='utf-8') as f:
|
PWD = path.abspath(path.dirname(__file__))
|
||||||
long_description = f.read()
|
|
||||||
|
with codecs_open(path.join(PWD, 'README.rst'), encoding='utf-8') as f:
|
||||||
|
LONG_DESCRIPTION = f.read()
|
||||||
|
|
||||||
|
INSTALL_REQUIRES = [
|
||||||
|
'pyyaml',
|
||||||
|
]
|
||||||
|
|
||||||
|
EXTRAS_REQUIRE = {
|
||||||
|
'dev': [
|
||||||
|
'pytest',
|
||||||
|
'pytest-cov',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='PyLg',
|
name='PyLg',
|
||||||
version='1.3.3',
|
version='1.3.3',
|
||||||
description='Python module to facilitate and automate the process of writing runtime logs.',
|
description=('Python module to facilitate and automate the process of '
|
||||||
long_description=long_description,
|
'writing runtime logs.'),
|
||||||
|
long_description=LONG_DESCRIPTION,
|
||||||
url='https://github.com/Wojtek242/pylg',
|
url='https://github.com/Wojtek242/pylg',
|
||||||
|
|
||||||
author='Wojciech Kozlowski',
|
author='Wojciech Kozlowski',
|
||||||
author_email='wk@wojciechkozlowski.eu',
|
author_email='wk@wojciechkozlowski.eu',
|
||||||
|
install_requires=INSTALL_REQUIRES,
|
||||||
|
extras_require=EXTRAS_REQUIRE,
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 4 - Beta',
|
'Development Status :: 4 - Beta',
|
||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'Topic :: Software Development :: Debuggers',
|
'Topic :: Software Development :: Debuggers',
|
||||||
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
|
('License :: OSI Approved :: '
|
||||||
|
'GNU General Public License v3 or later (GPLv3+)'),
|
||||||
'Programming Language :: Python :: 2.7',
|
'Programming Language :: Python :: 2.7',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user