feat: new alternate syntax and switch to black + isort (yeah, maybe not the best time, but that is done).
This commit is contained in:
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()})
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -3,6 +3,7 @@ import bonobo
|
||||
|
||||
def get_graph(**options):
|
||||
graph = bonobo.Graph()
|
||||
graph.get_cursor() >> ...
|
||||
return graph
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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...")
|
||||
|
||||
Reference in New Issue
Block a user