blob: 99e7d8705ca38a0d1cc181cf620ae7bfe7ee9007 [file] [edit]
# noqa: CPY001
# Slightly adapted from CPython's:
# https://github.com/python/cpython/blob/main/Doc/tools/extensions/availability.py
# Copyright (c) PSF
# Licensed under the Python Software Foundation License Version 2.
"""Support for `.. availability:: …` directive, to document platform
availability.
"""
from docutils import nodes
from sphinx.locale import _ as sphinx_gettext
from sphinx.util import logging
from sphinx.util.docutils import SphinxDirective
logger = logging.getLogger(__name__)
_PLATFORMS = frozenset({
"AIX",
"BSD",
"FreeBSD",
"Linux",
"Linux with glibc",
"macOS",
"NetBSD",
"OpenBSD",
"POSIX",
"SunOS",
"UNIX",
"Windows",
})
_LIBC = frozenset({
"glibc",
"musl",
})
KNOWN_PLATFORMS = _PLATFORMS | _LIBC
class Availability(SphinxDirective):
has_content = True
required_arguments = 1
optional_arguments = 0
final_argument_whitespace = True
def run(self):
title = sphinx_gettext("Availability")
sep = nodes.Text(" ")
parsed, msgs = self.state.inline_text(self.arguments[0], self.lineno)
pnode = nodes.paragraph(
title, "", nodes.emphasis(title, title + ":"), 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):
"""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 glibc
"""
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
unknown = set(platforms).difference(KNOWN_PLATFORMS)
if unknown:
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__,
location=self.get_location(),
)
return platforms
def setup(app):
app.add_directive("availability", Availability)
return {"parallel_read_safe": True, "parallel_write_safe": True}