@@ -204,6 +204,19 @@ def classname(object, modname):
204204name = object .__module__ + '.' + name
205205return name
206206
207+ def parentname (object ,modname ):
208+ """Get a name of the enclosing class (qualified it with a module name
209+ if necessary) or module."""
210+ if '.' in object .__qualname__ :
211+ name = object .__qualname__ .rpartition ('.' )[0 ]
212+ if object .__module__ != modname :
213+ return object .__module__ + '.' + name
214+ else :
215+ return name
216+ else :
217+ if object .__module__ != modname :
218+ return object .__module__
219+
207220def isdata (object ):
208221"""Check if an object is of a type that probably means it's data."""
209222return not (inspect .ismodule (object )or inspect .isclass (object )or
@@ -298,13 +311,15 @@ def visiblename(name, all=None, obj=None):
298311return not name .startswith ('_' )
299312
300313def classify_class_attrs (object ):
301- """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
314+ """Wrap inspect.classify_class_attrs, with fixup for data descriptors and bound methods ."""
302315results = []
303316for (name ,kind ,cls ,value )in inspect .classify_class_attrs (object ):
304317if inspect .isdatadescriptor (value ):
305318kind = 'data descriptor'
306319if isinstance (value ,property )and value .fset is None :
307320kind = 'readonly property'
321+ elif kind == 'method' and _is_bound_method (value ):
322+ kind = 'static method'
308323results .append ((name ,kind ,cls ,value ))
309324return results
310325
@@ -658,6 +673,25 @@ def classlink(self, object, modname):
658673module .__name__ ,name ,classname (object ,modname ))
659674return classname (object ,modname )
660675
676+ def parentlink (self ,object ,modname ):
677+ """Make a link for the enclosing class or module."""
678+ link = None
679+ name ,module = object .__name__ ,sys .modules .get (object .__module__ )
680+ if hasattr (module ,name )and getattr (module ,name )is object :
681+ if '.' in object .__qualname__ :
682+ name = object .__qualname__ .rpartition ('.' )[0 ]
683+ if object .__module__ != modname :
684+ link = '%s.html#%s' % (module .__name__ ,name )
685+ else :
686+ link = '#%s' % name
687+ else :
688+ if object .__module__ != modname :
689+ link = '%s.html' % module .__name__
690+ if link :
691+ return '<a href="%s">%s</a>' % (link ,parentname (object ,modname ))
692+ else :
693+ return parentname (object ,modname )
694+
661695def modulelink (self ,object ):
662696"""Make a link for a module."""
663697return '<a href="%s.html">%s</a>' % (object .__name__ ,object .__name__ )
@@ -902,7 +936,7 @@ def spill(msg, attrs, predicate):
902936push (self .docdata (value ,name ,mod ))
903937else :
904938push (self .document (value ,name ,mod ,
905- funcs ,classes ,mdict ,object ))
939+ funcs ,classes ,mdict ,object , homecls ))
906940push ('\n ' )
907941return attrs
908942
@@ -1025,24 +1059,44 @@ def formatvalue(self, object):
10251059return self .grey ('=' + self .repr (object ))
10261060
10271061def docroutine (self ,object ,name = None ,mod = None ,
1028- funcs = {},classes = {},methods = {},cl = None ):
1062+ funcs = {},classes = {},methods = {},cl = None , homecls = None ):
10291063"""Produce HTML documentation for a function or method object."""
10301064realname = object .__name__
10311065name = name or realname
1032- anchor = (cl and cl .__name__ or '' )+ '-' + name
1066+ if homecls is None :
1067+ homecls = cl
1068+ anchor = ('' if cl is None else cl .__name__ )+ '-' + name
10331069note = ''
1034- skipdocs = 0
1070+ skipdocs = False
1071+ imfunc = None
10351072if _is_bound_method (object ):
1036- imclass = object .__self__ .__class__
1037- if cl :
1038- if imclass is not cl :
1039- note = ' from ' + self .classlink (imclass ,mod )
1073+ imself = object .__self__
1074+ if imself is cl :
1075+ imfunc = getattr (object ,'__func__' ,None )
1076+ elif inspect .isclass (imself ):
1077+ note = ' class method of %s' % self .classlink (imself ,mod )
10401078else :
1041- if object .__self__ is not None :
1042- note = ' method of %s instance' % self .classlink (
1043- object .__self__ .__class__ ,mod )
1044- else :
1045- note = ' unbound %s method' % self .classlink (imclass ,mod )
1079+ note = ' method of %s instance' % self .classlink (
1080+ imself .__class__ ,mod )
1081+ elif (inspect .ismethoddescriptor (object )or
1082+ inspect .ismethodwrapper (object )):
1083+ try :
1084+ objclass = object .__objclass__
1085+ except AttributeError :
1086+ pass
1087+ else :
1088+ if cl is None :
1089+ note = ' unbound %s method' % self .classlink (objclass ,mod )
1090+ elif objclass is not homecls :
1091+ note = ' from ' + self .classlink (objclass ,mod )
1092+ else :
1093+ imfunc = object
1094+ if inspect .isfunction (imfunc )and homecls is not None and (
1095+ imfunc .__module__ != homecls .__module__ or
1096+ imfunc .__qualname__ != homecls .__qualname__ + '.' + realname ):
1097+ pname = self .parentlink (imfunc ,mod )
1098+ if pname :
1099+ note = ' from %s' % pname
10461100
10471101if (inspect .iscoroutinefunction (object )or
10481102inspect .isasyncgenfunction (object )):
@@ -1053,10 +1107,13 @@ def docroutine(self, object, name=None, mod=None,
10531107if name == realname :
10541108title = '<a name="%s"><strong>%s</strong></a>' % (anchor ,realname )
10551109else :
1056- if cl and inspect .getattr_static (cl ,realname , [])is object :
1110+ if (cl is not None and
1111+ inspect .getattr_static (cl ,realname , [])is object ):
10571112reallink = '<a href="#%s">%s</a>' % (
10581113cl .__name__ + '-' + realname ,realname )
1059- skipdocs = 1
1114+ skipdocs = True
1115+ if note .startswith (' from ' ):
1116+ note = ''
10601117else :
10611118reallink = realname
10621119title = '<a name="%s"><strong>%s</strong></a> = %s' % (
@@ -1089,7 +1146,7 @@ def docroutine(self, object, name=None, mod=None,
10891146doc = doc and '<dd><span class="code">%s</span></dd>' % doc
10901147return '<dl><dt>%s</dt>%s</dl>\n ' % (decl ,doc )
10911148
1092- def docdata (self ,object ,name = None ,mod = None ,cl = None ):
1149+ def docdata (self ,object ,name = None ,mod = None ,cl = None , * ignored ):
10931150"""Produce html documentation for a data descriptor."""
10941151results = []
10951152push = results .append
@@ -1200,7 +1257,7 @@ def formattree(self, tree, modname, parent=None, prefix=''):
12001257entry ,modname ,c ,prefix + ' ' )
12011258return result
12021259
1203- def docmodule (self ,object ,name = None ,mod = None ):
1260+ def docmodule (self ,object ,name = None ,mod = None , * ignored ):
12041261"""Produce text documentation for a given module object."""
12051262name = object .__name__ # ignore the passed-in name
12061263synop ,desc = splitdoc (getdoc (object ))
@@ -1384,7 +1441,7 @@ def spill(msg, attrs, predicate):
13841441push (self .docdata (value ,name ,mod ))
13851442else :
13861443push (self .document (value ,
1387- name ,mod ,object ))
1444+ name ,mod ,object , homecls ))
13881445return attrs
13891446
13901447def spilldescriptors (msg ,attrs ,predicate ):
@@ -1459,23 +1516,43 @@ def formatvalue(self, object):
14591516"""Format an argument default value as text."""
14601517return '=' + self .repr (object )
14611518
1462- def docroutine (self ,object ,name = None ,mod = None ,cl = None ):
1519+ def docroutine (self ,object ,name = None ,mod = None ,cl = None , homecls = None ):
14631520"""Produce text documentation for a function or method object."""
14641521realname = object .__name__
14651522name = name or realname
1523+ if homecls is None :
1524+ homecls = cl
14661525note = ''
1467- skipdocs = 0
1526+ skipdocs = False
1527+ imfunc = None
14681528if _is_bound_method (object ):
1469- imclass = object .__self__ .__class__
1470- if cl :
1471- if imclass is not cl :
1472- note = ' from ' + classname (imclass ,mod )
1529+ imself = object .__self__
1530+ if imself is cl :
1531+ imfunc = getattr (object ,'__func__' ,None )
1532+ elif inspect .isclass (imself ):
1533+ note = ' class method of %s' % classname (imself ,mod )
14731534else :
1474- if object .__self__ is not None :
1475- note = ' method of %s instance' % classname (
1476- object .__self__ .__class__ ,mod )
1477- else :
1478- note = ' unbound %s method' % classname (imclass ,mod )
1535+ note = ' method of %s instance' % classname (
1536+ imself .__class__ ,mod )
1537+ elif (inspect .ismethoddescriptor (object )or
1538+ inspect .ismethodwrapper (object )):
1539+ try :
1540+ objclass = object .__objclass__
1541+ except AttributeError :
1542+ pass
1543+ else :
1544+ if cl is None :
1545+ note = ' unbound %s method' % classname (objclass ,mod )
1546+ elif objclass is not homecls :
1547+ note = ' from ' + classname (objclass ,mod )
1548+ else :
1549+ imfunc = object
1550+ if inspect .isfunction (imfunc )and homecls is not None and (
1551+ imfunc .__module__ != homecls .__module__ or
1552+ imfunc .__qualname__ != homecls .__qualname__ + '.' + realname ):
1553+ pname = parentname (imfunc ,mod )
1554+ if pname :
1555+ note = ' from %s' % pname
14791556
14801557if (inspect .iscoroutinefunction (object )or
14811558inspect .isasyncgenfunction (object )):
@@ -1486,8 +1563,11 @@ def docroutine(self, object, name=None, mod=None, cl=None):
14861563if name == realname :
14871564title = self .bold (realname )
14881565else :
1489- if cl and inspect .getattr_static (cl ,realname , [])is object :
1490- skipdocs = 1
1566+ if (cl is not None and
1567+ inspect .getattr_static (cl ,realname , [])is object ):
1568+ skipdocs = True
1569+ if note .startswith (' from ' ):
1570+ note = ''
14911571title = self .bold (name )+ ' = ' + realname
14921572argspec = None
14931573
@@ -1514,7 +1594,7 @@ def docroutine(self, object, name=None, mod=None, cl=None):
15141594doc = getdoc (object )or ''
15151595return decl + '\n ' + (doc and self .indent (doc ).rstrip ()+ '\n ' )
15161596
1517- def docdata (self ,object ,name = None ,mod = None ,cl = None ):
1597+ def docdata (self ,object ,name = None ,mod = None ,cl = None , * ignored ):
15181598"""Produce text documentation for a data descriptor."""
15191599results = []
15201600push = results .append
@@ -1530,7 +1610,8 @@ def docdata(self, object, name=None, mod=None, cl=None):
15301610
15311611docproperty = docdata
15321612
1533- def docother (self ,object ,name = None ,mod = None ,parent = None ,maxlen = None ,doc = None ):
1613+ def docother (self ,object ,name = None ,mod = None ,parent = None ,* ignored ,
1614+ maxlen = None ,doc = None ):
15341615"""Produce text documentation for a data object."""
15351616repr = self .repr (object )
15361617if maxlen :