This commit is contained in:
ton
2024-10-07 10:13:40 +07:00
parent aa1631742f
commit 3a7d696db6
9729 changed files with 1832837 additions and 161742 deletions

View File

@@ -204,6 +204,19 @@ def classname(object, modname):
name = object.__module__ + '.' + name
return name
def parentname(object, modname):
"""Get a name of the enclosing class (qualified it with a module name
if necessary) or module."""
if '.' in object.__qualname__:
name = object.__qualname__.rpartition('.')[0]
if object.__module__ != modname:
return object.__module__ + '.' + name
else:
return name
else:
if object.__module__ != modname:
return object.__module__
def isdata(object):
"""Check if an object is of a type that probably means it's data."""
return not (inspect.ismodule(object) or inspect.isclass(object) or
@@ -298,13 +311,15 @@ def visiblename(name, all=None, obj=None):
return not name.startswith('_')
def classify_class_attrs(object):
"""Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
"""Wrap inspect.classify_class_attrs, with fixup for data descriptors and bound methods."""
results = []
for (name, kind, cls, value) in inspect.classify_class_attrs(object):
if inspect.isdatadescriptor(value):
kind = 'data descriptor'
if isinstance(value, property) and value.fset is None:
kind = 'readonly property'
elif kind == 'method' and _is_bound_method(value):
kind = 'static method'
results.append((name, kind, cls, value))
return results
@@ -514,7 +529,7 @@ class Doc:
'_thread', 'zipimport') or
(file.startswith(basedir) and
not file.startswith(os.path.join(basedir, 'site-packages')))) and
object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
object.__name__ not in ('xml.etree', 'test.test_pydoc.pydoc_mod')):
if docloc.startswith(("http://", "https://")):
docloc = "{}/{}.html".format(docloc.rstrip("/"), object.__name__.lower())
else:
@@ -658,6 +673,25 @@ class HTMLDoc(Doc):
module.__name__, name, classname(object, modname))
return classname(object, modname)
def parentlink(self, object, modname):
"""Make a link for the enclosing class or module."""
link = None
name, module = object.__name__, sys.modules.get(object.__module__)
if hasattr(module, name) and getattr(module, name) is object:
if '.' in object.__qualname__:
name = object.__qualname__.rpartition('.')[0]
if object.__module__ != modname:
link = '%s.html#%s' % (module.__name__, name)
else:
link = '#%s' % name
else:
if object.__module__ != modname:
link = '%s.html' % module.__name__
if link:
return '<a href="%s">%s</a>' % (link, parentname(object, modname))
else:
return parentname(object, modname)
def modulelink(self, object):
"""Make a link for a module."""
return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
@@ -902,7 +936,7 @@ class HTMLDoc(Doc):
push(self.docdata(value, name, mod))
else:
push(self.document(value, name, mod,
funcs, classes, mdict, object))
funcs, classes, mdict, object, homecls))
push('\n')
return attrs
@@ -1025,24 +1059,44 @@ class HTMLDoc(Doc):
return self.grey('=' + self.repr(object))
def docroutine(self, object, name=None, mod=None,
funcs={}, classes={}, methods={}, cl=None):
funcs={}, classes={}, methods={}, cl=None, homecls=None):
"""Produce HTML documentation for a function or method object."""
realname = object.__name__
name = name or realname
anchor = (cl and cl.__name__ or '') + '-' + name
if homecls is None:
homecls = cl
anchor = ('' if cl is None else cl.__name__) + '-' + name
note = ''
skipdocs = 0
skipdocs = False
imfunc = None
if _is_bound_method(object):
imclass = object.__self__.__class__
if cl:
if imclass is not cl:
note = ' from ' + self.classlink(imclass, mod)
imself = object.__self__
if imself is cl:
imfunc = getattr(object, '__func__', None)
elif inspect.isclass(imself):
note = ' class method of %s' % self.classlink(imself, mod)
else:
if object.__self__ is not None:
note = ' method of %s instance' % self.classlink(
object.__self__.__class__, mod)
else:
note = ' unbound %s method' % self.classlink(imclass,mod)
note = ' method of %s instance' % self.classlink(
imself.__class__, mod)
elif (inspect.ismethoddescriptor(object) or
inspect.ismethodwrapper(object)):
try:
objclass = object.__objclass__
except AttributeError:
pass
else:
if cl is None:
note = ' unbound %s method' % self.classlink(objclass, mod)
elif objclass is not homecls:
note = ' from ' + self.classlink(objclass, mod)
else:
imfunc = object
if inspect.isfunction(imfunc) and homecls is not None and (
imfunc.__module__ != homecls.__module__ or
imfunc.__qualname__ != homecls.__qualname__ + '.' + realname):
pname = self.parentlink(imfunc, mod)
if pname:
note = ' from %s' % pname
if (inspect.iscoroutinefunction(object) or
inspect.isasyncgenfunction(object)):
@@ -1053,10 +1107,13 @@ class HTMLDoc(Doc):
if name == realname:
title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
else:
if cl and inspect.getattr_static(cl, realname, []) is object:
if (cl is not None and
inspect.getattr_static(cl, realname, []) is object):
reallink = '<a href="#%s">%s</a>' % (
cl.__name__ + '-' + realname, realname)
skipdocs = 1
skipdocs = True
if note.startswith(' from '):
note = ''
else:
reallink = realname
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
@@ -1074,7 +1131,8 @@ class HTMLDoc(Doc):
# XXX lambda's won't usually have func_annotations['return']
# since the syntax doesn't support but it is possible.
# So removing parentheses isn't truly safe.
argspec = argspec[1:-1] # remove parentheses
if not object.__annotations__:
argspec = argspec[1:-1] # remove parentheses
if not argspec:
argspec = '(...)'
@@ -1089,7 +1147,7 @@ class HTMLDoc(Doc):
doc = doc and '<dd><span class="code">%s</span></dd>' % doc
return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
def docdata(self, object, name=None, mod=None, cl=None):
def docdata(self, object, name=None, mod=None, cl=None, *ignored):
"""Produce html documentation for a data descriptor."""
results = []
push = results.append
@@ -1200,7 +1258,7 @@ class TextDoc(Doc):
entry, modname, c, prefix + ' ')
return result
def docmodule(self, object, name=None, mod=None):
def docmodule(self, object, name=None, mod=None, *ignored):
"""Produce text documentation for a given module object."""
name = object.__name__ # ignore the passed-in name
synop, desc = splitdoc(getdoc(object))
@@ -1384,7 +1442,7 @@ location listed above.
push(self.docdata(value, name, mod))
else:
push(self.document(value,
name, mod, object))
name, mod, object, homecls))
return attrs
def spilldescriptors(msg, attrs, predicate):
@@ -1459,23 +1517,43 @@ location listed above.
"""Format an argument default value as text."""
return '=' + self.repr(object)
def docroutine(self, object, name=None, mod=None, cl=None):
def docroutine(self, object, name=None, mod=None, cl=None, homecls=None):
"""Produce text documentation for a function or method object."""
realname = object.__name__
name = name or realname
if homecls is None:
homecls = cl
note = ''
skipdocs = 0
skipdocs = False
imfunc = None
if _is_bound_method(object):
imclass = object.__self__.__class__
if cl:
if imclass is not cl:
note = ' from ' + classname(imclass, mod)
imself = object.__self__
if imself is cl:
imfunc = getattr(object, '__func__', None)
elif inspect.isclass(imself):
note = ' class method of %s' % classname(imself, mod)
else:
if object.__self__ is not None:
note = ' method of %s instance' % classname(
object.__self__.__class__, mod)
else:
note = ' unbound %s method' % classname(imclass,mod)
note = ' method of %s instance' % classname(
imself.__class__, mod)
elif (inspect.ismethoddescriptor(object) or
inspect.ismethodwrapper(object)):
try:
objclass = object.__objclass__
except AttributeError:
pass
else:
if cl is None:
note = ' unbound %s method' % classname(objclass, mod)
elif objclass is not homecls:
note = ' from ' + classname(objclass, mod)
else:
imfunc = object
if inspect.isfunction(imfunc) and homecls is not None and (
imfunc.__module__ != homecls.__module__ or
imfunc.__qualname__ != homecls.__qualname__ + '.' + realname):
pname = parentname(imfunc, mod)
if pname:
note = ' from %s' % pname
if (inspect.iscoroutinefunction(object) or
inspect.isasyncgenfunction(object)):
@@ -1486,8 +1564,11 @@ location listed above.
if name == realname:
title = self.bold(realname)
else:
if cl and inspect.getattr_static(cl, realname, []) is object:
skipdocs = 1
if (cl is not None and
inspect.getattr_static(cl, realname, []) is object):
skipdocs = True
if note.startswith(' from '):
note = ''
title = self.bold(name) + ' = ' + realname
argspec = None
@@ -1503,7 +1584,8 @@ location listed above.
# XXX lambda's won't usually have func_annotations['return']
# since the syntax doesn't support but it is possible.
# So removing parentheses isn't truly safe.
argspec = argspec[1:-1] # remove parentheses
if not object.__annotations__:
argspec = argspec[1:-1] # remove parentheses
if not argspec:
argspec = '(...)'
decl = asyncqualifier + title + argspec + note
@@ -1514,7 +1596,7 @@ location listed above.
doc = getdoc(object) or ''
return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
def docdata(self, object, name=None, mod=None, cl=None):
def docdata(self, object, name=None, mod=None, cl=None, *ignored):
"""Produce text documentation for a data descriptor."""
results = []
push = results.append
@@ -1530,7 +1612,8 @@ location listed above.
docproperty = docdata
def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
def docother(self, object, name=None, mod=None, parent=None, *ignored,
maxlen=None, doc=None):
"""Produce text documentation for a data object."""
repr = self.repr(object)
if maxlen:
@@ -2065,7 +2148,7 @@ has the same effect as typing a particular string at the help> prompt.
elif request in self.symbols: self.showsymbol(request)
elif request in ['True', 'False', 'None']:
# special case these keywords since they are objects too
doc(eval(request), 'Help on %s:', is_cli=is_cli)
doc(eval(request), 'Help on %s:', output=self._output, is_cli=is_cli)
elif request in self.keywords: self.showtopic(request)
elif request in self.topics: self.showtopic(request)
elif request: doc(request, 'Help on %s:', output=self._output, is_cli=is_cli)
@@ -2075,20 +2158,22 @@ has the same effect as typing a particular string at the help> prompt.
self.output.write('\n')
def intro(self):
self.output.write('''
Welcome to Python {0}'s help utility!
If this is your first time using Python, you should definitely check out
the tutorial on the internet at https://docs.python.org/{0}/tutorial/.
self.output.write('''\
Welcome to Python {0}'s help utility! If this is your first time using
Python, you should definitely check out the tutorial at
https://docs.python.org/{0}/tutorial/.
Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules. To quit this help utility and
return to the interpreter, just type "quit".
Python programs and using Python modules. To get a list of available
modules, keywords, symbols, or topics, enter "modules", "keywords",
"symbols", or "topics".
To get a list of available modules, keywords, symbols, or topics, type
"modules", "keywords", "symbols", or "topics". Each module also comes
with a one-line summary of what it does; to list the modules whose name
or summary contain a given string such as "spam", type "modules spam".
Each module also comes with a one-line summary of what it does; to list
the modules whose name or summary contain a given string such as "spam",
enter "modules spam".
To quit this help utility and return to the interpreter,
enter "q" or "quit".
'''.format('%d.%d' % sys.version_info[:2]))
def list(self, items, columns=4, width=80):
@@ -2156,7 +2241,11 @@ module "pydoc_data.topics" could not be found.
text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n'
wrapped_text = textwrap.wrap(text, 72)
doc += '\n%s\n' % '\n'.join(wrapped_text)
pager(doc)
if self._output is None:
pager(doc)
else:
self.output.write(doc)
def _gettopic(self, topic, more_xrefs=''):
"""Return unbuffered tuple of (topic, xrefs).
@@ -2408,6 +2497,7 @@ def _start_server(urlhandler, hostname, port):
threading.Thread.__init__(self)
self.serving = False
self.error = None
self.docserver = None
def run(self):
"""Start the server."""
@@ -2440,9 +2530,9 @@ def _start_server(urlhandler, hostname, port):
thread = ServerThread(urlhandler, hostname, port)
thread.start()
# Wait until thread.serving is True to make sure we are
# really up before returning.
while not thread.error and not thread.serving:
# Wait until thread.serving is True and thread.docserver is set
# to make sure we are really up before returning.
while not thread.error and not (thread.serving and thread.docserver):
time.sleep(.01)
return thread