This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Include type annotations in error messages for better errors
Type: enhancement Stage: resolved
Components: Interpreter Core Versions: Python 3.8
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: levkivskyi, rhettinger, terry.reedy, xtreak
Priority: normal Keywords:

Created on 2018-07-28 07:48 by xtreak, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (4)
msg322527 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2018-07-28 07:48
Python 3 supports type annotations in functions but when there is a TypeError due to calling a function then only the arguments are given in the error message. If the function has type annotations then adding them to the error message will give better experience and context. This doesn't break any existing code without type annotations but improves errors for code that has type annotations giving a better error reporting experience.

Currently format_missing method one of the methods used to raise TypeError that returns the name of the required positional arguments. The function receives the code object and type annotations are present in the function object. Hence I have used the code_object->co_name to get the function object from globals. After getting the function object I go through the annotations if present to form an error message to be attached with the existing error message.

I have implemented it in my branch : https://github.com/tirkarthi/cpython/tree/error-message-annotations


# foo_signature.py

from typing import List, Dict, NoReturn

def get_profile_a(user_id: int, likes: Dict[str, int]) -> Dict[str, int]:
    return {'user_id': user_id, 'likes': len(likes.keys())}

if __name__ == "__main__":
    get_profile_a()

# Error message for functions without type hints patch

cpython git:(master) ✗ ./python foo_signature.py
Traceback (most recent call last):
  File "foo_signature.py", line 11, in <module>
    get_profile_a()
TypeError: get_profile_a() missing 2 required positional arguments: 'user_id' and 'likes'

# Error message for functions with type hints patch in my branch

cpython git:(error-message-annotations) ✗ ./python foo_signature.py
Traceback (most recent call last):
  File "foo_signature.py", line 11, in <module>
    get_profile_a()
TypeError: get_profile_a() missing 2 required positional arguments: 'user_id' and 'likes'
Annotation: (user_id: <class 'int'>, likes: typing.Dict[str, int], return: typing.Dict[str, int])


The proposed patch adds the annotations in the end thus giving more context to the user. 

Pros :

* Better error reporting and more context that helps beginners like Elm/Rust that have improved error messages.
* This will also motivate developers to write type annotations since error messages become more useful.

Cons : 

* Since code_object is present in the call site where TypeError is raised I need to do a lookup of the globals to get the function object. This can be fixed in the way get_type_hints works on a function object. This also blocks me from writing tests where the function is defined inside a class that inherits from unittest.TestCase.
* After getting the annotations I need to form a string with the relevant parameters. Since most of them are hash lookups I don't think there is a cost involved here. Most of the time TypeError is raised to the user. My C skills are also low and I hope code can be improved much better here.

I am good with the core team rejecting this patch but just wanted to put forward the idea. I have also created a thread in python-ideas mailing list to gather feedback about this and hope it gains some traction. I received good feedback from Ethan Smith, mypy core developer on Reddit : https://www.reddit.com/r/Python/comments/92eh1g/type_annotations_in_error_messages_for_better/e3655z1/

python-ideas thread : https://mail.python.org/pipermail/python-ideas/2018-July/052463.html

I am adding Raymond and Terry since the previous PRs I have raised regarding error messages were reviewed by them. Also from the past discussions they make decisions on whether the change and it's effect is worth enough to be added to the core given the implementation complexity. Feel free to un-assign yourself if this is irrelevant.


Thanks
msg322566 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2018-07-28 15:09
I have added support for functions defined inside a function and methods of a class along with some basic tests. Since directly taking co_name from code object returns only the name without any context like Foo.square inside square when I try to access co_name. So I have passed the function object available at the calls as an additional parameter. Since the API is not public or documented I think it's okay to add an argument in those places. Thus by directly having the function object I am able to get the annotations directly instead of making a lookup in the globals.

This approach makes places where TypeError is raised to pass function object like too much of positional arguments and keyword arguments type of errors etc. The code to form the error string can be refactored out as a helper function thus the logic takes a function object and returns the error message. I think this would require more changes in places to pass function object than my original approach to cover more areas thus adding some complexity.

Thanks
msg323176 - (view) Author: Ivan Levkivskyi (levkivskyi) * (Python committer) Date: 2018-08-05 22:31
FWIW I am rather -1 on this. More detailed errors messages are always good, but in the proposed form it looks more like a distraction. I think just showing a fully qualified name of the function would be both more concise and more informative, since the user would likely need to look at the function code/docstring anyway in order to write a correct call.
msg323177 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2018-08-06 05:11
Thanks for the feedback on this. Brett also gave feedback on the python-ideas mailing list as below : 

> Two things to quickly mention: one is that type hints have no run-time semantics, so adding them to such a critical exception would be escalating their meaning a bit. The other point is this TypeError has nothing to do with the cause of the exception, so I would say that it's slightly distracting from the cause of the issue.

I am closing this.

Thanks
History
Date User Action Args
2022-04-11 14:59:03adminsetgithub: 78435
2018-08-06 05:11:21xtreaksetstatus: open -> closed
resolution: rejected
messages: + msg323177

stage: resolved
2018-08-05 22:31:57levkivskyisetnosy: + levkivskyi
messages: + msg323176
2018-07-28 15:09:47xtreaksetmessages: + msg322566
2018-07-28 07:48:32xtreakcreate