From 5448b911eb78556691fb7be9f908fb547cb0ed67 Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sun, 12 Oct 2025 15:12:35 -0700 Subject: [PATCH 1/2] Inventory Management --- inventory-management/.exercism/config.json | 24 ++ inventory-management/.exercism/metadata.json | 1 + inventory-management/HELP.md | 130 ++++++++++ inventory-management/HINTS.md | 49 ++++ inventory-management/README.md | 247 +++++++++++++++++++ inventory-management/dicts.py | 76 ++++++ inventory-management/dicts_test.py | 121 +++++++++ 7 files changed, 648 insertions(+) create mode 100644 inventory-management/.exercism/config.json create mode 100644 inventory-management/.exercism/metadata.json create mode 100644 inventory-management/HELP.md create mode 100644 inventory-management/HINTS.md create mode 100644 inventory-management/README.md create mode 100644 inventory-management/dicts.py create mode 100644 inventory-management/dicts_test.py diff --git a/inventory-management/.exercism/config.json b/inventory-management/.exercism/config.json new file mode 100644 index 0000000..c08624a --- /dev/null +++ b/inventory-management/.exercism/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + "j08k" + ], + "contributors": [ + "valentin-p", + "bethanyG", + "mukeshgurpude", + "kotp" + ], + "files": { + "solution": [ + "dicts.py" + ], + "test": [ + "dicts_test.py" + ], + "exemplar": [ + ".meta/exemplar.py" + ] + }, + "icon": "high-scores", + "blurb": "Learn about dicts by managing warehouse inventory." +} diff --git a/inventory-management/.exercism/metadata.json b/inventory-management/.exercism/metadata.json new file mode 100644 index 0000000..fc2c4b6 --- /dev/null +++ b/inventory-management/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"inventory-management","id":"39327930b14540e989ef273f25554fa2","url":"https://exercism.org/tracks/python/exercises/inventory-management","handle":"myFirstCode","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/inventory-management/HELP.md b/inventory-management/HELP.md new file mode 100644 index 0000000..1f8c21d --- /dev/null +++ b/inventory-management/HELP.md @@ -0,0 +1,130 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit dicts.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/inventory-management/HINTS.md b/inventory-management/HINTS.md new file mode 100644 index 0000000..da27ec3 --- /dev/null +++ b/inventory-management/HINTS.md @@ -0,0 +1,49 @@ +# Hints + +## General + +- [The Python Dictionary Tutorial][dict-tutorial] can be a great place to start. +- The Python docs on [Mapping Types - dicts][dict docs] is also pretty helpful. + +## 1. Create an inventory based on a list + +- You need a [for loop][for-loop] to iterate the list of items, then insert each item in the dictionary if missing and increment the item count using the dictionary accessor. +- You can use [`dict.setdefault`][dict setdefault] to make sure the value is set before incrementing the count of the item. +- This function should [return][return-keyword] a dict]. + +## 2. Add items from a list to an existing dictionary + +- You need a [for loop][for-loop] to iterate the list of items, then insert each item if not already in the dictionary and [increment][increment] the item count using the dictionary accessor. +- You can use [`dict.setdefault`][dict setdefault] to make sure the value is set before incrementing the count of the item. +- The function `add_items` can be used by the `create_inventory` function with an empty dictionary in parameter. +- This function should [return][return-keyword] a dict. + +## 3. Decrement items from the inventory + +- You need [for loop][for-loop] to iterate the list of items, if the number of items is not `0` then [decrement][decrement] the current number of items. +- You can use the check `key in dict` that returns `True` if the key exists to make sure the value is in the dictionary before decrementing the number of items. +- This function should [return][return-keyword] a dict. + +## 4. Remove an item entirely from the inventory + +- If item is in the dictionary, [remove it][dict-pop]. +- If item is not in the dictionary, do nothing. +- This function should [return][return-keyword] a dict. + +## 5. Return the inventory content + +- You need to use a [for loop][for-loop] on the inventory and if the number of item is greater of `0` then append the `tuple` to a `list`. +- You can use [`dict.items()`][dict items] to iterate on both the item and the value at the same time, `items()` returns a `tuple` that you can use or deconstruct, if needed. +- This function should [return][return-keyword] a [list][list] of [tuples][tuples]. + +[decrement]: https://www.w3schools.com/python/gloss_python_assignment_operators.asp +[dict docs]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict +[dict items]: https://docs.python.org/3/library/stdtypes.html#dict.items +[dict setdefault]: https://www.w3schools.com/python/ref_dictionary_setdefault.asp +[dict-pop]: https://www.w3schools.com/python/ref_dictionary_pop.asp +[dict-tutorial]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries +[for-loop]: https://docs.python.org/3/tutorial/controlflow.html#for-statements +[increment]: https://www.w3schools.com/python/gloss_python_assignment_operators.asp +[list]: https://docs.python.org/3/tutorial/introduction.html#lists +[return-keyword]: https://www.w3schools.com/python/ref_keyword_return.asp +[tuples]: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences \ No newline at end of file diff --git a/inventory-management/README.md b/inventory-management/README.md new file mode 100644 index 0000000..c5e1a38 --- /dev/null +++ b/inventory-management/README.md @@ -0,0 +1,247 @@ +# Inventory Management + +Welcome to Inventory Management on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. +If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :) + +## Introduction + +A dictionary (`dict`) in Python is a data structure that associates [hashable][term-hashable] _keys_ to _values_ and is known in other programming languages as a resizable [hash table][hashtable-wikipedia], hashmap, or [associative array][associative-array]. +Dictionaries are Python's only built-in [mapping type][mapping-types-dict]. + + +`Keys` must be hashable and unique across the dictionary. +Key types can include `numbers`, `str`, or `tuples` (of _immutable_ values). +They cannot contain _mutable_ data structures such as `lists`, `dict`s, or `set`s. +As of Python 3.7, `dict` key order is guaranteed to be the order in which entries are inserted. + +`values` can be of any data type or structure. + Values can also nest _arbitrarily_, so they can include lists-of-lists, sub-dictionaries, and other custom or compound data structures. + +Given a `key`, dictionaries can retrieve a `value` in (on average) constant time (_independent of the number of entries_). +Compared to searching for a value within a `list` or `array` (_without knowing the `index` position_), a `dict` uses significantly more memory, but has very rapid retrieval. +Dictionaries are especially useful in scenarios where the collection of items is large and must be accessed and updated frequently. + + +## Dictionary Construction + +Dictionaries can be created in many ways. +The two most straightforward are using the `dict()`constructor or declaring a `dict` _literal_. + +### The `dict()` Class Constructor + +`dict()` (_the constructor for the dictionary class_) can be used with any iterable of `key`, `value` pairs or with a series of `=` _arguments_: + +```python +#Passing a list of key,value tuples. +>>> wombat = dict([('name', 'Wombat'),('speed', 23),('land_animal', True)]) +{'name': 'Wombat', 'speed': 23, 'land_animal': True} + + +#Using key=value arguments. +>>> bear = dict(name="Black Bear", speed=40, land_animal=True) +{'name': 'Black Bear', 'speed': 40, 'land_animal': True} +``` + +### Dictionary Literals + +A `dict` can also be directly entered as a _dictionary literal_, using curly brackets (`{}`) enclosing `key : value` pairs: + +```python +>>> whale = {"name": "Blue Whale", "speed": 35, "land_animal": False} +{'name': 'Blue Whale', 'speed': 35, 'land_animal': False} +``` + +## Accessing Values in a Dictionary + +You can access an entry in a dictionary using a _key_ in square (`[]`) brackets. +If a `key` does not exist n the `dict`, a `KeyError` is thrown: + +```python +>>> bear["speed"] +40 + +>>> bear["color"] +Traceback (most recent call last): + File "", line 1, in +KeyError: 'color' +``` + +Accessing an entry via the `.get(, )` method can avoid the `KeyError`: + +```python +>>> bear.get("color", 'not found') +'not found' +``` + +## Changing or Adding Dictionary Values + +You can change an entry `value` by assigning to its _key_: + +```python +#Assigning the value "Grizzly Bear" to the name key. +>>> bear["name"] = "Grizzly Bear" +{'name': 'Grizzly Bear', 'speed': 40, 'land_animal': True} + +>>> whale["speed"] = 25 +{'name': 'Blue Whale', 'speed': 25, 'land_animal': False} +``` + +New `key`:`value` pairs can be _added_ in the same fashion: + +```python +# Adding a new "color" key with a new "tawney" value. +>>> bear["color"] = 'tawney' +{'name': 'Grizzly Bear', 'speed': 40, 'land_animal': True, 'color': 'tawney'} + +>>> whale["blowholes"] = 1 +{'name': 'Blue Whale', 'speed': 25, 'land_animal': False, 'blowholes': 1} +``` + +## Removing (Pop-ing) Dictionary Entries + +You can use the `.pop()` method to delete a dictionary entry. +`.pop()` removes the (`key`, `value`) pair and returns the `value` for use. +Like `.get()`, `.pop()` accepts second argument (_`dict.pop(, )`_) that will be returned if the `key` is not found. +This prevents a `KeyError` being raised: + +```python +#Using .pop() removes both the key and value, returning the value. +>>> bear.pop("name") +'Grizzly Bear' + + +#The "name" key is now removed from the dictionary. +#Attempting .pop() a second time will throw a KeyError. +>>> bear.pop("name") +Traceback (most recent call last): + File "", line 1, in +KeyError: 'name' + + +#Using a default argument with .pop() will prevent a KeyError from a missing key. +>>> bear.pop("name", "Unknown") +'Unknown' +``` + +## Looping through/Iterating over a Dictionary + +Looping through a dictionary using `for item in dict` or `while item` will iterate over only the _keys_ by default. +You can access the _values_ within the same loop by using _square brackets_: + +```python +>>> for key in bear: +>>> print((key, bear[key])) #this forms a tuple of (key, value) and prints it. +('name', 'Black Bear') +('speed', 40) +('land_animal', True) +``` + +You can also use the `.items()` method, which returns (`key`, `value`) tuples automatically: + +```python +#dict.items() forms (key, value tuples) that can be unpacked and iterated over. +>>> for key, value in whale.items(): +>>> print(key, ":", value) +name : Blue Whale +speed : 25 +land_animal : False +blowholes : 1 +``` + +Likewise, the `.keys()` method will return `keys` and the `.values()` method will return the `values`. + +[associative-array]: https://en.wikipedia.org/wiki/Associative_array#:~:text=In%20computer%20science%2C%20an%20associative,a%20function%20with%20finite%20domain. +[hashtable-wikipedia]: https://en.wikipedia.org/wiki/Hash_table +[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict +[term-hashable]: https://docs.python.org/3/glossary.html#term-hashable + +## Instructions + +In this exercise, you will be managing an inventory system. + +The inventory should be organized by the item name and it should keep track of the number of items available. + +You will have to handle adding items to an inventory. +Each time an item appears in a given list, the item's quantity should be increased by `1` in the inventory. +You will also have to handle deleting items from an inventory by decreasing quantities by `1` when requested. + +Finally, you will need to implement a function that will return all the key-value pairs in a given inventory as a `list` of `tuples`. + + +## 1. Create an inventory based on a list + +Implement the `create_inventory()` function that creates an "inventory" from an input list of items. +It should return a `dict` containing each item name paired with their respective quantity. + +```python +>>> create_inventory(["coal", "wood", "wood", "diamond", "diamond", "diamond"]) +{"coal":1, "wood":2, "diamond":3} +``` + +## 2. Add items from a list to an existing dictionary + +Implement the `add_items(, )` function that adds a list of items to the passed-in inventory: + +```python +>>> add_items({"coal":1}, ["wood", "iron", "coal", "wood"]) +{"coal":2, "wood":2, "iron":1} +``` + +## 3. Decrement items from the inventory + +Implement the `decrement_items(, )` function that takes a `list` of items. +Your function should remove `1` from an item count for each time that item appears on the `list`: + +```python +>>> decrement_items({"coal":3, "diamond":1, "iron":5}, ["diamond", "coal", "iron", "iron"]) +{"coal":2, "diamond":0, "iron":3} +``` + +Item counts in the inventory should not be allowed to fall below 0. + If the number of times an item appears on the input `list` exceeds the count available, the quantity listed for that item should remain at 0. + Additional requests for removing counts should be ignored once the count falls to zero. + +```python +>>> decrement_items({"coal":2, "wood":1, "diamond":2}, ["coal", "coal", "wood", "wood", "diamond"]) +{"coal":0, "wood":0, "diamond":1} +``` + +## 4. Remove an entry entirely from the inventory + +Implement the `remove_item(, )` function that removes an item and its count entirely from an inventory: + +```python +>>> remove_item({"coal":2, "wood":1, "diamond":2}, "coal") +{"wood":1, "diamond":2} +``` + +If the item is not found in the inventory, the function should return the original inventory unchanged. + +```python +>>> remove_item({"coal":2, "wood":1, "diamond":2}, "gold") +{"coal":2, "wood":1, "diamond":2} +``` + +## 5. Return the entire content of the inventory + +Implement the `list_inventory()` function that takes an inventory and returns a list of `(item, quantity)` tuples. +The list should only include the _available_ items (_with a quantity greater than zero_): + +```python +>>> list_inventory({"coal":7, "wood":11, "diamond":2, "iron":7, "silver":0}) +[('coal', 7), ('diamond', 2), ('iron', 7), ('wood', 11)] +``` + +## Source + +### Created by + +- @j08k + +### Contributed to by + +- @valentin-p +- @bethanyG +- @mukeshgurpude +- @kotp \ No newline at end of file diff --git a/inventory-management/dicts.py b/inventory-management/dicts.py new file mode 100644 index 0000000..2089267 --- /dev/null +++ b/inventory-management/dicts.py @@ -0,0 +1,76 @@ +"""Functions to keep track and alter inventory.""" + + +def create_inventory(items: list) -> dict: + """ + Create a dict that tracks the amount (count) of each element + on the `items` list. + + :param items: list - list of items to create an inventory from. + :return: dict - the inventory dictionary. + """ + inventory: dict = {} + for item in items: + inventory[item] = items.count(item) + return inventory + + +def add_items(inventory: dict, items: list) -> dict: + """ + Add or increment items in inventory using elements from the items `list`. + + :param inventory: dict - dictionary of existing inventory. + :param items: list - list of items to update the inventory with. + :return: dict - the inventory updated with the new items. + """ + for item in set(items): + count: int = items.count(item) + if item in inventory: + inventory[item] += count + else: + inventory[item] = count + return inventory + + +def decrement_items(inventory: dict, items: list) -> dict: + """ + Decrement items in inventory using elements from the `items` list. + + :param inventory: dict - inventory dictionary. + :param items: list - list of items to decrement from the inventory. + :return: dict - updated inventory with items decremented. + """ + for item in set(items): + if item in inventory: + quantity: int = items.count(item) + if inventory[item] >= quantity: + inventory[item] -= quantity + else: + inventory[item] = 0 + return inventory + + +def remove_item(inventory: dict, item: str) -> dict: + """ + Remove item from inventory if it matches `item` string. + + :param inventory: dict - inventory dictionary. + :param item: str - item to remove from the inventory. + :return: dict - updated inventory with item removed. + Current inventory if item does not match. + """ + if item in inventory: + inventory.pop(item) + return inventory + + +def list_inventory(inventory: dict) -> list: + """ + Create a list containing only available + (item_name, item_count > 0) pairs in inventory. + + :param inventory: dict - an inventory dictionary. + :return: list of tuples - list of key, value pairs from the + inventory dictionary. + """ + return [(key, inventory[key]) for key in inventory if inventory[key] != 0] diff --git a/inventory-management/dicts_test.py b/inventory-management/dicts_test.py new file mode 100644 index 0000000..da01dc4 --- /dev/null +++ b/inventory-management/dicts_test.py @@ -0,0 +1,121 @@ +# pylint: disable=C0301, C0114, C0115, C0116, R0904 +import unittest +import pytest +from dicts import (create_inventory, + add_items, + decrement_items, + remove_item, + list_inventory) + + +class InventoryTest(unittest.TestCase): + + @pytest.mark.task(taskno=1) + def test_create_inventory(self): + + actual_result = create_inventory(["wood", "iron", "iron", "diamond", "diamond"]) + expected = {"wood": 1, "iron": 2, "diamond": 2} + error_message = ('Called create_inventory(["wood", "iron", "iron", "diamond", "diamond"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_add_one_item(self): + actual_result = add_items({"wood": 4, "iron": 2}, ["iron", "iron"]) + expected = {"wood": 4, "iron": 4} + error_message = ('Called add_items({"wood": 4, "iron": 2}, ["iron", "iron"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_add_multiple_items(self): + actual_result = add_items({"wood": 2, "gold": 1, "diamond": 3}, ["wood", "gold", "gold"]) + expected = {"wood": 3, "gold": 3, "diamond": 3} + error_message = ('Called add_items({"wood": 2, "gold": 1, "diamond": 3}, ["wood", "gold", "gold"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_add_new_item(self): + actual_result = add_items({"iron": 1, "diamond": 2}, ["iron", "wood", "wood"]) + expected = {"iron": 2, "diamond": 2, "wood": 2} + error_message = ('Called add_items({"iron": 1, "diamond": 2}, ["iron", "wood", "wood"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=2) + def test_add_from_empty_dict(self): + actual_result = add_items({}, ["iron", "iron", "diamond"]) + expected = {"iron": 2, "diamond": 1} + error_message = ('Called add_items({}, ["iron", "iron", "diamond"]). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_decrement_items(self): + actual_result = decrement_items({"iron": 3, "diamond": 4, "gold": 2}, + ["iron", "iron", "diamond", "gold", "gold"]) + expected = {"iron": 1, "diamond": 3, "gold": 0} + error_message = ('Called decrement_items({"iron": 3, "diamond": 4, "gold": 2},' + '["iron", "iron", "diamond", "gold", "gold"]). The function ' + f'returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_not_below_zero(self): + actual_result = decrement_items({"wood": 2, "iron": 3, "diamond": 1}, + ["wood", "wood", "wood", "iron", "diamond", "diamond"]) + expected = {"wood": 0, "iron": 2, "diamond": 0} + error_message = ('Called decrement_items({"wood": 2, "iron": 3, "diamond": 1}, ' + '["wood", "wood", "wood", "iron", "diamond", "diamond"]). The ' + f'function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=3) + def test_decrement_items_not_in_inventory(self): + actual_result = decrement_items({"iron": 3, "gold": 2}, + ["iron", "wood", "iron", "diamond"]) + + expected = {"iron": 1, "gold": 2} + error_message = ('Called decrement_items({"iron": 3, "gold": 2}, ' + '["iron", "wood", "iron", "diamond"]). The function ' + f'returned {actual_result}, but the tests ' + f'expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_remove_item(self): + actual_result = remove_item({"iron": 1, "diamond": 2, "gold": 1}, "diamond") + expected = {"iron": 1, "gold": 1} + error_message = ('Called remove_item({"iron": 1, "diamond": 2, "gold": 1}, "diamond"). ' + f'The function returned {actual_result}, but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=4) + def test_remove_item_not_in_inventory(self): + actual_result = remove_item({"iron": 1, "diamond": 2, "gold": 1}, "wood") + expected = {"iron": 1, "gold": 1, "diamond": 2} + error_message = ('Called remove_item({"iron": 1, "diamond": 2, "gold": 1}, "wood"). ' + f'The function returned {actual_result}, ' + f'but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) + + @pytest.mark.task(taskno=5) + def test_list_inventory(self): + actual_result = list_inventory({"coal": 15, "diamond": 3, "wood": 67, "silver": 0}) + expected = [("coal", 15), ("diamond", 3), ("wood", 67)] + error_message = ('Called list_inventory({"coal": 15, "diamond": 3, "wood": 67, "silver": 0}). ' + f'The function returned {actual_result}, ' + f'but the tests expected {expected}.') + + self.assertEqual(actual_result, expected, msg=error_message) From 4ef1e624562f78978f92d04baf12efad05ec216d Mon Sep 17 00:00:00 2001 From: Egor Kostan Date: Sun, 12 Oct 2025 15:28:12 -0700 Subject: [PATCH 2/2] Update dicts.py --- inventory-management/dicts.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/inventory-management/dicts.py b/inventory-management/dicts.py index 2089267..e189313 100644 --- a/inventory-management/dicts.py +++ b/inventory-management/dicts.py @@ -9,10 +9,7 @@ def create_inventory(items: list) -> dict: :param items: list - list of items to create an inventory from. :return: dict - the inventory dictionary. """ - inventory: dict = {} - for item in items: - inventory[item] = items.count(item) - return inventory + return add_items({}, items) def add_items(inventory: dict, items: list) -> dict: