コード例 #1
0
    def test__resolve_single_injectable__when_there_are_multiple_primary_injectables(
        self, ):
        # given
        matches = {MagicMock(primary=True), MagicMock(primary=True)}

        # then when
        with pytest.raises(InjectionError):
            resolve_single_injectable("TEST", RegistryType.CLASS, matches)
コード例 #2
0
    def test__resolve_single_injectable__obvious_case(self):
        # given
        expected_injectable = MagicMock(spec=Injectable)()
        matches = {expected_injectable}

        # when
        injectable = resolve_single_injectable("TEST", RegistryType.CLASS,
                                               matches)

        # then
        assert injectable == expected_injectable
コード例 #3
0
    def test__resolve_single_injectable__when_there_are_one_primary_injectables(
            self):
        # given
        primary_injectable = MagicMock(primary=True)
        non_primary_injectable = MagicMock(primary=False)
        matches = {primary_injectable, non_primary_injectable}

        # when
        injectable = resolve_single_injectable("TEST", RegistryType.CLASS,
                                               matches)

        # then
        assert injectable is primary_injectable
コード例 #4
0
def inject(
    dependency: Union[Type[T], str],
    *,
    namespace: str = None,
    group: str = None,
    exclude_groups: Sequence[str] = None,
    lazy: bool = False,
    optional: bool = False,
) -> T:
    """
    Injects the requested dependency by instantiating a new instance of it or a
    singleton instance if specified by the injectable. Returns an instance of the
    requested dependency.

    One can use this method directly for injecting dependencies though this is not
    recommended. Use the :meth:`@autowired <injectable.autowired>` decorator and the
    :class:`Autowired <injectable.Autowired>` type annotation for dependency injection
    to be automatically wired to a function's call instead.

    Will log a warning indicating that the injection container is empty when invoked
    before :meth:`load_injection_container <injectable.load_injection_container>` is
    called.

    Raises
    :class:`InjectionError <injectable.errors.InjectionError>`
    when unable to resolve the requested dependency. This can be due to a variety of
    reasons: the requested dependency wasn't loaded into the container; the namespace
    isn't correct; the group isn't correct; there are multiple injectables for the
    dependency and none or multiple are marked as primary. When parameter ``optional``
    is ``True`` no error will be raised when no injectable that matches requested
    qualifier/class and group is found in the specified namespace though in ambiguous
    cases that resolving a primary injectable is impossible an error will still be
    raised.

    :param dependency: class, base class or qualifier of the dependency to be used for
            lookup among the registered injectables.
    :param namespace: (optional) namespace in which to look for the dependency. Defaults
            to :const:`injectable.constants.DEFAULT_NAMESPACE`.
    :param group: (optional) group to filter out other injectables outside of this
            group. Defaults to None.
    :param exclude_groups: (optional) list of groups to be excluded. Defaults to None.
    :param lazy: (optional) when True will return an instance which will automatically
            initialize itself when first used but not before that. Defaults to False.
    :param optional: (optional) when True this function returns None if no injectable
            matches the qualifier/class and group inside the specified namespace instead
            of raising an :class:`InjectionError <injectable.errors.InjectionError>`.
            Ambiguous cases where resolving a primary injectable is impossible will
            still raise :class:`InjectionError <injectable.errors.InjectionError>`.
            Defaults to False.

    Usage::

      >>> from foo import Foo
      >>> from injectable import inject
      >>>
      >>> class Bar:
      ...     def __init__(self, foo: Foo = None):
      ...         self.foo = foo or inject(Foo)
    """
    dependency_name = get_dependency_name(dependency)
    registry_type = get_dependency_registry_type(dependency)
    matches = get_namespace_injectables(
        dependency_name, registry_type, namespace or DEFAULT_NAMESPACE
    )
    if not matches:
        if not optional:
            raise InjectionError(
                f"No injectable matches {registry_type.value} '{dependency_name}'"
            )
        return None
    if group is not None or exclude_groups is not None:
        matches = filter_by_group(matches, group, exclude_groups)
        if not matches:
            if not optional:
                raise InjectionError(
                    f"No injectable for {registry_type.value} '{dependency_name}'"
                    f" matches group '{group}'"
                )
            return None
    injectable = resolve_single_injectable(dependency_name, registry_type, matches)
    return injectable.get_instance(lazy=lazy)