Skip to content

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

Merged
merged 9 commits into from
Nov 5, 2019

Conversation

jdemeyer
Copy link
Contributor

@jdemeyer jdemeyer commented Jul 21, 2019

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

@vstinner
Copy link
Member

I would prefer to make it private at the beginning: replace Py with _Py.

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Aug 4, 2019

I would prefer to make it private at the beginning: replace Py with _Py.

Done.

@jdemeyer jdemeyer changed the title bpo-37645: add new function PyObject_FunctionStr() bpo-37645: add new function _PyObject_FunctionStr() Aug 4, 2019
Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Member

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?

Copy link
Contributor Author

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".

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Aug 13, 2019

Before changing this PR, could you reply on my last comment on bpo-37645? It might be a better solution to just use str(func) in the error message and then changing some __str__ implementations.

@@ -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"
Copy link
Member

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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, this is confusing.

Copy link
Contributor Author

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.

.. 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
Copy link
Member

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.

Copy link
Contributor Author

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__.

@@ -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"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, this is confusing.

@jdemeyer
Copy link
Contributor Author

I tried to address all comments.

@encukou
Copy link
Member

encukou commented Oct 8, 2019

One more nitpick above. Otherwise, this does look like an improvement in the error messages – not only in custom extension callables!

@miss-islington
Copy link
Contributor

@jdemeyer: Status check is done, and it's a success ✅ .

@miss-islington
Copy link
Contributor

Sorry, I can't merge this PR. Reason: Required status check "Azure Pipelines PR" is expected..

@miss-islington
Copy link
Contributor

@jdemeyer: Status check is done, and it's a success ✅ .

@miss-islington
Copy link
Contributor

Sorry, I can't merge this PR. Reason: Required status check "Azure Pipelines PR" is expected..

@miss-islington
Copy link
Contributor

@jdemeyer: Status check is done, and it's a success ✅ .

@miss-islington
Copy link
Contributor

Sorry, I can't merge this PR. Reason: Required status check "Azure Pipelines PR" is expected..

@encukou
Copy link
Member

encukou commented Oct 22, 2019

@zooba What's the best way to get Azure Pipelines to run on this PR?
I asked the same at #16497 (comment) and things got moving when I did. Was that you pushing a button somewhere?

@jdemeyer
Copy link
Contributor Author

Thanks for going through with this.

@rlamy
Copy link
Contributor

rlamy commented Oct 31, 2019

Shouldn't format_kwargs_error be changed as well, to stay consistent with check_args_iterable?

@encukou
Copy link
Member

encukou commented Nov 5, 2019

Good catch, thank you!

The conflicting change in master is to use _PyErr_Format
(with explicit thread state argument) instead of PyErr_Format
@miss-islington
Copy link
Contributor

@jdemeyer: Status check is done, and it's a success ✅ .

@miss-islington miss-islington merged commit bf17d41 into python:master Nov 5, 2019
jacobneiltaylor pushed a commit to jacobneiltaylor/cpython that referenced this pull request Dec 5, 2019
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
shihai1991 pushed a commit to shihai1991/cpython that referenced this pull request Jan 31, 2020
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants