Repository: ipython/ipython

Issue:
Setting `__module__` to None breaks pretty printing
```
In [1]: class Test: pass

In [2]: Test.__module__ = None

In [4]: Test
Out[4]: ---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-2205e48de5f9> in <module>()
----> 1 Test

/Users/aaronmeurer/Documents/ipython/IPython/core/displayhook.pyc in __call__(self, result)
    236             self.start_displayhook()
    237             self.write_output_prompt()
--> 238             format_dict = self.compute_format_data(result)
    239             self.write_format_data(format_dict)
    240             self.update_user_ns(result)

/Users/aaronmeurer/Documents/ipython/IPython/core/displayhook.pyc in compute_format_data(self, result)
    148             MIME type representation of the object.
    149         """
--> 150         return self.shell.display_formatter.format(result)
    151
    152     def write_format_data(self, format_dict):

/Users/aaronmeurer/Documents/ipython/IPython/core/formatters.pyc in format(self, obj, include, exclude)
    124                     continue
    125             try:
--> 126                 data = formatter(obj)
    127             except:
    128                 # FIXME: log the exception

/Users/aaronmeurer/Documents/ipython/IPython/core/formatters.pyc in __call__(self, obj)
    445                 type_pprinters=self.type_printers,
    446                 deferred_pprinters=self.deferred_printers)
--> 447             printer.pretty(obj)
    448             printer.flush()
    449             return stream.getvalue()

/Users/aaronmeurer/Documents/ipython/IPython/lib/pretty.pyc in pretty(self, obj)
    343                 if cls in self.type_pprinters:
    344                     # printer registered in self.type_pprinters
--> 345                     return self.type_pprinters[cls](obj, self, cycle)
    346                 else:
    347                     # deferred printer

/Users/aaronmeurer/Documents/ipython/IPython/lib/pretty.pyc in _type_pprint(obj, p, cycle)
    612         name = obj.__name__
    613     else:
--> 614         name = mod + '.' + obj.__name__
    615     p.text(name)
    616

TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
```

Setting `__module__` to None is a way to make pickling work for dynamically defined classes in certain cases (see for example https://code.google.com/p/sympy/issues/detail?id=1198).  The `whichmodule` function in the pickling module does a custom search for the module if `__module__` is set to None. 



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
@@ -638,10 +638,10 @@ def _re_pattern_pprint(obj, p, cycle):
 
 def _type_pprint(obj, p, cycle):
     """The pprint for classes and types."""
-    try:
-        mod = obj.__module__
-    except AttributeError:
-        # Heap allocated types might not have the module attribute.
+    mod = getattr(obj, '__module__', None)
+    if mod is None:
+        # Heap allocated types might not have the module attribute,
+        # and others may set it to None.
         return p.text(obj.__name__)
 
     if mod in ('__builtin__', 'exceptions'):


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
@@ -53,6 +53,11 @@ def _repr_pretty_(self, p, cycle):
 class Dummy2(Dummy1):
     _repr_pretty_ = None
 
+class NoModule(object):
+    pass
+
+NoModule.__module__ = None
+
 
 def test_indentation():
     """Test correct indentation in groups"""
@@ -106,3 +111,10 @@ def test_pprint_heap_allocated_type():
     import xxlimited
     output = pretty.pretty(xxlimited.Null)
     nt.assert_equal(output, 'xxlimited.Null')
+
+def test_pprint_nomod():
+    """
+    Test that pprint works for classes with no __module__.
+    """
+    output = pretty.pretty(NoModule)
+    nt.assert_equal(output, 'NoModule')