<div dir="ltr">FWIW, I personally think this went to python-dev prematurely. This is a shallow problem and IMO doesn't need all that much handwringing. Yes, there are a few different alternatives. So list them all concisely in the tracker and think about it for a few minutes and then pick one. No matter what's picked it'll be better than the status quo -- which is that printing a class name produces either a full or a short name depending on whether it's defined in C or Python, and there's no simple pattern (in C) to print either the full or the short name.<br></div><br><div class="gmail_quote"><div dir="ltr">On Tue, Sep 11, 2018 at 4:09 PM MRAB <<a href="mailto:python@mrabarnett.plus.com">python@mrabarnett.plus.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 2018-09-11 23:23, Victor Stinner wrote:<br>
> Hi,<br>
> <br>
> Last week, I opened an issue to propose to add a new %T formatter to<br>
> PyUnicode_FromFormatV() and so indirectly to PyUnicode_FromFormat()<br>
> and PyErr_Format():<br>
> <br>
>     <a href="https://bugs.python.org/issue34595" rel="noreferrer" target="_blank">https://bugs.python.org/issue34595</a><br>
> <br>
> I merged my change, but then Serhiy Storchaka asked if we can add<br>
> something to get the "fully qualified name" (FQN) of a type, ex<br>
> "datetime.timedelta" (FQN) vs "timedelta" (what I call "short" name).<br>
> I proposed a second pull request to add %t (short) in addition to %T<br>
> (FQN).<br>
> <br>
> But then Petr Viktorin asked me to open a thread on python-dev to get<br>
> a wider discussion. So here I am.<br>
> <br>
> <br>
> The rationale for this change is to fix multiple issues:<br>
> <br>
> * C extensions use Py_TYPE(obj)->tp_name which returns a fully<br>
> qualified name for C types, but the name (without the module) for<br>
> Python name. Python modules use type(obj).__name__ which always return<br>
> the short name.<br>
> <br>
> * currently, many C extensions truncate the type name: use "%.80s"<br>
> instead of "%s" to format a type name<br>
> <br>
> * "%s" with Py_TYPE(obj)->tp_name is used more than 200 times in the C<br>
> code, and I dislike this complex pattern. IMHO "%t" with obj would be<br>
> simpler to read, write and maintain.<br>
> <br>
> * I want C extensions and Python modules to have the same behavior:<br>
> respect the PEP 399. Petr considers that error messages are not part<br>
> of the PEP 399, but the issue is wider than only error messages.<br>
> <br>
> <br>
> The main issue is that at the C level, Py_TYPE(obj)->tp_name is<br>
> "usually" the fully qualified name for types defined in C, but it's<br>
> only the "short" name for types defined in Python.<br>
> <br>
> For example, if you get the C accelerator "_datetime",<br>
> PyTYPE(obj)->tp_name of a datetime.timedelta object gives you<br>
> "datetime.timedelta", but if you don't have the accelerator, tp_name<br>
> is just "timedelta".<br>
> <br>
> Another example, this script displays "mytimedelta(0)" if you have the<br>
> C accelerator, but "__main__.mytimedelta(0)" if you use the Python<br>
> implementation:<br>
> ---<br>
> import sys<br>
> #sys.modules['_datetime'] = None<br>
> import datetime<br>
> <br>
> class mytimedelta(datetime.timedelta):<br>
>      pass<br>
> <br>
> print(repr(mytimedelta()))<br>
> ---<br>
> <br>
> So I would like to fix this kind of issue.<br>
> <br>
> <br>
> Type names are mainly used for two purposes:<br>
> <br>
> * format an error message<br>
> * obj.__repr__()<br>
> <br>
> It's unclear to me if we should use the "short" or the "fully<br>
> qualified" name. It should maybe be decided on a case by case basis.<br>
> <br>
> There is also a 3rd usage: to implement __reduce__, here backward<br>
> compatibility matters.<br>
> <br>
> <br>
> Note: The discussion evolved since my first implementation of %T which<br>
> just used the not well defined Py_TYPE(obj)->tp_name.<br>
> <br>
> --<br>
> <br>
> Petr asked me why not exposing functions to get these names. For<br>
> example, with my second PR (not merged), there are 3 (private)<br>
> functions:<br>
> <br>
> /* type.__name__ */<br>
> const char* _PyType_Name(PyTypeObject *type);<br>
> /* type.__qualname__ */<br>
> PyObject* _PyType_QualName(PyTypeObject *type);<br>
> * type.__module__ "." type.__qualname__ (but type.__qualname__ for<br>
> builtin types) */<br>
> PyObject * _PyType_FullName(PyTypeObject *type);<br>
> <br>
> My concern here is that each caller has to handler error:<br>
> <br>
>    PyErr_Format(PyExc_TypeError, "must be str, not %.100s",<br>
> Py_TYPE(obj)->tp_name);<br>
> <br>
> would become:<br>
> <br>
>    PyObject *type_name = _PyType_FullName(Py_TYPE(obj));<br>
>    if (name == NULL) { /* do something with this error ... */<br>
>    PyErr_Format(PyExc_TypeError, "must be str, not %U", type_name);<br>
>    Py_DECREF(name);<br>
> <br>
> When I report an error, I dislike having to handle *new* errors... I<br>
> prefer that the error handling is done inside PyErr_Format() for me,<br>
> to reduce the risk of additional bugs.<br>
> <br>
> --<br>
> <br>
> Serhiy also asked if we could expose the same feature at the *Python*<br>
> level: provide something to get the fully qualified name of a type.<br>
> It's not just f"{type(obj).__module}.{type(obj).__name__}", but you<br>
> have to skip the module for builtin types like "str" (not return<br>
> "builtins.str").<br>
> <br>
> Maybe we can have "name: {0:t}, FQN: {0:T}".format(type(obj)). "t" for<br>
> name and "T" for fully qualfied name. We would only have to modify<br>
> type.__format__().<br>
> <br>
> I'm not sure if we need to add new formatters to str % args.<br>
> <br>
> Example of Python code:<br>
> <br>
>     raise TypeError("must be str, not %s" % type(fmt).__name__)<br>
> <br>
> I'm not sure about Python changes. My first concern was just to avoid<br>
> Py_TYPE(obj)->tp_name at the C level. But again, we should keep C and<br>
> Python consistent. If the behavior of C extensions change, Python<br>
> modules should be adapted as well, to get the same behavior.<br>
> <br>
> <br>
> Note: I reverted my change which added the %T formatter from<br>
> PyUnicode_FromFormatV() to clarify the status of this issue.<br>
> <br>
I'm not sure about having 2 different, though similar, format codes for <br>
2 similar, though slightly different, cases. (And, for all we know, we <br>
might want to use "%t" at some later date for something else.)<br>
<br>
Perhaps we could have a single format code plus an optional '#' for the <br>
"alternate form":<br>
<br>
%T for short form<br>
%#T for fully qualified name<br>
_______________________________________________<br>
Python-Dev mailing list<br>
<a href="mailto:Python-Dev@python.org" target="_blank">Python-Dev@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-dev" rel="noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-dev</a><br>
Unsubscribe: <a href="https://mail.python.org/mailman/options/python-dev/guido%40python.org" rel="noreferrer" target="_blank">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
</blockquote></div><br clear="all"><br>-- <br><div dir="ltr" class="gmail_signature" data-smartmail="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>