[cli] adds python logging facility configuration.

This commit is contained in:
Romain Dorgueil
2017-05-31 22:06:08 +02:00
parent 2c2bc4fca9
commit 88d46a724d
7 changed files with 122 additions and 27 deletions

View File

@ -1,12 +1,13 @@
import argparse
import logging
from stevedore import ExtensionManager
from bonobo import logging, settings
logger = logging.get_logger()
def entrypoint(args=None):
logging.basicConfig()
parser = argparse.ArgumentParser()
parser.add_argument('--debug', '-D', action='store_true')
subparsers = parser.add_subparsers(dest='command')
subparsers.required = True
@ -18,10 +19,17 @@ def entrypoint(args=None):
parser = subparsers.add_parser(ext.name)
commands[ext.name] = ext.plugin(parser)
except Exception:
logging.exception('Error while loading command {}.'.format(ext.name))
logger.exception('Error while loading command {}.'.format(ext.name))
from stevedore import ExtensionManager
mgr = ExtensionManager(namespace='bonobo.commands')
mgr.map(register_extension)
args = parser.parse_args(args).__dict__
if args.pop('debug', False):
settings.DEBUG = True
settings.LOGGING_LEVEL = logging.DEBUG
logging.set_level(settings.LOGGING_LEVEL)
logger.debug('Command: ' + args['command'] + ' Arguments: ' + repr(args))
commands[args.pop('command')](**args)

View File

@ -1,6 +1,3 @@
import os
def execute(name):
try:
from cookiecutter.main import cookiecutter

View File

@ -1,10 +1,4 @@
import importlib
import os
import runpy
import pip
import bonobo
DEFAULT_SERVICES_FILENAME = '_services.py'
DEFAULT_SERVICES_ATTR = 'get_services'
@ -12,7 +6,6 @@ DEFAULT_SERVICES_ATTR = 'get_services'
DEFAULT_GRAPH_FILENAME = '__main__.py'
DEFAULT_GRAPH_ATTR = 'get_graph'
def get_default_services(filename, services=None):
dirname = os.path.dirname(filename)
services_filename = os.path.join(dirname, DEFAULT_SERVICES_FILENAME)
@ -33,7 +26,8 @@ def get_default_services(filename, services=None):
def execute(filename, module, install=False, quiet=False, verbose=False):
from bonobo import settings
import runpy
from bonobo import Graph, run, settings
if quiet:
settings.QUIET = True
@ -44,6 +38,8 @@ def execute(filename, module, install=False, quiet=False, verbose=False):
if filename:
if os.path.isdir(filename):
if install:
import importlib
import pip
requirements = os.path.join(filename, 'requirements.txt')
pip.main(['install', '-r', requirements])
# Some shenanigans to be sure everything is importable after this, especially .egg-link files which
@ -62,7 +58,7 @@ def execute(filename, module, install=False, quiet=False, verbose=False):
else:
raise RuntimeError('UNEXPECTED: argparse should not allow this.')
graphs = dict((k, v) for k, v in context.items() if isinstance(v, bonobo.Graph))
graphs = dict((k, v) for k, v in context.items() if isinstance(v, Graph))
assert len(graphs) == 1, (
'Having zero or more than one graph definition in one file is unsupported for now, '
@ -73,7 +69,7 @@ def execute(filename, module, install=False, quiet=False, verbose=False):
# todo if console and not quiet, then add the console plugin
# todo when better console plugin, add it if console and just disable display
return bonobo.run(
return run(
graph,
plugins=[],
services=get_default_services(
@ -82,8 +78,8 @@ def execute(filename, module, install=False, quiet=False, verbose=False):
)
def register_generic_run_arguments(parser):
source_group = parser.add_mutually_exclusive_group(required=True)
def register_generic_run_arguments(parser, required=True):
source_group = parser.add_mutually_exclusive_group(required=required)
source_group.add_argument('filename', nargs='?', type=str)
source_group.add_argument('--module', '-m', type=str)
return parser

View File

@ -1,8 +1,5 @@
import bonobo
from bonobo.util.pkgs import bonobo_packages
def format_version(mod, *, name=None, quiet=False):
from bonobo.util.pkgs import bonobo_packages
args = {
'name': name or mod.__name__,
'version': mod.__version__,
@ -20,6 +17,9 @@ def format_version(mod, *, name=None, quiet=False):
def execute(all=False, quiet=False):
import bonobo
from bonobo.util.pkgs import bonobo_packages
print(format_version(bonobo, quiet=quiet))
if all:
for name in sorted(bonobo_packages):

75
bonobo/logging.py Normal file
View File

@ -0,0 +1,75 @@
import logging
import sys
import textwrap
from logging import CRITICAL, DEBUG, ERROR, INFO, WARNING
from colorama import Fore, Style
from bonobo import settings
from bonobo.util.term import CLEAR_EOL
def get_format():
yield '{b}[%(fg)s%(levelname)s{b}][{w}'
yield '{b}][{w}'.join(('%(spent)04d', '%(name)s'))
yield '{b}]'
yield ' %(fg)s%(message)s{r}'
yield CLEAR_EOL
colors = {
'b': Fore.BLACK,
'w': Fore.LIGHTBLACK_EX,
'r': Style.RESET_ALL,
}
format = (''.join(get_format())).format(**colors)
class Filter(logging.Filter):
def filter(self, record):
record.spent = record.relativeCreated // 1000
if record.levelname == 'DEBG':
record.fg = Fore.LIGHTBLACK_EX
elif record.levelname == 'INFO':
record.fg = Fore.LIGHTWHITE_EX
elif record.levelname == 'WARN':
record.fg = Fore.LIGHTYELLOW_EX
elif record.levelname == 'ERR ':
record.fg = Fore.LIGHTRED_EX
elif record.levelname == 'CRIT':
record.fg = Fore.RED
else:
record.fg = Fore.LIGHTWHITE_EX
return True
class Formatter(logging.Formatter):
def formatException(self, ei):
tb = super().formatException(ei)
return textwrap.indent(tb, Fore.BLACK + ' | ' + Fore.WHITE)
def setup(level):
logging.addLevelName(DEBUG, 'DEBG')
logging.addLevelName(INFO, 'INFO')
logging.addLevelName(WARNING, 'WARN')
logging.addLevelName(ERROR, 'ERR ')
logging.addLevelName(CRITICAL, 'CRIT')
handler = logging.StreamHandler(sys.stderr)
handler.setFormatter(Formatter(format))
handler.addFilter(Filter())
root = logging.getLogger()
root.addHandler(handler)
root.setLevel(level)
def set_level(level):
logging.getLogger().setLevel(level)
def get_logger(name='bonobo'):
return logging.getLogger(name)
# Setup formating and level.
setup(level=settings.LOGGING_LEVEL)

View File

@ -1,5 +1,7 @@
import os
import logging
def to_bool(s):
if len(s):
@ -10,13 +12,16 @@ def to_bool(s):
# Debug/verbose mode.
DEBUG = to_bool(os.environ.get('BONOBO_DEBUG', 'f'))
DEBUG = to_bool(os.environ.get('DEBUG', 'f'))
# Profile mode.
PROFILE = to_bool(os.environ.get('BONOBO_PROFILE', 'f'))
PROFILE = to_bool(os.environ.get('PROFILE', 'f'))
# Quiet mode.
QUIET = to_bool(os.environ.get('BONOBO_QUIET', 'f'))
QUIET = to_bool(os.environ.get('QUIET', 'f'))
# Logging level.
LOGGING_LEVEL = logging.DEBUG if DEBUG else logging.INFO
def check():

View File

@ -1,4 +1,5 @@
""" Iterator utilities. """
import functools
def force_iterator(mixed):
@ -20,7 +21,20 @@ def force_iterator(mixed):
def ensure_tuple(tuple_or_mixed):
if isinstance(tuple_or_mixed, tuple):
return tuple_or_mixed
return (tuple_or_mixed, )
return (tuple_or_mixed,)
def tuplize(generator):
""" Takes a generator and make it a tuple-returning function. As a side
effect, it can also decorate any iterator-returning function to force
return value to be a tuple.
"""
@functools.wraps(generator)
def tuplized(*args, **kwargs):
return tuple(generator(*args, **kwargs))
return tuplized
def iter_if_not_sequence(mixed):