人类国际奥委会
flying-ioc的Python项目详细描述
人类控制反转(ioc)-用python编写
如何使用
pip安装飞行ioc
from flying_ioc import * ioc = IocManager() ioc.set_class(cls=HelperWrapper, singleton=True) ioc.set_class(cls=GRHelperService, singleton=True) ioc.set_class(name='api', cls=GRApiClient, singleton=True, thread_local=True) gr_service: GRHelperService = ioc.GRHelperService gr_service.start()
功能
- 支持将对象作为ioc管理器的属性获取
- 用参数的类名初始化类参数,如果不存在则用参数名初始化
- 支持继承-初始化父类所需的参数
- 支持值、类、工厂的映射
- 支持单线程、每线程类等映射配置
- 支持@notinject decorator
属性
gr_service: GRHelperService = ioc.GRHelperService gr_service.start()
初始化类
class ClassA: pass class ClassB: pass class ClassC: pass class ExampleClass: def __init__(self, arg1: ClassA, arg2, arg3: ClassC): assert arg1.__class__ == ClassA assert arg2.__class__ == ClassB assert arg3.__class__ == ClassC def test_arguments(): ioc = IocManager() ioc.set_class(cls=ClassA) ioc.set_class(name='arg2', cls=ClassB) ioc.set_class(name='arg3', cls=ClassC) ioc.set_class(cls=ExampleClass) assert ioc.ExampleClass.__class__ == ExampleClass
支持继承
class ClassA: pass class ClassB: pass class ClassC: pass class ParentD: def __init__(self, arg1: ClassA, **kwargs): self._arg1 = arg1 class ParentE(ParentD): def __init__(self, arg2: ClassB, **kwargs): super().__init__(**kwargs) self._arg2 = arg2 class ExampleClass(ParentE): def __init__(self, arg3: ClassC, **kwargs): super().__init__(**kwargs) assert self._arg1.__class__ == ClassA assert self._arg2.__class__ == ClassB assert arg3.__class__ == ClassC def test_arguments(): ioc = IocManager() ioc.set_class(cls=ClassA) ioc.set_class(cls=ClassB) ioc.set_class(cls=ClassC) ioc.set_class(cls=ExampleClass) assert ioc.ExampleClass.__class__ == ExampleClass
值
class ClassA: pass class ExampleClass: def __init__(self, value_text, value_class): assert value_text == 'Some text' assert value_class.__class__ == ClassA def test_arguments(): ioc = IocManager() ioc.set_value(name='value_text', value='Some text') ioc.set_value(name='value_class', value=ClassA()) ioc.set_class(cls=ExampleClass) assert ioc.ExampleClass.__class__ == ExampleClass
工厂
class ClassA: pass class ClassB: pass class ClassC: pass class Factory(IocFactory): @staticmethod def get_instance(ioc_manager: IocManager, name: str, frame_info: inspect.FrameInfo): if frame_info.function == 'test_factory_1': return ioc_manager.ClassA if name == 'factory1': return ioc_manager.ClassB return ioc_manager.ClassC ioc = IocManager() ioc.set_class(cls=ClassA) ioc.set_class(cls=ClassB) ioc.set_class(cls=ClassC) ioc.set_factory(name='factory1', cls=Factory) ioc.set_factory(name='factory2', cls=Factory) def test_factory_1(): assert ioc.factory1.__class__ == ClassA assert ioc.factory2.__class__ == ClassA def test_factory_2(): assert ioc.factory1.__class__ == ClassB assert ioc.factory2.__class__ == ClassC
单重态
class ClassA: pass class ClassB: pass def test_singleton(): ioc = IocManager() ioc.set_class(cls=ClassA) ioc.set_class(cls=ClassB, singleton=True) assert ioc.ClassA != ioc.ClassA assert ioc.ClassB == ioc.ClassB
每个线程的类
class ClassA: pass def _set_vars(ioc: IocManager, storage: dict): def wrapped(): storage['singleton1'] = ioc.singleton1 storage['singleton2'] = ioc.singleton2 return wrapped def test_class_per_thread(): ioc = IocManager() ioc.set_class(name='singleton1', cls=ClassA, singleton=True) ioc.set_class(name='singleton2', cls=ClassA, singleton=True, thread_local=True) assert ioc.singleton1 == ioc.singleton1 assert ioc.singleton2 == ioc.singleton2 thread_storage = {} thread = threading.Thread(target=_set_vars(ioc, thread_storage)) thread.start() thread.join() assert ioc.singleton1 == thread_storage['singleton1'] assert ioc.singleton2 != thread_storage['singleton2']
@不注入装饰器
在下面的示例中,@notinject decorator阻止ioc管理器在初始化example class时将arg1添加到kwargs参数中,父类需要arg1参数。
在本例中删除@notinject装饰符将导致异常。
@nonject decorator接受在初始化过程中要跳过的参数名列表。
class ClassA: pass class ClassB: pass class Parent: def __init__(self, arg1: ClassA, **kwargs): super().__init__(**kwargs) self._arg1 = arg1 @NotInject(['arg1']) class ExampleClass(Parent): def __init__(self, arg2: ClassB, **kwargs): arg1 = ClassA() super().__init__(arg1, **kwargs) assert self._arg1 == arg1 assert arg2.__class__ == ClassB def test_not_inject(): ioc = IocManager() ioc.set_class(cls=ClassA) ioc.set_class(cls=ClassB) ioc.set_class(cls=ExampleClass) assert ioc.ExampleClass.__class__ == ExampleClass
例外情况
IOC管理器引发两种类型的异常:
- attributeerror-尝试从IOC管理器获取未定义的属性时
- 类型错误-在以下情况下:
- IOC管理器缺少初始化 类或IT父类
- 初始化类时,会提供同一参数的多个实例 它的父类-由用户和ioc管理器注入。本期 可以使用@notinject decorator进行解析
class ClassA: pass class ClassB: pass class ClassC: pass class Parent: def __init__(self, arg1: ClassA, **kwargs): super().__init__(**kwargs) self._arg1 = arg1 class ExampleClass1(Parent): def __init__(self, arg2: ClassB, **kwargs): arg1 = ClassA() super().__init__(arg1, **kwargs) assert self._arg1 == arg1 assert arg2.__class__ == ClassB class ExampleClass2: def __init__(self, arg1: ClassC): pass class ExampleClass3(ExampleClass2): def __init__(self, **kwargs): super().__init__(**kwargs) ioc = IocManager() ioc.set_class(cls=ClassA) ioc.set_class(cls=ClassB) def test_exception_container_not_defined(): with pytest.raises(AttributeError) as e: ioc.NotExists assert e.value.args[0] == "Name 'NotExists' does not exist" def test_exception_missing_not_inject(): with pytest.raises(TypeError) as e: ioc.set_class(cls=ExampleClass1) ioc.ExampleClass1 assert e.value.args[0] == "__init__() got multiple values for argument 'arg1'" def test_exception_arg_is_not_defined(): with pytest.raises(TypeError) as e: ioc.set_class(cls=ExampleClass2) ioc.ExampleClass2 assert e.value.args[0].args[0] == "Can't get a container neither by class name ClassC, neither by arg name arg1" def test_exception_arg_for_parent_is_not_defined(): with pytest.raises(TypeError) as e: ioc.set_class(cls=ExampleClass3) ioc.ExampleClass3 assert e.value.args[0] == "__init__() missing 1 required positional argument: 'arg1'"