1- from typing import TypeVar , Generic , get_args
2- import dataclasses
1+ from typing import TypeVar , cast
32
43from docutils import nodes
54from docutils .frontend import get_default_settings
65from docutils .parsers .rst import Parser
76from docutils .utils import new_document
87from sphinx .util import logging
98
10- from dacite import from_dict
11-
129logger = logging .getLogger (__name__ )
1310
1411
@@ -23,10 +20,10 @@ def parse_text_to_nodes(text: str) -> list[nodes.Node]:
2320 return document .children
2421
2522
26- _Node = TypeVar ('_Element' , bound = nodes .Node )
23+ _Element = TypeVar ('_Element' , bound = nodes .Node )
2724
2825
29- def find_parent (node : nodes .Element | None , typ : type [_Node ]) -> _Node | None :
26+ def find_parent (node : nodes .Element | None , typ : type [_Element ]) -> _Element | None :
3027 if node is None or isinstance (node , typ ):
3128 return node
3229 return find_parent (node .parent , typ )
@@ -40,10 +37,10 @@ def find_current_document(node: nodes.Element | None) -> nodes.document | None:
4037 return find_parent (node , nodes .document )
4138
4239
43- def find_first_child (node : nodes .Element , cls : type [_Node ]) -> _Node | None :
40+ def find_first_child (node : nodes .Element , cls : type [_Element ]) -> _Element | None :
4441 if (index := node .first_child_matching_class (cls )) is None :
4542 return None
46- return node [index ] # type: ignore
43+ return cast ( _Element , node [index ])
4744
4845
4946def find_titular_node_upward (node : nodes .Element | None ) -> nodes .Node | None :
@@ -62,52 +59,3 @@ def find_titular_node_upward(node: nodes.Element | None) -> nodes.Node | None:
6259 if para := find_first_child (node , nodes .paragraph ):
6360 return para
6461 return find_titular_node_upward (node .parent )
65-
66-
67- DataT = TypeVar ('DataT' )
68-
69-
70- class TempData (Generic [DataT ]):
71- """A helper class for storing/accessing dataclasses to/from a docutils node."""
72-
73- KEY = 'sphinxnotes-data'
74-
75- @classmethod
76- def _get_data_type (cls ) -> type [DataT ]:
77- """
78- Dynamically extract the actual type of DataT from the class definition.
79-
80- Example: For `class MyHelper(TempData[MyStruct])`, this returns `MyStruct`.
81- """
82- # Access the original base classes (including generic type args)
83- # This attribute is available in Python 3.7+
84- for base in getattr (cls , '__orig_bases__' , []):
85- origin = getattr (base , '__origin__' , None )
86- # Check if this base is the TempData class itself
87- if origin is TempData :
88- args = get_args (base )
89- if args :
90- # Return the first generic argument, which corresponds to DataT
91- return args [0 ]
92- raise TypeError (
93- f'Cannot infer DataT from { cls .__name__ } . '
94- 'Ensure you are subclassing TempData[MyType] rather than using it directly.'
95- )
96-
97- @classmethod
98- def _get_type_name (cls ) -> str :
99- return cls ._get_data_type ().__name__
100-
101- @classmethod
102- def set (cls , node : nodes .Element , data : DataT ) -> None :
103- tempdata = node .setdefault (cls .KEY , {})
104- assert dataclasses .is_dataclass (data )
105- tempdata [cls ._get_type_name ()] = dataclasses .asdict (data ) # type: ignore
106-
107- @classmethod
108- def get (cls , node : nodes .Element ) -> DataT | None :
109- if (tempdata := node .get (cls .KEY )) is None :
110- return None
111- if (data := tempdata .get (cls ._get_type_name ())) is None :
112- return None
113- return from_dict (data_class = cls ._get_data_type (), data = data )
0 commit comments