Beispiel #1
0
    def import_(self, filepath):
        dicts_to_import = RecipeImporter._fetch_data_from_path(filepath)

        if len(dicts_to_import) > 1:
            self.delete(delete_all=True)

        for cocktail_dict in dicts_to_import:
            try:
                slug = Slug(cocktail_dict['display_name'])
                LogService.info("Working %s" % slug)
                c = CocktailFactory.raw_to_obj(cocktail_dict, slug)
            except KeyError as e:
                LogService.error("Something has bad data!")
                LogService.error(cocktail_dict)
                LogService.error(e)
                continue

            self.delete(cocktail=c)

            db_obj = CocktailModel(**ObjectSerializer.serialize(c, 'dict'))
            with self.pgconn.get_session() as session:
                session.add(db_obj)
                LogService.info("Successfully [re]created %s" % c.slug)

                ObjectValidator.validate(db_obj, session=session, fatal=False)

            Indexers.get_indexer(c).index(c)

        CocktailScanCache.invalidate()
Beispiel #2
0
    def _check_slug(self):
        slug = self.model.slug
        calculated_slug = Slug(self.model.display_name)

        if slug != calculated_slug:
            self.fail("Slug (%s) is inconsistent with display_name (%s)." %
                      (self.model.slug, self.model.display_name))
Beispiel #3
0
    def obj_to_index(cls, obj, format='dict'):
        base_recipe = ObjectSerializer.serialize(obj, format)
        base_recipe.update({'alpha': obj.alpha})

        tree = IngredientTreeCache.retrieve()

        specs = base_recipe.pop('specs')

        searchable_recipes = {}
        for spec in specs:
            # Holy F**k this took too long to figure out
            # https://thispointer.com/python-how-to-copy-a-dictionary-shallow-copy-vs-deep-copy/
            searchable = copy.deepcopy(base_recipe)
            searchable['spec'] = spec
            searchable_id = '%s::%s' % (searchable['slug'], spec['slug'])
            searchable_recipes[searchable_id] = searchable

            # This count is achievable with a filter query in ES.
            # https://stackoverflow.com/questions/58659527/elastic-search-update-specific-nested-object
            # { filter: { script: { script: { source: "doc['spec.components.slug'].value.length() == 3" } } }
            # But it seemed to return some weird results too. Also required fielddata enabled on
            # the index. Also need to refactor the searchquer builder to deal with a deep parameter. This is
            # just easier.
            #
            # Maybe someday this will also bring back the notion of "countable" ingredients (ie, exclude bitters).
            # Given the complexity around that (requires parent to lookup, also ZK list of slugs to exclude)
            # it's not quite worth it right now.
            searchable['spec']['component_count'] = len(spec['components'])

            # https://stackoverflow.com/questions/14071038/add-an-element-in-each-dictionary-of-a-list-list-comprehension
            for component in spec['components']:
                # the Slug() is needed for the TDFv3 name->slug conversion.
                component.update({'parents': tree.parents(Slug(component['slug']))})

        return [cls._index(meta={'id': key}, **value) for key, value in searchable_recipes.items()]
Beispiel #4
0
    def _get_glassware(instructions):

        for instruction in instructions:
            if 'glass' in instruction.get('text').lower():
                glass = re.sub(r"^(.*) (\w+) glass(.*)$", r'\2',
                               instruction.get('text').lower())
                return [{'slug': Slug(glass)}]
Beispiel #5
0
 def parse_slug(raw_input, key='slug'):
     """
     This is needed to get around having non-slugged values in a majority
     of the Torguga files. I'm not about to go retrofit all of those just to
     satisfy this so in some cases this is going to cause extra computation.
     Fortunately it's pretty simple and reliable.
     Also Tortuga Data Format v3 replaced all names with slugs, but it means that
     the slugs for specs are not accurate. Same problem for ingredients.
     :param raw_input:
     :param key:
     :return:
     """
     raw_value = raw_input.get(key)
     new_value = Slug(raw_value)
     raw_input.update({key: new_value})
     return raw_input
Beispiel #6
0
    def _model_to_obj(raw_recipe):
        slug = Slug(raw_recipe.title)
        recipe_dict = {
            'display_name':
            raw_recipe.title,
            'specs': [{
                # 'slug': raw_recipe.presentation,
                'slug': 'pdt',
                'display_name': 'PDT',
                'origin': MixologyTechConnector._get_origin(raw_recipe)
            }]
        }

        recipe_dict['specs'][0].update(
            MixologyTechConnector._detail_to_spec(raw_recipe.detail_json))

        print(recipe_dict)

        return CocktailFactory.raw_to_obj(raw_recipe=recipe_dict, slug=slug)
Beispiel #7
0
    def _get_garnish(self):
        raw_strings = [
            element.text.strip() for element in self.content.ul.find_all('li')
        ]
        garnishes = []

        for raw_string in raw_strings:
            if 'garnish' not in raw_string.lower():
                continue
            tokens = re.split(r"^(.*) \(Garnish\)$", raw_string)
            for token in tokens:
                if not token:
                    tokens.remove(token)

            garnish = {'slug': Slug(tokens[0])}

            garnishes.append(garnish)

        return garnishes
Beispiel #8
0
    def get_ingredients(self):
        all_ingredients = IngredientModel.query.all()
        # Log.info("Total ingredient count is %i" % len(all_ingredients))

        standardized_ingredients = []
        orphan_count = 0
        for ingredient in all_ingredients:
            # Log.info("Parsing %s" % ingredient.canonical_name)

            parent = self._get_parent_name(ingredient)
            if parent:
                kind = ProductKind.value
            else:
                kind = IngredientKind.value
                orphan_count += 1
            # Log.info("Parent is %s" % parent)

            standardized_ingredient = {
                'display_name': ingredient.canonical_name,
                'slug': Slug(ingredient.canonical_name),
                'aliases': self._get_ingredient_aliases(ingredient),
                'parent': parent,
                'kind': kind,
            }

            standardized_ingredients.append(standardized_ingredient)
            LogService.info(
                standardized_ingredient
            ) if not standardized_ingredient['parent'] else None

        # print(len(IngredientModel.query.all()))
        # for ingredient in IngredientModel.query.all():
        # print(ingredient.canonical_name)
        # for altname in IngredientAlternateSpellingModel.query.all():
        # print(altname.ingredient_id)
        LogService.info("Orphans at %i" % orphan_count)
        return standardized_ingredients
Beispiel #9
0
 def _get_spec_slug(self):
     slug = self.content.h3.p.a.text
     return Slug(slug)