Exemplo n.º 1
0
    def __new__(cls, class_name, bases, namespace):

        if not bases:
            namespace["__dependencies__"] = {}
            namespace["__wrapped__"] = None  # Doctest module compatibility.
            namespace["_subs_tree"] = None  # Typing module compatibility.
            return type.__new__(cls, class_name, bases, namespace)

        _check_inheritance(bases, Injector)
        ns = {}
        for attr in ("__module__", "__doc__", "__weakref__", "__qualname__"):
            try:
                ns[attr] = namespace.pop(attr)
            except KeyError:
                pass
        for name in namespace:
            _check_dunder_name(name)
            _check_attrs_redefinition(name)
        dependencies = {}
        for base in reversed(bases):
            dependencies.update(base.__dependencies__)
        for name, dep in namespace.items():
            dependencies[name] = _make_dependency_spec(name, dep)
        _check_loops(class_name, dependencies)
        _check_circles(dependencies)
        ns["__dependencies__"] = dependencies
        return type.__new__(cls, class_name, bases, ns)
Exemplo n.º 2
0
    def __getattr__(cls, attrname):
        __tracebackhide__ = True

        cache, cached = {"__self__": cls}, {"__self__"}
        current_attr, attrs_stack = attrname, [attrname]
        have_default = False

        while attrname not in cache:

            spec = cls.__dependencies__.get(current_attr)

            if spec is None:
                if have_default:
                    cached.add(current_attr)
                    current_attr = attrs_stack.pop()
                    have_default = False
                    continue
                if len(attrs_stack) > 1:
                    message = "{!r} can not resolve attribute {!r} while building {!r}".format(  # noqa: E501
                        cls.__name__, current_attr, attrs_stack.pop())
                else:
                    message = "{!r} can not resolve attribute {!r}".format(
                        cls.__name__, current_attr)
                raise DependencyError(message)

            marker, attribute, args, have_defaults = spec

            if set(args).issubset(cached):
                kwargs = {k: cache[k] for k in args if k in cache}

                try:
                    cache[current_attr] = attribute(**kwargs)
                except _Replace as replace:
                    _deep_replace_dependency(cls, current_attr, replace)
                    _check_loops(cls.__name__, cls.__dependencies__)
                    _check_circles(cls.__dependencies__)
                    continue

                cached.add(current_attr)
                current_attr = attrs_stack.pop()
                have_default = False
                continue

            for n, arg in enumerate(args, 1):
                if arg not in cached:
                    attrs_stack.append(current_attr)
                    current_attr = arg
                    have_default = False if n < have_defaults else True
                    break

        return cache[attrname]
Exemplo n.º 3
0
    def __getattr__(cls, attrname):
        __tracebackhide__ = True

        cache, cached = {"__self__": cls}, {"__self__"}
        current_attr, attrs_stack = attrname, [attrname]
        have_default = False
        replaced_dependencies = {}

        while attrname not in cache:

            spec = cls.__dependencies__.get(current_attr)

            if spec is None:
                if have_default:
                    cached.add(current_attr)
                    current_attr = attrs_stack.pop()
                    have_default = False
                    continue
                if len(attrs_stack) > 1:
                    message = "{!r} can not resolve attribute {!r} while building {!r}".format(  # noqa: E501
                        cls.__name__, current_attr, attrs_stack.pop()
                    )
                else:
                    message = "{!r} can not resolve attribute {!r}".format(
                        cls.__name__, current_attr
                    )
                raise DependencyError(message)

            marker, attribute, args, have_defaults = spec

            if set(args).issubset(cached):
                kwargs = {k: cache[k] for k in args if k in cache}

                try:
                    dependency = attribute(**kwargs)
                    if ('nested' not in marker
                            and inspect.isclass(dependency)
                            and not current_attr.endswith("_class")):
                        spec = _make_init_spec(dependency)
                        replaced_dependency = _replace_dependency(cls, current_attr, spec)
                        replaced_dependencies[current_attr] = replaced_dependency
                        continue
                    elif isinstance(dependency, This):
                        spec = _make_this_spec(dependency)
                        replaced_dependency = _replace_dependency(cls, current_attr, spec)
                        replaced_dependencies[current_attr] = replaced_dependency
                        continue
                    else:
                        cache[current_attr] = dependency
                except _Replace as replace:
                    _deep_replace_dependency(cls, current_attr, replace)
                    _check_loops(cls.__name__, cls.__dependencies__)
                    _check_circles(cls.__dependencies__)
                    continue

                cached.add(current_attr)
                current_attr = attrs_stack.pop()
                have_default = False
                continue

            for n, arg in enumerate(args, 1):
                if arg not in cached:
                    attrs_stack.append(current_attr)
                    current_attr = arg
                    have_default = False if n < have_defaults else True
                    break

        # Restore @value dependencies that returned a class from the result class
        # to their defining function
        for attr, dep in replaced_dependencies.items():
            cls.__dependencies__[attr] = dep

        return cache[attrname]
Exemplo n.º 4
0
def _replace_dependency(injector, current_attr, spec):
    replaced_dependency = injector.__dependencies__[current_attr]
    injector.__dependencies__[current_attr] = spec
    _check_loops(injector.__name__, injector.__dependencies__)
    _check_circles(injector.__dependencies__)
    return replaced_dependency