#Python/Cater-Waiter/singleton_ingredients

13 messages · Page 1 of 1 (latest)

unique tundra
#

I'm getting a TypeError: unbound method set.union() needs an argument when running the test.
There is no set.union() in my function and I wonder if it's caused by the set.union() in the sets_test_data.py?
I've copied over the function as well as the relevant lists and sets from the sets_test_data.py and sets_categories_data.py to my local jupyter and used the loop of the test script to see if I can debug the error locally, but I'm not getting any errors here, the function works as expected.

My function is as follows:

def singleton_ingredients(dishes, intersection):
    """Determine which `dishes` have a singleton ingredient (an ingredient that only appears once across dishes).

    :param dishes: list - of ingredient sets.
    :param intersection: constant - can be one of `<CATEGORY>_INTERSECTIONS` constants imported from `sets_categories_data.py`.
    :return: set - containing singleton ingredients.

    Each dish is represented by a `set` of its ingredients.

    Each `<CATEGORY>_INTERSECTIONS` is an `intersection` of all dishes in the category. `<CATEGORY>` can be any one of:
        (VEGAN, VEGETARIAN, PALEO, KETO, or OMNIVORE).

    The function should return a `set` of ingredients that only appear in a single dish.
    """

    full_list = [ingredient for dish in dishes for ingredient in dish if ingredient not in intersection]
    unique_ingredients = {item for item in set(full_list) if full_list.count(item) == 1}
    return unique_ingredients

I've included the test error as screenshot.

I hope someone can help, thanks in advance!

runic silo
#

Could you share the test exception as text in a codeblock? Please do not use images to share text.

unique tundra
# runic silo Could you share the test exception as text in a codeblock? Please do not use ima...

of course:
the test code:

test_data = zip(dishes_and_overlap, singletons)

for variant, (item, result) in enumerate(test_data, start=1):
    with self.subTest(f"variation #{variant}", inputs="overlapping ingredients",
                      results="ingredients in only one dish"):

        error_message = ("Expected only ingredients that belong to exactly "
                        "one dish, but got multi-dish ingredients instead.")
        self.assertEqual(singleton_ingredients(item[0], item[1]), (result), msg=error_message)

resulting in:

TypeError: unbound method set.union() needs an argument
runic silo
#

@unique tundra Is there a test variation below that which you can expand and get more details?

unique tundra
# runic silo <@803054940384919623> Is there a test variation below that which you can expand ...

no, that's the only one.

I've copied over:

intersections = (VEGAN_INTERSECTIONS, VEGETARIAN_INTERSECTIONS, PALEO_INTERSECTIONS,
                 KETO_INTERSECTIONS, OMNIVORE_INTERSECTIONS)

dishes_and_overlap = [(item[0], item[1]) for item in zip(ingredients_only, intersections)]
ingredients = (set.union(*group) for group in ingredients_only)
singletons  = (item[0] ^ item[1] for item in zip(ingredients, intersections))

as well as all the intersections in the intersections Tuple, as well as ingredients_only, which I will not post here as they're large lists and sets

Then I've copied parts of the test code and modified for debugging:

test_data = zip(dishes_and_overlap, singletons)

for variant, (item, result) in enumerate(test_data, start=1):
    print(variant)
    print(singleton_ingredients(item[0], item[1]))
    print(result)

then I also changed the outputs to show types, len() and so on.

They all were as expected locally, I can't reproduce that error at all

runic silo
#

When I copy/paste your function, the tests all pass for me

#

Can you share your entire code file?

unique tundra
# runic silo Can you share your entire code file?

of course - removed the docstrings for space:

"""Functions for compiling dishes and ingredients for a catering company."""


from sets_categories_data import (VEGAN,
                                  VEGETARIAN,
                                  KETO,
                                  PALEO,
                                  OMNIVORE,
                                  ALCOHOLS,
                                  SPECIAL_INGREDIENTS)


def clean_ingredients(dish_name, dish_ingredients):
    return (dish_name, set(dish_ingredients))


def check_drinks(drink_name, drink_ingredients):
    drink_type = 'Cocktail' if set(drink_ingredients).intersection(ALCOHOLS) else 'Mocktail'
    return drink_name + ' ' + drink_type


def categorize_dish(dish_name, dish_ingredients):
    categories = ["VEGAN", "VEGETARIAN", "PALEO", "KETO", "OMNIVORE"]
    catlist = [VEGAN, VEGETARIAN, PALEO, KETO, OMNIVORE]

    for idx, category in enumerate(catlist):
        if len(dish_ingredients.intersection(category)) == len(dish_ingredients):
            dish_cat = categories[idx]
    return dish_name + ": " + dish_cat


def tag_special_ingredients(dish):
    special_ingredients = set(dish[1]).intersection(SPECIAL_INGREDIENTS)
    return (dish[0], special_ingredients)


def compile_ingredients(dishes):
    ingreds = set()
    for num in range(len(dishes)):
        ingreds.update(dishes.pop())
    return ingreds


def separate_appetizers(dishes, appetizers):
    return list({dish for dish in dishes if dish not in appetizers})


def singleton_ingredients(dishes, intersection):
    full_list = [ingredient for dish in dishes for ingredient in dish if ingredient not in intersection]
    unique_ingredients = {item for item in set(full_list) if full_list.count(item) == 1}
    return unique_ingredients
cloud void
unique tundra
#

code with all the docstrings how I last ran it

runic silo
#

ingreds.update(dishes.pop())
That might be mutating test data

unique tundra
#

omg yes that was it! thanks!

changed to use a copy and now everything is green 👍

def compile_ingredients(dishes):
    """Create a master list of ingredients.

    :param dishes: list - of dish ingredient sets.
    :return: set - of ingredients compiled from `dishes`.

    This function should return a `set` of all ingredients from all listed dishes.
    """

    dishes_cp = dishes.copy()
    ingreds = set()
    for num in range(len(dishes_cp)):
        ingreds.update(dishes_cp.pop())
    return ingreds