@@ -225,6 +225,19 @@ def classname(object, modname):
225
225
name = object .__module__ + '.' + name
226
226
return name
227
227
228
+ def parentname (object , modname ):
229
+ """Get a name of the enclosing class (qualified it with a module name
230
+ if necessary) or module."""
231
+ if '.' in object .__qualname__ :
232
+ name = object .__qualname__ .rpartition ('.' )[0 ]
233
+ if object .__module__ != modname :
234
+ return object .__module__ + '.' + name
235
+ else :
236
+ return name
237
+ else :
238
+ if object .__module__ != modname :
239
+ return object .__module__
240
+
228
241
def isdata (object ):
229
242
"""Check if an object is of a type that probably means it's data."""
230
243
return not (inspect .ismodule (object ) or inspect .isclass (object ) or
@@ -319,13 +332,15 @@ def visiblename(name, all=None, obj=None):
319
332
return not name .startswith ('_' )
320
333
321
334
def classify_class_attrs (object ):
322
- """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
335
+ """Wrap inspect.classify_class_attrs, with fixup for data descriptors and bound methods ."""
323
336
results = []
324
337
for (name , kind , cls , value ) in inspect .classify_class_attrs (object ):
325
338
if inspect .isdatadescriptor (value ):
326
339
kind = 'data descriptor'
327
340
if isinstance (value , property ) and value .fset is None :
328
341
kind = 'readonly property'
342
+ elif kind == 'method' and _is_bound_method (value ):
343
+ kind = 'static method'
329
344
results .append ((name , kind , cls , value ))
330
345
return results
331
346
@@ -681,6 +696,25 @@ def classlink(self, object, modname):
681
696
module .__name__ , name , classname (object , modname ))
682
697
return classname (object , modname )
683
698
699
+ def parentlink (self , object , modname ):
700
+ """Make a link for the enclosing class or module."""
701
+ link = None
702
+ name , module = object .__name__ , sys .modules .get (object .__module__ )
703
+ if hasattr (module , name ) and getattr (module , name ) is object :
704
+ if '.' in object .__qualname__ :
705
+ name = object .__qualname__ .rpartition ('.' )[0 ]
706
+ if object .__module__ != modname :
707
+ link = '%s.html#%s' % (module .__name__ , name )
708
+ else :
709
+ link = '#%s' % name
710
+ else :
711
+ if object .__module__ != modname :
712
+ link = '%s.html' % module .__name__
713
+ if link :
714
+ return '<a href="%s">%s</a>' % (link , parentname (object , modname ))
715
+ else :
716
+ return parentname (object , modname )
717
+
684
718
def modulelink (self , object ):
685
719
"""Make a link for a module."""
686
720
return '<a href="%s.html">%s</a>' % (object .__name__ , object .__name__ )
@@ -925,7 +959,7 @@ def spill(msg, attrs, predicate):
925
959
push (self .docdata (value , name , mod ))
926
960
else :
927
961
push (self .document (value , name , mod ,
928
- funcs , classes , mdict , object ))
962
+ funcs , classes , mdict , object , homecls ))
929
963
push ('\n ' )
930
964
return attrs
931
965
@@ -1043,24 +1077,44 @@ def formatvalue(self, object):
1043
1077
return self .grey ('=' + self .repr (object ))
1044
1078
1045
1079
def docroutine (self , object , name = None , mod = None ,
1046
- funcs = {}, classes = {}, methods = {}, cl = None ):
1080
+ funcs = {}, classes = {}, methods = {}, cl = None , homecls = None ):
1047
1081
"""Produce HTML documentation for a function or method object."""
1048
1082
realname = object .__name__
1049
1083
name = name or realname
1050
- anchor = (cl and cl .__name__ or '' ) + '-' + name
1084
+ if homecls is None :
1085
+ homecls = cl
1086
+ anchor = ('' if cl is None else cl .__name__ ) + '-' + name
1051
1087
note = ''
1052
- skipdocs = 0
1088
+ skipdocs = False
1089
+ imfunc = None
1053
1090
if _is_bound_method (object ):
1054
- imclass = object .__self__ .__class__
1055
- if cl :
1056
- if imclass is not cl :
1057
- note = ' from ' + self .classlink (imclass , mod )
1091
+ imself = object .__self__
1092
+ if imself is cl :
1093
+ imfunc = getattr (object , '__func__' , None )
1094
+ elif inspect .isclass (imself ):
1095
+ note = ' class method of %s' % self .classlink (imself , mod )
1058
1096
else :
1059
- if object .__self__ is not None :
1060
- note = ' method of %s instance' % self .classlink (
1061
- object .__self__ .__class__ , mod )
1062
- else :
1063
- note = ' unbound %s method' % self .classlink (imclass ,mod )
1097
+ note = ' method of %s instance' % self .classlink (
1098
+ imself .__class__ , mod )
1099
+ elif (inspect .ismethoddescriptor (object ) or
1100
+ inspect .ismethodwrapper (object )):
1101
+ try :
1102
+ objclass = object .__objclass__
1103
+ except AttributeError :
1104
+ pass
1105
+ else :
1106
+ if cl is None :
1107
+ note = ' unbound %s method' % self .classlink (objclass , mod )
1108
+ elif objclass is not homecls :
1109
+ note = ' from ' + self .classlink (objclass , mod )
1110
+ else :
1111
+ imfunc = object
1112
+ if inspect .isfunction (imfunc ) and homecls is not None and (
1113
+ imfunc .__module__ != homecls .__module__ or
1114
+ imfunc .__qualname__ != homecls .__qualname__ + '.' + realname ):
1115
+ pname = self .parentlink (imfunc , mod )
1116
+ if pname :
1117
+ note = ' from %s' % pname
1064
1118
1065
1119
if (inspect .iscoroutinefunction (object ) or
1066
1120
inspect .isasyncgenfunction (object )):
@@ -1071,10 +1125,13 @@ def docroutine(self, object, name=None, mod=None,
1071
1125
if name == realname :
1072
1126
title = '<a name="%s"><strong>%s</strong></a>' % (anchor , realname )
1073
1127
else :
1074
- if cl and inspect .getattr_static (cl , realname , []) is object :
1128
+ if (cl is not None and
1129
+ inspect .getattr_static (cl , realname , []) is object ):
1075
1130
reallink = '<a href="#%s">%s</a>' % (
1076
1131
cl .__name__ + '-' + realname , realname )
1077
- skipdocs = 1
1132
+ skipdocs = True
1133
+ if note .startswith (' from ' ):
1134
+ note = ''
1078
1135
else :
1079
1136
reallink = realname
1080
1137
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
@@ -1102,7 +1159,7 @@ def docroutine(self, object, name=None, mod=None,
1102
1159
doc = doc and '<dd><span class="code">%s</span></dd>' % doc
1103
1160
return '<dl><dt>%s</dt>%s</dl>\n ' % (decl , doc )
1104
1161
1105
- def docdata (self , object , name = None , mod = None , cl = None ):
1162
+ def docdata (self , object , name = None , mod = None , cl = None , * ignored ):
1106
1163
"""Produce html documentation for a data descriptor."""
1107
1164
results = []
1108
1165
push = results .append
@@ -1213,7 +1270,7 @@ def formattree(self, tree, modname, parent=None, prefix=''):
1213
1270
entry , modname , c , prefix + ' ' )
1214
1271
return result
1215
1272
1216
- def docmodule (self , object , name = None , mod = None ):
1273
+ def docmodule (self , object , name = None , mod = None , * ignored ):
1217
1274
"""Produce text documentation for a given module object."""
1218
1275
name = object .__name__ # ignore the passed-in name
1219
1276
synop , desc = splitdoc (getdoc (object ))
@@ -1392,7 +1449,7 @@ def spill(msg, attrs, predicate):
1392
1449
push (self .docdata (value , name , mod ))
1393
1450
else :
1394
1451
push (self .document (value ,
1395
- name , mod , object ))
1452
+ name , mod , object , homecls ))
1396
1453
return attrs
1397
1454
1398
1455
def spilldescriptors (msg , attrs , predicate ):
@@ -1467,23 +1524,43 @@ def formatvalue(self, object):
1467
1524
"""Format an argument default value as text."""
1468
1525
return '=' + self .repr (object )
1469
1526
1470
- def docroutine (self , object , name = None , mod = None , cl = None ):
1527
+ def docroutine (self , object , name = None , mod = None , cl = None , homecls = None ):
1471
1528
"""Produce text documentation for a function or method object."""
1472
1529
realname = object .__name__
1473
1530
name = name or realname
1531
+ if homecls is None :
1532
+ homecls = cl
1474
1533
note = ''
1475
- skipdocs = 0
1534
+ skipdocs = False
1535
+ imfunc = None
1476
1536
if _is_bound_method (object ):
1477
- imclass = object .__self__ .__class__
1478
- if cl :
1479
- if imclass is not cl :
1480
- note = ' from ' + classname (imclass , mod )
1537
+ imself = object .__self__
1538
+ if imself is cl :
1539
+ imfunc = getattr (object , '__func__' , None )
1540
+ elif inspect .isclass (imself ):
1541
+ note = ' class method of %s' % classname (imself , mod )
1481
1542
else :
1482
- if object .__self__ is not None :
1483
- note = ' method of %s instance' % classname (
1484
- object .__self__ .__class__ , mod )
1485
- else :
1486
- note = ' unbound %s method' % classname (imclass ,mod )
1543
+ note = ' method of %s instance' % classname (
1544
+ imself .__class__ , mod )
1545
+ elif (inspect .ismethoddescriptor (object ) or
1546
+ inspect .ismethodwrapper (object )):
1547
+ try :
1548
+ objclass = object .__objclass__
1549
+ except AttributeError :
1550
+ pass
1551
+ else :
1552
+ if cl is None :
1553
+ note = ' unbound %s method' % classname (objclass , mod )
1554
+ elif objclass is not homecls :
1555
+ note = ' from ' + classname (objclass , mod )
1556
+ else :
1557
+ imfunc = object
1558
+ if inspect .isfunction (imfunc ) and homecls is not None and (
1559
+ imfunc .__module__ != homecls .__module__ or
1560
+ imfunc .__qualname__ != homecls .__qualname__ + '.' + realname ):
1561
+ pname = parentname (imfunc , mod )
1562
+ if pname :
1563
+ note = ' from %s' % pname
1487
1564
1488
1565
if (inspect .iscoroutinefunction (object ) or
1489
1566
inspect .isasyncgenfunction (object )):
@@ -1494,8 +1571,11 @@ def docroutine(self, object, name=None, mod=None, cl=None):
1494
1571
if name == realname :
1495
1572
title = self .bold (realname )
1496
1573
else :
1497
- if cl and inspect .getattr_static (cl , realname , []) is object :
1498
- skipdocs = 1
1574
+ if (cl is not None and
1575
+ inspect .getattr_static (cl , realname , []) is object ):
1576
+ skipdocs = True
1577
+ if note .startswith (' from ' ):
1578
+ note = ''
1499
1579
title = self .bold (name ) + ' = ' + realname
1500
1580
argspec = None
1501
1581
@@ -1517,7 +1597,7 @@ def docroutine(self, object, name=None, mod=None, cl=None):
1517
1597
doc = getdoc (object ) or ''
1518
1598
return decl + '\n ' + (doc and self .indent (doc ).rstrip () + '\n ' )
1519
1599
1520
- def docdata (self , object , name = None , mod = None , cl = None ):
1600
+ def docdata (self , object , name = None , mod = None , cl = None , * ignored ):
1521
1601
"""Produce text documentation for a data descriptor."""
1522
1602
results = []
1523
1603
push = results .append
@@ -1533,7 +1613,8 @@ def docdata(self, object, name=None, mod=None, cl=None):
1533
1613
1534
1614
docproperty = docdata
1535
1615
1536
- def docother (self , object , name = None , mod = None , parent = None , maxlen = None , doc = None ):
1616
+ def docother (self , object , name = None , mod = None , parent = None , * ignored ,
1617
+ maxlen = None , doc = None ):
1537
1618
"""Produce text documentation for a data object."""
1538
1619
repr = self .repr (object )
1539
1620
if maxlen :
0 commit comments