Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions Lib/ctypes/test/test_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,14 +324,11 @@ class Person(Structure):

cls, msg = self.get_except(Person, b"Someone", (1, 2))
self.assertEqual(cls, RuntimeError)
self.assertEqual(msg,
"(Phone) <class 'TypeError'>: "
"expected bytes, int found")
self.assertEqual(msg, "(Phone) TypeError: expected bytes, int found")

cls, msg = self.get_except(Person, b"Someone", (b"a", b"b", b"c"))
self.assertEqual(cls, RuntimeError)
self.assertEqual(msg,
"(Phone) <class 'TypeError'>: too many initializers")
self.assertEqual(msg, "(Phone) TypeError: too many initializers")

def test_huge_field_name(self):
# issue12881: segfault with large structure field names
Expand Down
2 changes: 1 addition & 1 deletion Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,7 @@ def _find_impl(cls, registry):
if (t in registry and t not in cls.__mro__
and match not in cls.__mro__
and not issubclass(match, t)):
raise RuntimeError("Ambiguous dispatch: {} or {}".format(
raise RuntimeError("Ambiguous dispatch: {!r} or {!r}".format(
match, t))
break
if t in registry:
Expand Down
2 changes: 1 addition & 1 deletion Lib/idlelib/idle_test/test_autoexpand.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class AutoExpandTest(unittest.TestCase):

@classmethod
def setUpClass(cls):
if 'tkinter' in str(Text):
if 'tkinter' in repr(Text):
requires('gui')
cls.tk = Tk()
cls.text = Text(cls.tk)
Expand Down
2 changes: 1 addition & 1 deletion Lib/optparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ def _check_choice(self):
elif not isinstance(self.choices, (tuple, list)):
raise OptionError(
"choices must be a list of strings ('%s' supplied)"
% str(type(self.choices)).split("'")[1], self)
% type(self.choices), self)
elif self.choices is not None:
raise OptionError(
"must not supply choices for type %r" % self.type, self)
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_cmd_line_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def _check_import_error(self, script_name, expected_msg,
self.assertIn(expected_msg.encode('utf-8'), err)

def test_dash_c_loader(self):
rc, out, err = assert_python_ok("-c", "print(__loader__)")
rc, out, err = assert_python_ok("-c", "print(repr(__loader__))")
expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8")
self.assertIn(expected, out)

Expand All @@ -167,7 +167,7 @@ def test_stdin_loader(self):
# stdin is an interactive tty.
p = spawn_python()
try:
p.stdin.write(b"print(__loader__)\n")
p.stdin.write(b"print(repr(__loader__))\n")
p.stdin.flush()
finally:
out = kill_python(p)
Expand Down
24 changes: 12 additions & 12 deletions Lib/test/test_descrtut.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,18 @@ def merge(self, other):

Here's the new type at work:

>>> print(defaultdict) # show our type
>>> defaultdict # show our type
<class 'test.test_descrtut.defaultdict'>
>>> print(type(defaultdict)) # its metatype
>>> type(defaultdict) # its metatype
<class 'type'>
>>> a = defaultdict(default=0.0) # create an instance
>>> print(a) # show the instance
{}
>>> print(type(a)) # show its type
>>> type(a) # show its type
<class 'test.test_descrtut.defaultdict'>
>>> print(a.__class__) # show its class
>>> a.__class__ # show its class
<class 'test.test_descrtut.defaultdict'>
>>> print(type(a) is a.__class__) # its type is its class
>>> type(a) is a.__class__ # its type is its class
True
>>> a[1] = 3.25 # modify the instance
>>> print(a) # show the new value
Expand Down Expand Up @@ -259,21 +259,21 @@ def merge(self, other):
... print("classmethod", cls, y)

>>> C.foo(1)
classmethod <class 'test.test_descrtut.C'> 1
classmethod C 1

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We want classmethod test.test_descrtut.C 1

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Turns out we don't: qualname is defined to not include the module name, so C is good here.

Alternative: change the code of the foo method to print repr(cls) instead of cls.

>>> c = C()
>>> c.foo(1)
classmethod <class 'test.test_descrtut.C'> 1
classmethod C 1

>>> class D(C):
... pass

>>> D.foo(1)
classmethod <class 'test.test_descrtut.D'> 1
classmethod D 1
>>> d = D()
>>> d.foo(1)
classmethod <class 'test.test_descrtut.D'> 1
classmethod D 1

This prints "classmethod __main__.D 1" both times; in other words, the
This prints "classmethod D 1" both times; in other words, the
class passed as the first argument of foo() is the class involved in the
call, not the class involved in the definition of foo().

Expand All @@ -287,11 +287,11 @@ class passed as the first argument of foo() is the class involved in the

>>> E.foo(1)
E.foo() called
classmethod <class 'test.test_descrtut.C'> 1
classmethod C 1
>>> e = E()
>>> e.foo(1)
E.foo() called
classmethod <class 'test.test_descrtut.C'> 1
classmethod C 1

In this example, the call to C.foo() from E.foo() will see class C as its
first argument, not class E. This is to be expected, since the call
Expand Down
4 changes: 2 additions & 2 deletions Lib/test/test_pdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -928,11 +928,11 @@ def test_pdb_issue_20766():
> <doctest test.test_pdb.test_pdb_issue_20766[0]>(6)test_function()
-> print('pdb %d: %s' % (i, sess._previous_sigint_handler))
(Pdb) continue
pdb 1: <built-in function default_int_handler>
pdb 1: default_int_handler
> <doctest test.test_pdb.test_pdb_issue_20766[0]>(5)test_function()
-> sess.set_trace(sys._getframe())
(Pdb) continue
pdb 2: <built-in function default_int_handler>
pdb 2: default_int_handler
"""

class PdbTestCase(unittest.TestCase):
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ def child():
sleep(1)
# As a non-daemon thread we SHOULD wake up and nothing
# should be torn down yet
print("Woke up, sleep function is:", sleep)
print("Woke up, sleep function is: %r" % sleep)

threading.Thread(target=child).start()
raise SystemExit
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,8 +660,7 @@ class C(Generic[T]):
self.assertNotEqual(Z, Y[int])
self.assertNotEqual(Z, Y[T])

self.assertTrue(str(Z).endswith(
'.C[typing.Tuple[str, int]]'))
self.assertTrue(repr(Z).endswith('.C[typing.Tuple[str, int]]'))

def test_new_repr(self):
T = TypeVar('T')
Expand Down
7 changes: 3 additions & 4 deletions Lib/test/test_xmlrpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -910,13 +910,12 @@ def test_non_existing_multicall(self):
result = multicall()

# result.results contains;
# [{'faultCode': 1, 'faultString': '<class \'exceptions.Exception\'>:'
# 'method "this_is_not_exists" is not supported'>}]
# [{'faultCode': 1, 'faultString': 'exceptions.Exception:'
# 'method "this_is_not_exists" is not supported'}]

self.assertEqual(result.results[0]['faultCode'], 1)
self.assertEqual(result.results[0]['faultString'],
'<class \'Exception\'>:method "this_is_not_exists" '
'is not supported')
'Exception:method "this_is_not_exists" is not supported')
except (xmlrpclib.ProtocolError, OSError) as e:
# ignore failures due to non-blocking socket 'unavailable' errors
if not is_unavailable_exception(e):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Change str(x) to return only the qualname for classes, functions and modules
6 changes: 6 additions & 0 deletions Objects/funcobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,12 @@ func_repr(PyFunctionObject *op)
op->func_qualname, op);
}

static PyObject*
func_str(PyFunctionObject *op)
{
return PyUnicode_FromFormat("%U", op->func_qualname);
}

static int
func_traverse(PyFunctionObject *f, visitproc visit, void *arg)
{
Expand Down
15 changes: 13 additions & 2 deletions Objects/methodobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ meth_repr(PyCFunctionObject *m)
m->m_self);
}

static PyObject *
meth_str(PyCFunctionObject *m)
{
if (m->m_self == NULL || PyModule_Check(m->m_self))
return PyUnicode_FromFormat("%s", m->m_ml->ml_name);
return PyUnicode_FromFormat("<built-in method %s of %s object at %p>",
m->m_ml->ml_name,
m->m_self->ob_type->tp_name,
m->m_self);
}

static PyObject *
meth_richcompare(PyObject *self, PyObject *other, int op)
{
Expand Down Expand Up @@ -284,11 +295,11 @@ PyTypeObject PyCFunction_Type = {
0, /* tp_as_mapping */
(hashfunc)meth_hash, /* tp_hash */
PyCFunction_Call, /* tp_call */
0, /* tp_str */
(reprfunc)meth_str, /* tp_str */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just use meth_repr.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The point of the change is to have a __str__ that’s different than __repr__ :) But see the ticket, I think I will scale back this PR to classes only.

@merwok merwok Sep 19, 2017 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Oh well, it is Guido who wanted a unified behaviour for modules, classes and functions (since they are things created by syntax (import*, class and def) with a __name__ attribute).

* I think a module’s __name__ depends on its loader, not on the name used in the import statement (import as doesn’t change __name__)

PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0, /* tp_doc */
(traverseproc)meth_traverse, /* tp_traverse */
0, /* tp_clear */
Expand Down
21 changes: 21 additions & 0 deletions Objects/moduleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,27 @@ module_getattro(PyModuleObject *m, PyObject *name)
return NULL;
}

static PyObject *
module_str(PyModuleObject *m)
{
PyObject *name, *str;

name = PyModule_GetNameObject((PyObject *)m);
if (name == NULL) {
/* XXX PyUnicode_FromStringAndSize is documented as part of
the legacy API */

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Address this

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Really? I never heart that PyUnicode_FromStringAndSize is a legacy API. This is the main way of creating strings in C. Could you point the place in the documentation where it declared legacy?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks for the comment. I don’t have the original Mercurial clone on this laptop, so I can’t look for my original commit. This code is removed in my latest changes (not pushed yet).

PyErr_Clear();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Don't silence all errors. Only AttributeError.

name = PyUnicode_FromStringAndSize("?", 1);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Wouldn't be better to fall back to repr()?

if (name == NULL) /* */
return NULL;
}

str = PyUnicode_FromFormat("%U", name);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is the purpose of this line?


Py_DECREF(name);
return str;
}

static int
module_traverse(PyModuleObject *m, visitproc visit, void *arg)
{
Expand Down
17 changes: 16 additions & 1 deletion Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,21 @@ type_repr(PyTypeObject *type)
return rtn;
}

static PyObject *
type_str(PyTypeObject *type)
{
PyObject *name, *rtn;

name = type_qualname(type, NULL);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Wouldn't be better to include a module name for getting rid of ambiguity?

I would just return PyUnicode_FromString(type->tp_name).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The original discussion on the ticket mentioned only the type qualname, without its module. Looking at Lib/typing.py and other files (for example the error message in functools), I think maybe including the module name too would be useful. Let’s see comments after I get a smaller patch that passes the test suite.

if (name == NULL)
return NULL;

rtn = PyUnicode_FromFormat("%U", name);

Py_DECREF(name);
return rtn;
}

static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
Expand Down Expand Up @@ -3458,7 +3473,7 @@ PyTypeObject PyType_Type = {
0, /* tp_as_mapping */
0, /* tp_hash */
(ternaryfunc)type_call, /* tp_call */
0, /* tp_str */
(reprfunc)type_str, /* tp_str */
(getattrofunc)type_getattro, /* tp_getattro */
(setattrofunc)type_setattro, /* tp_setattro */
0, /* tp_as_buffer */
Expand Down