mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
[3.13] GH-121970: Extract `availability
` into a new extension (GH-125082) (#125237)
(cherry picked from commit cbfd392479
)
This commit is contained in:
parent
288a0692ed
commit
abb01fd938
3 changed files with 126 additions and 76 deletions
|
@ -21,6 +21,7 @@ from pyspecific import SOURCE_URI
|
||||||
|
|
||||||
extensions = [
|
extensions = [
|
||||||
'audit_events',
|
'audit_events',
|
||||||
|
'availability',
|
||||||
'c_annotations',
|
'c_annotations',
|
||||||
'glossary_search',
|
'glossary_search',
|
||||||
'lexers',
|
'lexers',
|
||||||
|
|
125
Doc/tools/extensions/availability.py
Normal file
125
Doc/tools/extensions/availability.py
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
"""Support for documenting platform availability"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from docutils import nodes
|
||||||
|
from sphinx import addnodes
|
||||||
|
from sphinx.util import logging
|
||||||
|
from sphinx.util.docutils import SphinxDirective
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from sphinx.application import Sphinx
|
||||||
|
from sphinx.util.typing import ExtensionMetadata
|
||||||
|
|
||||||
|
logger = logging.getLogger("availability")
|
||||||
|
|
||||||
|
# known platform, libc, and threading implementations
|
||||||
|
_PLATFORMS = frozenset({
|
||||||
|
"AIX",
|
||||||
|
"Android",
|
||||||
|
"BSD",
|
||||||
|
"DragonFlyBSD",
|
||||||
|
"Emscripten",
|
||||||
|
"FreeBSD",
|
||||||
|
"GNU/kFreeBSD",
|
||||||
|
"iOS",
|
||||||
|
"Linux",
|
||||||
|
"macOS",
|
||||||
|
"NetBSD",
|
||||||
|
"OpenBSD",
|
||||||
|
"POSIX",
|
||||||
|
"Solaris",
|
||||||
|
"Unix",
|
||||||
|
"VxWorks",
|
||||||
|
"WASI",
|
||||||
|
"Windows",
|
||||||
|
})
|
||||||
|
_LIBC = frozenset({
|
||||||
|
"BSD libc",
|
||||||
|
"glibc",
|
||||||
|
"musl",
|
||||||
|
})
|
||||||
|
_THREADING = frozenset({
|
||||||
|
# POSIX platforms with pthreads
|
||||||
|
"pthreads",
|
||||||
|
})
|
||||||
|
KNOWN_PLATFORMS = _PLATFORMS | _LIBC | _THREADING
|
||||||
|
|
||||||
|
|
||||||
|
class Availability(SphinxDirective):
|
||||||
|
has_content = True
|
||||||
|
required_arguments = 1
|
||||||
|
optional_arguments = 0
|
||||||
|
final_argument_whitespace = True
|
||||||
|
|
||||||
|
def run(self) -> list[nodes.container]:
|
||||||
|
title = "Availability"
|
||||||
|
refnode = addnodes.pending_xref(
|
||||||
|
title,
|
||||||
|
nodes.inline(title, title, classes=["xref", "std", "std-ref"]),
|
||||||
|
refdoc=self.env.docname,
|
||||||
|
refdomain="std",
|
||||||
|
refexplicit=True,
|
||||||
|
reftarget="availability",
|
||||||
|
reftype="ref",
|
||||||
|
refwarn=True,
|
||||||
|
)
|
||||||
|
sep = nodes.Text(": ")
|
||||||
|
parsed, msgs = self.state.inline_text(self.arguments[0], self.lineno)
|
||||||
|
pnode = nodes.paragraph(title, "", refnode, sep, *parsed, *msgs)
|
||||||
|
self.set_source_info(pnode)
|
||||||
|
cnode = nodes.container("", pnode, classes=["availability"])
|
||||||
|
self.set_source_info(cnode)
|
||||||
|
if self.content:
|
||||||
|
self.state.nested_parse(self.content, self.content_offset, cnode)
|
||||||
|
self.parse_platforms()
|
||||||
|
|
||||||
|
return [cnode]
|
||||||
|
|
||||||
|
def parse_platforms(self) -> dict[str, str | bool]:
|
||||||
|
"""Parse platform information from arguments
|
||||||
|
|
||||||
|
Arguments is a comma-separated string of platforms. A platform may
|
||||||
|
be prefixed with "not " to indicate that a feature is not available.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
.. availability:: Windows, Linux >= 4.2, not WASI
|
||||||
|
|
||||||
|
Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not
|
||||||
|
parsed into separate tokens.
|
||||||
|
"""
|
||||||
|
platforms = {}
|
||||||
|
for arg in self.arguments[0].rstrip(".").split(","):
|
||||||
|
arg = arg.strip()
|
||||||
|
platform, _, version = arg.partition(" >= ")
|
||||||
|
if platform.startswith("not "):
|
||||||
|
version = False
|
||||||
|
platform = platform.removeprefix("not ")
|
||||||
|
elif not version:
|
||||||
|
version = True
|
||||||
|
platforms[platform] = version
|
||||||
|
|
||||||
|
if unknown := set(platforms).difference(KNOWN_PLATFORMS):
|
||||||
|
logger.warning(
|
||||||
|
"Unknown platform%s or syntax '%s' in '.. availability:: %s', "
|
||||||
|
"see %s:KNOWN_PLATFORMS for a set of known platforms.",
|
||||||
|
"s" if len(platforms) != 1 else "",
|
||||||
|
" ".join(sorted(unknown)),
|
||||||
|
self.arguments[0],
|
||||||
|
__file__,
|
||||||
|
)
|
||||||
|
|
||||||
|
return platforms
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app: Sphinx) -> ExtensionMetadata:
|
||||||
|
app.add_directive("availability", Availability)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"version": "1.0",
|
||||||
|
"parallel_read_safe": True,
|
||||||
|
"parallel_write_safe": True,
|
||||||
|
}
|
|
@ -24,7 +24,6 @@ from sphinx.builders import Builder
|
||||||
from sphinx.domains.changeset import VersionChange, versionlabels, versionlabel_classes
|
from sphinx.domains.changeset import VersionChange, versionlabels, versionlabel_classes
|
||||||
from sphinx.domains.python import PyFunction, PyMethod, PyModule
|
from sphinx.domains.python import PyFunction, PyMethod, PyModule
|
||||||
from sphinx.locale import _ as sphinx_gettext
|
from sphinx.locale import _ as sphinx_gettext
|
||||||
from sphinx.util import logging
|
|
||||||
from sphinx.util.docutils import SphinxDirective
|
from sphinx.util.docutils import SphinxDirective
|
||||||
from sphinx.writers.text import TextWriter, TextTranslator
|
from sphinx.writers.text import TextWriter, TextTranslator
|
||||||
from sphinx.util.display import status_iterator
|
from sphinx.util.display import status_iterator
|
||||||
|
@ -108,80 +107,6 @@ class ImplementationDetail(SphinxDirective):
|
||||||
return [pnode]
|
return [pnode]
|
||||||
|
|
||||||
|
|
||||||
# Support for documenting platform availability
|
|
||||||
|
|
||||||
class Availability(SphinxDirective):
|
|
||||||
|
|
||||||
has_content = True
|
|
||||||
required_arguments = 1
|
|
||||||
optional_arguments = 0
|
|
||||||
final_argument_whitespace = True
|
|
||||||
|
|
||||||
# known platform, libc, and threading implementations
|
|
||||||
known_platforms = frozenset({
|
|
||||||
"AIX", "Android", "BSD", "DragonFlyBSD", "Emscripten", "FreeBSD",
|
|
||||||
"GNU/kFreeBSD", "Linux", "NetBSD", "OpenBSD", "POSIX", "Solaris",
|
|
||||||
"Unix", "VxWorks", "WASI", "Windows", "macOS", "iOS",
|
|
||||||
# libc
|
|
||||||
"BSD libc", "glibc", "musl",
|
|
||||||
# POSIX platforms with pthreads
|
|
||||||
"pthreads",
|
|
||||||
})
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
availability_ref = ':ref:`Availability <availability>`: '
|
|
||||||
avail_nodes, avail_msgs = self.state.inline_text(
|
|
||||||
availability_ref + self.arguments[0],
|
|
||||||
self.lineno)
|
|
||||||
pnode = nodes.paragraph(availability_ref + self.arguments[0],
|
|
||||||
'', *avail_nodes, *avail_msgs)
|
|
||||||
self.set_source_info(pnode)
|
|
||||||
cnode = nodes.container("", pnode, classes=["availability"])
|
|
||||||
self.set_source_info(cnode)
|
|
||||||
if self.content:
|
|
||||||
self.state.nested_parse(self.content, self.content_offset, cnode)
|
|
||||||
self.parse_platforms()
|
|
||||||
|
|
||||||
return [cnode]
|
|
||||||
|
|
||||||
def parse_platforms(self):
|
|
||||||
"""Parse platform information from arguments
|
|
||||||
|
|
||||||
Arguments is a comma-separated string of platforms. A platform may
|
|
||||||
be prefixed with "not " to indicate that a feature is not available.
|
|
||||||
|
|
||||||
Example::
|
|
||||||
|
|
||||||
.. availability:: Windows, Linux >= 4.2, not WASI
|
|
||||||
|
|
||||||
Arguments like "Linux >= 3.17 with glibc >= 2.27" are currently not
|
|
||||||
parsed into separate tokens.
|
|
||||||
"""
|
|
||||||
platforms = {}
|
|
||||||
for arg in self.arguments[0].rstrip(".").split(","):
|
|
||||||
arg = arg.strip()
|
|
||||||
platform, _, version = arg.partition(" >= ")
|
|
||||||
if platform.startswith("not "):
|
|
||||||
version = False
|
|
||||||
platform = platform[4:]
|
|
||||||
elif not version:
|
|
||||||
version = True
|
|
||||||
platforms[platform] = version
|
|
||||||
|
|
||||||
unknown = set(platforms).difference(self.known_platforms)
|
|
||||||
if unknown:
|
|
||||||
cls = type(self)
|
|
||||||
logger = logging.getLogger(cls.__qualname__)
|
|
||||||
logger.warning(
|
|
||||||
f"Unknown platform(s) or syntax '{' '.join(sorted(unknown))}' "
|
|
||||||
f"in '.. availability:: {self.arguments[0]}', see "
|
|
||||||
f"{__file__}:{cls.__qualname__}.known_platforms for a set "
|
|
||||||
"known platforms."
|
|
||||||
)
|
|
||||||
|
|
||||||
return platforms
|
|
||||||
|
|
||||||
|
|
||||||
# Support for documenting decorators
|
# Support for documenting decorators
|
||||||
|
|
||||||
class PyDecoratorMixin(object):
|
class PyDecoratorMixin(object):
|
||||||
|
@ -473,7 +398,6 @@ def setup(app):
|
||||||
app.add_role('issue', issue_role)
|
app.add_role('issue', issue_role)
|
||||||
app.add_role('gh', gh_issue_role)
|
app.add_role('gh', gh_issue_role)
|
||||||
app.add_directive('impl-detail', ImplementationDetail)
|
app.add_directive('impl-detail', ImplementationDetail)
|
||||||
app.add_directive('availability', Availability)
|
|
||||||
app.add_directive('deprecated-removed', DeprecatedRemoved)
|
app.add_directive('deprecated-removed', DeprecatedRemoved)
|
||||||
app.add_builder(PydocTopicsBuilder)
|
app.add_builder(PydocTopicsBuilder)
|
||||||
app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
|
app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue