Skip to content

Commit bcedc6a

Browse files
author
Release Manager
committed
gh-38619: Re-add py3.9 support to sage_autodoc.py This PR corrects the fact the sage_autodoc.py changes needed for sphinx 8 dropped python 3.9 support. This is a consequence of the fact that sphinx 8 has dropped python 3.9. Since we still want to support python 3.9, some support has to be re- introduced. See #38549 (comment) and after. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. URL: #38619 Reported by: François Bissey Reviewer(s): Kwankyu Lee
2 parents 011111c + 57f5d16 commit bcedc6a

File tree

1 file changed

+65
-9
lines changed

1 file changed

+65
-9
lines changed

src/sage_docbuild/ext/sage_autodoc.py

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,15 @@
3333
- Kwankyu Lee (2024-02-14): rebased on Sphinx 7.2.6
3434
3535
- François Bissey (2024-08-24): rebased on Sphinx 8.0.2
36+
37+
- François Bissey (2024-09-10): Tweaks to support python 3.9 (and older sphinx) as well
3638
"""
3739

3840
from __future__ import annotations
3941

4042
import functools
4143
import operator
44+
import sys
4245
import re
4346
from inspect import Parameter, Signature
4447
from typing import TYPE_CHECKING, Any, ClassVar, NewType, TypeVar
@@ -670,7 +673,7 @@ def add_content(self, more_content: StringList | None) -> None:
670673

671674
# add additional content (e.g. from document), if present
672675
if more_content:
673-
for line, src in zip(more_content.data, more_content.items, strict=True):
676+
for line, src in zip(more_content.data, more_content.items):
674677
self.add_line(line, src[0], src[1])
675678

676679
def get_object_members(self, want_all: bool) -> tuple[bool, list[ObjectMember]]:
@@ -1041,7 +1044,7 @@ def add_content(self, more_content: StringList | None) -> None:
10411044
super().add_content(None)
10421045
self.indent = old_indent
10431046
if more_content:
1044-
for line, src in zip(more_content.data, more_content.items, strict=True):
1047+
for line, src in zip(more_content.data, more_content.items):
10451048
self.add_line(line, src[0], src[1])
10461049

10471050
@classmethod
@@ -1576,8 +1579,14 @@ def __init__(self, *args: Any) -> None:
15761579
def can_document_member(
15771580
cls: type[Documenter], member: Any, membername: str, isattr: bool, parent: Any,
15781581
) -> bool:
1579-
return isinstance(member, type) or (
1580-
isattr and isinstance(member, NewType | TypeVar))
1582+
# support both sphinx 8 and py3.9/older sphinx
1583+
try:
1584+
result_bool = isinstance(member, type) or (
1585+
isattr and isinstance(member, NewType | TypeVar))
1586+
except:
1587+
result_bool = isinstance(member, type) or (
1588+
isattr and (inspect.isNewType(member) or isinstance(member, TypeVar)))
1589+
return result_bool
15811590

15821591
def import_object(self, raiseerror: bool = False) -> bool:
15831592
ret = super().import_object(raiseerror)
@@ -1650,7 +1659,12 @@ def import_object(self, raiseerror: bool = False) -> bool:
16501659
# -------------------------------------------------------------------
16511660
else:
16521661
self.doc_as_attr = True
1653-
if isinstance(self.object, NewType | TypeVar):
1662+
# support both sphinx 8 and py3.9/older sphinx
1663+
try:
1664+
test_bool = isinstance(self.object, NewType | TypeVar)
1665+
except:
1666+
test_bool = inspect.isNewType(self.object) or isinstance(self.object, TypeVar)
1667+
if test_bool:
16541668
modname = getattr(self.object, '__module__', self.modname)
16551669
if modname != self.modname and self.modname.startswith(modname):
16561670
bases = self.modname[len(modname):].strip('.').split('.')
@@ -1659,7 +1673,12 @@ def import_object(self, raiseerror: bool = False) -> bool:
16591673
return ret
16601674

16611675
def _get_signature(self) -> tuple[Any | None, str | None, Signature | None]:
1662-
if isinstance(self.object, NewType | TypeVar):
1676+
# support both sphinx 8 and py3.9/older sphinx
1677+
try:
1678+
test_bool = isinstance(self.object, NewType | TypeVar)
1679+
except:
1680+
test_bool = inspect.isNewType(self.object) or isinstance(self.object, TypeVar)
1681+
if test_bool:
16631682
# Suppress signature
16641683
return None, None, None
16651684

@@ -1844,14 +1863,24 @@ def add_directive_header(self, sig: str) -> None:
18441863
self.directivetype = 'attribute'
18451864
super().add_directive_header(sig)
18461865

1847-
if isinstance(self.object, NewType | TypeVar):
1866+
# support both sphinx 8 and py3.9/older sphinx
1867+
try:
1868+
test_bool = isinstance(self.object, NewType | TypeVar)
1869+
except:
1870+
test_bool = inspect.isNewType(self.object) or isinstance(self.object, TypeVar)
1871+
if test_bool:
18481872
return
18491873

18501874
if self.analyzer and '.'.join(self.objpath) in self.analyzer.finals:
18511875
self.add_line(' :final:', sourcename)
18521876

18531877
canonical_fullname = self.get_canonical_fullname()
1854-
if (not self.doc_as_attr and not isinstance(self.object, NewType)
1878+
# support both sphinx 8 and py3.9/older sphinx
1879+
try:
1880+
newtype_test = isinstance(self.object, NewType)
1881+
except:
1882+
newtype_test = inspect.isNewType(self.object)
1883+
if (not self.doc_as_attr and not newtype_test
18551884
and canonical_fullname and self.fullname != canonical_fullname):
18561885
self.add_line(' :canonical: %s' % canonical_fullname, sourcename)
18571886

@@ -1903,6 +1932,28 @@ def get_doc(self) -> list[list[str]] | None:
19031932
if isinstance(self.object, TypeVar):
19041933
if self.object.__doc__ == TypeVar.__doc__:
19051934
return []
1935+
# ------------------------------------------------------------------
1936+
# This section is kept for compatibility with python 3.9
1937+
# see https://github.com/sagemath/sage/pull/38549#issuecomment-2327790930
1938+
if sys.version_info[:2] < (3, 10):
1939+
if inspect.isNewType(self.object) or isinstance(self.object, TypeVar):
1940+
parts = self.modname.strip('.').split('.')
1941+
orig_objpath = self.objpath
1942+
for i in range(len(parts)):
1943+
new_modname = '.'.join(parts[:len(parts) - i])
1944+
new_objpath = parts[len(parts) - i:] + orig_objpath
1945+
try:
1946+
analyzer = ModuleAnalyzer.for_module(new_modname)
1947+
analyzer.analyze()
1948+
key = ('', new_objpath[-1])
1949+
comment = list(analyzer.attr_docs.get(key, []))
1950+
if comment:
1951+
self.objpath = new_objpath
1952+
self.modname = new_modname
1953+
return [comment]
1954+
except PycodeError:
1955+
pass
1956+
# ------------------------------------------------------------------
19061957
if self.doc_as_attr:
19071958
# Don't show the docstring of the class when it is an alias.
19081959
if self.get_variable_comment():
@@ -1966,7 +2017,12 @@ def get_variable_comment(self) -> list[str] | None:
19662017
return None
19672018

19682019
def add_content(self, more_content: StringList | None) -> None:
1969-
if isinstance(self.object, NewType):
2020+
# support both sphinx 8 and py3.9/older sphinx
2021+
try:
2022+
newtype_test = isinstance(self.object, NewType)
2023+
except:
2024+
newtype_test = inspect.isNewType(self.object)
2025+
if newtype_test:
19702026
if self.config.autodoc_typehints_format == "short":
19712027
supertype = restify(self.object.__supertype__, "smart")
19722028
else:

0 commit comments

Comments
 (0)