def decorator( callback: event_manager_.CallbackT[event_manager_.EventT_co], ) -> event_manager_.CallbackT[event_manager_.EventT_co]: nonlocal event_type # Avoid resolving forward references in the function's signature if # event_type was explicitly provided as this may lead to errors. if event_type is not None: _assert_is_listener( iter(inspect.signature(callback).parameters.values())) else: signature = reflect.resolve_signature(callback) params = signature.parameters.values() _assert_is_listener(iter(params)) event_param = next(iter(params)) if event_param.annotation is event_param.empty: raise TypeError( "Must provide the event type in the @listen decorator or as a type hint!" ) event_type = event_param.annotation self.subscribe(event_type, callback, _nested=1) return callback
def decorator( callback: event_manager.CallbackT[event_manager.EventT_co], ) -> event_manager.CallbackT[event_manager.EventT_co]: nonlocal event_type signature = reflect.resolve_signature(callback) params = signature.parameters.values() if len(params) != 1: raise TypeError( "Event listener must have exactly one parameter, the event object." ) event_param = next(iter(params)) if event_type is None: if event_param.annotation is event_param.empty: raise TypeError( "Must provide the event type in the @listen decorator or as a type hint!" ) event_type = event_param.annotation self.subscribe(event_type, callback, _nested=1) return callback
def test_handles_NoneType(self): def foo(bar: type(None)) -> type(None): ... signature = reflect.resolve_signature(foo) assert signature.parameters["bar"].annotation is None assert signature.return_annotation is None
def decorator( callback: event_manager_.CallbackT[base_events.EventT], ) -> event_manager_.CallbackT[base_events.EventT]: # Avoid resolving forward references in the function's signature if # event_type was explicitly provided as this may lead to errors. if event_types: _assert_is_listener(iter(inspect.signature(callback).parameters.values())) resolved_types = event_types else: signature = reflect.resolve_signature(callback) params = signature.parameters.values() _assert_is_listener(iter(params)) event_param = next(iter(params)) annotation = event_param.annotation if annotation is event_param.empty: raise TypeError("Must provide the event type in the @listen decorator or as a type hint!") if typing.get_origin(annotation) in _UNIONS: # Resolve the types inside the union resolved_types = typing.get_args(annotation) else: # Just pass back the annotation resolved_types = (annotation,) for resolved_type in resolved_types: self.subscribe(resolved_type, callback, _nested=1) return callback
def test_handles_nested_annotations(self): def foo(bar: typing.Optional[typing.Iterator[int]]): ... signature = reflect.resolve_signature(foo) assert signature.parameters["bar"].annotation == typing.Optional[ typing.Iterator[int]]
def test_handles_mixed_annotations(self): def foo(bar: str, bat: "int"): ... signature = reflect.resolve_signature(foo) assert signature.parameters["bar"].annotation is str assert signature.parameters["bat"].annotation is int assert signature.return_annotation is reflect.EMPTY
def test_handles_forward_annotations(self): def foo(bar: "str", bat: "int") -> "str": ... signature = reflect.resolve_signature(foo) assert signature.parameters["bar"].annotation is str assert signature.parameters["bat"].annotation is int assert signature.return_annotation is str
def test_handles_normal_no_annotations(self): def foo(bar, bat): ... signature = reflect.resolve_signature(foo) assert signature.parameters["bar"].annotation is reflect.EMPTY assert signature.parameters["bat"].annotation is reflect.EMPTY assert signature.return_annotation is reflect.EMPTY
def test_handles_normal_references(self): def foo(bar: str, bat: int) -> str: ... signature = reflect.resolve_signature(foo) assert signature.parameters["bar"].annotation is str assert signature.parameters["bat"].annotation is int assert signature.return_annotation is str
def test_resolve_signature(): foo = object() with mock.patch.object(inspect, "signature") as signature: sig = reflect.resolve_signature(foo) assert sig is signature.return_value signature.assert_called_once_with(foo, eval_str=True)
def test_handles_only_return_annotated(self): def foo(bar, bat) -> str: ... signature = reflect.resolve_signature(foo) assert signature.parameters["bar"].annotation is reflect.EMPTY assert signature.parameters["bat"].annotation is reflect.EMPTY assert signature.return_annotation is str