33from collections .abc import Awaitable , Callable , Iterator
44from dataclasses import dataclass , field
55from functools import partial
6- from inspect import getmro , isclass
6+ from inspect import Parameter , getmro , isclass
7+ from inspect import signature as inspect_signature
78from typing import Any , Protocol , Self , runtime_checkable
89
910import injection
@@ -88,16 +89,41 @@ class HandlerDecorator[I, O]:
8889 manager : HandlerManager [I , O ]
8990 injection_module : injection .Module = field (default_factory = injection .mod )
9091
91- def __call__ (self , input_type : type [I ], / ) -> Any :
92- def decorator (wrapped : type [Handler [[I ], O ]]) -> type [Handler [[I ], O ]]:
93- if not isclass (wrapped ) or not issubclass (wrapped , Handler ):
94- raise TypeError (f"`{ wrapped } ` isn't a valid handler." )
95-
92+ def __call__ (
93+ self ,
94+ input_or_handler : type [I ] | HandlerType [[I ], O ] | None = None ,
95+ / ,
96+ ) -> Any :
97+ def decorator (
98+ wrapped : HandlerType [[I ], O ],
99+ * ,
100+ input_type : type [I ] | None = None ,
101+ ) -> HandlerType [[I ], O ]:
96102 factory = self .injection_module .make_async_factory (wrapped )
103+ input_type = input_type or _resolve_input_type (wrapped )
97104 self .manager .subscribe (input_type , factory )
98105 return wrapped
99106
100- return decorator
107+ if input_or_handler is None :
108+ return decorator
109+
110+ elif isclass (input_or_handler ) and issubclass (input_or_handler , Handler ):
111+ return decorator (input_or_handler )
112+
113+ else :
114+ return partial (decorator , input_type = input_or_handler ) # type: ignore[arg-type]
115+
116+
117+ def _resolve_input_type [I , O ](handler_type : HandlerType [[I ], O ]) -> type [I ]:
118+ fake_handle_method = handler_type .handle .__get__ (NotImplemented )
119+ signature = inspect_signature (fake_handle_method , eval_str = True )
120+ parameters = iter (signature .parameters .values ())
121+ input_type = next (parameters ).annotation
122+
123+ if input_type is Parameter .empty :
124+ raise TypeError ("Unable to resolve input type." )
125+
126+ return input_type
101127
102128
103129def _make_handle_function [I , O ](
@@ -106,6 +132,6 @@ def _make_handle_function[I, O](
106132 return partial (__handle , factory = factory )
107133
108134
109- async def __handle [I , O ](input_value : I , factory : HandlerFactory [[I ], O ]) -> O :
135+ async def __handle [I , O ](input_value : I , * , factory : HandlerFactory [[I ], O ]) -> O :
110136 handler = await factory ()
111137 return await handler .handle (input_value )
0 commit comments