11from abc import ABC , abstractmethod
2- from typing import Optional , Union , Iterable , Self , Mapping , Final , Callable , _UnionGenericAlias
2+ from typing import Optional , Any , Union , Iterable , Self , Mapping , Final , Callable , _UnionGenericAlias
33
44
55class FormalAnnotation :
@@ -19,7 +19,7 @@ def __init__(self, instance_doc: Optional[str] = None):
1919 def __repr__ (self ) -> str :
2020 return f"<{ self .__class__ .__name__ } >"
2121
22- def __getitem__ (self , resource : any ) -> any :
22+ def __getitem__ (self , resource : Any ) -> Any :
2323 return resource
2424
2525
@@ -31,18 +31,18 @@ class AnnotationFactory(ABC):
3131 Can be used via [] (preferred) or by normal call.
3232 """
3333
34- def __call__ (self , annotation : any ) -> any :
34+ def __call__ (self , annotation : Any ) -> Any :
3535 return self ._create_full_annotation_by (annotation )
3636
37- def __getitem__ (self , annotation : any ) -> any :
37+ def __getitem__ (self , annotation : Any ) -> Any :
3838 return self ._create_full_annotation_by (
3939 Union [annotation ]
4040 if isinstance (annotation , Iterable )
4141 else annotation
4242 )
4343
4444 @abstractmethod
45- def _create_full_annotation_by (self , annotation : any ) -> any :
45+ def _create_full_annotation_by (self , annotation : Any ) -> Any :
4646 """Annotation Creation Method from an input annotation."""
4747
4848
@@ -65,20 +65,25 @@ def __new__(cls, *args, **kwargs):
6565 def __repr__ (self ) -> str :
6666 return '<input_annotation>'
6767
68- def __or__ (self , other : any ) -> Union :
68+ def __or__ (self , other : Any ) -> Union :
6969 return Union [self , other ]
7070
71- def __ror__ (self , other : any ) -> Union :
71+ def __ror__ (self , other : Any ) -> Union :
7272 return Union [other , self ]
7373
7474
75- class CustomAnnotationFactory (AnnotationFactory ):
75+ class AnnotationTemplate (AnnotationFactory ):
7676 """
7777 AnnotationFactory class delegating the construction of another factory's
7878 annotation.
7979
8080 When called, replaces the InputAnnotationAnnotation instances from its
8181 arguments and their subcollections with the input annotation.
82+
83+ Templateizes Union.
84+
85+ Delegates responsibilities to other templates when passing them as
86+ annotations.
8287 """
8388
8489 def __init__ (self , original_factory : Mapping , annotations : Iterable ):
@@ -103,12 +108,16 @@ def __repr__(self) -> str:
103108 arguments = str (self .__recursively_format (self ._annotations )).replace ('\' ' , str ())
104109 )
105110
106- def _create_full_annotation_by (self , annotation : any ) -> any :
111+ def _create_full_annotation_by (self , annotation : Any ) -> Any :
112+ formatted_annotations = self .__get_formatted_annotations_from (self ._annotations , annotation )
113+
107114 return self ._original_factory [
108- * self .__get_formatted_annotations_from (self ._annotations , annotation )
115+ formatted_annotations [0 ]
116+ if len (formatted_annotations ) == 1
117+ else formatted_annotations
109118 ]
110119
111- def __get_formatted_annotations_from (self , annotations : Iterable , replacement_annotation : any ) -> tuple :
120+ def __get_formatted_annotations_from (self , annotations : Iterable , replacement_annotation : Any ) -> tuple :
112121 """
113122 Recursive function to replace element(s) of the input collection (and
114123 its subcollections) equal to the annotation anonation with the input
@@ -120,11 +129,16 @@ def __get_formatted_annotations_from(self, annotations: Iterable, replacement_an
120129 for annotation in annotations :
121130 if isinstance (annotation , InputAnnotationAnnotation ):
122131 annotation = replacement_annotation
132+
123133 elif isinstance (annotation , Iterable ) and not isinstance (annotation , str ):
124134 annotation = self .__get_formatted_annotations_from (
125135 annotation ,
126136 replacement_annotation
127137 )
138+
139+ elif isinstance (annotation , AnnotationTemplate ):
140+ annotation = annotation [replacement_annotation ]
141+
128142 elif type (annotation ) in (Union , _UnionGenericAlias , type (int | float )):
129143 annotation = Union [
130144 * self .__get_formatted_annotations_from (
@@ -156,7 +170,43 @@ def __recursively_format(self, collection: Iterable) -> list:
156170 return formatted_collection
157171
158172
173+ class Special :
174+ """
175+ Annotation class for formally specifying specific behavior for subclasses.
176+
177+ Returns the second input annotation, or Any if none.
178+
179+ Specifies additional behavior for the first annotation.
180+
181+ Implies use like Special[type_for_special_behavior, generic_type] or
182+ Special[type_for_special_behavior].
183+ """
184+
185+ def __class_getitem__ (cls , annotation_resource : tuple [Any , Any ] | Any ) -> Any :
186+ if not isinstance (annotation_resource , Iterable ):
187+ return Any
188+
189+ elif len (annotation_resource ) != 2 :
190+ raise TypeError (
191+ "Special must be used as Special[type_for_special_behavior, generic_type] or Special[type_for_special_behavior]"
192+ )
193+
194+ return annotation_resource [1 ]
195+
196+
197+ number : Final = int | float | complex
198+
159199# Pre-created instance without permanent formal creation of a new one.
160200input_annotation : Final [InputAnnotationAnnotation ] = InputAnnotationAnnotation ()
161201
162- number : Final = int | float | complex
202+
203+ many_or_one : Final [AnnotationTemplate ] = AnnotationTemplate (
204+ Union ,
205+ [input_annotation , AnnotationTemplate (Iterable , [input_annotation ])]
206+ )
207+
208+
209+ method_of : Final [AnnotationTemplate ] = AnnotationTemplate (
210+ Callable ,
211+ [[input_annotation , ...], Any ]
212+ )
0 commit comments