Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
# Our custom Sphinx extensions are found in Doc/Tools/extensions/
extensions = [
'audit_events',
'availability',
'c_annotations',
'changes',
'glossary_search',
Expand Down
72 changes: 72 additions & 0 deletions Doc/tools/extensions/pyspecific.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from docutils.utils import unescape
from sphinx import addnodes
from sphinx.domains.python import PyFunction, PyMethod, PyModule
from sphinx.util import logging
from sphinx.locale import _ as sphinx_gettext
from sphinx.util.docutils import SphinxDirective

Expand Down Expand Up @@ -90,6 +91,76 @@ def run(self):
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


class PyCoroutineMixin(object):
def handle_signature(self, sig, signode):
ret = super(PyCoroutineMixin, self).handle_signature(sig, signode)
Expand Down Expand Up @@ -260,6 +331,7 @@ def setup(app):
app.add_role('issue', issue_role)
app.add_role('gh', gh_issue_role)
app.add_directive('impl-detail', ImplementationDetail)
app.add_directive('availability', Availability)
app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command)
app.add_object_type('monitoring-event', 'monitoring-event', '%s (monitoring event)', parse_monitoring_event)
Expand Down
Loading