-
-
Notifications
You must be signed in to change notification settings - Fork 32k
bpo-37645: add new function _PyObject_FunctionStr() #14890
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
I would prefer to make it private at the beginning: replace Py with _Py. |
Done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doc/c-api/object.rst
Outdated
Return a user-friendly string representation of the function-like object | ||
*func*. This returns ``func.__qualname__ + "()"`` if there is a | ||
``__qualname__`` attribute and ``type(func).__name__ + " object"`` | ||
otherwise. Note that there is no check that *func* is actually callable. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not using the qualified name for type(func)?
Would it be possible to also add the module, except for builtin functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not using the qualified name for type(func)?
I decided to use str(func)
as fallback, which looks more useful than f"{type(func)} object"
.
Before changing this PR, could you reply on my last comment on bpo-37645? It might be a better solution to just use |
Lib/test/test_descr.py
Outdated
@@ -1967,7 +1967,7 @@ def test_methods_in_c(self): | |||
# different error messages. | |||
set_add = set.add | |||
|
|||
expected_errmsg = "descriptor 'add' of 'set' object needs an argument" | |||
expected_errmsg = "set.add() needs an argument" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I consider this a regression: the message is now too similar to calling the method on an instance, but missing an argument.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: set.add() takes exactly one argument (0 given)
>>> set.add()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: set.add() needs an argument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, this is confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can change the error message to anything you like, except that it must contain the string set.add
(the function name). So it could be
TypeError: unbound method set.add() needs an argument
or whatever (surely, this is better than anything mentioning descriptors).
Small rant: the bug is really this:
>>> set().add()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: add() takes exactly one argument (0 given)
For a Python method, it would correctly note that 2 arguments are required. This is difficult to fix in CPython since builtin_function_or_method
doesn't really know whether it's a function or method. This was one of the things that the rejected PEP 580 would have addressed.
Doc/c-api/object.rst
Outdated
.. c:function:: PyObject* _PyObject_FunctionStr(PyObject *func) | ||
|
||
Return a user-friendly string representation of the function-like object | ||
*func*. This returns ``func.__qualname__ + "()"`` if there is a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning __qualname__
without module is not particularly useful.
If you want to return a full qualified name (long but unambiguous), return __module__ + '.' + __qualname__
. __module__
can be omitted if it is 'builtins'
.
If you want to return a short name (it is enough in many times), return __name__
.
if __qualname__
is not available, you can use __name__
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if
__qualname__
is not available, you can use__name__
instead.
This is mainly meant as replacement for PyEval_GetFuncName
and all classes supported by that function implement __qualname__
. So I see little reason for the additional complexity of supporting __name__
.
Lib/test/test_descr.py
Outdated
@@ -1967,7 +1967,7 @@ def test_methods_in_c(self): | |||
# different error messages. | |||
set_add = set.add | |||
|
|||
expected_errmsg = "descriptor 'add' of 'set' object needs an argument" | |||
expected_errmsg = "set.add() needs an argument" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, this is confusing.
I tried to address all comments. |
One more nitpick above. Otherwise, this does look like an improvement in the error messages – not only in custom extension callables! |
@jdemeyer: Status check is done, and it's a success ✅ . |
Sorry, I can't merge this PR. Reason: |
@jdemeyer: Status check is done, and it's a success ✅ . |
Sorry, I can't merge this PR. Reason: |
@jdemeyer: Status check is done, and it's a success ✅ . |
Sorry, I can't merge this PR. Reason: |
@zooba What's the best way to get Azure Pipelines to run on this PR? |
Thanks for going through with this. |
Shouldn't |
Good catch, thank you! |
The conflicting change in master is to use _PyErr_Format (with explicit thread state argument) instead of PyErr_Format
@jdemeyer: Status check is done, and it's a success ✅ . |
Additional note: the `method_check_args` function in `Objects/descrobject.c` is written in such a way that it applies to all kinds of descriptors. In particular, a future re-implementation of `wrapper_descriptor` could use that code. CC @vstinner @encukou https://bugs.python.org/issue37645 Automerge-Triggered-By: @encukou
Additional note: the `method_check_args` function in `Objects/descrobject.c` is written in such a way that it applies to all kinds of descriptors. In particular, a future re-implementation of `wrapper_descriptor` could use that code. CC @vstinner @encukou https://bugs.python.org/issue37645 Automerge-Triggered-By: @encukou
Additional note: the
method_check_args
function inObjects/descrobject.c
is written in such a way that it applies to all kinds of descriptors. In particular, a future re-implementation ofwrapper_descriptor
could use that code.CC @vstinner @encukou
https://bugs.python.org/issue37645
Automerge-Triggered-By: @encukou