Commit 4b532b60 authored by ∞'s avatar 💻

Simplification: remove Command class

From now on, Callable itself is considered as a potential Command.

Also, Importable.factory might return a Callable instead of just an
Importable, in the case the argument turns out to be a callable.

This greatly improves introspection overall.
parent 1c177a95
Pipeline #1822 passed with stages
in 36 seconds
......@@ -4,7 +4,7 @@ from .colors import * # noqa
from .exceptions import Cli2Exception, Cli2ArgsException
from .parser import Parser
from .introspection import docfile, Callable, Importable, DocDescriptor
from .command import command, Command, option, Option
from .command import command, option, Option
from .console_script import ConsoleScript, Group
from .test import autotest
from .cli import debug, docmod, help, run
import collections
from .introspection import Callable
from .colors import YELLOW
class Command(Callable):
def __init__(self, name, target, color=None, options=None, doc=None):
super().__init__(name, target)
self.color = color or YELLOW
self.options = options or collections.OrderedDict()
def command(**config):
def wrap(cb):
if 'cli2' not in cb.__dict__:
cb.cli2 = Command(cb.__name__, cb, **config)
cb.cli2 = Callable(cb.__name__, cb, **config)
return cb
......@@ -7,9 +7,8 @@ import types
from .colors import RESET
from .parser import Parser
from .command import Command
from .exceptions import Cli2ArgsException, Cli2Exception
from .introspection import Importable
from .introspection import Callable, Importable
class GroupDocDescriptor:
......@@ -56,7 +55,7 @@ class Group(collections.OrderedDict):
def add_help(self):
from .cli import help
self['help'] = Command('help', help)
return self
def add_module(self, module_name):
......@@ -66,17 +65,13 @@ class Group(collections.OrderedDict):
raise Cli2Exception('Module not found' + importable.module)
for cb in importable.get_callables():
self[] = getattr(, 'cli2', Command(,
self[] = Callable.for_callback(
return self
def add_commands(self, *callbacks):
for cb in callbacks:
self[cb.__name__] = getattr(
cb, 'cli2',
Command(cb.__name__, cb)
self[cb.__name__] = Callable.for_callback(cb)
return self
import collections
import inspect
import importlib
import types
import os
from .colors import GREEN, RED, RESET
from .colors import GREEN, RED, RESET, YELLOW
from .exceptions import Cli2Exception, Cli2ArgsException
......@@ -123,6 +124,12 @@ class Importable:
ret = ret[int(part)]
ret = getattr(ret, part, None)
if getattr(ret, 'cli2', None):
return ret.cli2
if module != ret:
cls = Callable
ret = None
......@@ -155,6 +162,17 @@ class Importable:
class Callable(Importable):
doc = DocDescriptor()
def __init__(self, name, target, module=None, color=None, options=None,
super().__init__(name, target, module=module)
self.color = color or YELLOW
self.options = options or collections.OrderedDict()
def for_callback(cls, cb):
return getattr(cb, 'cli2', cls(cb.__name__, cb))
def __call__(self, *args, **kwargs):
if len(args) < len(self.required_args):
raise Cli2ArgsException(self, args)
from .command import Command
class Parser:
......@@ -17,6 +16,7 @@ class Parser:
self.options = {}
def parse(self):
from .introspection import Callable
from .console_script import Group
for arg in self.argv_all:
......@@ -25,7 +25,7 @@ class Parser:
if isinstance(item, Group): = item
elif isinstance(item, Command):
elif isinstance(item, Callable):
self.command = item
import cli2
from .command import command, option
......@@ -35,9 +33,3 @@ def test_chain():
assert foo.cli2.color == 'test'
# should not have removed any option
assert foo.cli2.options['foo'].color == 'foocolor'
def test_command_color_default():
def foo():
assert cli2.Command('foo', foo).color == cli2.YELLOW
......@@ -12,3 +12,9 @@ def test_importable_get_callables():
result = [*importable.get_callables()]
assert cli2.Callable('run', in result
assert cli2.Callable('help', in result
def test_command_color_default():
def foo():
assert cli2.Callable('foo', foo).color == cli2.YELLOW
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment