-
Notifications
You must be signed in to change notification settings - Fork 26
C22 Luqi Xie and Anees Quateja #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
6533bc3
4c347bb
dcbe314
7187666
6103c5d
13488dd
df59637
4dd0fda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,14 @@ | ||
| class Clothing: | ||
| pass | ||
| from swap_meet.item import Item | ||
| import uuid | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need to import |
||
|
|
||
| class Clothing(Item): | ||
| def __init__(self, id=None, fabric="Unknown", condition=0): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 It's usually preferred to follow the same order of parameters as used by the parent type for the parameters that are shared in common def __init__(self, id=None, condition=0, fabric="Unknown"): |
||
| super().__init__(id, condition) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Using |
||
| self.fabric = fabric | ||
|
|
||
| def get_category(self): | ||
| return "Clothing" | ||
|
Comment on lines
+9
to
+10
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 Because your implementation of Why might that be? |
||
|
|
||
| def __str__(self): | ||
| return f"An object of type Clothing with id {self.id}. It is made from {self.fabric} fabric." | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notice that the first part of the description here is the same as what
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As written, this line is getting a bit long. Consider wrapping the line. return (
f"An object of type Clothing with id {self.id}. "
f"It is made from {self.fabric} fabric."
)Alternatively, reusing the description from |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,15 @@ | ||
| 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 get_category(self): | ||
| return "Decor" | ||
|
|
||
| def __str__(self): | ||
| return f"An object of type Decor with id {self.id}. It takes up a {self.width} by {self.length} sized space." | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,15 @@ | ||
| 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) | ||
| self.type = type | ||
|
|
||
|
|
||
| def get_category(self): | ||
| return "Electronics" | ||
|
|
||
| def __str__(self): | ||
| return f"An object of type Electronics with id {self.id}. This is a {self.type} device." | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,27 @@ | ||
| import uuid | ||
|
|
||
| class Item: | ||
| pass | ||
| def __init__(self, id=None, condition=0): | ||
| self.id = uuid.uuid4().int if id is None else id | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Good use of a sentinel check to generate a new id. We can't just put the |
||
| self.condition = float(condition) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's no particular need to force this to be a |
||
|
|
||
| def get_category(self): | ||
| return type(self).__name__ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 All we were really looking for folks to do here was to Be sure that you have a clear idea of how this works for the subclasses. |
||
|
|
||
| def __str__(self): | ||
| return f"An object of type {self.get_category()} with id {self.id}." | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Using |
||
|
|
||
| def condition_description(self): | ||
| if self.condition == 5: | ||
| return "Brand New" | ||
| elif self.condition == 4: | ||
| return "Like New" | ||
| elif self.condition == 3: | ||
| return "Lightly Used" | ||
| elif self.condition == 2: | ||
| return "Moderately Used" | ||
| elif self.condition == 1: | ||
| return "Heavily Used" | ||
|
Comment on lines
+15
to
+24
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Writing explicit checks works, but has some drawbacks. In the general case, there could be an arbitrary number of conditions, and we would have to write more code to cover those conditions. What would this code be like if there we 10 condition rankings? 100? Notice how this is very similar to our snowman drawing code, where initially we picked a string to draw based on some input, but then later, we refactored it by moving those strings into a list, and using the input as an index into the list. So we could think about doing the same thing here. To get the maximum benefit, we would want to declare the description data structure outside the function (just like snowman did), so that it only gets initialized a single time, rather than every time the function is called.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While we don't have a test that tries to get the condition description for a floating point condition, we do check that we can make an In the case where we move the description strings into a data structure, how could we provide a useful behavior for values between the integer conditions? |
||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,98 @@ | ||
| from swap_meet.item import Item | ||
| class Vendor: | ||
| pass | ||
| def __init__(self, inventory=None): | ||
| self.inventory = [] if inventory is None else inventory | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 We should avoid mutable values as default parameters. So if we need to setup of a default mutable value for a class, we use a default sentinel immutable value (a specific value we can look for), and if we see it, create a new mutable instance. |
||
|
|
||
| def add(self, item): | ||
| self.inventory.append(item) | ||
| return item | ||
|
|
||
| def remove(self, item): | ||
| if item in self.inventory: | ||
| self.inventory.remove(item) | ||
| return item | ||
| return False | ||
|
Comment on lines
+11
to
+14
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 We need to check the item is actually there before using Consider reordering the statements as if item not in self.inventory:
return False
self.inventory.remove(item)
return itemwhich allows us to emphasize the important code by unindenting and placing it in a more significant part of the function, rather than being just one branch of a condition.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One minor quibble could be made that this is returning the object instance that was passed to the function rather than the instance that was found in the inventory. If we really want to be sure that we're returning the one from the inventory, we could use In practice, with how we implement
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know the spec says this should return |
||
|
|
||
| # Wave_2 | ||
|
|
||
| def get_by_id(self, id): | ||
| for item in self.inventory: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 We need to iterate through the list to find the object with the matching id. |
||
| if id == item.id: | ||
| return item | ||
| return None | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider adding a blank line before this return to help visually seperate it from the loop. |
||
|
|
||
|
|
||
| #wave_3 | ||
|
|
||
| def swap_items(self, other_vendor, my_item, their_item): | ||
|
|
||
| if not my_item in self.inventory or not their_item in other_vendor.inventory: | ||
| return False | ||
|
Comment on lines
+29
to
+30
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 We do need to check that both items are in their respective list before starting to remove things, or else we could end up in a situation where we start updating (removing from) one list, but then find that the other item is missing, leaving us with a partial change we don't want. |
||
|
|
||
|
|
||
| self.remove(my_item) #removes `my_item` from this `Vendor`'s inventory | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: PEP8 recommends starting "inline" comments at least two spaces after the code part, and there should always be a space between the self.remove(my_item) # removes `my_item` from this `Vendor`'s inventory |
||
| other_vendor.add(my_item) #adds it to the friend's inventory | ||
| self.add(their_item) #adds it to this `Vendor`'s inventory | ||
| other_vendor.remove(their_item) #removes `their_item` from the other `Vendor`'s inventory | ||
|
|
||
| return True | ||
|
|
||
|
|
||
| # Wave_4 | ||
|
|
||
| def swap_first_item(self, other_vendor): | ||
|
|
||
| if not self.inventory or not other_vendor.inventory: | ||
| return False | ||
|
Comment on lines
+45
to
+46
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Trying to get position 0 from an empty inventory would be an error. |
||
|
|
||
| # Remove the first item from both vendors' inventories | ||
| self_first_item = self.inventory.pop(0) | ||
| others_first_item = other_vendor.inventory.pop(0) | ||
|
|
||
| # Add the first item from the other vendor to each vendor's inventory | ||
| self.inventory.insert(0, others_first_item) | ||
| other_vendor.inventory.insert(0,self_first_item) | ||
|
Comment on lines
+48
to
+54
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notice that both For the To work around the linear cost for But if we're thinking about exchanging references, we could exchange the object references between the two inventories directly. Something like self_first_item = self.inventory[0] # set aside reference to our first item
self.inventory[0] = other_vendor.inventory[0] # replace our first item with the other's
other_vendor.inventory[0] = self_first_item # replace the other's first item with ours that we set asideThere are more concise ways of writing this (look up tuple swap), but the effect would be the same.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another approach could be to use our |
||
|
|
||
| # Return True to indicate the swap was successful | ||
| return True | ||
|
|
||
|
|
||
| # Wave_6 | ||
| def get_by_category(self, category): | ||
| list_of_objects = [] | ||
| for item in self.inventory: | ||
| if category == item.get_category(): | ||
| list_of_objects.append(item) | ||
| return list_of_objects | ||
|
Comment on lines
+62
to
+66
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 We need to loop to find all the items with the specified category. This would be a great opportunity to try using list comprehension syntax. |
||
|
|
||
|
|
||
| def get_best_by_category(self, category): | ||
| if not self.get_by_category(category): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Nice reuse of the previously written function. But rather than calling the function multiple times below, save the result once in a variable, and then use that variable. Otherwise, each time the function is called it will need to iterate through the inventory again. category_items = self.get_by_category(category) # then use category_items below
if not category_items:
... |
||
| return None | ||
|
|
||
| best_item = self.get_by_category(category)[0] | ||
| for item in self.get_by_category(category): | ||
| if item.condition > best_item.condition: | ||
| best_item = item | ||
|
Comment on lines
+73
to
+76
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 Nice logic to loop through and find the item with the best condition. |
||
| return best_item | ||
|
|
||
| def swap_best_by_category(self, other_vendor, my_priority, their_priority): | ||
| if not self.inventory or not other_vendor.inventory: | ||
| return False | ||
|
|
||
| my_best_item = self.get_best_by_category(their_priority) | ||
| their_best_item = other_vendor.get_best_by_category(my_priority) | ||
| if not my_best_item or not their_best_item: | ||
| return False | ||
|
|
||
| if my_best_item.get_category() == their_priority and their_best_item.get_category() == my_priority: | ||
| other_vendor.add(my_best_item) | ||
| self.remove(my_best_item) | ||
| self.add(their_best_item) | ||
| other_vendor.remove(their_best_item) | ||
| return True | ||
|
Comment on lines
+88
to
+93
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 Notice that this condition check is unnecessary. If we found an item for each of the Once we have the two items to swap, this is the same as swapping any two other items, so we could reuse our |
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,12 +2,13 @@ | |
| 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) | ||
|
|
@@ -16,7 +17,8 @@ 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" | ||
|
|
@@ -27,7 +29,8 @@ 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( | ||
|
|
@@ -40,7 +43,8 @@ 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_is_false(): | ||
| item = "item to remove" | ||
| vendor = Vendor( | ||
|
|
@@ -49,7 +53,17 @@ def test_removing_not_found_is_false(): | |
|
|
||
| result = vendor.remove(item) | ||
|
|
||
| raise Exception("Complete this test according to comments below.") | ||
| assert result is False | ||
|
|
||
| assert len(vendor.inventory) == 3 | ||
|
|
||
| assert "a" in vendor.inventory | ||
| assert "b" in vendor.inventory | ||
| assert "c" in vendor.inventory | ||
|
|
||
|
|
||
| # raise Exception("Complete this test according to comments below.") | ||
| # ********************************************************************* | ||
| # ****** Complete Assert Portion of this test ********** | ||
| # ********************************************************************* | ||
| assert result == False | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This line is redundant with line 65. Of the two, if we do literally want to compare with one of the boolean constants, we usually use Note that in application code, we rarely if ever compare against one of the boolean constants (with |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
|
@@ -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() | ||
|
|
@@ -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() | ||
|
|
@@ -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() | ||
|
|
@@ -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=[] | ||
|
|
@@ -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() | ||
|
|
@@ -131,7 +131,9 @@ 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.") | ||
| # raise Exception("Complete this test according to comments below.") | ||
| # ********************************************************************* | ||
| # ****** Complete Assert Portion of this test ********** | ||
| # ********************************************************************* | ||
|
|
||
| assert result is False | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In addition to checking for the expected return value, since |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 We need to import
Itemsince we use it by name in theClothingdeclaration.