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..e189313
--- /dev/null
+++ b/inventory-management/dicts.py
@@ -0,0 +1,73 @@
+"""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.
+ """
+ return add_items({}, items)
+
+
+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)