From 819efc4810f2b6c9e2e34d01ac004ac69f0cb14b 2018-01-02 13:05:07 From: Min RK Date: 2018-01-02 13:05:07 Subject: [PATCH] Merge pull request #10959 from takluyver/i10950 Defining __repr__ should override pretty printer for parent class --- diff --git a/IPython/core/tests/test_formatters.py b/IPython/core/tests/test_formatters.py index 35edc75..cde43c9 100644 --- a/IPython/core/tests/test_formatters.py +++ b/IPython/core/tests/test_formatters.py @@ -49,7 +49,7 @@ def test_pretty(): f = PlainTextFormatter() f.for_type(A, foo_printer) nt.assert_equal(f(A()), 'foo') - nt.assert_equal(f(B()), 'foo') + nt.assert_equal(f(B()), 'B()') nt.assert_equal(f(GoodPretty()), 'foo') # Just don't raise an exception for the following: f(BadPretty()) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index 5f2520c..6345d6d 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -395,6 +395,10 @@ class RepresentationPrinter(PrettyPrinter): meth = cls._repr_pretty_ if callable(meth): return meth(obj, self, cycle) + if cls is not object \ + and callable(cls.__dict__.get('__repr__')): + return _repr_pprint(obj, self, cycle) + return _default_pprint(obj, self, cycle) finally: self.end_group() @@ -540,17 +544,12 @@ def _default_pprint(obj, p, cycle): p.end_group(1, '>') -def _seq_pprinter_factory(start, end, basetype): +def _seq_pprinter_factory(start, end): """ Factory that returns a pprint function useful for sequences. Used by the default pprint for tuples, dicts, and lists. """ def inner(obj, p, cycle): - typ = type(obj) - if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__: - # If the subclass provides its own repr, use it instead. - return p.text(typ.__repr__(obj)) - if cycle: return p.text(start + '...' + end) step = len(start) @@ -567,21 +566,16 @@ def _seq_pprinter_factory(start, end, basetype): return inner -def _set_pprinter_factory(start, end, basetype): +def _set_pprinter_factory(start, end): """ Factory that returns a pprint function useful for sets and frozensets. """ def inner(obj, p, cycle): - typ = type(obj) - if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__: - # If the subclass provides its own repr, use it instead. - return p.text(typ.__repr__(obj)) - if cycle: return p.text(start + '...' + end) if len(obj) == 0: # Special case. - p.text(basetype.__name__ + '()') + p.text(type(obj).__name__ + '()') else: step = len(start) p.begin_group(step, start) @@ -599,17 +593,12 @@ def _set_pprinter_factory(start, end, basetype): return inner -def _dict_pprinter_factory(start, end, basetype=None): +def _dict_pprinter_factory(start, end): """ Factory that returns a pprint function used by the default pprint of dicts and dict proxies. """ def inner(obj, p, cycle): - typ = type(obj) - if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__: - # If the subclass provides its own repr, use it instead. - return p.text(typ.__repr__(obj)) - if cycle: return p.text('{...}') step = len(start) @@ -750,12 +739,12 @@ _type_pprinters = { int: _repr_pprint, float: _repr_pprint, str: _repr_pprint, - tuple: _seq_pprinter_factory('(', ')', tuple), - list: _seq_pprinter_factory('[', ']', list), - dict: _dict_pprinter_factory('{', '}', dict), + tuple: _seq_pprinter_factory('(', ')'), + list: _seq_pprinter_factory('[', ']'), + dict: _dict_pprinter_factory('{', '}'), - set: _set_pprinter_factory('{', '}', set), - frozenset: _set_pprinter_factory('frozenset({', '})', frozenset), + set: _set_pprinter_factory('{', '}'), + frozenset: _set_pprinter_factory('frozenset({', '})'), super: _super_pprint, _re_pattern_type: _re_pattern_pprint, type: _type_pprint, diff --git a/IPython/lib/tests/test_pretty.py b/IPython/lib/tests/test_pretty.py index 6d65743..68e90ec 100644 --- a/IPython/lib/tests/test_pretty.py +++ b/IPython/lib/tests/test_pretty.py @@ -420,4 +420,24 @@ def test_function_pretty(): return "Don't panic" nt.assert_in('meaning_of_life(question=None)', pretty.pretty(meaning_of_life)) - + + +class OrderedCounter(Counter, OrderedDict): + 'Counter that remembers the order elements are first encountered' + + def __repr__(self): + return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) + + def __reduce__(self): + return self.__class__, (OrderedDict(self),) + +class MySet(set): # Override repr of a basic type + def __repr__(self): + return 'mine' + +def test_custom_repr(): + """A custom repr should override a pretty printer for a parent type""" + oc = OrderedCounter("abracadabra") + nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc)) + + nt.assert_equal(pretty.pretty(MySet()), 'mine')