Repository: ipython/ipython

Issue:
pretty print broken for types created with PyType_FromSpec
The pretty print system breaks for types created using [PyType_FromSpec](http://docs.python.org/dev/c-api/type.html#PyType_FromSpec), as the `__module__` attribute is not accessible.  For a demo, use the `xxlimited` module which should probably be installed in your Python 3 distribution.

Transcript follows:

```
$ ipy3
Python 3.2.3 (default, Oct 19 2012, 20:10:41) 
Type "copyright", "credits" or "license" for more information.

IPython 0.14.dev -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import xxlimited

In [2]: type(xxlimited.Null)
Out[2]: builtins.type

In [3]: xxlimited.Null
Out[3]: ---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-de3f08f6c91b> in <module>()
----> 1 xxlimited.Null

/home/bfroehle/src/ipython/IPython/core/displayhook.py in __call__(self, result)
    240             self.start_displayhook()
    241             self.write_output_prompt()
--> 242             format_dict = self.compute_format_data(result)
    243             self.write_format_data(format_dict)
    244             self.update_user_ns(result)

/home/bfroehle/src/ipython/IPython/core/displayhook.py in compute_format_data(self, result)
    152             MIME type representation of the object.
    153         """
--> 154         return self.shell.display_formatter.format(result)
    155 
    156     def write_format_data(self, format_dict):

/home/bfroehle/src/ipython/IPython/core/formatters.py in format(self, obj, include, exclude)
    128                     continue
    129             try:
--> 130                 data = formatter(obj)
    131             except:
    132                 # FIXME: log the exception

/home/bfroehle/src/ipython/IPython/core/formatters.py in __call__(self, obj)
    448                 singleton_pprinters=self.singleton_printers,
    449                 type_pprinters=self.type_printers,
--> 450                 deferred_pprinters=self.deferred_printers)
    451             printer.pretty(obj)
    452             printer.flush()

/home/bfroehle/src/ipython/IPython/lib/pretty.py in pretty(self, obj)
    346                     # printer registered in self.type_pprinters
    347                     return self.type_pprinters[cls](obj, self, cycle)
--> 348                 else:
    349                     # deferred printer
    350                     printer = self._in_deferred_types(cls)

/home/bfroehle/src/ipython/IPython/lib/pretty.py in _type_pprint(obj, p, cycle)
    606     """The pprint for classes and types."""
    607     if obj.__module__ in ('__builtin__', 'exceptions'):
--> 608         name = obj.__name__
    609     else:
    610         name = obj.__module__ + '.' + obj.__name__

AttributeError: __module__
```

Please ignore the fact that the traceback line numbers are off by one.. this is a side effect of my [rt2to3](https://github.com/bfroehle/rt2to3) setup.



Discussion:

Resolving patch:
diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py
--- a/IPython/lib/pretty.py
+++ b/IPython/lib/pretty.py
@@ -604,10 +604,16 @@ def _re_pattern_pprint(obj, p, cycle):
 
 def _type_pprint(obj, p, cycle):
     """The pprint for classes and types."""
-    if obj.__module__ in ('__builtin__', 'exceptions'):
+    try:
+        mod = obj.__module__
+    except AttributeError:
+        # Heap allocated types might not have the module attribute.
+        return p.text(obj.__name__)
+
+    if mod in ('__builtin__', 'exceptions'):
         name = obj.__name__
     else:
-        name = obj.__module__ + '.' + obj.__name__
+        name = mod + '.' + obj.__name__
     p.text(name)
 
 


Test patch:
diff --git a/IPython/lib/tests/test_pretty.py b/IPython/lib/tests/test_pretty.py
--- a/IPython/lib/tests/test_pretty.py
+++ b/IPython/lib/tests/test_pretty.py
@@ -18,6 +18,7 @@
 
 # Our own imports
 from IPython.lib import pretty
+from IPython.testing.decorators import skip_without
 
 #-----------------------------------------------------------------------------
 # Classes and functions
@@ -82,3 +83,12 @@ def test_callability_checking():
     expectedoutput = "Dummy1(...)"
 
     nt.assert_equal(gotoutput, expectedoutput)
+
+@skip_without('xxlimited')
+def test_pprint_heap_allocated_type():
+    """
+    Test that pprint works for heap allocated types.
+    """
+    import xxlimited
+    output = pretty.pretty(xxlimited.Null)
+    nt.assert_equal(output, 'xxlimited.Null')