# Copyright (C) 2016 Niklas Rosenstein
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from craftr import session, module, ModuleError
from craftr import magic, path, tty
import sys
import traceback
# Log-level metadata about the minimum required verbosity level for
# printing a stack-trace and the colors for colorized output.
LOG_METADATA = {
'debug': {'strace_min_verbosity': 3, 'fg': tty.compile('yellow', attrs='bold')},
'info': {'strace_min_verbosity': 2, 'fg': tty.compile('cyan', attrs='bold')},
'warn': {'strace_min_verbosity': 2, 'fg': tty.compile('magenta', attrs='bold')},
'error': {'strace_min_verbosity': 1, 'fg': tty.compile('red', attrs='bold')},
}
def _walk_frames(start_frame=None, stacklevel=1, max_frames=0):
if start_frame is None:
start_frame = magic.get_frame(stacklevel)
frame = start_frame
count = 0
while frame and (max_frames == 0 or count < max_frames):
yield frame
frame = frame.f_back
count += 1
[docs]def debug(*args, stacklevel=1, verbosity=None, **kwargs):
if verbosity is None and session:
verbosity = session.verbosity
if verbosity is None or verbosity >= 1:
stacklevel += 1
log('debug', *args, stacklevel=stacklevel, **kwargs)
def log(level, *args, stacklevel=1, module_name=None, show_trace=None, **kwargs):
meta = LOG_METADATA[level]
prefix = 'craftr: ' + meta['fg'] + '[{0:<5}]'.format(level.upper())
if not module_name and module:
module_name = module.project_name
if module_name:
prefix += ' (' + module_name
if module:
prefix += '|L' + str(magic.get_module_frame(module).f_lineno)
prefix += ')'
prefix += ': ' + tty.reset
kwargs.setdefault('file', sys.stderr)
end = kwargs.pop('end', '\n')
kwargs['file'].write(prefix)
print(*args, end='', **kwargs)
kwargs['file'].write(tty.reset)
kwargs['file'].write(end)
if show_trace is None:
show_trace = bool(session and module and session.verbosity >= meta['strace_min_verbosity'])
if show_trace:
max_frames = session.strace_depth
frames = list(_walk_frames(stacklevel=(stacklevel + 1), max_frames=max_frames))
for frame in reversed(frames):
fn = frame.f_code.co_filename
if fn.startswith('<'):
fn = tty.colored(fn, 'yellow', attrs='bold')
else:
fn = path.relpath(fn, session.cwd, only_sub=True)
fn = tty.colored(fn, 'red', attrs='bold')
func = frame.f_code.co_name
if func == '<module>' and 'project_name' in frame.f_globals:
func = '<craftr.ext.{0}>'.format(frame.f_globals['project_name'])
if func.startswith('<'):
func = tty.colored(func, 'yellow', attrs='bold')
else:
func = tty.colored(func + '()', 'blue', attrs='bold')
lineno = frame.f_lineno
print(' In', func, '[{0}|L{1}]'.format(fn, lineno))
[docs]def info(*args, stacklevel=1, **kwargs):
stacklevel += 1
log('info', *args, stacklevel=stacklevel, **kwargs)
[docs]def warn(*args, stacklevel=1, **kwargs):
stacklevel += 1
log('warn', *args, stacklevel=stacklevel, **kwargs)
[docs]def error(*args, stacklevel=1, raise_=True, **kwargs):
stacklevel += 1
log('error', *args, stacklevel=stacklevel, **kwargs)
if raise_ and module:
raise ModuleError()