Merge branch 'develop' into dev_graphviz

This commit is contained in:
Romain Dorgueil
2017-08-11 07:38:53 +02:00
139 changed files with 6088 additions and 1669 deletions

View File

@ -1,11 +1,13 @@
import argparse
import logging
from stevedore import ExtensionManager
from bonobo import logging, settings
logger = logging.get_logger()
def entrypoint(args=None):
parser = argparse.ArgumentParser()
parser.add_argument('--debug', '-D', action='store_true')
subparsers = parser.add_subparsers(dest='command')
subparsers.required = True
@ -17,12 +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))
mgr = ExtensionManager(
namespace='bonobo.commands',
)
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.set(True)
settings.LOGGING_LEVEL.set(logging.DEBUG)
logging.set_level(settings.LOGGING_LEVEL.get())
logger.debug('Command: ' + args['command'] + ' Arguments: ' + repr(args))
commands[args.pop('command')](**args)

View File

@ -1,16 +1,20 @@
import os
def execute():
def execute(name, branch):
try:
from edgy.project.__main__ import handle_init
from cookiecutter.main import cookiecutter
except ImportError as exc:
raise ImportError(
'You must install "edgy.project" to use this command.\n\n $ pip install edgy.project\n'
'You must install "cookiecutter" to use this command.\n\n $ pip install cookiecutter\n'
) from exc
return handle_init(os.path.join(os.getcwd(), 'Projectfile'))
return cookiecutter(
'https://github.com/python-bonobo/cookiecutter-bonobo.git',
extra_context={'name': name},
no_input=True,
checkout=branch
)
def register(parser):
parser.add_argument('name')
parser.add_argument('--branch', '-b', default='master')
return execute

View File

@ -3,6 +3,9 @@ import os
import bonobo
from bonobo.constants import DEFAULT_SERVICES_ATTR, DEFAULT_SERVICES_FILENAME
DEFAULT_GRAPH_FILENAMES = ('__main__.py', 'main.py',)
DEFAULT_GRAPH_ATTR = 'get_graph'
def get_default_services(filename, services=None):
dirname = os.path.dirname(filename)
@ -14,10 +17,8 @@ def get_default_services(filename, services=None):
'__name__': '__bonobo__',
'__file__': services_filename,
}
try:
exec(code, context)
except Exception:
raise
exec(code, context)
return {
**context[DEFAULT_SERVICES_ATTR](),
**(services or {}),
@ -25,26 +26,54 @@ def get_default_services(filename, services=None):
return services or {}
def read_file(file):
with file:
code = compile(file.read(), file.name, 'exec')
def _install_requirements(requirements):
"""Install requirements given a path to requirements.txt file."""
import importlib
import pip
# TODO: A few special variables should be set before running the file:
#
# See:
# - https://docs.python.org/3/reference/import.html#import-mod-attrs
# - https://docs.python.org/3/library/runpy.html#runpy.run_module
context = {
'__name__': '__bonobo__',
'__file__': file.name,
}
pip.main(['install', '-r', requirements])
# Some shenanigans to be sure everything is importable after this, especially .egg-link files which
# are referenced in *.pth files and apparently loaded by site.py at some magic bootstrap moment of the
# python interpreter.
pip.utils.pkg_resources = importlib.reload(pip.utils.pkg_resources)
import site
importlib.reload(site)
try:
exec(code, context)
except Exception as exc:
raise
graphs = dict((k, v) for k, v in context.items() if isinstance(v, bonobo.Graph))
def execute(filename, module, install=False, quiet=False, verbose=False):
import runpy
from bonobo import Graph, settings
if quiet:
settings.QUIET.set(True)
if verbose:
settings.DEBUG.set(True)
if filename:
if os.path.isdir(filename):
if install:
requirements = os.path.join(filename, 'requirements.txt')
_install_requirements(requirements)
pathname = filename
for filename in DEFAULT_GRAPH_FILENAMES:
filename = os.path.join(pathname, filename)
if os.path.exists(filename):
break
if not os.path.exists(filename):
raise IOError('Could not find entrypoint (candidates: {}).'.format(', '.join(DEFAULT_GRAPH_FILENAMES)))
elif install:
requirements = os.path.join(os.path.dirname(filename), 'requirements.txt')
_install_requirements(requirements)
context = runpy.run_path(filename, run_name='__bonobo__')
elif module:
context = runpy.run_module(module, run_name='__bonobo__')
filename = context['__file__']
else:
raise RuntimeError('UNEXPECTED: argparse should not allow this.')
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, '
@ -54,22 +83,27 @@ def read_file(file):
graph = list(graphs.values())[0]
plugins = []
services = get_default_services(
file.name, context.get(DEFAULT_SERVICES_ATTR)() if DEFAULT_SERVICES_ATTR in context else None
filename, context.get(DEFAULT_SERVICES_ATTR)() if DEFAULT_SERVICES_ATTR in context else None
)
return graph, plugins, services
return bonobo.run(
graph,
plugins=plugins,
services=services
)
def execute(file, quiet=False):
graph, plugins, services = read_file(file)
# 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(graph, plugins=plugins, services=services)
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
def register(parser):
import argparse
parser.add_argument('file', type=argparse.FileType())
parser.add_argument('--quiet', action='store_true')
parser = register_generic_run_arguments(parser)
verbosity_group = parser.add_mutually_exclusive_group()
verbosity_group.add_argument('--quiet', '-q', action='store_true')
verbosity_group.add_argument('--verbose', '-v', action='store_true')
parser.add_argument('--install', '-I', action='store_true')
return execute

View File

@ -1,9 +1,40 @@
import bonobo
def format_version(mod, *, name=None, quiet=False):
from bonobo.util.pkgs import bonobo_packages
args = {
'name': name or mod.__name__,
'version': mod.__version__,
'location': bonobo_packages[name or mod.__name__].location
}
if not quiet:
return '{name} v.{version} (in {location})'.format(**args)
if quiet < 2:
return '{name} {version}'.format(**args)
if quiet < 3:
return '{version}'.format(**args)
raise RuntimeError('Hard to be so quiet...')
def execute():
print('{} v.{}'.format(bonobo.__name__, bonobo.__version__))
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):
if name != 'bonobo':
try:
mod = __import__(name.replace('-', '_'))
try:
print(format_version(mod, name=name, quiet=quiet))
except Exception as exc:
print('{} ({})'.format(name, exc))
except ImportError as exc:
print('{} is not importable ({}).'.format(name, exc))
def register(parser):
parser.add_argument('--all', '-a', action='store_true')
parser.add_argument('--quiet', '-q', action='count')
return execute