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
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)
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
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
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()
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