예제 #1
0
def test_plan_non_annotated_args():
    class WithNonAnnArgs:

        def __init__(self, a: A, b: B, non_ann, non_ann_def=0, *,
                     non_ann_kw, non_ann_kw_def=1):
            pass

    plan = andi.plan(
        WithNonAnnArgs.__init__,
        is_injectable=ALL,
        externally_provided={A}
    )

    assert dict(plan.dependencies) == {A: {}, B: {}}
    assert _final_kwargs_spec(plan) == {'a': A, 'b': B}
    assert not plan.full_final_kwargs

    plan_class = andi.plan(WithNonAnnArgs,
                           is_injectable=ALL,
                           externally_provided=[A])
    assert plan_class.dependencies == plan.dependencies
    assert _final_kwargs_spec(plan_class) == _final_kwargs_spec(plan)
    assert not plan.full_final_kwargs

    with pytest.raises(TypeError):
        build(plan)

    instances = build(plan.dependencies, instances_stock={A: ""})
    o = WithNonAnnArgs(non_ann=None, non_ann_kw=None,
                       **plan.final_kwargs(instances))
    assert isinstance(o, WithNonAnnArgs)

    with pytest.raises(andi.NonProvidableError) as ex_info:
        andi.plan(WithNonAnnArgs, is_injectable=ALL,
                  externally_provided=[A], full_final_kwargs=True)
    assert error_causes(ex_info) == [
        ('non_ann', [LackingAnnotationErrCase('non_ann', WithNonAnnArgs)]),
        ('non_ann_def', [LackingAnnotationErrCase('non_ann_def',
                                                  WithNonAnnArgs)]),
        ('non_ann_kw', [LackingAnnotationErrCase('non_ann_kw',
                                                 WithNonAnnArgs)]),
        ('non_ann_kw_def', [LackingAnnotationErrCase('non_ann_kw_def',
                                                     WithNonAnnArgs)]),
    ]
예제 #2
0
def test_plan_no_args(full_final_kwargs):
    def fn():
        return True

    plan = andi.plan(fn, is_injectable=[], full_final_kwargs=full_final_kwargs)
    assert plan == [(fn, {})]
    assert plan.full_final_kwargs
    instances = build(plan)
    assert instances[fn]
    assert fn(**plan.final_kwargs(instances))
예제 #3
0
def test_plan_similar_for_class_or_func(cls, is_injectable, externally_provided):
    is_injectable = is_injectable + [cl.__init__ for cl in is_injectable]
    externally_provided = externally_provided + [cl.__init__
                                                 for cl in externally_provided]
    external_deps = {cl: "external" for cl in externally_provided}

    plan_cls = andi.plan(cls, is_injectable=is_injectable,
                         externally_provided=externally_provided)
    plan_func = andi.plan(cls.__init__, is_injectable=is_injectable,
                          externally_provided=externally_provided)

    plan_func[-1] = (cls, plan_func[-1][1])  # To make plans compatible
    assert plan_cls == plan_func
    assert plan_cls.full_final_kwargs
    assert plan_cls.full_final_kwargs == plan_func.full_final_kwargs


    instances = build(plan_cls, external_deps)
    assert type(instances[cls]) == cls or instances[cls] == "external"
    instances = build(plan_func, external_deps)
    assert type(instances[cls]) == cls or instances[cls] == "external"
예제 #4
0
def test_plan_for_func():
    def fn(other: str, e: E, c: C):
        assert other == 'yeah!'
        assert type(e) == E
        assert type(c) == C

    plan = andi.plan(fn, is_injectable=ALL,
                     externally_provided={A})
    assert _final_kwargs_spec(plan) == {'e': E, 'c': C}
    assert not plan.full_final_kwargs
    instances = build(plan.dependencies, {A: ""})
    fn(other="yeah!", **plan.final_kwargs(instances))

    with pytest.raises(TypeError):
        build(plan, {A: ""})

    with pytest.raises(andi.NonProvidableError) as ex_info:
        andi.plan(fn, is_injectable=ALL, externally_provided=[A],
                  full_final_kwargs=True)
    assert error_causes(ex_info) == [
        ('other', [NonInjectableOrExternalErrCase('other', fn, [str])])]
예제 #5
0
def test_plan_and_build():
    plan = andi.plan(E, is_injectable=lambda x: True,
                     externally_provided={A})
    assert dict(plan[:2]).keys() == {A, B}
    assert list(dict(plan[:2]).values()) == [{}, {}]
    assert plan[2:] == [
        (C, {'a': A, 'b': B}),
        (D, {'a': A, 'c': C}),
        (E, {'b': B, 'c': C, 'd': D})
    ]
    assert plan.full_final_kwargs
    instances = build(plan, {A: ""})
    assert type(instances[E]) == E
예제 #6
0
def test_plan_use_fn_as_annotations(full_final_kwargs):
    def fn_ann(b: B):
        setattr(b, "modified", True)
        return b

    def fn(b: fn_ann):
        return b

    plan = andi.plan(fn, is_injectable=[fn_ann, B],
                     full_final_kwargs=full_final_kwargs)
    assert plan.full_final_kwargs
    instances = build(plan)
    assert instances[fn].modified
예제 #7
0
def test_plan_with_optionals_and_union():
    def fn(str_or_b_or_None: Optional[Union[str, B]]):
        return str_or_b_or_None

    plan = andi.plan(fn, is_injectable={str, B, type(None)})
    assert type(build(plan)[fn]) == str

    plan = andi.plan(fn, is_injectable={B, type(None)})
    assert type(build(plan)[fn]) == B

    plan = andi.plan(fn, is_injectable={B, type(None)},
                     externally_provided={str})
    assert type(build(plan)[fn]) == str

    plan = andi.plan(fn, is_injectable={type(None)})
    assert build(plan)[fn] is None

    plan = andi.plan(fn, is_injectable={type(None)},
                     externally_provided={str})
    assert type(build(plan)[fn]) == str

    plan = andi.plan(fn, is_injectable={type(None)},
                     externally_provided={str, B})
    assert type(build(plan)[fn]) == str

    plan = andi.plan(fn, is_injectable={type(None)},
                     externally_provided={B})
    assert type(build(plan)[fn]) == B

    plan = andi.plan(fn, is_injectable={})
    assert plan == [(fn, {})]
    assert not plan.full_final_kwargs

    with pytest.raises(NonProvidableError) as ex_info:
        andi.plan(fn, is_injectable={}, full_final_kwargs=True)
    assert error_causes(ex_info) == [
        ('str_or_b_or_None', [
            NonInjectableOrExternalErrCase('str_or_b_or_None', fn,
                                           [str, B, type(None)])
        ])
    ]
예제 #8
0
def test_plan_with_optionals():
    def fn(a: Optional[str]):
        assert a is None
        return "invoked!"

    plan = andi.plan(fn, is_injectable={type(None), str},
                     externally_provided={str})
    assert plan ==  [(str, {}), (fn, {'a': str})]
    assert plan.full_final_kwargs

    plan = andi.plan(fn, is_injectable={type(None)})
    assert plan.dependencies == [(type(None), {})]
    assert _final_kwargs_spec(plan) == {'a': type(None)}
    assert plan.full_final_kwargs

    instances = build(plan)
    assert instances[type(None)] is None
    assert instances[fn] == "invoked!"

    with pytest.raises(andi.NonProvidableError) as ex_info:
        andi.plan(fn, is_injectable={}, full_final_kwargs=True)
    assert error_causes(ex_info) == [
        ('a', [NonInjectableOrExternalErrCase('a', fn, [str, type(None)])])]