Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions swap_meet/clothing.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
class Clothing:
pass
from swap_meet.item import Item

class Clothing(Item):
def __init__(self, id=None, fabric="Unknown", condition=0):
super().__init__(id, condition)
self.fabric = fabric

def __str__(self):
return super().__str__() + f'. It is made from {self.fabric} fabric.'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are using an f-string already, another option would be to call the superclass function from a placeholder:

return f"{super().__str__()}. It is made from {self.fabric} fabric."

12 changes: 10 additions & 2 deletions swap_meet/decor.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
class Decor:
pass
from swap_meet.item import Item

class Decor(Item):
def __init__(self, id=None, width=0, length=0, condition=0):
super().__init__(id, condition)
self.width = width
self.length = length

def __str__(self):
return super().__str__() + f'. It takes up a {self.width} by {self.length} sized space.'
15 changes: 13 additions & 2 deletions swap_meet/electronics.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
class Electronics:
pass
from swap_meet.item import Item

class Electronics(Item):
def __init__(self, id=None, type="Unknown", condition=0):
super().__init__(id, condition)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of inheritance across the child classes 👍

self.type = type

def get_category(self):
return f'{self.__class__.__name__}'
Comment on lines +8 to +9

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Clothing and Decor use the parent class' get_category method, but Electronics has its own implementation. Can Electronics use the parent class too?


def __str__(self):
return super().__str__() + f'. This is a {self.type} device.'

32 changes: 30 additions & 2 deletions swap_meet/item.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,30 @@
class Item:
pass
import uuid

class Item:
def __init__(self, id=None, condition=0):
if not id:
id = uuid.uuid4().int
self.id = id
Comment on lines +5 to +7

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice solution, another option here could use conditional assignment:

# Assigns self.id to the parameter id if id is truthy, 
# otherwise assigns self.id the return value of uuid.uuid4().int
self.id = id if id else uuid.uuid4().int

self.condition = condition

def get_category(self):
return self.__class__.__name__

def __str__(self):
return f"An object of type {self.get_category()} with id {self.id}"

def condition_description(self):
if self.condition == 0:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice handling for condition description! It looks like the code assumes that self.condition will always be an integer, but what if we allowed decimals like a condition of 3.5? How could we adapt our code to convert the decimal to an int we could use here, or alternately, change the if-statements to support decimals?

return f'Heavily used'
elif self.condition == 1:
return f'Acceptable'
elif self.condition == 2:
return f'Good'
elif self.condition == 3:
return f'Very good'
elif self.condition == 4:
return f'Like new'
else:
return f"Brand New"


103 changes: 102 additions & 1 deletion swap_meet/vendor.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,103 @@
class Vendor:
pass
#default value should not be mutable!!!
def __init__(self, inventory=None):
if not inventory:
self.inventory = []
else:
self.inventory = inventory

def add(self, item):
self.inventory.append(item)
return item

def remove(self, item):
if item not in self.inventory:
return None
self.inventory.remove(item)
return item

def get_by_id(self, id): #if id is None? ==> wave02
for item in self.inventory:
if item.id == id:
return item
return None

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that you're explicitly returning None when an item can't be found.


def swap_items(self, other_vendor, my_item, their_item):
if my_item not in self.inventory or their_item not in other_vendor.inventory:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With indentation this line is a little long, I would consider breaking it up at the or statement.

if (my_item not in self.inventory 
        or their_item not in other_vendor.inventory):
    return False

The PEP8 style guide doesn't give a strict recommendation on how to break an if-statement across multiple lines, but they give a few suggestions in the second half of the section on indentation: https://peps.python.org/pep-0008/#indentation

return False
other_vendor.add(my_item)
self.remove(my_item)
Comment on lines +28 to +29

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of the Vendor methods 🙂

self.add(their_item)
other_vendor.remove(their_item)
return True

#TODO reuse swap_itme()
def swap_first_item(self, other_vendor):
if not other_vendor.inventory or not self.inventory:
return False
first_my_item = self.remove(self.inventory[0])
other_vendor.add(first_my_item)
first_their_item = other_vendor.remove(other_vendor.inventory[0])
self.add(first_their_item)
Comment on lines +38 to +41

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you have a note above about reusing swap_items - that would be great here to reduce the similar code in both functions!

return True

def get_by_category(self, category):
items = []
for item in self.inventory:
if item.get_category() == category:
items.append(item)
return items
Comment on lines +45 to +49

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notice this pattern of:

result_list = []
for element in source_list:
    if some_condition(element):
        result_list.append(element)

can be rewritten using a list comprehension as:

result_list = [element for element in source_list if some_condition(element)]

Which here would look like:

items = [item for item in self.inventory if item.get_category() == category]

At first, this may seem more difficult to read, but comprehensions are a very common python style, so I encourage y’all to practice working with them!


def get_best_by_category(self, category=""):
items = self.get_by_category(category)
best_condition = 0.0
best_item = None
for item in items:
if item.condition > best_condition:
best_item = item
best_condition = item.condition
return best_item
Comment on lines +55 to +59

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice loop! The time complexity would be the same, but another way we could write this is using the max function with a lambda function that tells max to use the item's condition attribute:

return max(items, key=lambda item: item.condition)


def swap_best_by_category(self, other_vendor, my_priority, their_priority):
my_item = self.get_best_by_category(their_priority)
their_item = other_vendor.get_best_by_category(my_priority)

return self.swap_items(other_vendor, my_item, their_item)

#wave 07
def display_inventory(self, category=""):
if not self.inventory:
print("No inventory to display.")
elif not category:
for i, item in enumerate(self.inventory):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great use for enumerate! If we don't want to manually add the +1 to i, enumerate can take a second parameter that tells the counter i where to start: enumerate(self.inventory, start=1)

print(f"{i+1}. {str(item)}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because we have implemented the __str__ method, this is one of the situations where python will implicitly call it for us, we don't need to wrap item in a call to str:

print(f"{i+1}. {item}")

else:
display_items = self.get_by_category(category)
if not display_items:
print("No inventory to display.")
else:
for i, item in enumerate(display_items):
print(f"{i+1}. {str(item)}")
Comment on lines +69 to +80

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if-tree is pretty nested and we repeat our looping and no inventory code. If we first resolve what list of items we want to iterate over, then error handle if it is empty, we can remove some of the if-elses:

# If `category` is not empty or None, get a list of items with that category, 
# otherwise set `display_items` to `self.inventory`
display_items = self.get_by_category(category) if category else self.inventory
# The line above would be equivalent to
# if category:
#     display_items = self.get_by_category(category)
# else:
#     display_items = self.inventory

# We can now remove code that was repeated when the list of items was empty
if not display_items:
    print("No inventory to display.") 
    return

# If we've gotten here, there must be an inventory to print
for index, item in enumerate(display_items, start=1):
    print(f"{index}. {item}")


def swap_by_id(self, other_vendor, my_item_id,their_item_id):
my_item = self.get_by_id(my_item_id)
their_item = other_vendor.get_by_id(their_item_id)

return self.swap_items(other_vendor, my_item, their_item)

def choose_and_swap_items(self, other_vendor, category=""):

self.display_inventory(category)
my_item_id = int(input("Enter an item id from your inventory: "))

other_vendor.display_inventory(category)
their_item_id = int(input("Enter an item id from your friend's inventory: "))

return self.swap_by_id(other_vendor, my_item_id, their_item_id)







2 changes: 1 addition & 1 deletion tests/integration_tests/test_wave_01_02_03.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from swap_meet.vendor import Vendor
from swap_meet.item import Item

@pytest.mark.skip
# @pytest.mark.skip
@pytest.mark.integration_test
def test_integration_wave_01_02_03():
# make a vendor
Expand Down
2 changes: 1 addition & 1 deletion tests/integration_tests/test_wave_04_05_06_07.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from swap_meet.decor import Decor
from swap_meet.electronics import Electronics

@pytest.mark.skip
# @pytest.mark.skip
@pytest.mark.integration_test
def test_integration_wave_04_05_06(capfd):
camila = Vendor()
Expand Down
14 changes: 8 additions & 6 deletions tests/unit_tests/test_wave_01.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
import pytest
from swap_meet.vendor import Vendor

@pytest.mark.skip
# @pytest.mark.skip
def test_vendor_has_inventory():
vendor = Vendor()
assert len(vendor.inventory) == 0

@pytest.mark.skip
# @pytest.mark.skip
def test_vendor_takes_optional_inventory():
inventory = ["a", "b", "c"]
vendor = Vendor(inventory=inventory)
Expand All @@ -16,7 +16,7 @@ def test_vendor_takes_optional_inventory():
assert "b" in vendor.inventory
assert "c" in vendor.inventory

@pytest.mark.skip
# @pytest.mark.skip
def test_adding_to_inventory():
vendor = Vendor()
item = "new item"
Expand All @@ -27,7 +27,7 @@ def test_adding_to_inventory():
assert item in vendor.inventory
assert result == item

@pytest.mark.skip
# @pytest.mark.skip
def test_removing_from_inventory_returns_item():
item = "item to remove"
vendor = Vendor(
Expand All @@ -40,7 +40,7 @@ def test_removing_from_inventory_returns_item():
assert item not in vendor.inventory
assert result == item

@pytest.mark.skip
# @pytest.mark.skip
def test_removing_not_found_returns_none():
item = "item to remove"
vendor = Vendor(
Expand All @@ -49,7 +49,9 @@ def test_removing_not_found_returns_none():

result = vendor.remove(item)

raise Exception("Complete this test according to comments below.")
assert result is None

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice assert, we definitely want to confirm our return value is None. We generally also want to confirm that there weren't side affects or changes to the input that we didn't intend. What could we check about the vendor's inventory to confirm that its content didn’t change?


# raise Exception("Complete this test according to comments below.")
# *********************************************************************
# ****** Complete Assert Portion of this test **********
# *********************************************************************
12 changes: 6 additions & 6 deletions tests/unit_tests/test_wave_02.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,30 @@
from swap_meet.vendor import Vendor
from swap_meet.item import Item

@pytest.mark.skip
# @pytest.mark.skip
def test_items_have_default_uuid_length_id():
item = Item()
assert isinstance(item.id, int)
assert len(str(item.id)) >= 32

@pytest.mark.skip
# @pytest.mark.skip
def test_item_instances_have_different_default_ids():
item_a = Item()
item_b = Item()
assert item_a.id != item_b.id

@pytest.mark.skip
# @pytest.mark.skip
def test_items_use_custom_id_if_passed():
item = Item(id=12345)
assert isinstance(item.id, int)
assert item.id == 12345

@pytest.mark.skip
# @pytest.mark.skip
def test_item_obj_returns_text_item_for_category():
item = Item()
assert item.get_category() == "Item"

@pytest.mark.skip
# @pytest.mark.skip
def test_get_item_by_id():
test_id = 12345
item_custom_id = Item(id=test_id)
Expand All @@ -36,7 +36,7 @@ def test_get_item_by_id():
result_item = vendor.get_by_id(test_id)
assert result_item is item_custom_id

@pytest.mark.skip
# @pytest.mark.skip
def test_get_item_by_id_no_matching():
test_id = 12345
item_a = Item()
Expand Down
15 changes: 8 additions & 7 deletions tests/unit_tests/test_wave_03.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from swap_meet.vendor import Vendor
from swap_meet.item import Item

@pytest.mark.skip
# @pytest.mark.skip
def test_item_overrides_to_string():
test_id = 12345
item = Item(id=test_id)
Expand All @@ -12,7 +12,7 @@ def test_item_overrides_to_string():
expected_result = f"An object of type Item with id {test_id}"
assert item_as_string == expected_result

@pytest.mark.skip
# @pytest.mark.skip
def test_swap_items_returns_true():
item_a = Item()
item_b = Item()
Expand Down Expand Up @@ -40,7 +40,7 @@ def test_swap_items_returns_true():
assert item_b in jolie.inventory
assert result

@pytest.mark.skip
# @pytest.mark.skip
def test_swap_items_when_my_item_is_missing_returns_false():
item_a = Item()
item_b = Item()
Expand All @@ -67,7 +67,7 @@ def test_swap_items_when_my_item_is_missing_returns_false():
assert item_e in jolie.inventory
assert not result

@pytest.mark.skip
# @pytest.mark.skip
def test_swap_items_when_their_item_is_missing_returns_false():
item_a = Item()
item_b = Item()
Expand All @@ -94,7 +94,7 @@ def test_swap_items_when_their_item_is_missing_returns_false():
assert item_e in jolie.inventory
assert not result

@pytest.mark.skip
# @pytest.mark.skip
def test_swap_items_from_my_empty_returns_false():
fatimah = Vendor(
inventory=[]
Expand All @@ -114,7 +114,7 @@ def test_swap_items_from_my_empty_returns_false():
assert len(jolie.inventory) == 2
assert not result

@pytest.mark.skip
# @pytest.mark.skip
def test_swap_items_from_their_empty_returns_false():
item_a = Item()
item_b = Item()
Expand All @@ -131,7 +131,8 @@ def test_swap_items_from_their_empty_returns_false():

result = fatimah.swap_items(jolie, item_b, nobodys_item)

raise Exception("Complete this test according to comments below.")
assert not result

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feedback in wave 1 applies here as well, what else would be helpful to assert to ensure there were no unintended side effects?

# raise Exception("Complete this test according to comments below.")
# *********************************************************************
# ****** Complete Assert Portion of this test **********
# *********************************************************************
6 changes: 3 additions & 3 deletions tests/unit_tests/test_wave_04.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from swap_meet.vendor import Vendor
from swap_meet.item import Item

@pytest.mark.skip
# @pytest.mark.skip
def test_swap_first_item_returns_true():
item_a = Item()
item_b = Item()
Expand Down Expand Up @@ -30,7 +30,7 @@ def test_swap_first_item_returns_true():
assert item_a in jolie.inventory
assert result

@pytest.mark.skip
# @pytest.mark.skip
def test_swap_first_item_from_my_empty_returns_false():
fatimah = Vendor(
inventory=[]
Expand All @@ -48,7 +48,7 @@ def test_swap_first_item_from_my_empty_returns_false():
assert len(jolie.inventory) == 2
assert not result

@pytest.mark.skip
# @pytest.mark.skip
def test_swap_first_item_from_their_empty_returns_false():
item_a = Item()
item_b = Item()
Expand Down
Loading