diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2026-09-03 09:42:53 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2026-09-03 09:42:53 +0100 |
| commit | 1a8f18541eef8761a709e44708758a4c08b50a15 (patch) | |
| tree | 59331c717ca730432093402e46bbe6cc27c381be /docs | |
| parent | c513597761d6fc06690b5b7cf10dfb7ab05815d0 (diff) | |
| parent | 4061c0e95c6e2736926ab8723606cddf582f58e6 (diff) | |
| download | qemu-1a8f18541eef8761a709e44708758a4c08b50a15.tar.gz qemu-1a8f18541eef8761a709e44708758a4c08b50a15.zip | |
Merge tag 'python-pull-request' of https://gitlab.com/jsnow/qemu into staging
python
upgrade to py312
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEE+ber27ys35W+dsvQfe+BBqr8OQ4FAmqYepEACgkQfe+BBqr8
# OQ6Nyg//SFe2COs76DIzWWTN21N/wo4pHAf6Q0nGGj2NKiPozN0aIAcKA9mw8ZXo
# 6HQTjMJKOq4jnL9pYLNS2MzrhiJrvrR0gBymi0aD93EOAMtqXcLxgaCnpI4wFu8v
# wosIehLduYMytrb80aY8oCbUOl+uTPOYHuDtUc7msBV5iqhFg56emjvOh7B+5SuE
# iKc6ivljUVxoVat3pzKSZsxbVd+iYz3UI8cBPa8ISNkfxgCjUw/+t6cm3fBj+v8u
# q0U2qVBfvMH6wPQ7qA+VZvwnf7UgTymbprGko17EkPZwgtKzM+k2Lr75GjfwLHx5
# i7sjKu7doWfRa7/+bNyYj+lZtCAcGJGZu6yuIE6vBj6eBB8LxGbw/zLU+p5Q+QJe
# +np4dFLkK2rlBRNrg4o/66rCWO/b97F6GBtVOoNx44fWmXZfuKJxh0F6FCpvPvlf
# fiAEHiSNmfmUXIeFGgq3OcP4ZB6BIGlHWA+F4U7gn1ZxGrtvZDImRdy0Qj2IjsL0
# lwBXSdS9FgX/lOe2oOGScZIepJsVhMVZ7y+u4g+//GLjLPO2JGLh3oZZdDXa6af8
# N//steftVLII0JWTB5z+6Hv3A5ek9AxiVSPPYLpTGcvp1Cgni+5BdiGqPs5554qC
# Yh5/F0aafIJsMDSs9sO6U4X46DYp8/DSfJwr3Vn+Y9SSVgdSGlU=
# =QZ+f
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Sep 2 20:35:45 2026 BST
# gpg: using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [full]
# Primary key fingerprint: FAEB 9711 A12C F475 812F 18F2 88A9 064D 1835 61EB
# Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76 CBD0 7DEF 8106 AAFC 390E
* tag 'python-pull-request' of https://gitlab.com/jsnow/qemu:
sphinx: drop qapidoc back-compat overboiled spaghetti dinner
sphinx: drop fakedbusdoc
sphinx: require sphinx 7.2.6
python: remove stale setup.cfg options
python: remove distutils workarounds
python: allow mypy to run as the current python version
python: fix license configuration
python: upgrade to Python3.12+
qapi: update type hint for objects_seen
tests: update emsdk-wasm64-cross
tests: add Python3.12 to centos9.docker
tests: re-add opencv2 and numpy dependencies
tests: drop python3-devel mapping
tests: update netbsd dependencies
tests: update libvirt-ci, lcitool
tests: update vm tests to prefer locally-built QEMU
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/conf.py | 11 | ||||
| -rw-r--r-- | docs/interop/dbus-display.rst | 14 | ||||
| -rw-r--r-- | docs/interop/dbus-vmstate.rst | 14 | ||||
| -rw-r--r-- | docs/interop/dbus-vnc.rst | 14 | ||||
| -rw-r--r-- | docs/requirements.txt | 2 | ||||
| -rw-r--r-- | docs/sphinx/compat.py | 230 | ||||
| -rw-r--r-- | docs/sphinx/fakedbusdoc.py | 30 | ||||
| -rw-r--r-- | docs/sphinx/qapi_domain.py | 53 |
8 files changed, 35 insertions, 333 deletions
diff --git a/docs/conf.py b/docs/conf.py index 7e35d2158d..914bae67d9 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,14 +51,15 @@ sys.path.insert(0, os.path.join(qemu_docdir, "../scripts")) # If your documentation needs a minimal Sphinx version, state it here. # -# 3.4.3 is the oldest version of Sphinx that ships on a platform we +# 7.2.6 is the oldest version of Sphinx that ships on a platform we # pledge build support for. -needs_sphinx = '3.4.3' +needs_sphinx = '7.2.6' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ + 'dbusdoc', 'depfile', 'hxtool', 'kerneldoc', @@ -67,12 +68,6 @@ extensions = [ 'qmp_lexer', ] -if sphinx.version_info[:3] > (4, 0, 0): - tags.add('sphinx4') - extensions += ['dbusdoc'] -else: - extensions += ['fakedbusdoc'] - # Add any paths that contain templates here, relative to this directory. templates_path = [os.path.join(qemu_docdir, '_templates')] diff --git a/docs/interop/dbus-display.rst b/docs/interop/dbus-display.rst index 87648e91dc..c87a04c969 100644 --- a/docs/interop/dbus-display.rst +++ b/docs/interop/dbus-display.rst @@ -18,16 +18,4 @@ QEMU also implements the standard interfaces, such as :local: :depth: 1 -.. only:: sphinx4 - - .. dbus-doc:: ui/dbus-display1.xml - -.. only:: not sphinx4 - - .. warning:: - Sphinx 4 is required to build D-Bus documentation. - - This is the content of ``ui/dbus-display1.xml``: - - .. literalinclude:: ../../ui/dbus-display1.xml - :language: xml +.. dbus-doc:: ui/dbus-display1.xml diff --git a/docs/interop/dbus-vmstate.rst b/docs/interop/dbus-vmstate.rst index 5fb3f279e2..5f8c6d125d 100644 --- a/docs/interop/dbus-vmstate.rst +++ b/docs/interop/dbus-vmstate.rst @@ -23,16 +23,4 @@ dbus-vmstate object can be configured with the expected list of helpers by setting its ``id-list`` property, with a comma-separated ``Id`` list. -.. only:: sphinx4 - - .. dbus-doc:: backends/dbus-vmstate1.xml - -.. only:: not sphinx4 - - .. warning:: - Sphinx 4 is required to build D-Bus documentation. - - This is the content of ``backends/dbus-vmstate1.xml``: - - .. literalinclude:: ../../backends/dbus-vmstate1.xml - :language: xml +.. dbus-doc:: backends/dbus-vmstate1.xml diff --git a/docs/interop/dbus-vnc.rst b/docs/interop/dbus-vnc.rst index d2b77978f6..5ea4fd5718 100644 --- a/docs/interop/dbus-vnc.rst +++ b/docs/interop/dbus-vnc.rst @@ -11,16 +11,4 @@ Objects are exported under ``/org/qemu/Vnc1/``. :local: :depth: 1 -.. only:: sphinx4 - - .. dbus-doc:: tools/qemu-vnc/qemu-vnc1.xml - -.. only:: not sphinx4 - - .. warning:: - Sphinx 4 is required to build D-Bus documentation. - - This is the content of ``tools/qemu-vnc/qemu-vnc1.xml``: - - .. literalinclude:: ../../tools/qemu-vnc/qemu-vnc1.xml - :language: xml +.. dbus-doc:: tools/qemu-vnc/qemu-vnc1.xml diff --git a/docs/requirements.txt b/docs/requirements.txt index 87f7afcb2e..c10c4cf7c9 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ # Used by readthedocs.io # Should be in sync with the "installed" key of pythondeps.toml -sphinx==6.2.1 +sphinx==7.2.6 sphinx_rtd_theme==1.2.2 diff --git a/docs/sphinx/compat.py b/docs/sphinx/compat.py deleted file mode 100644 index 9cf7fe006e..0000000000 --- a/docs/sphinx/compat.py +++ /dev/null @@ -1,230 +0,0 @@ -""" -Sphinx cross-version compatibility goop -""" - -import re -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Optional, - Type, -) - -from docutils import nodes -from docutils.nodes import Element, Node, Text -from docutils.statemachine import StringList - -import sphinx -from sphinx import addnodes, util -from sphinx.directives import ObjectDescription -from sphinx.environment import BuildEnvironment -from sphinx.roles import XRefRole -from sphinx.util import docfields -from sphinx.util.docutils import ( - ReferenceRole, - SphinxDirective, - switch_source_input, -) -from sphinx.util.typing import TextlikeNode - - -MAKE_XREF_WORKAROUND = sphinx.version_info[:3] < (4, 1, 0) - - -SpaceNode: Callable[[str], Node] -KeywordNode: Callable[[str, str], Node] - -if sphinx.version_info[:3] >= (4, 0, 0): - SpaceNode = addnodes.desc_sig_space - KeywordNode = addnodes.desc_sig_keyword -else: - SpaceNode = Text - KeywordNode = addnodes.desc_annotation - - -def nested_parse_with_titles( - directive: SphinxDirective, content_node: Element -) -> None: - """ - This helper preserves error parsing context across sphinx versions. - """ - - # necessary so that the child nodes get the right source/line set - content_node.document = directive.state.document - - try: - # Modern sphinx (6.2.0+) supports proper offsetting for - # nested parse error context management - util.nodes.nested_parse_with_titles( - directive.state, - directive.content, - content_node, - content_offset=directive.content_offset, - ) - except TypeError: - # No content_offset argument. Fall back to SSI method. - with switch_source_input(directive.state, directive.content): - util.nodes.nested_parse_with_titles( - directive.state, directive.content, content_node - ) - - -# ########################################### -# xref compatibility hacks for Sphinx < 4.1 # -# ########################################### - -# When we require >= Sphinx 4.1, the following function and the -# subsequent 3 compatibility classes can be removed. Anywhere in -# qapi_domain that uses one of these Compat* types can be switched to -# using the garden-variety lib-provided classes with no trickery. - - -def _compat_make_xref( # pylint: disable=unused-argument - self: sphinx.util.docfields.Field, - rolename: str, - domain: str, - target: str, - innernode: Type[TextlikeNode] = addnodes.literal_emphasis, - contnode: Optional[Node] = None, - env: Optional[BuildEnvironment] = None, - inliner: Any = None, - location: Any = None, -) -> Node: - """ - Compatibility workaround for Sphinx versions prior to 4.1.0. - - Older sphinx versions do not use the domain's XRefRole for parsing - and formatting cross-references, so we need to perform this magick - ourselves to avoid needing to write the parser/formatter in two - separate places. - - This workaround isn't brick-for-brick compatible with modern Sphinx - versions, because we do not have access to the parent directive's - state during this parsing like we do in more modern versions. - - It's no worse than what pre-Sphinx 4.1.0 does, so... oh well! - """ - - # Yes, this function is gross. Pre-4.1 support is a miracle. - # pylint: disable=too-many-locals - - assert env - # Note: Sphinx's own code ignores the type warning here, too. - if not rolename: - return contnode or innernode(target, target) # type: ignore[call-arg] - - # Get the role instance, but don't *execute it* - we lack the - # correct state to do so. Instead, we'll just use its public - # methods to do our reference formatting, and emulate the rest. - role = env.get_domain(domain).roles[rolename] - assert isinstance(role, XRefRole) - - # XRefRole features not supported by this compatibility shim; - # these were not supported in Sphinx 3.x either, so nothing of - # value is really lost. - assert not target.startswith("!") - assert not re.match(ReferenceRole.explicit_title_re, target) - assert not role.lowercase - assert not role.fix_parens - - # Code below based mostly on sphinx.roles.XRefRole; run() and - # create_xref_node() - options = { - "refdoc": env.docname, - "refdomain": domain, - "reftype": rolename, - "refexplicit": False, - "refwarn": role.warn_dangling, - } - refnode = role.nodeclass(target, **options) - title, target = role.process_link(env, refnode, False, target, target) - refnode["reftarget"] = target - classes = ["xref", domain, f"{domain}-{rolename}"] - refnode += role.innernodeclass(target, title, classes=classes) - - # This is the very gross part of the hack. Normally, - # result_nodes takes a document object to which we would pass - # self.inliner.document. Prior to Sphinx 4.1, we don't *have* an - # inliner to pass, so we have nothing to pass here. However, the - # actual implementation of role.result_nodes in this case - # doesn't actually use that argument, so this winds up being - # ... fine. Rest easy at night knowing this code only runs under - # old versions of Sphinx, so at least it won't change in the - # future on us and lead to surprising new failures. - # Gross, I know. - result_nodes, _messages = role.result_nodes( - None, # type: ignore - env, - refnode, - is_ref=True, - ) - return nodes.inline(target, "", *result_nodes) - - -class CompatField(docfields.Field): - if MAKE_XREF_WORKAROUND: - make_xref = _compat_make_xref - - -class CompatGroupedField(docfields.GroupedField): - if MAKE_XREF_WORKAROUND: - make_xref = _compat_make_xref - - -class CompatTypedField(docfields.TypedField): - if MAKE_XREF_WORKAROUND: - make_xref = _compat_make_xref - - -# ################################################################ -# Nested parsing error location fix for Sphinx 5.3.0 < x < 6.2.0 # -# ################################################################ - -# When we require Sphinx 4.x, the TYPE_CHECKING hack where we avoid -# subscripting ObjectDescription at runtime can be removed in favor of -# just always subscripting the class. - -# When we require Sphinx > 6.2.0, the rest of this compatibility hack -# can be dropped and QAPIObject can just inherit directly from -# ObjectDescription[Signature]. - -SOURCE_LOCATION_FIX = (5, 3, 0) <= sphinx.version_info[:3] < (6, 2, 0) - -Signature = str - - -if TYPE_CHECKING: - _BaseClass = ObjectDescription[Signature] -else: - _BaseClass = ObjectDescription - - -class ParserFix(_BaseClass): - - _temp_content: StringList - _temp_offset: int - _temp_node: Optional[addnodes.desc_content] - - def before_content(self) -> None: - # Work around a sphinx bug and parse the content ourselves. - self._temp_content = self.content - self._temp_offset = self.content_offset - self._temp_node = None - - if SOURCE_LOCATION_FIX: - self._temp_node = addnodes.desc_content() - self.state.nested_parse( - self.content, self.content_offset, self._temp_node - ) - # Sphinx will try to parse the content block itself, - # Give it nothingness to parse instead. - self.content = StringList() - self.content_offset = 0 - - def transform_content(self, content_node: addnodes.desc_content) -> None: - # Sphinx workaround: Inject our parsed content and restore state. - if self._temp_node: - content_node += self._temp_node.children - self.content = self._temp_content - self.content_offset = self._temp_offset diff --git a/docs/sphinx/fakedbusdoc.py b/docs/sphinx/fakedbusdoc.py deleted file mode 100644 index 2d2e6ef640..0000000000 --- a/docs/sphinx/fakedbusdoc.py +++ /dev/null @@ -1,30 +0,0 @@ -# D-Bus XML documentation extension, compatibility gunk for <sphinx4 -# -# Copyright (C) 2021, Red Hat Inc. -# -# SPDX-License-Identifier: LGPL-2.1-or-later -# -# Author: Marc-André Lureau <marcandre.lureau@redhat.com> -"""dbus-doc is a Sphinx extension that provides documentation from D-Bus XML.""" - -from docutils.parsers.rst import Directive -from sphinx.application import Sphinx -from typing import Any, Dict - - -class FakeDBusDocDirective(Directive): - has_content = True - required_arguments = 1 - - def run(self): - return [] - - -def setup(app: Sphinx) -> Dict[str, Any]: - """Register a fake dbus-doc directive with Sphinx""" - app.add_directive("dbus-doc", FakeDBusDocDirective) - - return dict( - parallel_read_safe = True, - parallel_write_safe = True - ) diff --git a/docs/sphinx/qapi_domain.py b/docs/sphinx/qapi_domain.py index f561dc465f..159857113a 100644 --- a/docs/sphinx/qapi_domain.py +++ b/docs/sphinx/qapi_domain.py @@ -30,20 +30,10 @@ from sphinx.domains import ( ) from sphinx.locale import _, __ from sphinx.roles import XRefRole -from sphinx.util import logging +from sphinx.util import docfields, logging from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import make_id, make_refnode -from compat import ( - CompatField, - CompatGroupedField, - CompatTypedField, - KeywordNode, - ParserFix, - Signature, - SpaceNode, -) - if TYPE_CHECKING: from typing import ( @@ -157,7 +147,10 @@ class QAPIXRefRole(XRefRole): return results, [] -class QAPIDescription(ParserFix): +Signature = str + + +class QAPIDescription(ObjectDescription[Signature]): """ Generic QAPI description. @@ -315,7 +308,7 @@ class QAPIObject(QAPIDescription): doc_field_types = [ # :feat name: descr - CompatGroupedField( + docfields.GroupedField( "feature", label=_("Features"), names=("feat",), @@ -327,8 +320,8 @@ class QAPIObject(QAPIDescription): """Return a prefix to put before the object name in the signature.""" assert self.objtype return [ - KeywordNode("", self.objtype.title()), - SpaceNode(" "), + addnodes.desc_sig_keyword("", self.objtype.title()), + addnodes.desc_sig_space(" "), ] def get_signature_suffix(self) -> List[nodes.Node]: @@ -337,7 +330,7 @@ class QAPIObject(QAPIDescription): if "since" in self.options: ret += [ - SpaceNode(" "), + addnodes.desc_sig_space(" "), addnodes.desc_sig_element( "", f"(Since: {self.options['since']})" ), @@ -376,7 +369,7 @@ class QAPIObject(QAPIDescription): return sig - def _add_infopips(self, contentnode: addnodes.desc_content) -> None: + def _add_infopips(self, content_node: addnodes.desc_content) -> None: # Add various eye-catches and things that go below the signature # bar, but precede the user-defined content. infopips = nodes.container() @@ -420,7 +413,7 @@ class QAPIObject(QAPIDescription): ) if infopips.children: - contentnode.insert(0, infopips) + content_node.insert(0, infopips) def _validate_field(self, field: nodes.field) -> None: """Validate field lists in this QAPI Object Description.""" @@ -470,7 +463,17 @@ class QAPIObject(QAPIDescription): ) logger.warning(msg, location=field) - def transform_content(self, content_node: addnodes.desc_content) -> None: + def transform_content( + self, + # Sphinx changed the name of the content_node parameter + # sometime after Sphinx 7.2.6, so no matter which name we + # choose, either our minimum tests or our bleeding edge tests + # will complain about the parameter rename. Use the eventual + # name and silence the error for our minreq tests. + # + # pylint: disable=arguments-renamed + content_node: addnodes.desc_content + ) -> None: # This hook runs after before_content and the nested parse, but # before the DocFieldTransformer is executed. super().transform_content(content_node) @@ -485,7 +488,7 @@ class QAPIObject(QAPIDescription): self._validate_field(field) -class SpecialTypedField(CompatTypedField): +class SpecialTypedField(docfields.TypedField): def make_field(self, *args: Any, **kwargs: Any) -> nodes.field: ret = super().make_field(*args, **kwargs) @@ -518,14 +521,14 @@ class QAPICommand(QAPIObject): can_collapse=False, ), # :error: descr - CompatField( + docfields.Field( "error", label=_("Errors"), names=("error", "errors"), has_arg=False, ), # :return TypeName: descr - CompatGroupedField( + docfields.GroupedField( "returnvalue", label=_("Return"), rolename="type", @@ -533,7 +536,7 @@ class QAPICommand(QAPIObject): can_collapse=True, ), # :return-nodesc: TypeName - CompatField( + docfields.Field( "returnvalue", label=_("Return"), names=("return-nodesc",), @@ -551,7 +554,7 @@ class QAPIEnum(QAPIObject): doc_field_types.extend( [ # :value name: descr - CompatGroupedField( + docfields.GroupedField( "value", label=_("Values"), names=("value",), @@ -568,7 +571,7 @@ class QAPIAlternate(QAPIObject): doc_field_types.extend( [ # :alt type name: descr - CompatTypedField( + docfields.TypedField( "alternative", label=_("Alternatives"), names=("alt",), |
