[cli] Adds a --filter option to "convert" command, allowing to use arbitrary filters to a command line conversion. Also adds --print and "-" output to pretty print to terminal instead of file output.

This commit is contained in:
Romain Dorgueil
2017-10-13 17:21:25 +02:00
parent b1d7498054
commit 64875a05bd
2 changed files with 68 additions and 14 deletions

View File

@ -3,6 +3,9 @@ import os
import bonobo import bonobo
from bonobo.commands.util.arguments import parse_variable_argument from bonobo.commands.util.arguments import parse_variable_argument
from bonobo.util import require
from bonobo.util.iterators import tuplize
from bonobo.util.python import WorkingDirectoryModulesRegistry
SHORTCUTS = { SHORTCUTS = {
'csv': 'text/csv', 'csv': 'text/csv',
@ -62,14 +65,42 @@ def resolve_factory(name, filename, factory_type, options=None):
raise ValueError('Invalid factory type.') raise ValueError('Invalid factory type.')
def execute(input, output, reader=None, reader_options=None, writer=None, writer_options=None, options=None): @tuplize
reader_factory, reader_options = resolve_factory(reader, input, READER, (options or []) + (reader_options or [])) def resolve_filters(filters):
writer_factory, writer_options = resolve_factory(writer, output, WRITER, (options or []) + (writer_options or [])) registry = WorkingDirectoryModulesRegistry()
for f in filters:
try:
mod, attr = f.split(':', 1)
yield getattr(registry.require(mod), attr)
except ValueError:
yield getattr(bonobo, f)
def execute(
input,
output,
reader=None,
reader_option=None,
writer=None,
writer_option=None,
option=None,
filter=None,
do_print=False
):
reader_factory, reader_option = resolve_factory(reader, input, READER, (option or []) + (reader_option or []))
if output == '-':
writer_factory, writer_option = bonobo.PrettyPrinter, {}
else:
writer_factory, writer_option = resolve_factory(writer, output, WRITER, (option or []) + (writer_option or []))
filters = resolve_filters(filter)
graph = bonobo.Graph() graph = bonobo.Graph()
graph.add_chain( graph.add_chain(
reader_factory(input, **reader_options), reader_factory(input, **reader_option),
writer_factory(output, **writer_options), *filters,
writer_factory(output, **writer_option),
) )
return bonobo.run( return bonobo.run(
@ -92,25 +123,39 @@ def register(parser):
'-w', '-w',
help='Choose the writer factory if it cannot be detected from extension, or if detection is wrong.' help='Choose the writer factory if it cannot be detected from extension, or if detection is wrong.'
) )
parser.add_argument(
'--filter',
'-f',
dest='filter',
action='append',
help='Add a filter between input and output',
)
parser.add_argument(
'--print',
'-p',
dest='do_print',
action='store_true',
help='Replace the output by a pretty printer.',
)
parser.add_argument( parser.add_argument(
'--option', '--option',
'-O', '-O',
dest='options', dest='option',
action='append', action='append',
help='Add a named option to both reader and writer factories (i.e. foo="bar").' help='Add a named option to both reader and writer factories (i.e. foo="bar").',
) )
parser.add_argument( parser.add_argument(
'--' + READER + '-option', '--' + READER + '-option',
'-' + READER[0].upper(), '-' + READER[0].upper(),
dest=READER + '_options', dest=READER + '_option',
action='append', action='append',
help='Add a named option to the reader factory.' help='Add a named option to the reader factory.',
) )
parser.add_argument( parser.add_argument(
'--' + WRITER + '-option', '--' + WRITER + '-option',
'-' + WRITER[0].upper(), '-' + WRITER[0].upper(),
dest=WRITER + '_options', dest=WRITER + '_option',
action='append', action='append',
help='Add a named option to the writer factory.' help='Add a named option to the writer factory.',
) )
return execute return execute

View File

@ -9,14 +9,23 @@ class _RequiredModule:
class _RequiredModulesRegistry(dict): class _RequiredModulesRegistry(dict):
@property
def pathname(self):
return os.path.join(os.getcwd(), os.path.dirname(inspect.getfile(inspect.stack()[1][0])))
def require(self, name): def require(self, name):
if name not in self: if name not in self:
bits = name.split('.') bits = name.split('.')
pathname = os.path.join(os.getcwd(), os.path.dirname(inspect.getfile(inspect.stack()[1][0]))) filename = os.path.join(self.pathname, *bits[:-1], bits[-1] + '.py')
filename = os.path.join(pathname, *bits[:-1], bits[-1] + '.py')
self[name] = _RequiredModule(runpy.run_path(filename, run_name=name)) self[name] = _RequiredModule(runpy.run_path(filename, run_name=name))
return self[name] return self[name]
class WorkingDirectoryModulesRegistry(_RequiredModulesRegistry):
@property
def pathname(self):
return os.getcwd()
registry = _RequiredModulesRegistry() registry = _RequiredModulesRegistry()
require = registry.require require = registry.require