Ejemplo n.º 1
0
 def __init__(self, owner, dependency_store):
     self.owner = owner
     self.dependency_store = dependency_store
     self._lookup = {
         class_name_to_kw_arg(cls.__name__): cls
         for cls in dependency_store
     }
Ejemplo n.º 2
0
    def create_and_update_dependencies(self, *provided_and_desired_dependencies):
        """in order creation of dependencies and updating of self._dependency_store
        to include instances, indexed by page class.  If a (HasCreate, dict()) tuple is
        provided as a desired dependency, the dict() will be unpacked as kwargs for the
        `HasCreate.create(**dict())` call.

        ***
        Providing (HasCreate, dict()) tuples for dependency args to this method
        removes the assurance that all shared dependencies types will be the same instance
        and only one instance of each type is created
        (Tech Debt: can create orphans if default dependency isn't claimed).
        The provided args are only in scope of the desired page, override any previously created
        instance of the same class, and replace said instances in the continuing chain.
        ***

        ```
        ex:
        self.dependencies = [awxkit.api.pages.Inventory]
        self.create_and_update_dependencies()
        inventory = self._dependency_store[awxkit.api.pages.Inventory]

        ex:
        self.dependencies = [awxkit.api.pages.Inventory]
        self.create_and_update_dependencies((awxkit.api.pages.Inventory, dict(attr_one=1, attr_two=2)))
        inventory = self._dependency_store[awxkit.api.pages.Inventory]
        # assume kwargs are set as attributes by Inventory.create()
        inventory.attr_one == 1
        > True
        inventory.attr_two == 2
        > True

        ex:
        self.dependencies = []
        self.optional_dependencies = [awxkit.api.pages.Organization]
        self.create_and_update_dependencies(awxkit.api.pages.Organization)
        organization = self._dependency_store[awxkit.api.pages.Organization]

        ex:
        self.dependencies = [awxkit.api.pages.Inventory]
        inventory = v2.inventories.create()
        self.create_and_update_dependencies(inventory)
        inventory == self._dependency_store[awxkit.api.pages.Inventory]
        > True
        ```
        """
        if not any((self.dependencies, self.optional_dependencies)):
            return

        # remove falsy values
        provided_and_desired_dependencies = [x for x in provided_and_desired_dependencies if x]
        # (HasCreate(), True) tells HasCreate._update_dependencies to link
        provided_dependencies = [(x, True) for x in provided_and_desired_dependencies
                                 if not isinstance(x, type) and not isinstance(x, tuple)]

        # Since dependencies are often declared at runtime, we need to use some introspection
        # to determine previously created ones for proper dependency store linking.
        # This is done by keeping an updated dependency record by the root caller's frame
        caller_frame = inspect.currentframe()
        self.parent_frame = None
        for frame in inspect.stack()[1:]:
            if frame[3] == 'create_and_update_dependencies':
                self.parent_frame = frame[0]

        if not self.parent_frame:
            # a maintained dict of instantiated resources keyed by lowercase class name to be
            # expanded as keyword args during `create()` calls
            all_instantiated = all_instantiated_dependencies(*[d[0] for d in provided_dependencies])
            scoped_dependencies = {class_name_to_kw_arg(d.__class__.__name__): d for d in all_instantiated}
            self._scoped_dependencies_by_frame[caller_frame] = [self, scoped_dependencies]
        else:
            scoped_dependencies = self._scoped_dependencies_by_frame[self.parent_frame][1]

        desired_dependencies = []
        desired_dependency_classes = []
        for item in provided_and_desired_dependencies:
            if isinstance(item, tuple):
                item_cls = item[0]
            elif inspect.isclass(item):
                item_cls = item
            else:
                item_cls = item.__class__
            if item_cls not in [x[0].__class__ for x in provided_dependencies]:
                desired_dependency_classes.append(item_cls)
                desired_dependencies.append(item)

        if desired_dependencies:
            ordered_desired_dependencies = []
            creation_order = [item for s in page_creation_order(*desired_dependency_classes) for item in s]
            for item in creation_order:
                for desired in desired_dependency_classes:
                    if desired == item or is_proper_subclass(desired, item):
                        ordered_desired_dependencies.append(desired)
                        desired_dependency_classes.remove(desired)
                        break

            # keep track of (HasCreate, kwarg_dict)
            provided_with_kwargs = dict()
            for page_cls, provided_kwargs in [x for x in desired_dependencies if isinstance(x, tuple)]:
                provided_with_kwargs[page_cls] = provided_kwargs

            for to_create in ordered_desired_dependencies:
                scoped_args = dict(scoped_dependencies)

                if to_create in provided_with_kwargs:
                    scoped_args.pop(to_create, None)  # remove any conflicts in favor of explicit kwargs
                    scoped_args.update(provided_with_kwargs.pop(to_create))

                scoped_args.pop(class_name_to_kw_arg(to_create.__name__), None)

                created = to_create(self.connection).create(**scoped_args)
                provided_dependencies.append((created, True))

                for dependency, _ in provided_dependencies:
                    if dependency not in scoped_dependencies:
                        scoped_dependencies[class_name_to_kw_arg(dependency.__class__.__name__)] = dependency

        self._update_dependencies(provided_dependencies)

        if not self.parent_frame:
            del self._scoped_dependencies_by_frame[caller_frame]
Ejemplo n.º 3
0
def test_class_name_to_kw_arg(inp, out):
    assert utils.class_name_to_kw_arg(inp) == out