python / cpython

The Python programming language
https://www.python.org
Other
63.33k stars 30.31k forks source link

signature.bind error messages are sub-optimal #68393

Closed bitdancer closed 9 years ago

bitdancer commented 9 years ago
BPO 24205
Nosy @bitdancer, @ethanfurman, @vadmium, @1st1
Files
  • sig_exc.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields: ```python assignee = 'https://github.com/1st1' closed_at = created_at = labels = ['type-bug', 'library'] title = 'signature.bind error messages are sub-optimal' updated_at = user = 'https://github.com/bitdancer' ``` bugs.python.org fields: ```python activity = actor = 'yselivanov' assignee = 'yselivanov' closed = True closed_date = closer = 'yselivanov' components = ['Library (Lib)'] creation = creator = 'r.david.murray' dependencies = [] files = ['39422'] hgrepos = [] issue_num = 24205 keywords = ['patch'] message_count = 4.0 messages = ['243287', '243519', '243548', '243554'] nosy_count = 5.0 nosy_names = ['r.david.murray', 'ethan.furman', 'python-dev', 'martin.panter', 'yselivanov'] pr_nums = [] priority = 'normal' resolution = 'fixed' stage = 'resolved' status = 'closed' superseder = None type = 'behavior' url = 'https://bugs.python.org/issue24205' versions = ['Python 3.5'] ```

    bitdancer commented 9 years ago

    I have an application where I'm calling a handler function with passed in arguments. I want to generate an error if the handler is called with the wrong arguments. I can't just catch TypeError since a TypeError could easily result from some programming error in the handler, rather than an error in the calling args. So, doing this seems obvious:

        sig = signature(handler)
        try:
            bound = sig.bind(message, payload, *args, **kw)
        except TypeError as exc:
            print("Invalid handler call: {}".format(str(exc))
        handler(*bound.args, **bound.kwargs)

    Now, suppose I have a function like:

        def foo(message, payload, anarg, akeyword='bar'):
            pass

    If I call it directly with an invalid keyword argument I get:

        >>> foo(1, 2, 3, badword=7)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        TypeError: foo() got an unexpected keyword argument 'badword'

    However, bind gives me:

        >>> sig.bind(1, 2, 3, badword=7)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
          File "/home/rdmurray/python/p35/Lib/inspect.py", line 2818, in bind
            return args[0]._bind(args[1:], kwargs)
          File "/home/rdmurray/python/p35/Lib/inspect.py", line 2809, in _bind
            raise TypeError('too many keyword arguments')
        TypeError: too many keyword arguments

    Similarly, for a missing argument I get:

        >>> foo(1, 2)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        TypeError: foo() missing 1 required positional argument: 'anarg'

    While bind gives:

        >>> sig.bind(1, 2)
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
          File "/home/rdmurray/python/p35/Lib/inspect.py", line 2818, in bind
            return args[0]._bind(args[1:], kwargs)
          File "/home/rdmurray/python/p35/Lib/inspect.py", line 2737, in _bind
            raise TypeError(msg) from None
        TypeError: 'anarg' parameter lacking default value

    So, using this to replace catching the TypeError from incorrectly calling a function does not work. Nor are the messages in fact accurate. Is there any chance we could make bind's error handling work like regular function binding? That's certainly what I expected would happen!

    1st1 commented 9 years ago

    Hi David, Please see the attached patch. It doesn't make Signature.bind() exceptions look exactly like system messages, but it's now much closer.

    vadmium commented 9 years ago

    I think the patch is okay. Just beware that next(iter(kwargs)) can return different names if there is more than one unexpected argument, so the error message could vary. But it looks like the test cases are only when there is exactly one extra argument, so no problem.

    1762cc99-3127-4a62-9baf-30c3d0f51ef7 commented 9 years ago

    New changeset 3cc368d334c5 by Yury Selivanov in branch 'default': bpo-24205: Improve inspect.Signature.bind() error messages. https://hg.python.org/cpython/rev/3cc368d334c5