From 214532823f12d609a121b45abf5cd5f81017823e Mon Sep 17 00:00:00 2001 From: Drew Winstel Date: Sat, 22 Feb 2020 07:53:04 -0600 Subject: [PATCH] Strip exact matches from brewery name during beer lookup (#302) * Strip exact matches from brewery name during beer lookup Addresses #301 * Try stripping common brewery names before removing from beer name * fix test * Restore manufacturer name if it starts with an obvious punctuation Fixes #321 * refactor into a function and add a test * add trailing blank line * Fix some pylint issues --- tap_list_providers/base.py | 14 ++++++++++++++ tap_list_providers/parsers/taphunter.py | 17 ++++++++++++----- tap_list_providers/test/test_base.py | 16 ++++++++++++++++ tap_list_providers/test/test_beermenus.py | 20 +++++++++++++++++--- 4 files changed, 59 insertions(+), 8 deletions(-) diff --git a/tap_list_providers/base.py b/tap_list_providers/base.py index 595d3383..0b7b0b51 100644 --- a/tap_list_providers/base.py +++ b/tap_list_providers/base.py @@ -116,6 +116,15 @@ def get_style(self, name): self.styles[name.casefold()] = style return style + def reformat_beer_name(self, name: str, mfg_name: str) -> str: + """Try to strip the manufacturer name if possible""" + original_name = name.strip() + name = name.replace(mfg_name, '').strip() + if name.startswith(tuple('/-_')): + # it's likely a collaboration beer. Put the manufacturer back in there. + name = original_name + return name + def guess_style(self, beer_name): """Try to guess the style from the beer name""" ci_name = beer_name.casefold() @@ -157,6 +166,11 @@ def get_beer(self, name, manufacturer, pricing=None, venue=None, **defaults): 'get_beer(): name %s, mfg %s, defaults %s', name, manufacturer, defaults, ) + mfg_name = manufacturer.name + for ending in COMMON_BREWERY_ENDINGS: + if mfg_name.endswith(ending): + mfg_name = mfg_name.replace(ending, '').strip() + name = self.reformat_beer_name(name, mfg_name) unique_fields = ( 'manufacturer_url', 'untappd_url', 'beer_advocate_url', 'taphunter_url', 'taplist_io_pk', 'beermenus_slug', diff --git a/tap_list_providers/parsers/taphunter.py b/tap_list_providers/parsers/taphunter.py index f15e9048..51b6355b 100644 --- a/tap_list_providers/parsers/taphunter.py +++ b/tap_list_providers/parsers/taphunter.py @@ -1,3 +1,5 @@ +"""Parse beers from TapHunter""" +import argparse import decimal import logging import os @@ -31,6 +33,7 @@ class TaphunterParser(BaseTapListProvider): def __init__(self, location=None): """Constructor.""" self.url = None + self.json = {} if location: self.url = self.URL.format(location) super().__init__() @@ -92,7 +95,7 @@ def handle_venue(self, venue): manufacturers[manufacturer.name] = manufacturer # 3. get the beer, creating if necessary parsed_beer = self.parse_beer(entry) - name = parsed_beer.pop('name') + name = parsed_beer['name'] style = parsed_beer.pop('style', {}) if style: parsed_beer['style'] = f"{style['category']} - {style['name']}" @@ -104,7 +107,7 @@ def handle_venue(self, venue): name, manufacturer, parsed_beer, ) beer = self.get_beer( - name, manufacturer, pricing=self.parse_pricing(entry), + manufacturer=manufacturer, pricing=self.parse_pricing(entry), venue=venue, **parsed_beer, ) # 4. assign the beer to the tap @@ -182,6 +185,7 @@ def parse_pricing(self, tap): def fetch(self): data = requests.get(self.url).json() + self.json = data return data def taps(self): @@ -195,9 +199,8 @@ def taps(self): return ret -if __name__ == '__main__': - import argparse - +def main(): + """Simple console stuff""" locations = { 'wholefoods': '5963904507707392', 'lexpress': '6200813693698048', @@ -217,3 +220,7 @@ def taps(self): else: for tap in t.taps(): print(json.dumps(tap, indent=4)) + + +if __name__ == '__main__': + main() diff --git a/tap_list_providers/test/test_base.py b/tap_list_providers/test/test_base.py index 8896e5d6..15cae5f8 100644 --- a/tap_list_providers/test/test_base.py +++ b/tap_list_providers/test/test_base.py @@ -53,3 +53,19 @@ def test_style_strip_none(self): style = StyleFactory(name='test style') looked_up = provider.get_style('None - TEST STYLE') self.assertEqual(looked_up, style) + + +class FixBeerNameTestCase(TestCase): + """Test reformatting beer names""" + + def test_standard(self): + """Test the standard case""" + provider = BaseTapListProvider() + name = provider.reformat_beer_name('Stone IPA', 'Stone') + self.assertEqual(name, 'IPA') + + def test_collab(self): + """Test collaborations (See #321)""" + provider = BaseTapListProvider() + name = provider.reformat_beer_name('Hi-Wire / New Belgium Belgian Stout', 'Hi-Wire') + self.assertEqual(name, 'Hi-Wire / New Belgium Belgian Stout') diff --git a/tap_list_providers/test/test_beermenus.py b/tap_list_providers/test/test_beermenus.py index 865c59da..b9208690 100644 --- a/tap_list_providers/test/test_beermenus.py +++ b/tap_list_providers/test/test_beermenus.py @@ -6,7 +6,8 @@ from django.test import TestCase import responses -from beers.models import Beer, Manufacturer +from beers.models import Beer, Manufacturer, ManufacturerAlternateName +from beers.test.factories import ManufacturerFactory from venues.test.factories import VenueFactory from venues.models import Venue, VenueAPIConfiguration from taps.models import Tap @@ -60,6 +61,10 @@ def setUpTestData(cls): ) with open(os.path.join(PATH, name)) as infile: cls.locations.append((url, name, infile.read())) + rocket = ManufacturerFactory(name='Rocket Republic Brewing Company') + ManufacturerAlternateName.objects.create( + name='Rocket Republic', manufacturer=rocket, + ) def beer_menu_callback(self, request): if request.url.endswith('?section_id=12'): @@ -85,7 +90,6 @@ def test_import_beermenus_data(self): self.assertFalse(Tap.objects.exists()) self.assertEqual(Venue.objects.count(), 1) self.assertFalse(Beer.objects.exists()) - self.assertFalse(Manufacturer.objects.exists()) deleted_tap = Tap.objects.create( venue=self.venue, tap_number=3000, @@ -101,7 +105,7 @@ def test_import_beermenus_data(self): self.assertEqual(Manufacturer.objects.count(), 22) self.assertEqual(Tap.objects.count(), 24) taps = Tap.objects.filter( - venue=self.venue, tap_number__in=[1, 17], + venue=self.venue, tap_number__in=[1, 17, 2, 19], ).select_related( 'beer__style', 'beer__manufacturer', ).order_by('tap_number') @@ -121,6 +125,10 @@ def test_import_beermenus_data(self): self.assertEqual(price.serving_size.volume_oz, 16) tap = taps[1] + self.assertEqual(tap.beer.name, 'Crisp Apple Cider') + self.assertEqual(tap.beer.manufacturer.name, 'Angry Orchard') + + tap = taps[2] self.assertEqual( tap.beer.name, 'Modelo Especial', @@ -134,3 +142,9 @@ def test_import_beermenus_data(self): self.assertEqual(price.price, 6) self.assertEqual(price.serving_size.volume_oz, 16) self.assertFalse(Tap.objects.filter(id=deleted_tap.id).exists()) + + tap = taps[3] + self.assertEqual(tap.beer.name, 'Vapor Trail Cream Ale') + self.assertEqual( + tap.beer.manufacturer.name, 'Rocket Republic Brewing Company', + )