Repository: ipython/ipython

Issue:
Function name printing should use __qualname__ instead of __name__ (Python 3)
There is a bug in the formatting of functions belonging to a class in IPython 2.0.0 running in Python3.

```
In [1]: class A:
   ...:     def f(self):
   ...:         pass
   ...:

In [2]: A.f
Out[2]: <function __main__.f>

In [3]: str(A.f)
Out[3]: '<function A.f at 0x10b283840>'
```

The function name formatting is using the `__name__` attribute of the function instead of `__qualname__`, which results in incorrectly showing the function `f` here in our example belongs to `__main__` instead of `__main__.A`.

A quick fix would be a one line change in https://github.com/ipython/ipython/blob/master/IPython/lib/pretty.py#L749 to use `__qualname__` instead, but will break in Python 2.x as there is no `__qualname__` support.

```
def _function_pprint(obj, p, cycle):
    """Base pprint for all functions and builtin functions."""
    if obj.__module__ in ('__builtin__', 'builtins', 'exceptions') or not obj.__module__:
        name = obj.__name__
    else:
        name = obj.__module__ + '.' + obj.__name__  # use obj.__qualname__
    p.text('<function %s>' % name)
```



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
@@ -723,17 +723,15 @@ def _re_pattern_pprint(obj, p, cycle):
 
 def _type_pprint(obj, p, cycle):
     """The pprint for classes and types."""
+    # Heap allocated types might not have the module attribute,
+    # and others may set it to None.
     mod = _safe_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__)
+    name = _safe_getattr(obj, '__qualname__', obj.__name__)
 
-    if mod in ('__builtin__', 'builtins', 'exceptions'):
-        name = obj.__name__
+    if mod in (None, '__builtin__', 'builtins', 'exceptions'):
+        p.text(name)
     else:
-        name = mod + '.' + obj.__name__
-    p.text(name)
+        p.text(mod + '.' + name)
 
 
 def _repr_pprint(obj, p, cycle):
@@ -743,22 +741,18 @@ def _repr_pprint(obj, p, cycle):
 
 def _function_pprint(obj, p, cycle):
     """Base pprint for all functions and builtin functions."""
-    if obj.__module__ in ('__builtin__', 'builtins', 'exceptions') or not obj.__module__:
-        name = obj.__name__
-    else:
-        name = obj.__module__ + '.' + obj.__name__
+    name = _safe_getattr(obj, '__qualname__', obj.__name__)
+    mod = obj.__module__
+    if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
+        name = mod + '.' + name
     p.text('<function %s>' % name)
 
 
 def _exception_pprint(obj, p, cycle):
     """Base pprint for all exceptions."""
-    if obj.__class__.__module__ in ('exceptions', 'builtins'):
-        name = obj.__class__.__name__
-    else:
-        name = '%s.%s' % (
-            obj.__class__.__module__,
-            obj.__class__.__name__
-        )
+    name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
+    if obj.__class__.__module__ not in ('exceptions', 'builtins'):
+        name = '%s.%s' % (obj.__class__.__module__, name)
     step = len(name) + 1
     p.begin_group(step, name + '(')
     for idx, arg in enumerate(getattr(obj, 'args', ())):


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
@@ -45,6 +45,10 @@ class MyDict(dict):
     def _repr_pretty_(self, p, cycle):
         p.text("MyDict(...)")
 
+class MyObj(object):
+    def somemethod(self):
+        pass
+
 
 class Dummy1(object):
     def _repr_pretty_(self, p, cycle):
@@ -222,3 +226,6 @@ def test_long_dict():
     last2 = p.rsplit('\n', 2)[-2:]
     nt.assert_equal(last2, [' 999: 999,', ' ...}'])
 
+def test_unbound_method():
+    output = pretty.pretty(MyObj.somemethod)
+    nt.assert_in('MyObj.somemethod', output)
\ No newline at end of file