@@ -204,6 +204,19 @@ def classname(object, modname):
204
204
name = object .__module__ + '.' + name
205
205
return name
206
206
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
+
207
220
def isdata (object ):
208
221
"""Check if an object is of a type that probably means it's data."""
209
222
return not (inspect .ismodule (object ) or inspect .isclass (object ) or
@@ -298,13 +311,15 @@ def visiblename(name, all=None, obj=None):
298
311
return not name .startswith ('_' )
299
312
300
313
def 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 ."""
302
315
results = []
303
316
for (name , kind , cls , value ) in inspect .classify_class_attrs (object ):
304
317
if inspect .isdatadescriptor (value ):
305
318
kind = 'data descriptor'
306
319
if isinstance (value , property ) and value .fset is None :
307
320
kind = 'readonly property'
321
+ elif kind == 'method' and _is_bound_method (value ):
322
+ kind = 'static method'
308
323
results .append ((name , kind , cls , value ))
309
324
return results
310
325
@@ -658,6 +673,25 @@ def classlink(self, object, modname):
658
673
module .__name__ , name , classname (object , modname ))
659
674
return classname (object , modname )
660
675
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
+
661
695
def modulelink (self , object ):
662
696
"""Make a link for a module."""
663
697
return '<a href="%s.html">%s</a>' % (object .__name__ , object .__name__ )
@@ -902,7 +936,7 @@ def spill(msg, attrs, predicate):
902
936
push (self .docdata (value , name , mod ))
903
937
else :
904
938
push (self .document (value , name , mod ,
905
- funcs , classes , mdict , object ))
939
+ funcs , classes , mdict , object , homecls ))
906
940
push ('\n ' )
907
941
return attrs
908
942
@@ -1025,24 +1059,44 @@ def formatvalue(self, object):
1025
1059
return self .grey ('=' + self .repr (object ))
1026
1060
1027
1061
def docroutine (self , object , name = None , mod = None ,
1028
- funcs = {}, classes = {}, methods = {}, cl = None ):
1062
+ funcs = {}, classes = {}, methods = {}, cl = None , homecls = None ):
1029
1063
"""Produce HTML documentation for a function or method object."""
1030
1064
realname = object .__name__
1031
1065
name = 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
1033
1069
note = ''
1034
- skipdocs = 0
1070
+ skipdocs = False
1071
+ imfunc = None
1035
1072
if _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 )
1040
1078
else :
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
1046
1100
1047
1101
if (inspect .iscoroutinefunction (object ) or
1048
1102
inspect .isasyncgenfunction (object )):
@@ -1053,10 +1107,13 @@ def docroutine(self, object, name=None, mod=None,
1053
1107
if name == realname :
1054
1108
title = '<a name="%s"><strong>%s</strong></a>' % (anchor , realname )
1055
1109
else :
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 ):
1057
1112
reallink = '<a href="#%s">%s</a>' % (
1058
1113
cl .__name__ + '-' + realname , realname )
1059
- skipdocs = 1
1114
+ skipdocs = True
1115
+ if note .startswith (' from ' ):
1116
+ note = ''
1060
1117
else :
1061
1118
reallink = realname
1062
1119
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
@@ -1089,7 +1146,7 @@ def docroutine(self, object, name=None, mod=None,
1089
1146
doc = doc and '<dd><span class="code">%s</span></dd>' % doc
1090
1147
return '<dl><dt>%s</dt>%s</dl>\n ' % (decl , doc )
1091
1148
1092
- def docdata (self , object , name = None , mod = None , cl = None ):
1149
+ def docdata (self , object , name = None , mod = None , cl = None , * ignored ):
1093
1150
"""Produce html documentation for a data descriptor."""
1094
1151
results = []
1095
1152
push = results .append
@@ -1200,7 +1257,7 @@ def formattree(self, tree, modname, parent=None, prefix=''):
1200
1257
entry , modname , c , prefix + ' ' )
1201
1258
return result
1202
1259
1203
- def docmodule (self , object , name = None , mod = None ):
1260
+ def docmodule (self , object , name = None , mod = None , * ignored ):
1204
1261
"""Produce text documentation for a given module object."""
1205
1262
name = object .__name__ # ignore the passed-in name
1206
1263
synop , desc = splitdoc (getdoc (object ))
@@ -1384,7 +1441,7 @@ def spill(msg, attrs, predicate):
1384
1441
push (self .docdata (value , name , mod ))
1385
1442
else :
1386
1443
push (self .document (value ,
1387
- name , mod , object ))
1444
+ name , mod , object , homecls ))
1388
1445
return attrs
1389
1446
1390
1447
def spilldescriptors (msg , attrs , predicate ):
@@ -1459,23 +1516,43 @@ def formatvalue(self, object):
1459
1516
"""Format an argument default value as text."""
1460
1517
return '=' + self .repr (object )
1461
1518
1462
- def docroutine (self , object , name = None , mod = None , cl = None ):
1519
+ def docroutine (self , object , name = None , mod = None , cl = None , homecls = None ):
1463
1520
"""Produce text documentation for a function or method object."""
1464
1521
realname = object .__name__
1465
1522
name = name or realname
1523
+ if homecls is None :
1524
+ homecls = cl
1466
1525
note = ''
1467
- skipdocs = 0
1526
+ skipdocs = False
1527
+ imfunc = None
1468
1528
if _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 )
1473
1534
else :
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
1479
1556
1480
1557
if (inspect .iscoroutinefunction (object ) or
1481
1558
inspect .isasyncgenfunction (object )):
@@ -1486,8 +1563,11 @@ def docroutine(self, object, name=None, mod=None, cl=None):
1486
1563
if name == realname :
1487
1564
title = self .bold (realname )
1488
1565
else :
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 = ''
1491
1571
title = self .bold (name ) + ' = ' + realname
1492
1572
argspec = None
1493
1573
@@ -1514,7 +1594,7 @@ def docroutine(self, object, name=None, mod=None, cl=None):
1514
1594
doc = getdoc (object ) or ''
1515
1595
return decl + '\n ' + (doc and self .indent (doc ).rstrip () + '\n ' )
1516
1596
1517
- def docdata (self , object , name = None , mod = None , cl = None ):
1597
+ def docdata (self , object , name = None , mod = None , cl = None , * ignored ):
1518
1598
"""Produce text documentation for a data descriptor."""
1519
1599
results = []
1520
1600
push = results .append
@@ -1530,7 +1610,8 @@ def docdata(self, object, name=None, mod=None, cl=None):
1530
1610
1531
1611
docproperty = docdata
1532
1612
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 ):
1534
1615
"""Produce text documentation for a data object."""
1535
1616
repr = self .repr (object )
1536
1617
if maxlen :
0 commit comments