@@ -19,7 +19,8 @@ class TypedDataKind(enum.Enum):
1919
2020class _ConverterMeta (abc .ABCMeta ):
2121
22- _check_py_type : typing .Mapping [str , typing .Callable [[type ], bool ]] = {}
22+ _check_in_typeann : typing .Mapping [str , typing .Callable [[type ], bool ]] = {}
23+ _check_out_typeann : typing .Mapping [str , typing .Callable [[type ], bool ]] = {}
2324 _from_proto : typing .Mapping [str , typing .Callable ] = {}
2425 _to_proto : typing .Mapping [str , typing .Callable ] = {}
2526 _binding_types : typing .Mapping [str , bool ] = {}
@@ -37,11 +38,23 @@ def __new__(mcls, name, bases, dct, *,
3738 f'registered' )
3839 mcls ._binding_types [binding ] = trigger
3940
40- if binding in mcls ._check_py_type :
41- raise RuntimeError (
42- f'cannot register a second check_python_type implementation '
43- f'for { binding !r} binding' )
44- mcls ._check_py_type [binding ] = getattr (cls , 'check_python_type' )
41+ check_in_typesig = getattr (cls , 'check_input_type_annotation' , None )
42+ if (check_in_typesig is not None and
43+ not getattr (check_in_typesig , '__isabstractmethod__' , False )):
44+ if binding in mcls ._check_in_typeann :
45+ raise RuntimeError (
46+ f'cannot register a second check_input_type_annotation '
47+ f'implementation for { binding !r} binding' )
48+ mcls ._check_in_typeann [binding ] = check_in_typesig
49+
50+ check_out_typesig = getattr (cls , 'check_output_type_annotation' , None )
51+ if (check_out_typesig is not None and
52+ not getattr (check_out_typesig , '__isabstractmethod__' , False )):
53+ if binding in mcls ._check_out_typeann :
54+ raise RuntimeError (
55+ f'cannot register a second check_output_type_annotation '
56+ f'implementation for { binding !r} binding' )
57+ mcls ._check_out_typeann [binding ] = check_out_typesig
4558
4659 if issubclass (cls , InConverter ):
4760 if binding in mcls ._from_proto :
@@ -62,10 +75,6 @@ def __new__(mcls, name, bases, dct, *,
6275
6376class _BaseConverter (metaclass = _ConverterMeta , binding = None ):
6477
65- @abc .abstractclassmethod
66- def check_python_type (cls , pytype : type ) -> bool :
67- pass
68-
6978 @classmethod
7079 def _decode_typed_data (
7180 cls , data : typing .Optional [protos .TypedData ], * ,
@@ -125,6 +134,10 @@ def _decode_trigger_metadata_field(
125134
126135class InConverter (_BaseConverter , binding = None ):
127136
137+ @abc .abstractclassmethod
138+ def check_input_type_annotation (cls , pytype : type ) -> bool :
139+ pass
140+
128141 @abc .abstractclassmethod
129142 def from_proto (cls , data : protos .TypedData , * ,
130143 pytype : typing .Optional [type ],
@@ -134,6 +147,10 @@ def from_proto(cls, data: protos.TypedData, *,
134147
135148class OutConverter (_BaseConverter , binding = None ):
136149
150+ @abc .abstractclassmethod
151+ def check_output_type_annotation (cls , pytype : type ) -> bool :
152+ pass
153+
137154 @abc .abstractclassmethod
138155 def to_proto (cls , obj : typing .Any , * ,
139156 pytype : typing .Optional [type ]) -> protos .TypedData :
@@ -151,12 +168,23 @@ def is_trigger_binding(bind_name: str) -> bool:
151168 raise ValueError (f'unsupported binding type { bind_name !r} ' )
152169
153170
154- def check_type_annotation (binding : str , pytype : type ) -> bool :
171+ def check_input_type_annotation (binding : str , pytype : type ) -> bool :
172+ try :
173+ checker = _ConverterMeta ._check_in_typeann [binding ]
174+ except KeyError :
175+ raise TypeError (
176+ f'{ binding !r} input binding does not have '
177+ f'a corresponding Python type' ) from None
178+
179+ return checker (pytype )
180+
181+
182+ def check_output_type_annotation (binding : str , pytype : type ) -> bool :
155183 try :
156- checker = _ConverterMeta ._check_py_type [binding ]
184+ checker = _ConverterMeta ._check_out_typeann [binding ]
157185 except KeyError :
158186 raise TypeError (
159- f'bind type { binding !r} does not have '
187+ f'{ binding !r} output binding does not have '
160188 f'a corresponding Python type' ) from None
161189
162190 return checker (pytype )
0 commit comments