Lucretiel / autocommand

Autocommand turns a python function into a CLI program
GNU Lesser General Public License v3.0
53 stars 9 forks source link

AnnotationError when annotation is a function #13

Closed jaraco closed 7 years ago

jaraco commented 7 years ago

The docs say Any type (or in fact any callable) that returns an object when given a string argument can be used, though there are a few special cases that are described later. which conflicts with what the docs also say: If an invalid annotation is given (that is, it isn’t a type, str, (type, str), or (str, type), an AnnotationError is raised.

The latter seems to be true to the implementation:

$ cat test-autocommand.py
__requires__ = ['autocommand']

from autocommand import autocommand

def integer(val):
    return int(val)

@autocommand(__name__)
def print_number(n: integer):
    print(n)
$ python -m rwt -- test-autocommand.py
Loading requirements using autocommand
Traceback (most recent call last):
  File "test-autocommand.py", line 12, in <module>
    def print_number(n: integer):
  File "/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-v0i0w5tt/autocommand/autocommand.py", line 62, in autocommand_decorator
    parser=parser)
  File "/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-v0i0w5tt/autocommand/autoparse.py", line 249, in autoparse
    add_nos)
  File "/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-v0i0w5tt/autocommand/autoparse.py", line 189, in make_parser
    for flags, spec in _make_arguments(param, used_char_args, add_nos):
  File "/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-v0i0w5tt/autocommand/autoparse.py", line 87, in _make_arguments
    arg_type, description = _get_type_description(param.annotation)
  File "/var/folders/c6/v7hnmq453xb6p2dbz1gqc6rr0000gn/T/rwt-v0i0w5tt/autocommand/autoparse.py", line 65, in _get_type_description
    raise AnnotationError(annotation)
autocommand.autoparse.AnnotationError: <function integer at 0x101256f28>

I'd much prefer if any callable could be accepted. In particular, I'd like to do this:

def json_from_filename(filename):
    return json.load(open(filename))

# or

json_from_filename = compose(json.load, open)

@autocommand(__name__)
def cmd(doc: json_from_filename):
    do_something_with(doc)

Is there a reason the annotation can't be any callable?

Lucretiel commented 7 years ago

You are correct! That function is supposed to accept any callable as a type, since that's what argparse accepts, but the annotation checker is too strict. I'll post a fix shortly.

jaraco commented 7 years ago

Fast work and already working in my code too. Thanks much!