@@ -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
@@ -653,6 +668,25 @@ def classlink(self, object, modname):
653
668
module .__name__ , name , classname (object , modname ))
654
669
return classname (object , modname )
655
670
671
+ def parentlink (self , object , modname ):
672
+ """Make a link for the enclosing class or module."""
673
+ link = None
674
+ name , module = object .__name__ , sys .modules .get (object .__module__ )
675
+ if hasattr (module , name ) and getattr (module , name ) is object :
676
+ if '.' in object .__qualname__ :
677
+ name = object .__qualname__ .rpartition ('.' )[0 ]
678
+ if object .__module__ != modname :
679
+ link = '%s.html#%s' % (module .__name__ , name )
680
+ else :
681
+ link = '#%s' % name
682
+ else :
683
+ if object .__module__ != modname :
684
+ link = '%s.html' % module .__name__
685
+ if link :
686
+ return '<a href="%s">%s</a>' % (link , parentname (object , modname ))
687
+ else :
688
+ return parentname (object , modname )
689
+
656
690
def modulelink (self , object ):
657
691
"""Make a link for a module."""
658
692
return '<a href="%s.html">%s</a>' % (object .__name__ , object .__name__ )
@@ -899,7 +933,7 @@ def spill(msg, attrs, predicate):
899
933
push (self .docdata (value , name , mod ))
900
934
else :
901
935
push (self .document (value , name , mod ,
902
- funcs , classes , mdict , object ))
936
+ funcs , classes , mdict , object , homecls ))
903
937
push ('\n ' )
904
938
return attrs
905
939
@@ -1022,24 +1056,44 @@ def formatvalue(self, object):
1022
1056
return self .grey ('=' + self .repr (object ))
1023
1057
1024
1058
def docroutine (self , object , name = None , mod = None ,
1025
- funcs = {}, classes = {}, methods = {}, cl = None ):
1059
+ funcs = {}, classes = {}, methods = {}, cl = None , homecls = None ):
1026
1060
"""Produce HTML documentation for a function or method object."""
1027
1061
realname = object .__name__
1028
1062
name = name or realname
1029
- anchor = (cl and cl .__name__ or '' ) + '-' + name
1063
+ if homecls is None :
1064
+ homecls = cl
1065
+ anchor = ('' if cl is None else cl .__name__ ) + '-' + name
1030
1066
note = ''
1031
- skipdocs = 0
1067
+ skipdocs = False
1068
+ imfunc = None
1032
1069
if _is_bound_method (object ):
1033
- imclass = object .__self__ .__class__
1034
- if cl :
1035
- if imclass is not cl :
1036
- note = ' from ' + self .classlink (imclass , mod )
1070
+ imself = object .__self__
1071
+ if imself is cl :
1072
+ imfunc = getattr (object , '__func__' , None )
1073
+ elif inspect .isclass (imself ):
1074
+ note = ' class method of %s' % self .classlink (imself , mod )
1037
1075
else :
1038
- if object .__self__ is not None :
1039
- note = ' method of %s instance' % self .classlink (
1040
- object .__self__ .__class__ , mod )
1041
- else :
1042
- note = ' unbound %s method' % self .classlink (imclass ,mod )
1076
+ note = ' method of %s instance' % self .classlink (
1077
+ imself .__class__ , mod )
1078
+ elif (inspect .ismethoddescriptor (object ) or
1079
+ inspect .ismethodwrapper (object )):
1080
+ try :
1081
+ objclass = object .__objclass__
1082
+ except AttributeError :
1083
+ pass
1084
+ else :
1085
+ if cl is None :
1086
+ note = ' unbound %s method' % self .classlink (objclass , mod )
1087
+ elif objclass is not homecls :
1088
+ note = ' from ' + self .classlink (objclass , mod )
1089
+ else :
1090
+ imfunc = object
1091
+ if inspect .isfunction (imfunc ) and homecls is not None and (
1092
+ imfunc .__module__ != homecls .__module__ or
1093
+ imfunc .__qualname__ != homecls .__qualname__ + '.' + realname ):
1094
+ pname = self .parentlink (imfunc , mod )
1095
+ if pname :
1096
+ note = ' from %s' % pname
1043
1097
1044
1098
if (inspect .iscoroutinefunction (object ) or
1045
1099
inspect .isasyncgenfunction (object )):
@@ -1050,10 +1104,13 @@ def docroutine(self, object, name=None, mod=None,
1050
1104
if name == realname :
1051
1105
title = '<a name="%s"><strong>%s</strong></a>' % (anchor , realname )
1052
1106
else :
1053
- if cl and inspect .getattr_static (cl , realname , []) is object :
1107
+ if (cl is not None and
1108
+ inspect .getattr_static (cl , realname , []) is object ):
1054
1109
reallink = '<a href="#%s">%s</a>' % (
1055
1110
cl .__name__ + '-' + realname , realname )
1056
- skipdocs = 1
1111
+ skipdocs = True
1112
+ if note .startswith (' from ' ):
1113
+ note = ''
1057
1114
else :
1058
1115
reallink = realname
1059
1116
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
@@ -1086,7 +1143,7 @@ def docroutine(self, object, name=None, mod=None,
1086
1143
doc = doc and '<dd><span class="code">%s</span></dd>' % doc
1087
1144
return '<dl><dt>%s</dt>%s</dl>\n ' % (decl , doc )
1088
1145
1089
- def docdata (self , object , name = None , mod = None , cl = None ):
1146
+ def docdata (self , object , name = None , mod = None , cl = None , * ignored ):
1090
1147
"""Produce html documentation for a data descriptor."""
1091
1148
results = []
1092
1149
push = results .append
@@ -1198,7 +1255,7 @@ def formattree(self, tree, modname, parent=None, prefix=''):
1198
1255
entry , modname , c , prefix + ' ' )
1199
1256
return result
1200
1257
1201
- def docmodule (self , object , name = None , mod = None ):
1258
+ def docmodule (self , object , name = None , mod = None , * ignored ):
1202
1259
"""Produce text documentation for a given module object."""
1203
1260
name = object .__name__ # ignore the passed-in name
1204
1261
synop , desc = splitdoc (getdoc (object ))
@@ -1382,7 +1439,7 @@ def spill(msg, attrs, predicate):
1382
1439
push (self .docdata (value , name , mod ))
1383
1440
else :
1384
1441
push (self .document (value ,
1385
- name , mod , object ))
1442
+ name , mod , object , homecls ))
1386
1443
return attrs
1387
1444
1388
1445
def spilldescriptors (msg , attrs , predicate ):
@@ -1457,23 +1514,43 @@ def formatvalue(self, object):
1457
1514
"""Format an argument default value as text."""
1458
1515
return '=' + self .repr (object )
1459
1516
1460
- def docroutine (self , object , name = None , mod = None , cl = None ):
1517
+ def docroutine (self , object , name = None , mod = None , cl = None , homecls = None ):
1461
1518
"""Produce text documentation for a function or method object."""
1462
1519
realname = object .__name__
1463
1520
name = name or realname
1521
+ if homecls is None :
1522
+ homecls = cl
1464
1523
note = ''
1465
- skipdocs = 0
1524
+ skipdocs = False
1525
+ imfunc = None
1466
1526
if _is_bound_method (object ):
1467
- imclass = object .__self__ .__class__
1468
- if cl :
1469
- if imclass is not cl :
1470
- note = ' from ' + classname (imclass , mod )
1527
+ imself = object .__self__
1528
+ if imself is cl :
1529
+ imfunc = getattr (object , '__func__' , None )
1530
+ elif inspect .isclass (imself ):
1531
+ note = ' class method of %s' % classname (imself , mod )
1471
1532
else :
1472
- if object .__self__ is not None :
1473
- note = ' method of %s instance' % classname (
1474
- object .__self__ .__class__ , mod )
1475
- else :
1476
- note = ' unbound %s method' % classname (imclass ,mod )
1533
+ note = ' method of %s instance' % classname (
1534
+ imself .__class__ , mod )
1535
+ elif (inspect .ismethoddescriptor (object ) or
1536
+ inspect .ismethodwrapper (object )):
1537
+ try :
1538
+ objclass = object .__objclass__
1539
+ except AttributeError :
1540
+ pass
1541
+ else :
1542
+ if cl is None :
1543
+ note = ' unbound %s method' % classname (objclass , mod )
1544
+ elif objclass is not homecls :
1545
+ note = ' from ' + classname (objclass , mod )
1546
+ else :
1547
+ imfunc = object
1548
+ if inspect .isfunction (imfunc ) and homecls is not None and (
1549
+ imfunc .__module__ != homecls .__module__ or
1550
+ imfunc .__qualname__ != homecls .__qualname__ + '.' + realname ):
1551
+ pname = parentname (imfunc , mod )
1552
+ if pname :
1553
+ note = ' from %s' % pname
1477
1554
1478
1555
if (inspect .iscoroutinefunction (object ) or
1479
1556
inspect .isasyncgenfunction (object )):
@@ -1484,8 +1561,11 @@ def docroutine(self, object, name=None, mod=None, cl=None):
1484
1561
if name == realname :
1485
1562
title = self .bold (realname )
1486
1563
else :
1487
- if cl and inspect .getattr_static (cl , realname , []) is object :
1488
- skipdocs = 1
1564
+ if (cl is not None and
1565
+ inspect .getattr_static (cl , realname , []) is object ):
1566
+ skipdocs = True
1567
+ if note .startswith (' from ' ):
1568
+ note = ''
1489
1569
title = self .bold (name ) + ' = ' + realname
1490
1570
argspec = None
1491
1571
@@ -1512,7 +1592,7 @@ def docroutine(self, object, name=None, mod=None, cl=None):
1512
1592
doc = getdoc (object ) or ''
1513
1593
return decl + '\n ' + (doc and self .indent (doc ).rstrip () + '\n ' )
1514
1594
1515
- def docdata (self , object , name = None , mod = None , cl = None ):
1595
+ def docdata (self , object , name = None , mod = None , cl = None , * ignored ):
1516
1596
"""Produce text documentation for a data descriptor."""
1517
1597
results = []
1518
1598
push = results .append
@@ -1528,7 +1608,8 @@ def docdata(self, object, name=None, mod=None, cl=None):
1528
1608
1529
1609
docproperty = docdata
1530
1610
1531
- def docother (self , object , name = None , mod = None , parent = None , maxlen = None , doc = None ):
1611
+ def docother (self , object , name = None , mod = None , parent = None , * ignored ,
1612
+ maxlen = None , doc = None ):
1532
1613
"""Produce text documentation for a data object."""
1533
1614
repr = self .repr (object )
1534
1615
if maxlen :
0 commit comments