From 0528d9fdcf4e139feb8d4bafe00f2968adf69206 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Sat, 3 Oct 2020 13:10:03 +0300 Subject: [PATCH] doc: patch Sphinx to detect our `@final` for marking classes as `final` Thanks to Dominic Davis-Foster for code & assistance. --- changelog/7780.doc.rst | 1 + doc/en/conf.py | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 changelog/7780.doc.rst diff --git a/changelog/7780.doc.rst b/changelog/7780.doc.rst new file mode 100644 index 00000000000..631873b156e --- /dev/null +++ b/changelog/7780.doc.rst @@ -0,0 +1 @@ +Classes which should not be inherited from are now marked ``final class`` in the API reference. diff --git a/doc/en/conf.py b/doc/en/conf.py index 7e96c5de9fa..86093be28d0 100644 --- a/doc/en/conf.py +++ b/doc/en/conf.py @@ -15,9 +15,10 @@ # # The full version, including alpha/beta/rc tags. # The short X.Y version. +import ast import os import sys -from typing import TYPE_CHECKING +from typing import List from _pytest import __version__ as version @@ -398,3 +399,22 @@ def setup(app: "sphinx.application.Sphinx") -> None: ) configure_logging(app) + + # Make Sphinx mark classes with "final" when decorated with @final. + # We need this because we import final from pytest._compat, not from + # typing (for Python < 3.8 compat), so Sphinx doesn't detect it. + # To keep things simple we accept any `@final` decorator. + # Ref: https://github.com/pytest-dev/pytest/pull/7780 + import sphinx.pycode.ast + import sphinx.pycode.parser + + original_is_final = sphinx.pycode.parser.VariableCommentPicker.is_final + + def patched_is_final(self, decorators: List[ast.expr]) -> bool: + if original_is_final(self, decorators): + return True + return any( + sphinx.pycode.ast.unparse(decorator) == "final" for decorator in decorators + ) + + sphinx.pycode.parser.VariableCommentPicker.is_final = patched_is_final