Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
96de9be
wave 1 complete
LRyder17 Apr 3, 2023
be0f993
start wave 2, need to finish
Kguarnizo Apr 4, 2023
0cb1c85
Complete wave 2
Kguarnizo Apr 4, 2023
14fc5bc
don't save this
LRyder17 Apr 4, 2023
8469fd7
resolved merge conflict
LRyder17 Apr 4, 2023
62e5b2c
need to finish wave 3
Kguarnizo Apr 4, 2023
4b4855f
need to finish wave 3
Kguarnizo Apr 4, 2023
2cbdc4f
completes wave 3
LRyder17 Apr 5, 2023
b60804d
Commit to pull latest completion of wave 3
Kguarnizo Apr 5, 2023
6acb7f1
Merge branch 'main' of https://github.com/Kguarnizo/swap-meet
Kguarnizo Apr 5, 2023
fb27ffd
Complete wave 4
Kguarnizo Apr 5, 2023
496be4e
not this save
LRyder17 Apr 5, 2023
8b86ec4
Merge branch 'main' of https://github.com/Kguarnizo/swap-meet
LRyder17 Apr 5, 2023
efb330b
Start wave 5, need to complete
Kguarnizo Apr 5, 2023
7a1f546
Merge branch 'main' of https://github.com/Kguarnizo/swap-meet
LRyder17 Apr 5, 2023
3649570
completes wave 5
LRyder17 Apr 5, 2023
1e8ab64
Start wave 6, need to finish
Kguarnizo Apr 5, 2023
c8b64d7
completes get_items_by_category
LRyder17 Apr 6, 2023
b3d3ef2
completes swap_by_best_category
LRyder17 Apr 6, 2023
d214b66
need to pull latest changes
Kguarnizo Apr 6, 2023
5eef2f2
Merge branch 'main' of https://github.com/Kguarnizo/swap-meet
Kguarnizo Apr 6, 2023
accbafe
Complete last wave 6
Kguarnizo Apr 6, 2023
d82cb38
begin optional enhancements
Kguarnizo Apr 6, 2023
a304387
adds check by age function
LRyder17 Apr 7, 2023
0939b77
complete some optional enhancements. need to pull latest
Kguarnizo Apr 7, 2023
d7585c2
Complete some optional enhancements and passing 1st 3 integration tests
Kguarnizo Apr 7, 2023
a226137
passes test integrations
LRyder17 Apr 7, 2023
7b8a3d6
Merge branch 'main' of https://github.com/Kguarnizo/swap-meet
LRyder17 Apr 7, 2023
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
14 changes: 12 additions & 2 deletions swap_meet/clothing.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
class Clothing:
pass
from .item import Item


class Clothing(Item):
def __init__(self, id = None, age = 0.0, condition = 0.0, fabric = "Unknown"):
super().__init__(id= id, age = age, condition = condition)
self.fabric = fabric
Comment on lines +5 to +7

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Nice subclass constructors!



def __str__(self):
parent_str = super().__str__()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great use of the superclass method!

return (f'{parent_str} It is made from {self.fabric} fabric.')
14 changes: 12 additions & 2 deletions swap_meet/decor.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
class Decor:
pass
from .item import Item

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


def __str__(self):
parent_str = super().__str__()
return (f'{parent_str} 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 .item import Item

class Electronics(Item):

def __init__(self, id = None, age = 0.0, condition = 0.0, type = "Unknown"):
super().__init__(id = id, age = age, condition = condition)
self.type = type

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


48 changes: 47 additions & 1 deletion swap_meet/item.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,48 @@
import uuid

class Item:
pass
def __init__(self, age = 0.0 , id = None, condition = 0.0):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Tiny style nitpick:
Calling a function and providing keyword arguments or providing default arguments when defining a function are some of the only places where the PEP8 style guide recommends we don't place spaces around the = operator. (Docs: https://peps.python.org/pep-0008/#whitespace-in-expressions-and-statements:~:text=Don%E2%80%99t%20use%20spaces,%3D%20imag))

if id is None:
self.id = uuid.uuid4().int
else:
self.id = id
self.condition = condition
self.age = age

def __str__(self):
return f'An object of type {self.__class__.__name__} with id {self.id}.'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

How could we use get_category to D.R.Y. this line up a little?


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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great way to look up the class name dynamically!


def get_age(self):
return self.age

def condition_description(self):
if self.condition >= 0.0 and self.condition < 1.0:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great considerations in the conditionals for if self.condition is a decimal!

return "Should you get this? IT DEPENDS! ʕ •ᴥ• ʔ"
elif self.condition >= 1.0 and self.condition < 2.0:
return "One person's garbage is another's treasure."
elif self.condition >= 2.0 and self.condition < 3.0:
return "If you squint, you can't even tell."
elif self.condition >= 3.0 and self.condition < 4.0:
return "This is a bargan for the price."
elif self.condition >= 4.0 and self.condition < 5.0:
return "This item has been well cared for, but you can tell you're not the first owner."
elif self.condition >= 5.0:
return "This item is immaculate. If you don't buy it, I will!"
Comment on lines +22 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Another approach for finding the condition description could be to make a dictionary that maps conditions as keys to descriptions as values. There's a trade off of using more memory creating the map variable, but if memory isn't a concern, for me, it's a little easier to read.

condition_map = {
    0: "Not Usable”,
    1: "Gross",
    2: "Wear and Tear",
    3: "Not Great",
    4: "Gently used",
    5: "Like new"
}
        
return condition_map[int(self.condition)]


def age_description(self):
if self.age >= 0.0 and self.age < 1.0:
return "I've had this for less than a year!"
elif self.age >= 1.0 and self.age < 2.0:
return "I've had this for a little over a year!"
elif self.age >= 2.0 and self.age < 3.0:
return "I've had this for over two years but not more than three!"
elif self.age >= 3.0 and self.age < 4.0:
return "I've had this for over three years but not more than four!"
elif self.age >= 4.0 and self.age < 5.0:
return "I've had this for over four years but not more than five!"
elif self.age >= 5.0:
return "I've had this for over five years!"

92 changes: 91 additions & 1 deletion swap_meet/vendor.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,92 @@
from .item import Item
from .decor import Decor
from .electronics import Electronics
from .clothing import Clothing

class Vendor:
pass
def __init__(self, inventory = None):
self.inventory = [] if inventory is None else inventory

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great use for a ternary operator!


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

def remove(self, item):
if item not in self.inventory:
return False
else:
self.inventory.remove(item)
return item
Comment on lines +15 to +19

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The else keyword doesn't change the outcome of the code in this case, I suggest removing it so the code in that block can be un-indented:

if item not in self.inventory:
    return False

self.inventory.remove(item)
return item


def get_by_id(self, id):
for item in self.inventory:
if item.id == id:
return item
if isinstance(id, Item):
raise ValueError("id should be an int!")
Comment on lines +25 to +26

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

What does the expression isinstance(id, Item) tell us? Could you explain what this validation check is doing for the function overall?



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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

There is a small bug in this line that our test data doesn't account for.

  • Which vendors do their_item and my_item start out in?
  • What happens later in the code if their_item is not in other_vendor.inventory?
  • How could we fix this?

my_index, their_index = self.inventory.index(my_item), other_vendor.inventory.index(their_item)
self.inventory[my_index], other_vendor.inventory[their_index] = their_item, my_item
Comment on lines +33 to +34

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

To keep the line lengths under 79 characters and make these statements easy to read at a glance, I highly recommend splitting both the variable declarations and assignments into their own lines.

return True
return False


def swap_first_item(self, other_vendor):
if not self.inventory or not other_vendor.inventory:
return False

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I would consider adding a blank line after validation checks like this to give readers a visual separation between sections of our code that are doing slightly different things.

self.inventory[0], other_vendor.inventory[0] = (other_vendor.inventory[0], self.inventory[0])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Neat way to get O(1) time complexity for this function! This is another line I recommend refactoring for length, one option could be pulling the right side values into variables:

my_item = self.inventory[0]
their_item = other_vendor.inventory[0]
self.inventory[0], other_vendor.inventory[0] = their_item, my_item

return True

def get_by_category(self, category):
matching_items = []
matching_items = [item for item in self.inventory if item.get_category() == category]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great place for a list comprehension!

if matching_items:
return matching_items
else:
return []
Comment on lines +48 to +51

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I see an opportunity to reduce the code a little, do we need to create a new empty list on line 51 if matching_items is empty?


def get_best_by_category(self, category):
items = self.get_by_category(category)
if not items:
return None
return max(items, key=lambda item: item.condition)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Love the use of max here!


def swap_best_by_category(self, other_vendor, my_priority, their_priority):
my_best_item = self.get_best_by_category(their_priority)
their_best_item = other_vendor.get_best_by_category(my_priority)
if my_best_item and their_best_item:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could we change this into a guard statement to let us unindent the intended flow of the function?

if self.swap_items(other_vendor, my_best_item, their_best_item):
return True
return False

def get_by_age(self, age):
matching_items = []
matching_items = [item for item in self.inventory if item.get_age() == age]
if matching_items:
return matching_items
else:
return None

def get_best_by_age(self, vendor):
items = vendor.inventory
if not items:
return None
return min(items, key=lambda item: item.age)

def swap_best_by_age(self, other_vendor):
my_newest_item = self.get_best_by_age(self)
their_newest_item = other_vendor.get_best_by_age(other_vendor)
if my_newest_item and their_newest_item:
if self.swap_items(other_vendor, my_newest_item, their_newest_item):
return True
return False





4 changes: 2 additions & 2 deletions tests/integration_tests/test_wave_01_02_03.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from swap_meet.vendor import Vendor
from swap_meet.item import Item

@pytest.mark.skip
@pytest.mark.integration_test
# @pytest.mark.skip
# @pytest.mark.integration_test

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

For integration tests, we want to leave the decorator @pytest.mark.integration_test uncommented. This decorator tells pytest that this is an integration test, so we should run it after all of the unit tests.

def test_integration_wave_01_02_03():
# make a vendor
vendor = Vendor()
Expand Down
4 changes: 2 additions & 2 deletions tests/integration_tests/test_wave_04_05_06.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from swap_meet.decor import Decor
from swap_meet.electronics import Electronics

@pytest.mark.skip
@pytest.mark.integration_test
# @pytest.mark.skip
# @pytest.mark.integration_test
def test_integration_wave_04_05_06():
camila = Vendor()
valentina = Vendor()
Expand Down
110 changes: 110 additions & 0 deletions tests/unit_tests/test_age_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import pytest
from swap_meet.item import Item
from swap_meet.vendor import Vendor
from swap_meet.clothing import Clothing
from swap_meet.decor import Decor
from swap_meet.electronics import Electronics

def test_age_is_assigned_to_item_instances():
# Act
item_a = Clothing(age=2.0)
item_b = Decor(age=3.0)
item_c = Electronics(age=4.0)
tai = Vendor(
inventory=[item_a, item_b]
)

item_a_age, item_b_age, item_c_age = item_a.age, item_b.age, item_c.age

assert item_a_age == 2.0
assert item_b_age == 3.0
assert item_c_age == 4.0

def test_get_age_returns_correct_age_value():
item_a = Clothing(age=2.0)
item_b = Decor(age=3.0)
tai = Vendor(
inventory=[item_a, item_b]
)
result = item_a.get_age()

assert result == 2.0

def test_get_by_age_returns_items_with_matching_age():
item_a = Clothing()
item_a.age = 2.0
item_b = Electronics()
item_b.age = 3.0
item_c = Decor()
item_c.age = 3.0
vendor = Vendor(
inventory=[item_a, item_b, item_c]
)


items = vendor.get_by_age(3.0)

assert item_b in items
assert item_c in items
assert item_a not in items

def test_get_best_by_age_return_newest_item():
item_a = Clothing()
item_a.age = 2.0
item_b = Clothing()
item_b.age = 3.0
item_c = Clothing()
item_c.age = 4.0
item_d = Electronics()
item_d.age = 1.0
vendor = Vendor(
inventory=[item_a, item_b, item_c, item_d]
)

result = vendor.get_best_by_age(vendor)

assert result == item_d

def test_swap_best_by_age_returns_True():
item_a = Clothing()
item_a.age = 2.0
item_b = Clothing()
item_b.age = 3.0
item_c = Clothing()
item_c.age = 4.0
vendor = Vendor(
inventory=[item_a, item_b, item_c]
)
item_d = Clothing()
item_d.age = 4.0
item_e = Clothing()
item_e.age = 3.0
item_f = Clothing()
item_f.age = 2.0
james = Vendor(
inventory=[item_d, item_e, item_f]
)
result = vendor.swap_best_by_age(james)

assert result
assert item_a in james.inventory
assert item_f in vendor.inventory

def test_items_have_age_descriptions_that_are_the_same_regardless_of_type():
items = [
Clothing(age=5),
Decor(age=5),
Electronics(age=5)
]
five_age_description = items[0].age_description()
assert isinstance(five_age_description, str)
for item in items:
assert item.age_description() == five_age_description
items[0].age = 1
one_age_description = items[0].age_description()
assert isinstance(one_age_description, str)
for item in items:
item.age = 1
assert item.age_description() == one_age_description

assert one_age_description != five_age_description
15 changes: 6 additions & 9 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

def test_vendor_has_inventory():
vendor = Vendor()
assert len(vendor.inventory) == 0

@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

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

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

def test_removing_not_found_is_false():
item = "item to remove"
vendor = Vendor(
Expand All @@ -49,7 +49,4 @@ def test_removing_not_found_is_false():

result = vendor.remove(item)

raise Exception("Complete this test according to comments below.")
# *********************************************************************
# ****** Complete Assert Portion of this test **********
# *********************************************************************
assert result == False

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Something to consider, if the function returns False does that guarantee the function did not alter the inventory? Checking the vendor.inventory contents as well would confirm there are no unintended side effects.

  • What could that look like?
  • Are there tests in other waves that could benefit from similar changes?

Loading