From 5801ecb4408cd11f6e6ffcb1612ca68d9936a728 Mon Sep 17 00:00:00 2001 From: Kushal Das Date: Sat, 4 Jun 2016 16:21:13 -0700 Subject: [PATCH] Issue #25548: Showing memory address of class objects in repl --- Lib/ctypes/test/test_structures.py | 10 ++++---- Lib/statistics.py | 8 +++---- Lib/test/test_class.py | 10 ++++++++ Lib/test/test_cmd_line_script.py | 9 +++++++- Lib/test/test_defaultdict.py | 2 +- Lib/test/test_descr.py | 4 ++-- Lib/test/test_descrtut.py | 31 +++++++++++++------------ Lib/test/test_doctest.py | 2 +- Lib/test/test_doctest3.txt | 2 +- Lib/test/test_functools.py | 33 ++++++++++---------------- Lib/test/test_generators.py | 37 +++++++++++++++--------------- Lib/test/test_genexps.py | 5 ++-- Lib/test/test_metaclass.py | 9 ++++---- Lib/test/test_pprint.py | 9 ++++---- Lib/test/test_reprlib.py | 6 ++--- Lib/test/test_statistics.py | 2 +- Lib/test/test_wsgiref.py | 7 +++--- Lib/test/test_xmlrpc.py | 4 ++-- Misc/NEWS | 2 ++ Objects/typeobject.c | 6 ++--- 20 files changed, 106 insertions(+), 92 deletions(-) diff --git a/Lib/ctypes/test/test_structures.py b/Lib/ctypes/test/test_structures.py index e00bb046b44..736679f6302 100644 --- a/Lib/ctypes/test/test_structures.py +++ b/Lib/ctypes/test/test_structures.py @@ -320,14 +320,14 @@ class StructureTestCase(unittest.TestCase): cls, msg = self.get_except(Person, b"Someone", (1, 2)) self.assertEqual(cls, RuntimeError) - self.assertEqual(msg, - "(Phone) : " - "expected bytes, int found") + self.assertRegex(msg, + r"\(Phone\) : " + r"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) : too many initializers") + self.assertRegex(msg, + r"\(Phone\) : too many initializers") def test_huge_field_name(self): # issue12881: segfault with large structure field names diff --git a/Lib/statistics.py b/Lib/statistics.py index b081b5a0062..63adc1a44f8 100644 --- a/Lib/statistics.py +++ b/Lib/statistics.py @@ -131,23 +131,23 @@ def _sum(data, start=0): -------- >>> _sum([3, 2.25, 4.5, -0.5, 1.0], 0.75) - (, Fraction(11, 1), 5) + (, Fraction(11, 1), 5) Some sources of round-off error will be avoided: >>> _sum([1e50, 1, -1e50] * 1000) # Built-in sum returns zero. - (, Fraction(1000, 1), 3000) + (, Fraction(1000, 1), 3000) Fractions and Decimals are also supported: >>> from fractions import Fraction as F >>> _sum([F(2, 3), F(7, 5), F(1, 4), F(5, 6)]) - (, Fraction(63, 20), 4) + (, Fraction(63, 20), 4) >>> from decimal import Decimal as D >>> data = [D("0.1375"), D("0.2108"), D("0.3061"), D("0.0419")] >>> _sum(data) - (, Fraction(6963, 10000), 4) + (, Fraction(6963, 10000), 4) Mixed types are currently treated as an error, except that int is allowed. diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 4d554a397b4..e02a3cbb972 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -568,5 +568,15 @@ class ClassTests(unittest.TestCase): a = A(hash(A.f)^(-1)) hash(a.f) + def test_class_repr(self): + # We should get the address of the object + class A: + pass + + result = repr(A) + self.assertRegex(result, + ".A'" + " at 0x.+>") + if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index 01fb7dcf403..e7c6351317f 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -127,7 +127,10 @@ class CmdLineTest(unittest.TestCase): print(printed_package) print(printed_argv0) print(printed_cwd) - self.assertIn(printed_loader.encode('utf-8'), data) + expected = printed_loader.encode('utf-8') + idx = expected.find(b"at 0x") + expected = expected[:idx] + self.assertIn(expected, data) self.assertIn(printed_file.encode('utf-8'), data) self.assertIn(printed_package.encode('utf-8'), data) self.assertIn(printed_argv0.encode('utf-8'), data) @@ -158,6 +161,8 @@ class CmdLineTest(unittest.TestCase): def test_dash_c_loader(self): rc, out, err = assert_python_ok("-c", "print(__loader__)") expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8") + idx = expected.find(b"at 0x") + expected = expected[:idx] self.assertIn(expected, out) def test_stdin_loader(self): @@ -171,6 +176,8 @@ class CmdLineTest(unittest.TestCase): finally: out = kill_python(p) expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8") + idx = expected.find(b"at 0x") + expected = expected[:idx] self.assertIn(expected, out) @contextlib.contextmanager diff --git a/Lib/test/test_defaultdict.py b/Lib/test/test_defaultdict.py index a90bc2b488c..5bb4e122789 100644 --- a/Lib/test/test_defaultdict.py +++ b/Lib/test/test_defaultdict.py @@ -65,7 +65,7 @@ class TestDefaultDict(unittest.TestCase): d2 = defaultdict(int) self.assertEqual(d2.default_factory, int) d2[12] = 42 - self.assertEqual(repr(d2), "defaultdict(, {12: 42})") + self.assertRegex(repr(d2), r"defaultdict\(, {12: 42}\)") def foo(): return 43 d3 = defaultdict(foo) self.assertTrue(d3.default_factory is foo) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 0a5ecd5a0dc..954ef2d3b33 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -4544,9 +4544,9 @@ order (MRO) for bases """ pass foo = Foo() self.assertRegex(repr(foo.method), # access via instance - r">") + r">") self.assertRegex(repr(Foo.method), # access via the class - r">") + r">") class MyCallable: diff --git a/Lib/test/test_descrtut.py b/Lib/test/test_descrtut.py index 506d1abeb69..80cfa41ecb7 100644 --- a/Lib/test/test_descrtut.py +++ b/Lib/test/test_descrtut.py @@ -37,16 +37,16 @@ test_1 = """ Here's the new type at work: >>> print(defaultdict) # show our type - + >>> print(type(defaultdict)) # its metatype - + >>> a = defaultdict(default=0.0) # create an instance >>> print(a) # show the instance {} >>> print(type(a)) # show its type - + >>> print(a.__class__) # show its class - + >>> print(type(a) is a.__class__) # its type is its class True >>> a[1] = 3.25 # modify the instance @@ -149,11 +149,11 @@ Introspecting instances of built-in types For instance of built-in types, x.__class__ is now the same as type(x): >>> type([]) - + >>> [].__class__ - + >>> list - + >>> isinstance([], list) True >>> isinstance([], dict) @@ -258,19 +258,19 @@ implicit first argument that is the *class* for which they are invoked. ... print("classmethod", cls, y) >>> C.foo(1) - classmethod 1 + classmethod 1 >>> c = C() >>> c.foo(1) - classmethod 1 + classmethod 1 >>> class D(C): ... pass >>> D.foo(1) - classmethod 1 + classmethod 1 >>> d = D() >>> d.foo(1) - classmethod 1 + classmethod 1 This prints "classmethod __main__.D 1" both times; in other words, the class passed as the first argument of foo() is the class involved in the @@ -286,11 +286,11 @@ But notice this: >>> E.foo(1) E.foo() called - classmethod 1 + classmethod 1 >>> e = E() >>> e.foo(1) E.foo() called - classmethod 1 + classmethod 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 @@ -350,7 +350,7 @@ Hmm -- property is builtin now, so let's try it that way too. >>> del property # unmask the builtin >>> property - + >>> class C(object): ... def __init__(self): @@ -478,7 +478,8 @@ def test_main(verbose=None): # business is used the name can change depending on how the test is # invoked. from test import support, test_descrtut - support.run_doctest(test_descrtut, verbose) + import doctest + support.run_doctest(test_descrtut, verbose, optionflags=doctest.ELLIPSIS) # This part isn't needed for regrtest, but for running the test directly. if __name__ == "__main__": diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py index 2068fb70f82..ec12fe7372e 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py @@ -2338,7 +2338,7 @@ def test_DocFileSuite(): `__file__` global, which is set to the name of the file containing the tests: - >>> suite = doctest.DocFileSuite('test_doctest3.txt') + >>> suite = doctest.DocFileSuite('test_doctest3.txt', optionflags=doctest.ELLIPSIS) >>> suite.run(unittest.TestResult()) diff --git a/Lib/test/test_doctest3.txt b/Lib/test/test_doctest3.txt index dd8557e57a5..380ea76e4c8 100644 --- a/Lib/test/test_doctest3.txt +++ b/Lib/test/test_doctest3.txt @@ -2,4 +2,4 @@ Here we check that `__file__` is provided: >>> type(__file__) - + diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py index 9cf115d42b1..852173cc0af 100644 --- a/Lib/test/test_functools.py +++ b/Lib/test/test_functools.py @@ -1697,13 +1697,10 @@ class TestSingleDispatch(unittest.TestCase): c.Container.register(P) with self.assertRaises(RuntimeError) as re_one: g(p) - self.assertIn( - str(re_one.exception), - (("Ambiguous dispatch: " - "or "), - ("Ambiguous dispatch: " - "or ")), - ) + self.assertIn("Ambiguous dispatch:", str(re_one.exception)) + self.assertIn(" " - "or "), - ("Ambiguous dispatch: " - "or ")), - ) + self.assertIn("Ambiguous dispatch:", str(re_two.exception)) + self.assertIn(" " - "or "), - ("Ambiguous dispatch: " - "or ")), - ) + self.assertIn("Ambiguous dispatch:", str(re_three.exception)) + self.assertIn(">> type(g) - + >>> i = g() >>> type(i) - + >>> [s for s in dir(i) if not s.startswith('_')] ['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw'] >>> from test.support import HAVE_DOCSTRINGS @@ -691,7 +691,7 @@ And more, added later. >>> i.gi_running 0 >>> type(i.gi_frame) - + >>> i.gi_running = 42 Traceback (most recent call last): ... @@ -1066,27 +1066,27 @@ These are fine: >>> def f(): ... yield >>> type(f()) - + >>> def f(): ... if 0: ... yield >>> type(f()) - + >>> def f(): ... if 0: ... yield 1 >>> type(f()) - + >>> def f(): ... if "": ... yield None >>> type(f()) - + >>> def f(): ... return @@ -1110,7 +1110,7 @@ These are fine: ... x = 1 ... return >>> type(f()) - + >>> def f(): ... if 0: @@ -1118,7 +1118,7 @@ These are fine: ... yield 1 ... >>> type(f()) - + >>> def f(): ... if 0: @@ -1128,7 +1128,7 @@ These are fine: ... def f(self): ... yield 2 >>> type(f()) - + >>> def f(): ... if 0: @@ -1136,7 +1136,7 @@ These are fine: ... if 0: ... yield 2 >>> type(f()) - + This one caused a crash (see SF bug 567538): @@ -1791,7 +1791,7 @@ And a more sane, but still weird usage: >>> def f(): list(i for i in [(yield 26)]) >>> type(f()) - + A yield expression with augmented assignment. @@ -2047,25 +2047,25 @@ enclosing function a generator: >>> def f(): x += yield >>> type(f()) - + >>> def f(): x = yield >>> type(f()) - + >>> def f(): lambda x=(yield): 1 >>> type(f()) - + >>> def f(): x=(i for i in (yield) if (yield)) >>> type(f()) - + >>> def f(d): d[(yield "a")] = d[(yield "b")] = 27 >>> data = [1,2] >>> g = f(data) >>> type(g) - + >>> g.send(None) 'a' >>> data @@ -2174,8 +2174,9 @@ __test__ = {"tut": tutorial_tests, # so this works as expected in both ways of running regrtest. def test_main(verbose=None): from test import support, test_generators + import doctest support.run_unittest(__name__) - support.run_doctest(test_generators, verbose) + support.run_doctest(test_generators, verbose, optionflags=doctest.ELLIPSIS) # This part isn't needed for regrtest, but for running the test directly. if __name__ == "__main__": diff --git a/Lib/test/test_genexps.py b/Lib/test/test_genexps.py index fb531d6d472..c5e10dda8c6 100644 --- a/Lib/test/test_genexps.py +++ b/Lib/test/test_genexps.py @@ -27,7 +27,7 @@ Test first class >>> g = (i*i for i in range(4)) >>> type(g) - + >>> list(g) [0, 1, 4, 9] @@ -269,7 +269,8 @@ else: def test_main(verbose=None): from test import support from test import test_genexps - support.run_doctest(test_genexps, verbose) + import doctest + support.run_doctest(test_genexps, verbose, optionflags=doctest.ELLIPSIS) # verify reference counting if verbose and hasattr(sys, "gettotalrefcount"): diff --git a/Lib/test/test_metaclass.py b/Lib/test/test_metaclass.py index e6fe20a107c..be683dd1a14 100644 --- a/Lib/test/test_metaclass.py +++ b/Lib/test/test_metaclass.py @@ -78,7 +78,7 @@ Also pass another keyword. >>> class C(object, metaclass=M, other="haha"): ... pass ... - Prepare called: ('C', (,)) {'other': 'haha'} + Prepare called: ('C', (,)) {'other': 'haha'} New called: {'other': 'haha'} >>> C.__class__ is M True @@ -104,7 +104,7 @@ Use various combinations of explicit keywords and **kwds. >>> kwds = {'metaclass': M, 'other': 'haha'} >>> class C(*bases, **kwds): pass ... - Prepare called: ('C', (,)) {'other': 'haha'} + Prepare called: ('C', (,)) {'other': 'haha'} New called: {'other': 'haha'} >>> C.__class__ is M True @@ -114,7 +114,7 @@ Use various combinations of explicit keywords and **kwds. >>> kwds = {'other': 'haha'} >>> class C(B, metaclass=M, *bases, **kwds): pass ... - Prepare called: ('C', (, )) {'other': 'haha'} + Prepare called: ('C', (, )) {'other': 'haha'} New called: {'other': 'haha'} >>> C.__class__ is M True @@ -259,7 +259,8 @@ else: def test_main(verbose=False): from test import support from test import test_metaclass - support.run_doctest(test_metaclass, verbose) + import doctest + support.run_doctest(test_metaclass, verbose, optionflags=doctest.ELLIPSIS) if __name__ == "__main__": test_main(verbose=True) diff --git a/Lib/test/test_pprint.py b/Lib/test/test_pprint.py index 7ebc298337a..2283923cee3 100644 --- a/Lib/test/test_pprint.py +++ b/Lib/test/test_pprint.py @@ -848,12 +848,11 @@ bytearray(b'\\x00\\x01\\x02\\x03' def test_default_dict(self): d = collections.defaultdict(int) - self.assertEqual(pprint.pformat(d, width=1), "defaultdict(, {})") + self.assertRegex(pprint.pformat(d, width=1), r"defaultdict\(, {}\)") words = 'the quick brown fox jumped over a lazy dog'.split() d = collections.defaultdict(int, zip(words, itertools.count())) - self.assertEqual(pprint.pformat(d), -"""\ -defaultdict(, + self.assertRegex(pprint.pformat(d), +r"""defaultdict\(, {'a': 6, 'brown': 2, 'dog': 8, @@ -862,7 +861,7 @@ defaultdict(, 'lazy': 7, 'over': 5, 'quick': 1, - 'the': 0})""") + 'the': 0}\)""") def test_counter(self): d = collections.Counter() diff --git a/Lib/test/test_reprlib.py b/Lib/test/test_reprlib.py index 4bf91945ea4..2ecea0221e9 100644 --- a/Lib/test/test_reprlib.py +++ b/Lib/test/test_reprlib.py @@ -292,8 +292,8 @@ class foo(object): ''') importlib.invalidate_caches() from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import foo - eq(repr(foo.foo), - "" % foo.__name__) + self.assertRegex(repr(foo.foo), + r"" % foo.__name__) @unittest.skip('need a suitable object') def test_object(self): @@ -310,7 +310,7 @@ class bar: importlib.invalidate_caches() from areallylongpackageandmodulenametotestreprtruncation.areallylongpackageandmodulenametotestreprtruncation import bar # Module name may be prefixed with "test.", depending on how run. - self.assertEqual(repr(bar.bar), "" % bar.__name__) + self.assertRegex(repr(bar.bar), r"" % bar.__name__) def test_instance(self): self._check_path_limitations('baz') diff --git a/Lib/test/test_statistics.py b/Lib/test/test_statistics.py index 5275cb681d3..5dd50483f20 100644 --- a/Lib/test/test_statistics.py +++ b/Lib/test/test_statistics.py @@ -659,7 +659,7 @@ class DocTests(unittest.TestCase): @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -OO and above") def test_doc_tests(self): - failed, tried = doctest.testmod(statistics) + failed, tried = doctest.testmod(statistics, optionflags=doctest.ELLIPSIS) self.assertGreater(tried, 0) self.assertEqual(failed, 0) diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py index b7d02e868c9..3977e230b04 100644 --- a/Lib/test/test_wsgiref.py +++ b/Lib/test/test_wsgiref.py @@ -161,10 +161,10 @@ class IntegrationTests(TestCase): self.assertTrue(out.endswith( b"A server error occurred. Please contact the administrator." )) - self.assertEqual( + self.assertRegex( err.splitlines()[-2], - "AssertionError: Headers (('Content-Type', 'text/plain')) must" - " be of type list: " + r"AssertionError: Headers \(\('Content-Type', 'text/plain'\)\) must" + r" be of type list: " ) def test_status_validation_errors(self): @@ -704,3 +704,4 @@ class HandlerTests(TestCase): if __name__ == "__main__": unittest.main() + diff --git a/Lib/test/test_xmlrpc.py b/Lib/test/test_xmlrpc.py index 0773a86984a..f2fdc44cbe0 100644 --- a/Lib/test/test_xmlrpc.py +++ b/Lib/test/test_xmlrpc.py @@ -775,8 +775,8 @@ class SimpleServerTestCase(BaseServerTestCase): # 'method "this_is_not_exists" is not supported'>}] self.assertEqual(result.results[0]['faultCode'], 1) - self.assertEqual(result.results[0]['faultString'], - ':method "this_is_not_exists" ' + self.assertRegex(result.results[0]['faultString'], + ':method "this_is_not_exists" ' 'is not supported') except (xmlrpclib.ProtocolError, OSError) as e: # ignore failures due to non-blocking socket 'unavailable' errors diff --git a/Misc/NEWS b/Misc/NEWS index 9a02894676d..4b82ccd2dc7 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -73,6 +73,8 @@ Library - Issue #21271: New keyword only parameters in reset_mock call. +- Issue #25548: Showing memory address of class objects in repl. + IDLE ---- diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a64779177c0..78d5c1ee516 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -859,9 +859,9 @@ type_repr(PyTypeObject *type) } if (mod != NULL && _PyUnicode_CompareWithId(mod, &PyId_builtins)) - rtn = PyUnicode_FromFormat("", mod, name); - else - rtn = PyUnicode_FromFormat("", type->tp_name); + rtn = PyUnicode_FromFormat("", mod, name, type); + else + rtn = PyUnicode_FromFormat("", type->tp_name, type); Py_XDECREF(mod); Py_DECREF(name);