Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcfb79ca

Browse files
[3.12]gh-97959: Fix rendering of routines in pydoc (GH-113941) (GH-115296)
* Class methods no longer have "method of builtins.type instance" note.* Corresponding notes are now added for class and unbound methods.* Method and function aliases now have references to the module or the class where the origin was defined if it differs from the current.* Bound methods are now listed in the static methods section.* Methods of builtin classes are now supported as well as methods of Python classes.(cherry picked from commit2939ad0)
1 parentd8346d6 commitcfb79ca

File tree

5 files changed

+322
-52
lines changed

5 files changed

+322
-52
lines changed

‎Lib/pydoc.py‎

Lines changed: 115 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,19 @@ def classname(object, modname):
204204
name=object.__module__+'.'+name
205205
returnname
206206

207+
defparentname(object,modname):
208+
"""Get a name of the enclosing class (qualified it with a module name
209+
if necessary) or module."""
210+
if'.'inobject.__qualname__:
211+
name=object.__qualname__.rpartition('.')[0]
212+
ifobject.__module__!=modname:
213+
returnobject.__module__+'.'+name
214+
else:
215+
returnname
216+
else:
217+
ifobject.__module__!=modname:
218+
returnobject.__module__
219+
207220
defisdata(object):
208221
"""Check if an object is of a type that probably means it's data."""
209222
returnnot (inspect.ismodule(object)orinspect.isclass(object)or
@@ -298,13 +311,15 @@ def visiblename(name, all=None, obj=None):
298311
returnnotname.startswith('_')
299312

300313
defclassify_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."""
302315
results= []
303316
for (name,kind,cls,value)ininspect.classify_class_attrs(object):
304317
ifinspect.isdatadescriptor(value):
305318
kind='data descriptor'
306319
ifisinstance(value,property)andvalue.fsetisNone:
307320
kind='readonly property'
321+
elifkind=='method'and_is_bound_method(value):
322+
kind='static method'
308323
results.append((name,kind,cls,value))
309324
returnresults
310325

@@ -658,6 +673,25 @@ def classlink(self, object, modname):
658673
module.__name__,name,classname(object,modname))
659674
returnclassname(object,modname)
660675

676+
defparentlink(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+
ifhasattr(module,name)andgetattr(module,name)isobject:
681+
if'.'inobject.__qualname__:
682+
name=object.__qualname__.rpartition('.')[0]
683+
ifobject.__module__!=modname:
684+
link='%s.html#%s'% (module.__name__,name)
685+
else:
686+
link='#%s'%name
687+
else:
688+
ifobject.__module__!=modname:
689+
link='%s.html'%module.__name__
690+
iflink:
691+
return'<a href="%s">%s</a>'% (link,parentname(object,modname))
692+
else:
693+
returnparentname(object,modname)
694+
661695
defmodulelink(self,object):
662696
"""Make a link for a module."""
663697
return'<a href="%s.html">%s</a>'% (object.__name__,object.__name__)
@@ -902,7 +936,7 @@ def spill(msg, attrs, predicate):
902936
push(self.docdata(value,name,mod))
903937
else:
904938
push(self.document(value,name,mod,
905-
funcs,classes,mdict,object))
939+
funcs,classes,mdict,object,homecls))
906940
push('\n')
907941
returnattrs
908942

@@ -1025,24 +1059,44 @@ def formatvalue(self, object):
10251059
returnself.grey('='+self.repr(object))
10261060

10271061
defdocroutine(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."""
10301064
realname=object.__name__
10311065
name=nameorrealname
1032-
anchor= (clandcl.__name__or'')+'-'+name
1066+
ifhomeclsisNone:
1067+
homecls=cl
1068+
anchor= (''ifclisNoneelsecl.__name__)+'-'+name
10331069
note=''
1034-
skipdocs=0
1070+
skipdocs=False
1071+
imfunc=None
10351072
if_is_bound_method(object):
1036-
imclass=object.__self__.__class__
1037-
ifcl:
1038-
ifimclassisnotcl:
1039-
note=' from '+self.classlink(imclass,mod)
1073+
imself=object.__self__
1074+
ifimselfiscl:
1075+
imfunc=getattr(object,'__func__',None)
1076+
elifinspect.isclass(imself):
1077+
note=' class method of %s'%self.classlink(imself,mod)
10401078
else:
1041-
ifobject.__self__isnotNone:
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+
exceptAttributeError:
1086+
pass
1087+
else:
1088+
ifclisNone:
1089+
note=' unbound %s method'%self.classlink(objclass,mod)
1090+
elifobjclassisnothomecls:
1091+
note=' from '+self.classlink(objclass,mod)
1092+
else:
1093+
imfunc=object
1094+
ifinspect.isfunction(imfunc)andhomeclsisnotNoneand (
1095+
imfunc.__module__!=homecls.__module__or
1096+
imfunc.__qualname__!=homecls.__qualname__+'.'+realname):
1097+
pname=self.parentlink(imfunc,mod)
1098+
ifpname:
1099+
note=' from %s'%pname
10461100

10471101
if (inspect.iscoroutinefunction(object)or
10481102
inspect.isasyncgenfunction(object)):
@@ -1053,10 +1107,13 @@ def docroutine(self, object, name=None, mod=None,
10531107
ifname==realname:
10541108
title='<a name="%s"><strong>%s</strong></a>'% (anchor,realname)
10551109
else:
1056-
ifclandinspect.getattr_static(cl,realname, [])isobject:
1110+
if (clisnotNoneand
1111+
inspect.getattr_static(cl,realname, [])isobject):
10571112
reallink='<a href="#%s">%s</a>'% (
10581113
cl.__name__+'-'+realname,realname)
1059-
skipdocs=1
1114+
skipdocs=True
1115+
ifnote.startswith(' from '):
1116+
note=''
10601117
else:
10611118
reallink=realname
10621119
title='<a name="%s"><strong>%s</strong></a> = %s'% (
@@ -1089,7 +1146,7 @@ def docroutine(self, object, name=None, mod=None,
10891146
doc=docand'<dd><span class="code">%s</span></dd>'%doc
10901147
return'<dl><dt>%s</dt>%s</dl>\n'% (decl,doc)
10911148

1092-
defdocdata(self,object,name=None,mod=None,cl=None):
1149+
defdocdata(self,object,name=None,mod=None,cl=None,*ignored):
10931150
"""Produce html documentation for a data descriptor."""
10941151
results= []
10951152
push=results.append
@@ -1200,7 +1257,7 @@ def formattree(self, tree, modname, parent=None, prefix=''):
12001257
entry,modname,c,prefix+' ')
12011258
returnresult
12021259

1203-
defdocmodule(self,object,name=None,mod=None):
1260+
defdocmodule(self,object,name=None,mod=None,*ignored):
12041261
"""Produce text documentation for a given module object."""
12051262
name=object.__name__# ignore the passed-in name
12061263
synop,desc=splitdoc(getdoc(object))
@@ -1384,7 +1441,7 @@ def spill(msg, attrs, predicate):
13841441
push(self.docdata(value,name,mod))
13851442
else:
13861443
push(self.document(value,
1387-
name,mod,object))
1444+
name,mod,object,homecls))
13881445
returnattrs
13891446

13901447
defspilldescriptors(msg,attrs,predicate):
@@ -1459,23 +1516,43 @@ def formatvalue(self, object):
14591516
"""Format an argument default value as text."""
14601517
return'='+self.repr(object)
14611518

1462-
defdocroutine(self,object,name=None,mod=None,cl=None):
1519+
defdocroutine(self,object,name=None,mod=None,cl=None,homecls=None):
14631520
"""Produce text documentation for a function or method object."""
14641521
realname=object.__name__
14651522
name=nameorrealname
1523+
ifhomeclsisNone:
1524+
homecls=cl
14661525
note=''
1467-
skipdocs=0
1526+
skipdocs=False
1527+
imfunc=None
14681528
if_is_bound_method(object):
1469-
imclass=object.__self__.__class__
1470-
ifcl:
1471-
ifimclassisnotcl:
1472-
note=' from '+classname(imclass,mod)
1529+
imself=object.__self__
1530+
ifimselfiscl:
1531+
imfunc=getattr(object,'__func__',None)
1532+
elifinspect.isclass(imself):
1533+
note=' class method of %s'%classname(imself,mod)
14731534
else:
1474-
ifobject.__self__isnotNone:
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+
exceptAttributeError:
1542+
pass
1543+
else:
1544+
ifclisNone:
1545+
note=' unbound %s method'%classname(objclass,mod)
1546+
elifobjclassisnothomecls:
1547+
note=' from '+classname(objclass,mod)
1548+
else:
1549+
imfunc=object
1550+
ifinspect.isfunction(imfunc)andhomeclsisnotNoneand (
1551+
imfunc.__module__!=homecls.__module__or
1552+
imfunc.__qualname__!=homecls.__qualname__+'.'+realname):
1553+
pname=parentname(imfunc,mod)
1554+
ifpname:
1555+
note=' from %s'%pname
14791556

14801557
if (inspect.iscoroutinefunction(object)or
14811558
inspect.isasyncgenfunction(object)):
@@ -1486,8 +1563,11 @@ def docroutine(self, object, name=None, mod=None, cl=None):
14861563
ifname==realname:
14871564
title=self.bold(realname)
14881565
else:
1489-
ifclandinspect.getattr_static(cl,realname, [])isobject:
1490-
skipdocs=1
1566+
if (clisnotNoneand
1567+
inspect.getattr_static(cl,realname, [])isobject):
1568+
skipdocs=True
1569+
ifnote.startswith(' from '):
1570+
note=''
14911571
title=self.bold(name)+' = '+realname
14921572
argspec=None
14931573

@@ -1514,7 +1594,7 @@ def docroutine(self, object, name=None, mod=None, cl=None):
15141594
doc=getdoc(object)or''
15151595
returndecl+'\n'+ (docandself.indent(doc).rstrip()+'\n')
15161596

1517-
defdocdata(self,object,name=None,mod=None,cl=None):
1597+
defdocdata(self,object,name=None,mod=None,cl=None,*ignored):
15181598
"""Produce text documentation for a data descriptor."""
15191599
results= []
15201600
push=results.append
@@ -1530,7 +1610,8 @@ def docdata(self, object, name=None, mod=None, cl=None):
15301610

15311611
docproperty=docdata
15321612

1533-
defdocother(self,object,name=None,mod=None,parent=None,maxlen=None,doc=None):
1613+
defdocother(self,object,name=None,mod=None,parent=None,*ignored,
1614+
maxlen=None,doc=None):
15341615
"""Produce text documentation for a data object."""
15351616
repr=self.repr(object)
15361617
ifmaxlen:

‎Lib/test/pydocfodder.py‎

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
importtypes
44

5+
defglobal_func(x,y):
6+
"""Module global function"""
7+
8+
defglobal_func2(x,y):
9+
"""Module global function 2"""
10+
511
classA:
612
"A class."
713

@@ -26,7 +32,7 @@ def A_classmethod(cls, x):
2632
"A class method defined in A."
2733
A_classmethod=classmethod(A_classmethod)
2834

29-
defA_staticmethod():
35+
defA_staticmethod(x,y):
3036
"A static method defined in A."
3137
A_staticmethod=staticmethod(A_staticmethod)
3238

@@ -61,6 +67,28 @@ def BD_method(self):
6167
defBCD_method(self):
6268
"Method defined in B, C and D."
6369

70+
@classmethod
71+
defB_classmethod(cls,x):
72+
"A class method defined in B."
73+
74+
global_func=global_func# same name
75+
global_func_alias=global_func
76+
global_func2_alias=global_func2
77+
B_classmethod_alias=B_classmethod
78+
A_classmethod_ref=A.A_classmethod
79+
A_staticmethod=A.A_staticmethod# same name
80+
A_staticmethod_alias=A.A_staticmethod
81+
A_method_ref=A().A_method
82+
A_method_alias=A.A_method
83+
B_method_alias=B_method
84+
__repr__=object.__repr__# same name
85+
object_repr=object.__repr__
86+
get= {}.get# same name
87+
dict_get= {}.get
88+
89+
B.B_classmethod_ref=B.B_classmethod
90+
91+
6492
classC(A):
6593
"A class, derived from A."
6694

@@ -136,3 +164,21 @@ def __call__(self, inst):
136164

137165
submodule=types.ModuleType(__name__+'.submodule',
138166
"""A submodule, which should appear in its parent's summary""")
167+
168+
global_func_alias=global_func
169+
A_classmethod=A.A_classmethod# same name
170+
A_classmethod2=A.A_classmethod
171+
A_classmethod3=B.A_classmethod
172+
A_staticmethod=A.A_staticmethod# same name
173+
A_staticmethod_alias=A.A_staticmethod
174+
A_staticmethod_ref=A().A_staticmethod
175+
A_staticmethod_ref2=B().A_staticmethod
176+
A_method=A().A_method# same name
177+
A_method2=A().A_method
178+
A_method3=B().A_method
179+
B_method=B.B_method# same name
180+
B_method2=B.B_method
181+
count=list.count# same name
182+
list_count=list.count
183+
get= {}.get# same name
184+
dict_get= {}.get

‎Lib/test/test_enum.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4752,22 +4752,22 @@ class Color(enum.Enum)
47524752
| The value of the Enum member.
47534753
|
47544754
| ----------------------------------------------------------------------
4755-
|Methods inherited from enum.EnumType:
4755+
|Static methods inherited from enum.EnumType:
47564756
|
4757-
| __contains__(value) from enum.EnumType
4757+
| __contains__(value)
47584758
| Return True if `value` is in `cls`.
47594759
|
47604760
| `value` is in `cls` if:
47614761
| 1) `value` is a member of `cls`, or
47624762
| 2) `value` is the value of one of the `cls`'s members.
47634763
|
4764-
| __getitem__(name) from enum.EnumType
4764+
| __getitem__(name)
47654765
| Return the member matching `name`.
47664766
|
4767-
| __iter__() from enum.EnumType
4767+
| __iter__()
47684768
| Return members in definition order.
47694769
|
4770-
| __len__() from enum.EnumType
4770+
| __len__()
47714771
| Return the number of members (no aliases)
47724772
|
47734773
| ----------------------------------------------------------------------

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp