[cli] adds python logging facility configuration.
This commit is contained in:
@ -1,12 +1,13 @@
|
|||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import logging
|
from bonobo import logging, settings
|
||||||
from stevedore import ExtensionManager
|
|
||||||
|
logger = logging.get_logger()
|
||||||
|
|
||||||
|
|
||||||
def entrypoint(args=None):
|
def entrypoint(args=None):
|
||||||
logging.basicConfig()
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--debug', '-D', action='store_true')
|
||||||
|
|
||||||
subparsers = parser.add_subparsers(dest='command')
|
subparsers = parser.add_subparsers(dest='command')
|
||||||
subparsers.required = True
|
subparsers.required = True
|
||||||
@ -18,10 +19,17 @@ def entrypoint(args=None):
|
|||||||
parser = subparsers.add_parser(ext.name)
|
parser = subparsers.add_parser(ext.name)
|
||||||
commands[ext.name] = ext.plugin(parser)
|
commands[ext.name] = ext.plugin(parser)
|
||||||
except Exception:
|
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 = ExtensionManager(namespace='bonobo.commands')
|
||||||
mgr.map(register_extension)
|
mgr.map(register_extension)
|
||||||
|
|
||||||
args = parser.parse_args(args).__dict__
|
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)
|
commands[args.pop('command')](**args)
|
||||||
|
|||||||
@ -1,6 +1,3 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
def execute(name):
|
def execute(name):
|
||||||
try:
|
try:
|
||||||
from cookiecutter.main import cookiecutter
|
from cookiecutter.main import cookiecutter
|
||||||
|
|||||||
@ -1,10 +1,4 @@
|
|||||||
import importlib
|
|
||||||
import os
|
import os
|
||||||
import runpy
|
|
||||||
|
|
||||||
import pip
|
|
||||||
|
|
||||||
import bonobo
|
|
||||||
|
|
||||||
DEFAULT_SERVICES_FILENAME = '_services.py'
|
DEFAULT_SERVICES_FILENAME = '_services.py'
|
||||||
DEFAULT_SERVICES_ATTR = 'get_services'
|
DEFAULT_SERVICES_ATTR = 'get_services'
|
||||||
@ -12,7 +6,6 @@ DEFAULT_SERVICES_ATTR = 'get_services'
|
|||||||
DEFAULT_GRAPH_FILENAME = '__main__.py'
|
DEFAULT_GRAPH_FILENAME = '__main__.py'
|
||||||
DEFAULT_GRAPH_ATTR = 'get_graph'
|
DEFAULT_GRAPH_ATTR = 'get_graph'
|
||||||
|
|
||||||
|
|
||||||
def get_default_services(filename, services=None):
|
def get_default_services(filename, services=None):
|
||||||
dirname = os.path.dirname(filename)
|
dirname = os.path.dirname(filename)
|
||||||
services_filename = os.path.join(dirname, DEFAULT_SERVICES_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):
|
def execute(filename, module, install=False, quiet=False, verbose=False):
|
||||||
from bonobo import settings
|
import runpy
|
||||||
|
from bonobo import Graph, run, settings
|
||||||
|
|
||||||
if quiet:
|
if quiet:
|
||||||
settings.QUIET = True
|
settings.QUIET = True
|
||||||
@ -44,6 +38,8 @@ def execute(filename, module, install=False, quiet=False, verbose=False):
|
|||||||
if filename:
|
if filename:
|
||||||
if os.path.isdir(filename):
|
if os.path.isdir(filename):
|
||||||
if install:
|
if install:
|
||||||
|
import importlib
|
||||||
|
import pip
|
||||||
requirements = os.path.join(filename, 'requirements.txt')
|
requirements = os.path.join(filename, 'requirements.txt')
|
||||||
pip.main(['install', '-r', requirements])
|
pip.main(['install', '-r', requirements])
|
||||||
# Some shenanigans to be sure everything is importable after this, especially .egg-link files which
|
# 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:
|
else:
|
||||||
raise RuntimeError('UNEXPECTED: argparse should not allow this.')
|
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, (
|
assert len(graphs) == 1, (
|
||||||
'Having zero or more than one graph definition in one file is unsupported for now, '
|
'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 if console and not quiet, then add the console plugin
|
||||||
# todo when better console plugin, add it if console and just disable display
|
# todo when better console plugin, add it if console and just disable display
|
||||||
return bonobo.run(
|
return run(
|
||||||
graph,
|
graph,
|
||||||
plugins=[],
|
plugins=[],
|
||||||
services=get_default_services(
|
services=get_default_services(
|
||||||
@ -82,8 +78,8 @@ def execute(filename, module, install=False, quiet=False, verbose=False):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def register_generic_run_arguments(parser):
|
def register_generic_run_arguments(parser, required=True):
|
||||||
source_group = parser.add_mutually_exclusive_group(required=True)
|
source_group = parser.add_mutually_exclusive_group(required=required)
|
||||||
source_group.add_argument('filename', nargs='?', type=str)
|
source_group.add_argument('filename', nargs='?', type=str)
|
||||||
source_group.add_argument('--module', '-m', type=str)
|
source_group.add_argument('--module', '-m', type=str)
|
||||||
return parser
|
return parser
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
import bonobo
|
|
||||||
from bonobo.util.pkgs import bonobo_packages
|
|
||||||
|
|
||||||
|
|
||||||
def format_version(mod, *, name=None, quiet=False):
|
def format_version(mod, *, name=None, quiet=False):
|
||||||
|
from bonobo.util.pkgs import bonobo_packages
|
||||||
args = {
|
args = {
|
||||||
'name': name or mod.__name__,
|
'name': name or mod.__name__,
|
||||||
'version': mod.__version__,
|
'version': mod.__version__,
|
||||||
@ -20,6 +17,9 @@ def format_version(mod, *, name=None, quiet=False):
|
|||||||
|
|
||||||
|
|
||||||
def execute(all=False, quiet=False):
|
def execute(all=False, quiet=False):
|
||||||
|
import bonobo
|
||||||
|
from bonobo.util.pkgs import bonobo_packages
|
||||||
|
|
||||||
print(format_version(bonobo, quiet=quiet))
|
print(format_version(bonobo, quiet=quiet))
|
||||||
if all:
|
if all:
|
||||||
for name in sorted(bonobo_packages):
|
for name in sorted(bonobo_packages):
|
||||||
|
|||||||
75
bonobo/logging.py
Normal file
75
bonobo/logging.py
Normal 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)
|
||||||
@ -1,5 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
def to_bool(s):
|
def to_bool(s):
|
||||||
if len(s):
|
if len(s):
|
||||||
@ -10,13 +12,16 @@ def to_bool(s):
|
|||||||
|
|
||||||
|
|
||||||
# Debug/verbose mode.
|
# Debug/verbose mode.
|
||||||
DEBUG = to_bool(os.environ.get('BONOBO_DEBUG', 'f'))
|
DEBUG = to_bool(os.environ.get('DEBUG', 'f'))
|
||||||
|
|
||||||
# Profile mode.
|
# Profile mode.
|
||||||
PROFILE = to_bool(os.environ.get('BONOBO_PROFILE', 'f'))
|
PROFILE = to_bool(os.environ.get('PROFILE', 'f'))
|
||||||
|
|
||||||
# Quiet mode.
|
# 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():
|
def check():
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
""" Iterator utilities. """
|
""" Iterator utilities. """
|
||||||
|
import functools
|
||||||
|
|
||||||
|
|
||||||
def force_iterator(mixed):
|
def force_iterator(mixed):
|
||||||
@ -20,7 +21,20 @@ def force_iterator(mixed):
|
|||||||
def ensure_tuple(tuple_or_mixed):
|
def ensure_tuple(tuple_or_mixed):
|
||||||
if isinstance(tuple_or_mixed, tuple):
|
if isinstance(tuple_or_mixed, tuple):
|
||||||
return tuple_or_mixed
|
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):
|
def iter_if_not_sequence(mixed):
|
||||||
|
|||||||
Reference in New Issue
Block a user