Package: mediatr-ez
mediatr_pyThis is an async implementation of Mediator pattern with pipline behaviors.It is a port ofMediatrfrom .Net C#Requirements:Python >= 3.8Usage:installmediatr:pip install mediatr-ezDefine your request classclassGetArrayQuery():def__init__(self,items_count:int):self.items_count=items_countDefine your handler class or functionimportMediatorfrommediatr@Mediator.handlerasyncdefget_array_handler(request:GetArrayQuery):items=list()foriinrange(0,request.items_count):items.append(i)returnitems# or just Mediator.register_handler(get_array_handler)or class:@Mediator.handlerclassGetArrayQueryHandler():defhandle(self,request:GetArrayQuery):items=list()foriinrange(0,request.items_count):items.append(i)returnitems# or just Mediator.register_handler(GetArrayQueryHandler)Define your validator class or functionimportMediatorfrommediatr@Mediator.validatorasyncdefget_array_validator(request:GetArrayQuery):ifrequest.items_count>0:...etcelse:raiseException("Sorry, items_count number below zero")# or just Mediator.register_validator(get_array_handler)or class:@Mediator.validatorclassGetArrayQueryValidator():defvalidate(self,request:GetArrayQuery):ifrequest.items_count>0:...etcelse:raiseException("Sorry, items_count number below zero")# or just Mediator.register_validator(GetArrayQueryHandler)Run mediatorimportMediatorfrommediatrmediator=Mediator()request=GetArrayQuery(5)result=awaitmediator.send_async(request)# result = mediator.send(request) in synchronous modeprint(result)//[0,1,2,3,4]If you are using synchronousmediator.send(request)method, try to define synchronous handlers and behaviorsIn another case useasynciomodule for manual manage of event loop in synchronous codeRun mediator statically, without instanceimportMediatorfrommediatrrequest=GetArrayQuery(5)result=awaitMediator.send_async(request)# or:result=Mediator.send(request)#in synchronous mode. Async handlers and behaviors will not blocking!print(result)//[0,1,2,3,4]Note that instantiation ofMediator(handler_class_manager = my_manager_func)is useful if you have custom handlers creation. For example using an injector.
By default class handlers are instantiated with simple init:SomeRequestHandler(). handlers or behaviors as functions are executed directly.Using custom handler factory for handlers as classesIf your handlers registered as functions, it just executes them.In case with handlers, declared as classes with methodhandleMediator uses function, that instantiates handlers.defdefault_handler_class_manager(HandlerCls:type,is_behavior:bool=False):returnHandlerCls()For example, if you want to instantiate them with dependency injector or custom, pass your own factory function to Mediator:defmy_class_handler_manager(handler_class,is_behavior=False):ifis_behavior:# custom logicpassreturninjector.get(handler_class)mediator=Mediator(handler_class_manager=my_class_handler_manager)PS:Thenextfunction in behavior isasync, so if you want to take results or if your behavior is async, usemiddle_results = await next()Handler may be async too, if you need.Using with generic typing support (version >= 1.2):frommediatrimportMediator,GenericQueryclassUserModel(BaseModel):# For example sqlalchemy ORM entityid=Column(String,primary_key=True)name=Column(String)classFetchUserQuery(GenericQuery[UserModel])def__init__(self,user_id:str):self.user_id=user_idmediator=Mediator()request=FetchUserQuery(user_id="123456")user=mediator.send(request)# type of response will be a UserModel# -------------------------------------------------------------@Mediator.handlerclassFetchUserQueryHandler():defhandle(self,request:FetchUserQuery):db_session=Session()#sqlalchemy sessionreturndb_session.query(UserModel).filter(UserModel.id==request.user_id).one()# or handler as simple function:@Mediator.handlerdeffetch_user_query_handler(request:FetchUserQuery):db_session=Session()#sqlalchemy sessionreturndb_session.query(UserModel).filter(UserModel.id==request.user_id).one()Please give a star if the library is useful for you :smiley: