def test_injector_clone(): class A: pass def fn(i: Injector, kwarg: A): assert isinstance(kwarg, A) assert kwarg is ainst assert i[A] is kwarg assert i is not injector i[A] = "another" return injector.exec(fn2) def fn2(i: Injector): assert i[A] is ainst return "OK" injector = Injector() injector.provide(A) ainst = injector[A] = injector[A] def get_kw(a: A, *, name: str, type: type): if name == "kwarg": return a else: raise NoKwOnly() injectable = injector.provide(fn, provide=[KwOnly(get_kw)]) assert injectable(injector) == "OK" assert injector[fn] == "OK"
def test_injector_kwonly_def_error(): injector = Injector() def get_kwargs1(): pass def get_kwargs2(*, xyz): pass def get_kwargs3(*, type): pass with pytest.raises(ProvideError) as exc: injector.provide(KwOnly(get_kwargs1)) exc.match("Callable must have kwonly arguments") with pytest.raises(ProvideError) as exc: injector.provide(KwOnly(get_kwargs2)) exc.match( "Keyword argument resolver function muts have 'name' keyword only argument" ) with pytest.raises(ProvideError) as exc: injector.provide(KwOnly(get_kwargs3)) exc.match( "Keyword argument resolver function muts have 'name' keyword only argument" ) class X: pass with pytest.raises(ProvideError) as exc: injector.provide(KwOnly(X)) exc.match("Argument must be callable.")
def test_injector_descend2(): class A: pass def fn(i: Injector, a: A): assert isinstance(a, A) assert a is ainst assert injector[A] is not a return i.exec(fn2) def fn2(i: Injector, a: A): assert isinstance(a, A) assert a is ainst assert i[A] is a return "OK" injector = Injector() injector.provide(A) iclone = injector.descend() ainst = iclone[A] = iclone[A] assert iclone.exec(fn) == "OK" iclone2 = iclone.descend() assert iclone2.exec(fn) == "OK"
def test_injector_attribute_inheritance(): injector = Injector() class A: pass class B: a: Inject[A] def __init__(self): assert isinstance(self.a, A) class X: pass class C(B): x: Inject[X] def __init__(self): super().__init__() assert isinstance(self.x, X) injector.provide(A) injector.provide(X) c = injector.exec(C) assert isinstance(c, C) assert isinstance(c.a, A) assert isinstance(c.x, X)
def test_strategy_value(): injector = Injector() provided = "VALUE" injector.provide("V", provided, VALUE) assert injector["V"] == "VALUE" assert injector["V"] is provided assert injector.provide("V", provided, VALUE)(injector) == "VALUE"
def test_injectable_call(): injector = Injector() class A: pass injectable = injector.provide(A) assert isinstance(injectable(injector), A)
def test_forwardref_fn(): def fn(a: "A"): assert isinstance(a, A) return "OK" injector = Injector() injector.provide(A) assert injector.exec(fn) == "OK"
def test_descend(): injector = Injector() injector.provide(SelfInject) child = injector.descend() child.provide(injectable_func2) x = child[injectable_func2] assert isinstance(x, SelfInject)
def test_strategy_singleton(): class A: pass injector = Injector() injector.provide(A, A, SINGLETON) assert isinstance(injector[A], A) assert injector[A] is injector[A] assert injector[A] is injector[A]
def test_injector_injectable(benchmark): i = Injector() injectable = i.provide("PROVIDED", "PROVIDED", VALUE) benchmark.pedantic(lambda i: injectable(i), args=(i, ), iterations=10000, rounds=100) assert injectable(i) == "PROVIDED"
def test_injectable_bind(): injector = Injector() class A: pass injectable = injector.provide(A) bound = injectable.bind(injector) assert isinstance(bound, BoundInjectable) assert isinstance(bound(), A)
def test_injector_getitem(benchmark): i = Injector() i.provide("PROVIDED", "PROVIDED", VALUE) benchmark.pedantic(lambda i: i["PROVIDED"], args=(i, ), iterations=10000, rounds=100) assert i["PROVIDED"] == "PROVIDED"
def test_injector_exec_fn(): injector = Injector() class A: pass def x(a: A): assert isinstance(a, A) return "OK" injector.provide(A) assert injector.exec(x) == "OK"
def test_injector_exec_cls(): injector = Injector() class A: pass class B: def __init__(self, a: A): assert isinstance(a, A) injector.provide(A) assert isinstance(injector.exec(B), B)
def test_injectable_resolve_err(): injector = Injector() class A: pass injectable = injector.provide(A) with pytest.raises(TypeError) as exc: injectable.resolve() exc.match("resolve\\(\\) takes exactly one argument \\(0 given\\)") with pytest.raises(TypeError) as exc: injectable.resolve(None) exc.match("Bad argument, must call with 'Injector' instance")
def test_own_provide(benchmark): class A: pass def fn(a: A): return a injector = Injector() injector.provide(fn, provide=[A]) benchmark.pedantic(lambda i: injector.get(i), args=(fn, ), iterations=ITERS, rounds=100)
def test_injector_own_kwonly(): injector = Injector() class Config(dict): def __init__(self): super().__init__(some_key="OK") def get_kwarg(config: Config, *, name, type): assert name == "some_key" assert type is str return config[name] def fn(*, some_key: str): assert some_key == "OK" return "NICE" injector.provide(Config) injector.provide(fn, provide=[KwOnly(get_kwarg)]) assert injector.get(fn) == "NICE" with pytest.raises(InjectError) as exc: assert injector.exec(fn) == "NICE" exc.match( "Not found suitable value for: <ValueResolver name=some_key id=<class 'str'>>" )
def test_value(benchmark): class A: pass injector = Injector() injector.provide("A", A, VALUE) def fn(id): return injector[id] benchmark.pedantic(lambda i: fn(i), args=("A", ), iterations=ITERS, rounds=100)
def test_injectable_bind_err(): injector = Injector() class A: pass injectable = injector.provide(A) with pytest.raises(TypeError) as exc: injectable.bind(None) exc.match("Bad argument, must call with 'Injector' instance") bound = injectable.bind(injector) with pytest.raises(TypeError) as exc: bound(None) exc.match("__call__ expected 0 arguments, got 1")
def test_cached_provide(benchmark): class A: pass def fn(a: A): return a injector = Injector() injector.provide(A) factory = injector.provide(fn).resolve benchmark.pedantic(lambda i: factory(i), args=(injector, ), iterations=ITERS, rounds=100)
def test_class_with_type_annot(): class B: pass class A: something: "Something" b: Inject[B] injector = Injector() injector.provide(A) injector.provide(B) a = injector[A] assert isinstance(a, A) assert isinstance(a.b, B) assert not hasattr(a, "something")
def test_params_wo_type(): injector = Injector() r = Router() @r.on("/test/{any}") def action_any(): return "any" @r.on("/test/{number:int}") def action_number(): return "number" @r.on("/test/exact") def action_exact(): return "exact" handler, params = r.find("/test/42", b"GET") assert handler(injector) == "number" assert params["number"] == 42 handler, params = r.find("/test/something", b"GET") assert handler(injector) == "any" assert params["any"] == "something" handler, params = r.find("/test/exact", b"GET") assert handler(injector) == "exact" assert len(params) == 0
def test_injector_attribute(): injector = Injector() class A: pass class B: a: Inject[A] def __init__(self): assert isinstance(self.a, A) injector.provide(A) b = injector.exec(B) assert isinstance(b, B) assert isinstance(b.a, A)
def test_injector_exec_object(): BINST = "BInstance" injector = Injector() class A: pass class B: def __call__(self, a: A): assert isinstance(a, A) return "BBBB" def fn1(arg: B): assert isinstance(arg, B) return "fn1" def fn2(arg: BINST): assert arg == "BBBB" return "fn2" injector.provide(A) injector.provide(B) injector.provide(BINST, B()) assert injector.exec(fn1) == "fn1" assert injector.exec(fn2) == "fn2"
def test_injectable_cached(): injector = Injector() def test_fn(): return "NICE" injectable = Injectable(test_fn) assert isinstance(injectable, Injectable) assert injectable(injector) == "NICE"
def test_injector_inject_self(): injector = Injector() class A: inj: Inject[Injector] def __init__(self): assert isinstance(self.inj, Injector) assert isinstance(self.inj.get(B), B) class B: pass injector.provide(A) injector.provide(B) assert isinstance(injector.get(A), A) assert isinstance(injector[A], A)
def test_strategy_custom(): cscope = dict() def custom_strategy(injectable, injector): try: return cscope[injectable] except KeyError: value = cscope[injectable] = injectable(injector) return value class A: pass injector = Injector() injector.provide(A, A, custom_strategy) assert isinstance(injector[A], A) assert injector[A] is injector[A]
def test_injector_setitem(): class A: pass injector = Injector() injector[A] = A() def fn(a: A): assert isinstance(a, A) return "OK" assert injector.exec(fn) == "OK" del injector[A] with pytest.raises(InjectError) as exc: injector.exec(fn) == "OK" exc.match("Not found suitable value for")
def test_generic_param(): T = TypeVar("T") class A(Generic[T]): b: Inject[T] class B: pass def fn(a: A[B]): assert isinstance(a, A) assert isinstance(a.b, B) return "OK" injector = Injector() injector.provide(A) injector.provide(B) assert injector.exec(fn) == "OK"
def test_injector_kwonly2(): injector = Injector() class Config(dict): def __init__(self): super().__init__(some_key="OK") def __call__(self, *, name, type): assert name == "some_key" assert type is str return self[name] def fn(*, some_key: str): assert some_key == "OK" return "NICE" injector.provide(KwOnly(Config())) assert injector.exec(fn) == "NICE"