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
3840from __future__ import annotations
3941
4042import functools
4143import operator
44+ import sys
4245import re
4346from inspect import Parameter , Signature
4447from 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