feat: new alternate syntax and switch to black + isort (yeah, maybe not the best time, but that is done).

This commit is contained in:
Romain Dorgueil
2018-07-29 18:21:56 +01:00
parent 3094e43f9f
commit 89dda0dca6
123 changed files with 1672 additions and 1640 deletions

View File

@ -19,9 +19,9 @@ def entrypoint(args=None):
logger.setLevel(settings.LOGGING_LEVEL.get())
parser = argparse.ArgumentParser()
parser.add_argument('--debug', '-D', action='store_true')
parser.add_argument("--debug", "-D", action="store_true")
subparsers = parser.add_subparsers(dest='command')
subparsers = parser.add_subparsers(dest="command")
subparsers.required = True
commands = {}
@ -39,23 +39,24 @@ def entrypoint(args=None):
# old school, function based.
commands[ext.name] = ext.plugin(parser)
except Exception:
logger.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)
parsed_args = parser.parse_args(args).__dict__
if parsed_args.pop('debug', False):
if parsed_args.pop("debug", False):
settings.DEBUG.set(True)
settings.LOGGING_LEVEL.set(logging.DEBUG)
logger.setLevel(settings.LOGGING_LEVEL.get())
logger.debug('Command: ' + parsed_args['command'] + ' Arguments: ' + repr(parsed_args))
logger.debug("Command: " + parsed_args["command"] + " Arguments: " + repr(parsed_args))
# Get command handler, execute, rince.
command = commands[parsed_args.pop('command')]
command = commands[parsed_args.pop("command")]
command(**parsed_args)
return 0

View File

@ -33,7 +33,7 @@ class BaseCommand:
"""
The actual logic of the command. Subclasses must implement this method.
"""
raise NotImplementedError('Subclasses of BaseCommand must provide a handle() method')
raise NotImplementedError("Subclasses of BaseCommand must provide a handle() method")
class BaseGraphCommand(BaseCommand):
@ -48,8 +48,8 @@ class BaseGraphCommand(BaseCommand):
def add_arguments(self, parser):
# target arguments (cannot provide both).
source_group = parser.add_mutually_exclusive_group(required=self.required)
source_group.add_argument('file', nargs='?', type=str)
source_group.add_argument('-m', dest='mod', type=str)
source_group.add_argument("file", nargs="?", type=str)
source_group.add_argument("-m", dest="mod", type=str)
# add arguments to enforce system environment.
parser = get_argument_parser(parser)
@ -66,7 +66,7 @@ class BaseGraphCommand(BaseCommand):
def do_handle(self, graph, **options):
if not self.handler:
raise RuntimeError('{} has no handler defined.'.format(get_name(self)))
raise RuntimeError("{} has no handler defined.".format(get_name(self)))
return self.handler(graph, **options)
@contextmanager
@ -87,20 +87,20 @@ class BaseGraphCommand(BaseCommand):
sys.argv = [mod]
self._run_module(mod)
else:
raise RuntimeError('No target provided.')
raise RuntimeError("No target provided.")
finally:
sys.argv = _argv
if _graph is None:
raise RuntimeError('Could not find graph.')
raise RuntimeError("Could not find graph.")
yield _graph, _graph_execution_options, options
def _run_path(self, file):
return runpy.run_path(file, run_name='__main__')
return runpy.run_path(file, run_name="__main__")
def _run_module(self, mod):
return runpy.run_module(mod, run_name='__main__')
return runpy.run_module(mod, run_name="__main__")
@contextmanager

View File

@ -6,82 +6,75 @@ from bonobo.util.resolvers import _resolve_options, _resolve_transformations
class ConvertCommand(BaseCommand):
def add_arguments(self, parser):
parser.add_argument('input_filename', help='Input filename.')
parser.add_argument('output_filename', help='Output filename.')
parser.add_argument("input_filename", help="Input filename.")
parser.add_argument("output_filename", help="Output filename.")
parser.add_argument(
'--' + READER,
'-r',
help='Choose the reader factory if it cannot be detected from extension, or if detection is wrong.'
"--" + READER,
"-r",
help="Choose the reader factory if it cannot be detected from extension, or if detection is wrong.",
)
parser.add_argument(
'--' + WRITER,
'-w',
help=
'Choose the writer factory if it cannot be detected from extension, or if detection is wrong (use - for console pretty print).'
"--" + WRITER,
"-w",
help="Choose the writer factory if it cannot be detected from extension, or if detection is wrong (use - for console pretty print).",
)
parser.add_argument("--limit", "-l", type=int, help="Adds a Limit() after the reader instance.", default=None)
parser.add_argument(
"--transformation",
"-t",
dest="transformation",
action="append",
help="Add a transformation between input and output (can be used multiple times, order is preserved).",
)
parser.add_argument(
'--limit',
'-l',
type=int,
help='Adds a Limit() after the reader instance.',
default=None,
)
parser.add_argument(
'--transformation',
'-t',
dest='transformation',
action='append',
help='Add a transformation between input and output (can be used multiple times, order is preserved).',
)
parser.add_argument(
'--option',
'-O',
dest='option',
action='append',
"--option",
"-O",
dest="option",
action="append",
help='Add a named option to both reader and writer factories (i.e. foo="bar").',
)
parser.add_argument(
'--' + READER + '-option',
'-' + READER[0].upper(),
dest=READER + '_option',
action='append',
help='Add a named option to the reader factory.',
"--" + READER + "-option",
"-" + READER[0].upper(),
dest=READER + "_option",
action="append",
help="Add a named option to the reader factory.",
)
parser.add_argument(
'--' + WRITER + '-option',
'-' + WRITER[0].upper(),
dest=WRITER + '_option',
action='append',
help='Add a named option to the writer factory.',
"--" + WRITER + "-option",
"-" + WRITER[0].upper(),
dest=WRITER + "_option",
action="append",
help="Add a named option to the writer factory.",
)
def handle(
self,
input_filename,
output_filename,
reader=None,
reader_option=None,
writer=None,
writer_option=None,
option=None,
limit=None,
transformation=None,
self,
input_filename,
output_filename,
reader=None,
reader_option=None,
writer=None,
writer_option=None,
option=None,
limit=None,
transformation=None,
):
reader_factory = default_registry.get_reader_factory_for(input_filename, format=reader)
reader_kwargs = _resolve_options((option or []) + (reader_option or []))
if output_filename == '-':
if output_filename == "-":
writer_factory = bonobo.PrettyPrinter
writer_args = ()
else:
writer_factory = default_registry.get_writer_factory_for(output_filename, format=writer)
writer_args = (output_filename, )
writer_args = (output_filename,)
writer_kwargs = _resolve_options((option or []) + (writer_option or []))
transformations = ()
if limit:
transformations += (bonobo.Limit(limit), )
transformations += (bonobo.Limit(limit),)
transformations += _resolve_transformations(transformation)
@ -92,8 +85,4 @@ class ConvertCommand(BaseCommand):
writer_factory(*writer_args, **writer_kwargs),
)
return bonobo.run(
graph, services={
'fs': bonobo.open_fs(),
}
)
return bonobo.run(graph, services={"fs": bonobo.open_fs()})

View File

@ -6,28 +6,28 @@ import requests
import bonobo
from bonobo.commands import BaseCommand
EXAMPLES_BASE_URL = 'https://raw.githubusercontent.com/python-bonobo/bonobo/master/bonobo/examples/'
EXAMPLES_BASE_URL = "https://raw.githubusercontent.com/python-bonobo/bonobo/master/bonobo/examples/"
"""The URL to our git repository, in raw mode."""
class DownloadCommand(BaseCommand):
def handle(self, *, path, **options):
if not path.startswith('examples'):
raise ValueError('Download command currently supports examples only')
examples_path = re.sub('^examples/', '', path)
if not path.startswith("examples"):
raise ValueError("Download command currently supports examples only")
examples_path = re.sub("^examples/", "", path)
output_path = bonobo.get_examples_path(examples_path)
with _open_url(EXAMPLES_BASE_URL + examples_path) as response, open(output_path, 'wb') as fout:
with _open_url(EXAMPLES_BASE_URL + examples_path) as response, open(output_path, "wb") as fout:
for chunk in response.iter_content(io.DEFAULT_BUFFER_SIZE):
fout.write(chunk)
self.logger.info('Download saved to {}'.format(output_path))
self.logger.info("Download saved to {}".format(output_path))
def add_arguments(self, parser):
parser.add_argument('path', help='The relative path of the thing to download.')
parser.add_argument("path", help="The relative path of the thing to download.")
def _open_url(url):
"""Open a HTTP connection to the URL and return a file-like object."""
response = requests.get(url, stream=True)
if response.status_code != 200:
raise IOError('Unable to download {}, HTTP {}'.format(url, response.status_code))
raise IOError("Unable to download {}, HTTP {}".format(url, response.status_code))
return response

View File

@ -1,23 +1,23 @@
from bonobo.commands import BaseCommand
all_examples = (
'clock',
'datasets',
'environ',
'files.csv_handlers',
'files.json_handlers',
'files.pickle_handlers',
'files.text_handlers',
'types',
"clock",
"datasets",
"environ",
"files.csv_handlers",
"files.json_handlers",
"files.pickle_handlers",
"files.text_handlers",
"types",
)
class ExamplesCommand(BaseCommand):
def handle(self):
print('You can run the following examples:')
print("You can run the following examples:")
print()
for example in all_examples:
print(' $ python -m bonobo.examples.{}'.format(example))
print(" $ python -m bonobo.examples.{}".format(example))
print()
def add_arguments(self, parser):

View File

@ -6,67 +6,67 @@ from bonobo.commands import BaseCommand
class InitCommand(BaseCommand):
TEMPLATES = {'bare', 'default'}
TEMPLATES_PATH = os.path.join(os.path.dirname(__file__), 'templates')
TEMPLATES = {"bare", "default"}
TEMPLATES_PATH = os.path.join(os.path.dirname(__file__), "templates")
def add_arguments(self, parser):
parser.add_argument('filename')
parser.add_argument('--force', '-f', default=False, action='store_true')
parser.add_argument("filename")
parser.add_argument("--force", "-f", default=False, action="store_true")
target_group = parser.add_mutually_exclusive_group(required=False)
target_group.add_argument('--template', '-t', choices=self.TEMPLATES, default='default')
target_group.add_argument('--package', '-p', action='store_true', default=False)
target_group.add_argument("--template", "-t", choices=self.TEMPLATES, default="default")
target_group.add_argument("--package", "-p", action="store_true", default=False)
def create_file_from_template(self, *, template, filename):
template_name = template
name, ext = os.path.splitext(filename)
if ext != '.py':
if ext != ".py":
raise ValueError('Filenames should end with ".py".')
loader = FileSystemLoader(self.TEMPLATES_PATH)
env = Environment(loader=loader)
template = env.get_template(template_name + '.py-tpl')
template = env.get_template(template_name + ".py-tpl")
with open(filename, 'w+') as f:
with open(filename, "w+") as f:
f.write(template.render(name=name))
self.logger.info('Generated {} using template {!r}.'.format(filename, template_name))
self.logger.info("Generated {} using template {!r}.".format(filename, template_name))
def create_package(self, *, filename):
name, ext = os.path.splitext(filename)
if ext != '':
raise ValueError('Package names should not have an extension.')
if ext != "":
raise ValueError("Package names should not have an extension.")
try:
import medikit.commands
except ImportError as exc:
raise ImportError(
'To initialize a package, you need to install medikit (pip install --upgrade medikit).'
"To initialize a package, you need to install medikit (pip install --upgrade medikit)."
) from exc
package_name = os.path.basename(filename)
medikit.commands.handle_init(
os.path.join(os.getcwd(), filename, 'Projectfile'), name=package_name, requirements=['bonobo']
os.path.join(os.getcwd(), filename, "Projectfile"), name=package_name, requirements=["bonobo"]
)
self.logger.info('Generated "{}" package with medikit.'.format(package_name))
self.create_file_from_template(template='default', filename=os.path.join(filename, package_name, '__main__.py'))
self.create_file_from_template(template="default", filename=os.path.join(filename, package_name, "__main__.py"))
print('Your "{}" package has been created.'.format(package_name))
print()
print('Install it...')
print("Install it...")
print()
print(' pip install --editable {}'.format(filename))
print(" pip install --editable {}".format(filename))
print()
print('Then maybe run the example...')
print("Then maybe run the example...")
print()
print(' python -m {}'.format(package_name))
print(" python -m {}".format(package_name))
print()
print('Enjoy!')
print("Enjoy!")
def handle(self, *, template, filename, package=False, force=False):
if os.path.exists(filename) and not force:
raise FileExistsError('Target filename already exists, use --force to override.')
raise FileExistsError("Target filename already exists, use --force to override.")
if package:
self.create_package(filename=filename)

View File

@ -7,9 +7,9 @@ class InspectCommand(BaseGraphCommand):
def add_arguments(self, parser):
super(InspectCommand, self).add_arguments(parser)
parser.add_argument('--graph', '-g', dest='format', action='store_const', const='graph')
parser.add_argument("--graph", "-g", dest="format", action="store_const", const="graph")
def parse_options(self, **options):
if not options.get('format'):
raise RuntimeError('You must provide a format (try --graph).')
if not options.get("format"):
raise RuntimeError("You must provide a format (try --graph).")
return options

View File

@ -12,13 +12,14 @@ class RunCommand(BaseGraphCommand):
super(RunCommand, self).add_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')
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')
parser.add_argument("--install", "-I", action="store_true")
def parse_options(self, *, quiet=False, verbose=False, install=False, **options):
from bonobo import settings
settings.QUIET.set_if_true(quiet)
settings.DEBUG.set_if_true(verbose)
self.install = install
@ -28,9 +29,9 @@ class RunCommand(BaseGraphCommand):
# add install logic
if self.install:
if os.path.isdir(file):
requirements = os.path.join(file, 'requirements.txt')
requirements = os.path.join(file, "requirements.txt")
else:
requirements = os.path.join(os.path.dirname(file), 'requirements.txt')
requirements = os.path.join(os.path.dirname(file), "requirements.txt")
_install_requirements(requirements)
return super()._run_path(file)
@ -38,7 +39,7 @@ class RunCommand(BaseGraphCommand):
def _run_module(self, mod):
# install not implemented for a module, not sure it even make sense.
if self.install:
raise RuntimeError('--install behaviour when running a module is not defined.')
raise RuntimeError("--install behaviour when running a module is not defined.")
return super()._run_module(mod)
@ -59,10 +60,11 @@ def _install_requirements(requirements):
import importlib
import pip
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
# 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)

View File

@ -3,6 +3,7 @@ import bonobo
def get_graph(**options):
graph = bonobo.Graph()
graph.get_cursor() >> ...
return graph

View File

@ -27,7 +27,7 @@ def get_graph(**options):
"""
graph = bonobo.Graph()
graph.add_chain(extract, transform, load)
graph.get_cursor() >> extract >> transform >> load
return graph

View File

@ -9,15 +9,15 @@ def get_versions(*, all=False, quiet=None):
if all:
for name in sorted(bonobo_packages):
if name != 'bonobo':
if name != "bonobo":
try:
mod = __import__(name.replace('-', '_'))
mod = __import__(name.replace("-", "_"))
try:
yield _format_version(mod, name=name, quiet=quiet)
except Exception as exc:
yield '{} ({})'.format(name, exc)
yield "{} ({})".format(name, exc)
except ImportError as exc:
yield '{} is not importable ({}).'.format(name, exc)
yield "{} is not importable ({}).".format(name, exc)
class VersionCommand(BaseCommand):
@ -26,23 +26,24 @@ class VersionCommand(BaseCommand):
print(line)
def add_arguments(self, parser):
parser.add_argument('--all', '-a', action='store_true')
parser.add_argument('--quiet', '-q', action='count')
parser.add_argument("--all", "-a", action="store_true")
parser.add_argument("--quiet", "-q", action="count")
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
"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)
return "{name} v.{version} (in {location})".format(**args)
if quiet < 2:
return '{name} {version}'.format(**args)
return "{name} {version}".format(**args)
if quiet < 3:
return '{version}'.format(**args)
return "{version}".format(**args)
raise RuntimeError('Hard to be so quiet...')
raise RuntimeError("Hard to be so quiet...")