Example #1
0
    def _resolve_spec(inventory, cocktail, spec, tree):
        """
        Generate a RecipeResolutionSummary object for this particular recipe. Reminder
        that Recipe = Cocktail + Spec.
        :param inventory: The Inventory object to resolve against.
        :param cocktail: The Cocktail object to resolve.
        :param spec: The Spec object that you wanted to resolve.
        :param tree: IngredientTree.
        :return: A SpecResolutionSummary.
        """
        # Components use the ingredient slug as their slug so we can safely
        # assume a 1:1 mapping between them.
        LogService.info("Resolving spec %s" % spec.slug)
        rs = RecipeResolutionFactory.from_objects(inventory, cocktail, spec)
        try:
            rs = RecipeResolutionFactory.produce_obj(id=rs.id)
            LogService.info("Found resolution %s in the database" % rs.id)
        except KeyError:
            LogService.warn(
                "Document %s not found in database. Regenerating..." % rs.id)
            rs = RecipeResolver._populate_components(summary=rs,
                                                     cocktail=cocktail,
                                                     spec=spec,
                                                     inventory=inventory,
                                                     tree=tree)

        return rs
Example #2
0
    def delete(cls, obj, fatal=False):
        """
        Delete a specific object from its index.
        Fatal changed to implicitly be false since if something isn't
        in the index (kinda problematic?) whatevs thats the desired state.
        :param obj: barbados.objects.base.BarbadosObject child instance.
        :param fatal: Should not being in the index be a critical problem.
        :return: None
        """
        index_obj = cls.factory.obj_to_index(obj)

        try:
            cls.for_index.delete(index_obj)
        except NotFoundError as e:
            if fatal:
                raise SearchException(e)
            LogService.warn(
                "Object %s was not found in index on DELETE. This probably isn't a problem?"
                % obj)
Example #3
0
    def implies_root(self, node_id):
        """
        Return the node id (tag) of the root of the implied tree for the given
        node id. This generally means the first family in the parents.
        :param node_id: slug of the ingredient to look up.
        :return: slug of the root of the tree to use for implied ingredients.
        """
        # Families are the root of their implied trees.
        try:
            self_kind = self.node(node_id).data.kind
        except AttributeError:
            LogService.warn("Unable to find kind for %s" % node_id)
            return

        if self_kind in [FamilyKind, CategoryKind]:
            return node_id
        # Look through all parents until we find one. We can be reasonably sure
        # that all Ingredient/Product/Custom kinds have a family parent.
        for parent in self.parents(node_id):
            if self.node(parent).data.kind == FamilyKind:
                return parent
Example #4
0
    def siblings(self, node_id):
        """
        Return a list of all sibling nodes of this node. Siblings share the
        same parent. Note that siblings does NOT include children of this
        node.
        :param node_id: ID of the node to investigate.
        :return: List of node tags.
        """
        node = self.node(node_id)
        parent = self.parent(node_id)

        # I don't know how long this bug was there, but my gods...
        # Apparently I was deleting a bunch of stuff from the tree!
        # Remove this node from the list of siblings.
        siblings = []
        try:
            siblings = copy.deepcopy(parent.fpointer)
            siblings.remove(node.identifier)
        except AttributeError:
            LogService.warn("Error calculating siblings for %s" % node_id)

        return siblings
Example #5
0
    def insert_obj(cls, obj, overwrite=False):
        """
        Insert an object in the database. Maybe overwrite it? Up to you kid.
        :param obj: The object to store.
        :param overwrite: Use Merge rather than Add.
        :return: Model corresponding to the object.
        """
        with DatabaseService.get_session() as session:
            model = cls.obj_to_model(obj)

            # Validate it.
            if cls._validator is not None:
                cls._validator(model).validate(session=session)
            else:
                LogService.warn("No validator configured for %s" % cls._model)

            # Merge vs Add
            # https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy.orm.session.Session.merge
            if overwrite:
                session.merge(model)
            else:
                session.add(model)
            session.commit()
Example #6
0
    def implies(self, node_id):
        """
        Return a list of all ingredients that this node implies.
        This is done by looking at all parent ingredients up
        to the first family plus its direct children and (maybe) siblings.
        Examples:
          * the-dead-rabbit-irish-whiskey -> [irish-whiskey, jameson-irish-whiskey]
          * el-dorado-12-year-rum -> [aged-blended-rum, aged-rum, rum]
          * orange-bitters -> [citrus-bitters, angostura-orange-bitters, regans-orange-bitters, grapefruit-bitters]
          * tequila -> [casamigos-reposado-tequila, astral-blanco-tequila, tres-generaciones-anejo-tequila]
        :param node_id: ID of the node to investigate.
        :return: List of node tags (slugs).
        """
        try:
            self_node_kind = self.node(node_id).data.kind
        except AttributeError:
            LogService.warn("Problem calculating implies for %s" % node_id)
            return []

        # All nodes imply their children.
        implied_nodes = self.children(node_id, extended=True)

        # If the ingredientis indexed in something, imply its index.
        implied_nodes += self.indexed_in(node_id)

        # Families should not imply siblings or parents since they are the top
        # of the metaphorical phood chain (aka, implies_root). See the FamilyKind class for more.
        #
        # Products should imply their parents, any Custom children, and their siblings
        # since they generally can get swapped out for each other. Yes I know there are
        # differences between Laphroaig and Lagavulin but you get the idea I hope.
        #
        # Ingredients being the middleware shouldn't return their siblings.
        # Since Indexes are basically fancy Ingredients they should follow the
        # same rules as them.
        if self_node_kind != FamilyKind:
            # implied_nodes += self.siblings(node_id)
            for parent_node in self.parents(node_id,
                                            stop_at_first_family=True):
                implied_nodes += [parent_node]
                implied_nodes += self.implies(parent_node)

        # Indexes should imply their elements
        if self_node_kind == IndexKind.value:
            implied_nodes += self.node(node_id).data.elements

        # Dedup and sort the list
        implied_nodes = list(set(implied_nodes))
        implied_nodes.sort()

        # Figure out which IngredientKinds we allow for implicit substitution.
        implicit_kinds = [kind for kind in IngredientKinds.implicits]
        # LogService.info("Allowed implicit kinds are: %s" % implicit_kind_values)

        # Create a list of allowed parents based on whether the parent is
        # of an approved type.
        allowed_implicit_nodes = []
        for implied_node_id in implied_nodes:
            implied_node = self.node(node_id=implied_node_id)
            implied_node_kind = implied_node.data.kind
            # Log.info("Kind of parent %s is %s" % (parent, parent_kind))

            if implied_node_kind in implicit_kinds:
                allowed_implicit_nodes.append(implied_node_id)

        # LogService.info("Allowed implicit nodes for %s are: %s" % (node_id, allowed_implicit_nodes))
        return allowed_implicit_nodes