Repository: exercism/python
Pull request #3437 (2023-06-10 01:13:24)

Remove Python 2 references from the track
Remove Python 2 references from any files in the track.

BethanyG: @IsaacG - left you a not on Discord, but noting here too (so we have a record).

It is an unqualified PITA, but even blank lines in test files need to go through the templating system, sadly.  So for the following exercises/test files, you'll need to edit the JinJa2 template, then regenerate the test files and check BOTH into the PR.  Otherwise, the CI will complain and/or fail. 

I'd hold `complex-numbers` for its own PR.  Looks like the upstream tests have changed, so we'll need to run configlet, judge which cases we want to keep or omit, and re-do things.  Considering that we recently changed how that exercise works on this track, we probably want to take a hard look at it and make sure that nothing has gone wrong there.

The other exercises that need their template + re-generation are:

- [ ] Binary Search
- [ ] Rational Numbers
- [ ] Robot Simulator
- [ ] Roman Numerals
- [ ] Scale Generator

Option B is to just leave them out, and we can deal with them when the whole re-queueing thing is completed. 

Patch:
diff --git a/concepts/comparisons/about.md b/concepts/comparisons/about.md
index 568b6603..c2f5faaa 100644
--- a/concepts/comparisons/about.md
+++ b/concepts/comparisons/about.md
@@ -82,7 +82,7 @@ False
 Strings (`str`) are compared [_lexicographically_][lexographic order], using their individual Unicode code points (_the result of passing each code point in the `str` to the built-in function [`ord()`][ord], which returns an `int`_).
 If all code points in both strings match and are _**in the same order**_, the two strings are considered equal.
 This comparison is done in a 'pair-wise' fashion - first-to-first, second-to-second, etc.
-Unlike in Python 2.x, in Python 3.x, `str` and `bytes` cannot be directly coerced/compared.
+In Python 3.x, `str` and `bytes` cannot be directly coerced/compared.
 
 ```python
 >>> 'Python' > 'Rust'
diff --git a/concepts/dict-methods/about.md b/concepts/dict-methods/about.md
index e36fc708..d910d3e9 100644
--- a/concepts/dict-methods/about.md
+++ b/concepts/dict-methods/about.md
@@ -1,74 +1,75 @@
 # Dictionary Methods in Python
 
-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 [hash table or hashmap][hashtable-wikipedia].
-In Python, it's considered a [mapping type][mapping-types-dict].
-`dicts` enable the retrieval of a value in constant time (on average), given the key.
-
-Compared to searching for a value within a list or array (_without knowing the index position_), a dictionary uses significantly more memory, but has very rapid retrieval.
-It's especially useful in scenarios where the collection of items is large and must be accessed/updated frequently.
-
-## Dictionary Methods
-
 The `dict` class in Python provides many useful [methods][dict-methods] for working with dictionaries.
 Some were introduced in the concept for `dicts`.
-Here are a few more - along with some techniques for iterating through and manipulating `dicts`.
+Here we cover a few more - along with some techniques for iterating through and manipulating dictionaries.
 
-To quickly populate a dictionary with various `keys` and default values, the _class method_ [`dict.fromkeys(iterable, <default value>)`][fromkeys] will iterate through the `keys` and create a new `dict`.  All `values` will be set to the `default` value provided.
+- `dict.setdefault()` automatically adds keys without throwing a KeyError.
+- `dict.fromkeys(iterable, <default value>)` creates a new `dict` from any number of iterables.
+- `.keys()`, `.values()`, and `.items()` provide convenient iterators.
+- `sorted(<dict>.items())`. can easily re-order entries in a `dict`.
+- `dict_one.update(<dict_two>)` updates one `dict` with overlapping values from another `dict`.
+- `dict | other_dict` and `dict |= other_dict` merges or updates two `dict`s via operators.
+- `reversed(dict.keys())`, `reversed(dict.values())`, or `reversed(dict.items())` produce _reversed_ views.
+- `<dict>.popitem()` removes and returns a `key`, `value` pair.
 
-```python
->>> new_dict = dict.fromkeys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'], 'fill in hex color here')
->>> new_dict
-{'Grassy Green': 'fill in hex color here',
- 'Purple Mountains Majesty': 'fill in hex color here',
- 'Misty Mountain Pink': 'fill in hex color here'}
-```
 
-`dict.clear()` will removed all `key:value` pairs from the dictionary, leaving it empty and ready for new entries.
+## `setdefault()` for Error-Free Insertion
 
-```python
->>> pallette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
->>> pallette_II.clear()
->>> pallette_II
-{}
-```
+The dictionary concept previously covered that `.get(key, <default value>)` returns an existing `value` or the `default value` if a `key` is not found in a dictionary, thereby avoiding a `KeyError`.
+This works well in situations where you would rather not have extra error handling but cannot trust that a looked-for `key` will be present.
 
-`dict.get(key, <default return value>)` works similarly to `dict[key]` -- but it will return the `default` if the `key` is not in the dictionary.
-If no `default` is given, the method will return `None`.
+For a similarly "safe" (_without KeyError_) insertion operation, there is the `.setdefault(key, <default value>)` method.
+`setdefault(key, <default value>)` will return the `value` if the `key` is found in the dictionary.
+If the key is **not** found, it will _insert_ the (`key`, `default value`) pair and return the `default value` for use.
 
 ```python
 >>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
->>> palette_I['Factory Stone Purple']
-Traceback (most recent call last):
 
-  line 1, in <module>
-    palette_I['Factory Stone Purple']
+# Looking for the value associated with key "Rock Brown".The key does not exist, 
+# so it is added with the default value, and the value is returned.
+>>> palette.setdefault('Rock Brown', '#694605')
+'#694605'
 
-KeyError: 'Factory Stone Purple'
+# The (key, default value) pair has now been added to the dictionary.
+>>> palette_I
+{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Rock Brown': '#694605'}
+```
 
->>> palette_I.get('Factory Stone Purple', 'That color was not found.')
-'That color was not found.'
+## `fromkeys()` to Populate a Dictionary from an Iterable
 
->>> palette_I.get('Factory Stone Purple', False)
-False
+To quickly populate a dictionary with various `keys` and default values, the _class method_ [`fromkeys(iterable, <default value>)`][fromkeys] will iterate through an iterable of `keys` and create a new `dict`.
+All `values` will be set to the `default value` provided:
 
->>> palette_I.get('Factory Stone Purple')
-None
+```python
+>>> new_dict = dict.fromkeys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'], 'fill in hex color here')
+
+{'Grassy Green': 'fill in hex color here',
+ 'Purple Mountains Majesty': 'fill in hex color here',
+ 'Misty Mountain Pink': 'fill in hex color here'}
 ```
 
-`dict.popitem()`  removes & returns a single `key:value` pair from the `dict`.
-Pairs are returned in Last-in-First-out (LIFO) order.
-If the dictionary is empty, calling `.dict.popitem` will raise a `KeyError`.
+## Remove and Return a (key, value) Pair With `.popitem()`
+
+`.popitem()` removes & returns a single (`key`, `value`) pair from a dictionary.
+Pairs are returned in Last-in-First-out (`LIFO`) order.
+If the dictionary is empty, calling `popitem()` will raise a `KeyError`:
 
 ```python
->>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
+>>> palette_I = {'Grassy Green': '#9bc400', 
+                 'Purple Mountains Majesty': '#8076a3', 
+                 'Misty Mountain Pink': '#f9c5bd'}
 >>> palette_I.popitem()
 ('Misty Mountain Pink', '#f9c5bd')
+
 >>> palette_I.popitem()
 ('Purple Mountains Majesty', '#8076a3')
+
 >>> palette_I.popitem()
 ('Grassy Green', '#9bc400')
->>> palette_I.popitem()
 
+# All (key, value) pairs have been removed.
+>>> palette_I.popitem()
 Traceback (most recent call last):
 
   line 1, in <module>
@@ -77,25 +78,38 @@ Traceback (most recent call last):
 KeyError: 'popitem(): dictionary is empty'
 ```
 
-While `dict.clear()` and `dict.popitem()` are  _destructive_ actions, the  `.keys()`, `.values()`, and `.items()` methods return [_iterable views_][dict-views].
-These views can be used for looping over `dict` content without altering it and are  _dynamic_ -- when underlying dictionary data changes, the associated view object will reflect the change.
+## Iterating Over Entries in a Dictionary Via Views
+
+The `.keys()`, `.values()`, and `.items()` methods return [_iterable views_][dict-views] of a dictionary.
+
+These views can be used to easily loop over entries without altering them.
+Views are also _dynamic_ -- when underlying dictionary data changes, the associated `view object` will reflect the change:
 
 ```python
->>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
+>>> palette_I = {'Grassy Green': '#9bc400', 
+                 'Purple Mountains Majesty': '#8076a3', 
+                 'Misty Mountain Pink': '#f9c5bd'}
+
+# Using .keys() returns a list of keys.
 >>> palette_I.keys()
 dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'])
 
+# Using .values() returns a list of values.
 >>> palette_I.values()
 dict_values(['#9bc400', '#8076a3', '#f9c5bd'])
 
+# Using .items() returns a list of (key, value) tuples.
 >>> palette_I.items()
 dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', '#8076a3'), ('Misty Mountain Pink', '#f9c5bd')])
 
+# Views are dynamic.  Changing values in the dict 
+# changes all of the associated views.
 >>> palette_I['Purple Mountains Majesty'] = (128, 118, 163)
+>>> palette_I['Deep Red'] = '#932432'
+
 >>> palette_I.values()
-dict_values(['#9bc400', (128, 118, 163), '#f9c5bd'])
+dict_values(['#9bc400', (128, 118, 163), '#f9c5bd', '#932432'])
 
->>> palette_I['Deep Red'] = '#932432'
 >>> palette_I.keys()
 dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink', 'Deep Red'])
 
@@ -103,32 +117,69 @@ dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink', 'D
 dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', (128, 118, 163)), ('Misty Mountain Pink', '#f9c5bd'), ('Deep Red', '#932432')])
 ```
 
-`dict_one.update(<dict_two>)` can be used to _combine_ two dictionaries.
-This method will take the `key:value` pairs of `dict_two` and write them into `dict_one`.
+## More on `.keys()`, `.values()`, and `.items()`
+
+In Python 3.7+, `dicts` preserve the order in which entries are inserted allowing First-in, First-out (_`FIFO`_),  iteration when using `.keys()`, `.values()`, or `.items()`.
+
+In Python 3.8+, views are also _reversible_.
+This allows keys, values, or (`key`, `value`) pairs to be iterated over in Last-in, First-out (`LIFO`) order by using `reversed(<dict>.keys())`, `reversed(<dict>.values())`, or `reversed(<dict>.items())`:
 
 ```python
->>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
->>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
->>> palette_I.update(palette_II)
->>> palette_I
+>>> palette_II = {'Factory Stone Purple': '#7c677f', 
+                  'Green Treeline': '#478559', 
+                  'Purple baseline': '#161748'}
+>>> for item in palette_II.items():
+...     print(item)
 ...
+('Factory Stone Purple', '#7c677f')
+('Green Treeline', '#478559')
+('Purple baseline', '#161748')
 
-{'Grassy Green': '#9bc400',
- 'Purple Mountains Majesty': '#8076a3',
- 'Misty Mountain Pink': '#f9c5bd',
- 'Factory Stone Purple': '#7c677f',
- 'Green Treeline': '#478559', 
- 'Purple baseline': '#161748'}
+>>> for item in reversed(palette_II.items()):
+...    print (item)
+...
+('Purple baseline', '#161748')
+('Green Treeline', '#478559')
+('Factory Stone Purple', '#7c677f')
 ```
 
-Where keys in the two dictionaries _overlap_, the `value` in `dict_one` will be _overwritten_ by the corresponding `value` from `dict_two`.
+## Combine Dictionaries with `.update()`
+
+`<dict_one>.update(<dict_two>)` can be used to _combine_ two dictionaries.
+This method will take the (`key`,`value`) pairs of `<dict_two>` and write them into `<dict_one>`:
 
 ```python
->>> palette_I =   {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 
-                   'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
->>> palette_III = {'Grassy Green': (155, 196, 0), 'Purple Mountains Majesty': (128, 118, 163),
+>>> palette_I = {'Grassy Green': '#9bc400',
+                 'Purple Mountains Majesty': '#8076a3',
+                  'Misty Mountain Pink': '#f9c5bd'}
+>>> palette_II = {'Factory Stone Purple': '#7c677f',
+                  'Green Treeline': '#478559',
+                  'Purple Baseline': '#161748'}
+
+>>> palette_I.update(palette_II)
+
+# Note that new items from palette_II are added.
+>>> palette_I
+{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple Baseline': '#161748'}
+```
+
+Where keys in the two dictionaries _overlap_, the `value` in `dict_one` will be _overwritten_ by the corresponding `value` from `dict_two`:
+
+```python
+>>> palette_I =   {'Grassy Green': '#9bc400', 
+                   'Purple Mountains Majesty': '#8076a3', 
+                   'Misty Mountain Pink': '#f9c5bd', 
+                   'Factory Stone Purple': '#7c677f', 
+                   'Green Treeline': '#478559', 
+                   'Purple baseline': '#161748'}
+                   
+>>> palette_III = {'Grassy Green': (155, 196, 0), 
+                   'Purple Mountains Majesty': (128, 118, 163),
                    'Misty Mountain Pink': (249, 197, 189)}
 >>> palette_I.update(palette_III)
+
+# Overlapping values in palette_I are replaced with 
+# values from palette_III
 >>> palette_I
 {'Grassy Green': (155, 196, 0),
   'Purple Mountains Majesty': (128, 118, 163), 
@@ -137,14 +188,21 @@ Where keys in the two dictionaries _overlap_, the `value` in `dict_one` will be
   'Green Treeline': '#478559', 'Purple baseline': '#161748'}
 ```
 
-Python 3.9 introduces a different means of merging `dicts`:  the `union` operators.
-`dict | other_dict` will create a **new** `dict`, made up of the `key:value` pairs of `dict` and `other_dict`.
-When both dictionaries share keys, the `other_dict` values will take precedence.
-`dict |= other` will behave similar to `dict.update()`, but in this case, `other` can be either a `dict` or an iterable of `key:value` pairs.
+## Merge or Update Dictionaries Via the Union (`|`) Operators
+
+Python 3.9 introduces a different means of merging `dicts`: the `union` operators.
+`dict_one | dict_two` will create a **new dictionary**, made up of the (`key`, `value`) pairs of `dict_one` and `dict_two`.
+When both dictionaries share keys, `dict_two` values take precedence.
 
 ```python
->>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
->>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
+>>> palette_I = {'Grassy Green': '#9bc400', 
+                 'Purple Mountains Majesty': '#8076a3', 
+                 'Misty Mountain Pink': '#f9c5bd'}
+
+>>> palette_II = {'Factory Stone Purple': '#7c677f', 
+                  'Green Treeline': '#478559', 
+                  'Purple baseline': '#161748'}
+
 >>> new_dict = palette_I | palette_II
 >>> new_dict
 ...
@@ -154,44 +212,34 @@ When both dictionaries share keys, the `other_dict` values will take precedence.
  'Factory Stone Purple': '#7c677f',
  'Green Treeline': '#478559',
  'Purple baseline': '#161748'}
- 
- >>> palette_III = {'Grassy Green': (155, 196, 0), 'Purple Mountains Majesty': (128, 118, 163), 'Misty Mountain Pink': (249, 197, 189)}
- >>> new_dict |= palette_III
- >>> new_dict
- ...
- {'Grassy Green': (155, 196, 0),
- 'Purple Mountains Majesty': (128, 118, 163),
- 'Misty Mountain Pink': (249, 197, 189),
- 'Factory Stone Purple': '#7c677f',
- 'Green Treeline': '#478559',
- 'Purple baseline': '#161748'}
 ```
 
-## Tips and Tricks
-
-As of Python 3.6, `dicts` preserve the order in which items are inserted, allowing ordered iteration using `.items()`.  As of Python 3.8, `dict` _views_ are reversible, allowing keys, values or items to be iterated over reverse of insertion order by using `reversed(dict.keys())`, `reversed(dict.values())`, or `reversed(dict.items())`.
+`dict_one |= other` behaves similar to `<dict_one>.update(<dict_two>)`, but in this case, `other` can be either a `dict` or an iterable of (`key`, `value`) pairs:
 
 ```python
->>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
->>> for item in palette_II.items():
-...     print(item)
-...
-('Factory Stone Purple', '#7c677f')
-('Green Treeline', '#478559')
-('Purple baseline', '#161748')
-
->>> for item in reversed(palette_II.items()):
-...    print (item)
+>>> palette_III = {'Grassy Green': (155, 196, 0),
+                   'Purple Mountains Majesty': (128, 118, 163),
+                   'Misty Mountain Pink': (249, 197, 189)}
+>>> new_dict |= palette_III
+>>> new_dict
 ...
-('Purple baseline', '#161748')
-('Green Treeline', '#478559')
-('Factory Stone Purple', '#7c677f')
-
+{'Grassy Green': (155, 196, 0),
+'Purple Mountains Majesty': (128, 118, 163),
+'Misty Mountain Pink': (249, 197, 189),
+'Factory Stone Purple': '#7c677f',
+'Green Treeline': '#478559',
+'Purple baseline': '#161748'}
 ```
 
-While `dict` does not have a built-in sorting method, it is possible to sort a dictionary _view_ by keys or values using the built-in `sorted()` with `dict.items()`.  The sorted view can then be used to create a new, sorted dictionary.  Unless a _sort key_ is specified, the default sort is over dictionary keys.
+## Sorting a Dictionary
+
+Dictionaries do not have a built-in sorting method.
+However, it is possible to sort a `dict` _view_ using the built-in function `sorted()` with `.items()`.
+The sorted view can then be used to create a new dictionary.
+Unless a _sort key_ is specified, the default sort is over dictionary `keys`.
 
 ```python
+# Default ordering for a dictionary is last in, first out (LIFO).
 >>> color_palette = {'Grassy Green': '#9bc400', 
                     'Purple Mountains Majesty': '#8076a3', 
                     'Misty Mountain Pink': '#f9c5bd', 
@@ -200,6 +248,7 @@ While `dict` does not have a built-in sorting method, it is possible to sort a d
                     'Purple baseline': '#161748'}
  
  
+# The default sort order for a dictionary uses the keys.
 >>> sorted_palette = dict(sorted(color_palette.items()))
 >>> sorted_palette
 {'Factory Stone Purple': '#7c677f',
@@ -208,7 +257,10 @@ While `dict` does not have a built-in sorting method, it is possible to sort a d
  'Misty Mountain Pink': '#f9c5bd',
  'Purple Mountains Majesty': '#8076a3',
  'Purple baseline': '#161748'}
- 
+
+
+# A sort key can be provided in the form
+# of an anonymous function (lambda). 
 >>> value_sorted_palette = dict(sorted(color_palette.items(), key=lambda color: color[1]))
 >>> value_sorted_palette
 {'Purple baseline': '#161748',
@@ -217,110 +269,93 @@ While `dict` does not have a built-in sorting method, it is possible to sort a d
  'Purple Mountains Majesty': '#8076a3',
  'Grassy Green': '#9bc400',
  'Misty Mountain Pink': '#f9c5bd'} 
-
 ```
 
-Swapping keys and values reliably in a dictionary takes a little more work, but can be accomplished via a loop using `dict.items()`.  But if the values stored in the `dict` are not unique, extra checks are required.  Both methods assume that `dict` keys and values are _hashable_.
-
-```python
+## Transposing a Dictionaries Keys and Values
 
+Swapping keys and values reliably in a dictionary takes a little work, but can be accomplished via a `loop` using `dict.items()` or in a dictionary comprehension.
+Safe swapping assumes that `dict` keys and values are both _hashable_.
 
+```python
 color_reference = {'Purple Mountains Majesty': '#8076a3',
                    'Misty Mountain Pink': '#f9c5bd',
                    'Factory Stone Purple': '#7c677f',
                    'Green Treeline': '#478559',
-                   'Purple baseline': '#161748',
-                   'Pink highlight': '#f95d9b',
-                   'Bluewater lowlight': '#39a0ca',
-                   'Bright Red': '#DE354C',
-                   'Deep Red': '#932432',
-                   'Pure Purple': '#3C1874',
-                   'Purple Tinged Grey': '#283747',
-                   'Cloud': '#F3F3F3'}
-
->>> reversed_color_reference = {}
+                   'Purple baseline': '#161748'}
+
+# Creating a new dictionary to hold the swapped entries.
+>>> swapped_color_reference = {}
+
+# Iterating through the dictionary, using values as keys.
 >>> for key, value in color_reference.items():
-...     reversed_color_reference[value] = key
+...     swapped_color_reference[value] = key
+
+>>> swapped_color_reference
+{'#8076a3': 'Purple Mountains Majesty',
+ '#f9c5bd': 'Misty Mountain Pink',
+ '#7c677f': 'Factory Stone Purple',
+ '#478559': 'Green Treeline',
+ '#161748': 'Purple baseline'}
 
->>> reversed_color_reference
+ 
+# A dictionary comprehension can also be used to swap entries.
+>>> swapped = {value: key for key, value in
+               color_reference.items()}
+>>> swapped
 {'#8076a3': 'Purple Mountains Majesty',
  '#f9c5bd': 'Misty Mountain Pink',
  '#7c677f': 'Factory Stone Purple',
  '#478559': 'Green Treeline',
- '#161748': 'Purple baseline',
- '#f95d9b': 'Pink highlight',
- '#39a0ca': 'Bluewater lowlight',
- '#DE354C': 'Bright Red',
- '#932432': 'Deep Red',
- '#3C1874': 'Pure Purple',
- '#283747': 'Purple Tinged Grey',
- '#F3F3F3': 'Cloud'}
-    
-
->>> extended_color_reference = {'#8076a3': 'Purple Mountains Majesty',(128, 118, 163): 'Purple Mountains Majesty',
-                                (21, 28, 0, 36): 'Purple Mountains Majesty','#f9c5bd': 'Misty Mountain Pink',
-                                (249, 197, 189): 'Misty Mountain Pink',(0, 21, 24, 2): 'Misty Mountain Pink',
-                                '#7c677f': 'Factory Stone Purple',(124, 103, 127): 'Factory Stone Purple',
-                                (2, 19, 0, 50): 'Factory Stone Purple','#478559': 'Green Treeline',
-                                (71, 133, 89): 'Green Treeline',(47, 0, 33, 48): 'Green Treeline',
-                                '#161748': 'Purple baseline',(22, 23, 72): 'Purple baseline',
-                                (69, 68, 0, 72): 'Purple baseline','#f95d9b': 'Pink highlight',
-                                (249, 93, 155): 'Pink highlight',(0, 63, 38, 2): 'Pink highlight',
-                                '#39a0ca': 'Bluewater lowlight',(57, 160, 202): 'Bluewater lowlight',
-                                (72, 21, 0, 21): 'Bluewater lowlight','#DE354C': 'Bright Red',
-                                (222, 53, 76): 'Bright Red',(0, 76, 66, 13): 'Bright Red',
-                                '#932432': 'Deep Red',(147, 36, 50): 'Deep Red',
-                                (0, 76, 66, 42): 'Deep Red','#3C1874': 'Pure Purple',
-                                (60, 24, 116): 'Pure Purple',(48, 79, 0, 55): 'Pure Purple',
-                                '#283747': 'Purple Tinged Grey',(40, 55, 71): 'Purple Tinged Grey',
-                                (44, 23, 0, 72): 'Purple Tinged Grey','#F3F3F3': 'Cloud',
-                                (243, 243, 243): 'Cloud',(0, 0, 0, 5): 'Cloud'}
+ '#161748': 'Purple baseline'}
+```
 
+If the values stored in the `dict` are not unique, extra checks become necessary before key and value swapping can happen:
+
+```python
+# Things become more complicated if there are duplicates in 
+# potential key values.This dict is arranged by hex, RGB, and HSL
+# keys, but values repeat.
+>>> extended_colors = {'#8076a3': 'Purple Mountains Majesty',
+                       (128, 118, 163): 'Purple Mountains Majesty',
+                       (21, 28, 0, 36): 'Purple Mountains Majesty',
+                       '#f9c5bd': 'Misty Mountain Pink',
+                       (249, 197, 189): 'Misty Mountain Pink',
+                       (0, 21, 24, 2): 'Misty Mountain Pink',
+                       '#7c677f': 'Factory Stone Purple',
+                       (124, 103, 127): 'Factory Stone Purple',
+                       (2, 19, 0, 50): 'Factory Stone Purple',
+                       '#478559': 'Green Treeline',
+                       (71, 133, 89): 'Green Treeline',
+                       (47, 0, 33, 48): 'Green Treeline'}
+                                
+# New empty dictionary for holding swapped entries.
 >>> consolidated_colors = {}
+
+# Iterating over (key, value) pairs using .items()
 >>> for key, value in extended_color_reference.items():
-...    if value in consolidated_colors:
+...    if value in consolidated_colors: #Check if key has already been created.
 ...        consolidated_colors[value].append(key)
 ...    else:
-...        consolidated_colors[value] = [key]
+...        consolidated_colors[value] = [key]  #Create a value list with the former key in it.
 
 >>> consolidated_colors
 {'Purple Mountains Majesty': ['#8076a3', (128, 118, 163), (21, 28, 0, 36)],
  'Misty Mountain Pink': ['#f9c5bd', (249, 197, 189), (0, 21, 24, 2)],
  'Factory Stone Purple': ['#7c677f', (124, 103, 127), (2, 19, 0, 50)],
- 'Green Treeline': ['#478559', (71, 133, 89), (47, 0, 33, 48)],
- 'Purple baseline': ['#161748', (22, 23, 72), (69, 68, 0, 72)],
- 'Pink highlight': ['#f95d9b', (249, 93, 155), (0, 63, 38, 2)],
- 'Bluewater lowlight': ['#39a0ca', (57, 160, 202), (72, 21, 0, 21)],
- 'Bright Red': ['#DE354C', (222, 53, 76), (0, 76, 66, 13)],
- 'Deep Red': ['#932432', (147, 36, 50), (0, 76, 66, 42)],
- 'Pure Purple': ['#3C1874', (60, 24, 116), (48, 79, 0, 55)],
- 'Purple Tinged Grey': ['#283747', (40, 55, 71), (44, 23, 0, 72)],
- 'Cloud': ['#F3F3F3', (243, 243, 243), (0, 0, 0, 5)]}
-        
+ 'Green Treeline': ['#478559', (71, 133, 89), (47, 0, 33, 48)]}  
 ```
 
 For a detailed explanation of dictionaries and methods for working with them, the [official tutorial][dicts-docs] and the [official library reference][mapping-types-dict] are excellent starting places.
-For more on sorting, see the [Sorting HOW TO][sorting-howto] in the python docs.
- [Real Python][how-to-dicts] and [Finxter][fi-dict-guide] also have very thorough articles on Python dictionaries.
 
-## Extending Dictionaries: The collections module
+[Real Python][how-to-dicts] and [Finxter][fi-dict-guide] also have very thorough articles on Python dictionaries.
 
-The [`collections`][collections-docs] module adds more functionality to Python's standard collection-based datatypes (`dictionary`, `set`, `list`, `tuple`).
-A popular `dict`-oriented member of this module is the [`Counter`][counter-dicts], which automatically counts items and returns them a `dict` with the items as keys and their counts as values.
-There is also the [`OrderedDict`][ordered-dicts-docs], which has methods specialized for re-arranging the order of a dictionary.
-Finally, there is the [`defaultdict`][default-dicts], a subclass of the built-in `dict` module that, based on a factory method, sets a default value if a key is not found when trying to retrieve or assign the value.
+For more on sorting, see the [Sorting HOW TO][sorting-howto] in the Python docs.
 
-[term-hashable]: https://docs.python.org/3/glossary.html#term-hashable
-[hashtable-wikipedia]: https://en.wikipedia.org/wiki/Hash_table
-[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
-[dicts-docs]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
-[how-to-dicts]: https://www.w3schools.com/python/python_dictionaries.asp
-[fromkeys]: https://docs.python.org/3/library/stdtypes.html#dict.fromkeys
-[collections-docs]: https://docs.python.org/3/library/collections.html
-[counter-dicts]: https://docs.python.org/3/library/collections.html#collections.Counter
-[ordered-dicts-docs]: https://docs.python.org/3/library/collections.html#collections.OrderedDict
-[default-dicts]: https://docs.python.org/2/library/collections.html#collections.defaultdict
-[dict-views]: https://docs.python.org/3/library/stdtypes.html#dict-views
 [dict-methods]: https://docs.python.org/3/library/stdtypes.html#dict
+[dict-views]: https://docs.python.org/3/library/stdtypes.html#dict-views
+[dicts-docs]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
 [fi-dict-guide]: https://blog.finxter.com/python-dictionary
+[fromkeys]: https://docs.python.org/3/library/stdtypes.html#dict.fromkeys
+[how-to-dicts]: https://www.w3schools.com/python/python_dictionaries.asp
+[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
 [sorting-howto]: https://docs.python.org/3/howto/sorting.html
diff --git a/concepts/dict-methods/introduction.md b/concepts/dict-methods/introduction.md
index 52868299..c15fbc11 100644
--- a/concepts/dict-methods/introduction.md
+++ b/concepts/dict-methods/introduction.md
@@ -1,17 +1,16 @@
 # Dictionary Methods in Python
 
-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 [hash table or hashmap][hashtable-wikipedia].
-In Python, it's considered a [mapping type][mapping-types-dict].
-`dicts` enable the retrieval of a value in constant time (on average), given the key.
+The `dict` class in Python provides many useful [methods][dict-methods], some of which are introduced in the concept exercise for dictionaries.
 
-Compared to searching for a value within a list or array (_without knowing the index position_), a dictionary uses significantly more memory, but has very rapid retrieval.
-It's especially useful in scenarios where the collection of items is large and must be accessed/updated frequently.
+This concept tackles a few more:
 
-The `dict` class in Python provides many useful [methods][dict-methods] for working with dictionaries.
-Some are introduced in the concept exercise for `dicts`.
-This concept tackles a few more - along with some techniques for iterating through and manipulating `dicts`.
+- `dict.setdefault()` automatically adds keys without throwing a `KeyError`.
+- `dict.fromkeys(iterable, <default value>)` creates a new `dict` from any number of iterables.
+- `.keys()`, `.values()`, and `.items()` provide convenient iterators.
+- `sorted(<dict>.items())`. can easily re-order entries in a `dict`.
+- `dict_one.update(<dict_two>)` updates one `dict` with overlapping values from another `dict`.
+- `dict | other_dict` and `dict |= other_dict` merges or updates two `dict`s via operators.
+- `reversed(dict.keys())`, `reversed(dict.values())`, or `reversed(dict.items())` produce _reversed_ views.
+- `<dict>.popitem()` removes and returns a `key`, `value` pair.
 
-[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
-[hashtable-wikipedia]: https://en.wikipedia.org/wiki/Hash_table
-[term-hashable]: https://docs.python.org/3/glossary.html#term-hashable
 [dict-methods]: https://docs.python.org/3/library/stdtypes.html#dict
diff --git a/concepts/dicts/about.md b/concepts/dicts/about.md
index fb43067e..c34160b2 100644
--- a/concepts/dicts/about.md
+++ b/concepts/dicts/about.md
@@ -1,55 +1,292 @@
 # About
 
+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].
 
-A dictionary (`dict`) is a [mapping type][mapping-types-dict] data structure that associates [hashable][term-hashable] `keys` to `values` -- known in other programming languages as a resizable [hash table or hashmap][hashtable-wikipedia].
-  `Keys` can include `numbers`, `str`, `tuples` (of _immutable_ values), or `frozensets`, but must be hashable and unique across the dictionary.
-  `keys` are _immutable_ - once added to a `dict`, they can only be removed, they cannot be updated.
-  `values` can be of any or multiple data type(s) or structures, including other dictionaries, built-in types, custom types, or even objects like functions or classes.
-   `values` associated with any `key` are _mutable_, and can be replaced, updated or altered as long as the `key` entry exists.
-  Dictionaries enable the retrieval of a `value` in (on average) constant O(1) time, given the `key`.
+`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.
 
-  Compared to searching for a value within a `list` or `array` (_without knowing the `index` position_), a `dict` uses significantly more space in memory, but has significantly more rapid retrieval.
- Dictionaries are especially useful in scenarios where the collection of items is large and must be accessed and/or updated frequently.
+`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.
 
-## Dictionary creation
+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.
 
-A simple `dict` can be declared using the literal form `{<key_1>: <value_1>, <key_2>: <value_2>}`:
+Dictionaries are especially useful in scenarios where the collection of items is large and must be accessed and updated frequently.
 
- ```python
 
+## Dictionary Construction
 
+Dictionaries can be created in many different ways, including:
+ - Using the [`fromkeys()`][fromkeys] classmethod
+ - Creating [dictionary comprehensions][dict-comprehensions]
+ - Merging two dictionaries via unpacking (`**`)
+ - Merging dictionaries via the `|` (_update_) operator
+ - Using a loop to iteratively add entries to a previously created empty `dict`.
 
+The two most straightforward methods are the dictionary _constructor_ and the dictionary _literal_.
 
+### The Dictionary Constructor
+
+`dict()` (_the constructor for the `dict` class_) can be used with any iterable of `key`, `value` pairs.
+ It can also be called with a series of `<name>=<value>` _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}
+```
+
+The [documentation on `dicts`][dicts-docs] outlines additional variations and options in constructor use.
+
+
+### Dictionary Literals
+
+A dictionary can also be directly entered as a _dictionary literal_, using curly brackets (`{}`) enclosing `key : value` pairs.
+Entries that are enclosed in the `{}` can also appear on separate lines:
+
+```python
+>>> whale = {"name": "Blue Whale", 
+             "speed": 35, 
+             "land_animal": False}
+{'name': 'Blue Whale', 'speed': 35, 'land_animal': False}
+
+>>> wombat = {'name': 'Wombat',
+              'speed': 23,
+              'land_animal': True,
+              'color': 'Brindle'}
+
+>>> wombat
+{'name': 'Wombat', 'speed': 23, 'land_animal': True, 'color': 'Brindle'}
+```
+
+### Nested Dictionaries
+
+Dictionaries can be arbitrarily nested:
+
+```python
+animals = {
+            "Real" : {
+                "Winged" : {
+                            "Sparrow" : {'name': 'sparrow','speed': 12, 'land_animal': True},
+                            "Kestrel" : {'name': 'kestrel', 'speed': 15, 'land_animal': True}
+                           },
+                "Legged" : {
+                            "Wombat" : {'name': 'Wombat', 'speed': 23, 'land_animal': True},
+                            "Black Bear": {'name': 'Black Bear', 'speed': 40, 'land_animal': True},
+                            "Polecat" : {'name': 'Polecat', 'speed': 15, 'land_animal': True}
+                           },
+                "Other" :  {
+                            "Whale" : {'name': 'Blue Whale', 'speed': 35, 'land_animal': False},
+                            "Orca" : {'name': 'Orca', 'speed': 45, 'land_animal': False},
+                            "Snake" : {'name': 'Python', 'speed': 25, 'land_animal': True}
+                            }
+                },
+        
+        "Imaginary": {
+                "Winged" : {
+                            "Dragon" : {'name': 'Fire Dragon','speed': 100, 'land_animal': True},
+                            "Phoenix" : {'name': 'Phoenix', 'speed': 1500, 'land_animal': True}
+                            },
+                "Legged" : {
+                            "Sphinx" : {'name': 'Sphinx','speed': 10, 'land_animal': True},
+                            "Minotaur" : {'name': 'Minotaur', 'speed': 5, 'land_animal': True}
+                            },
+                "Other" :  {}
+                }
+       }
+```
+
+## Accessing Values in a `dict`
+
+You can access a `value` in a dictionary using a _key_ in square brackets.
+If a key does not exist, a `KeyError` is thrown:
+
+```python
+>>> bear["speed"]
+40
+
+>>> bear["color"]
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+KeyError: 'color'
+```
+
+Accessing an entry via the `get(<key>, <default value>)` method can avoid the `KeyError`:
+
+```python
+>>> bear.get("color", 'not found')
+'not found'
+```
+
+### Accessing Nested Dictionary Entries
+
+To access entries in nested dictionaries, use successive brackets.
+If a given key is missing, the usual KeyError will be thrown:
+
+```python
+# Using the animals nested dictionary.
+>>> animals["Real"]["winged"]["Kestrel"]["speed"]
+15
+
+>>> animals["Imaginary"]["winged"]["Kestrel"]["speed"]
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+KeyError: 'Kestrel'
+```
+
+To avoid the `KeyError`, `.get()` can be used, but the calls to `.get()` must be _chained_:
+
+```python
+# Using the animals nested dictionary.
+# Note the use of parenthesis to enable placing the 
+# .get() calls on separate lines.
+>>> (animals.get("Imaginary", {})
+            .get("Legged", {})
+            .get("Sphinx", {})
+            .get("Color", "I have no idea!"))
+'I have no idea!'
+```
+
+## 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 an 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 and del) Dictionary Entries
+
+You can use the `.pop(<key>)` method to delete a dictionary entry.
+`.pop()` removes the (`key`, `value`) pair and returns the `value` for use.
+Like `.get()`, `.pop(<key>)` accepts second argument (_`dict.pop(<key>, <default value>)`_) 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 "<stdin>", line 1, in <module>
+KeyError: 'name'
+
+
+# Using a default argument with .pop() will 
+# prevent a KeyError from a missing key.
+>>> bear.pop("name", "Unknown")
+'Unknown'
 ```
 
- The dictionary  constructor `dict(<key_1>=<value_1>, <key_2>=<value_2>)`, but there are many more ways of creating and initializing dictionaries including the use of a _dict comprehension_ or passing additional constructor parameters as illustrated in the [Python docs][mapping-types-dict].
+You can also use the `del` statement to remove a single or multiple entries.
+A `KeError` is raised if the entry to be removed is not found in the dictionary:
+
+```python
+>>> wombat = {'name': 'Wombat',
+              'speed': 23,
+              'land_animal': True,
+              'color': 'Brindle',
+              'talent': 'Singing',
+              'size': 'small'}
+
+# Remove a single entry from the dictionary.
+>>> del wombat["color"]
+>>> wombat
+{'name': 'Wombat', 'speed': 23, 'land_animal': True, 'talent': 'Singing', 'size': 'small'}
+
+
+# Remove multiple entries from the dictionary.
+>>> del wombat["talent"], wombat["size"]
+>>> wombat
+{'name': 'Wombat', 'speed': 23, 'land_animal': True}
 
 
+# Attempting a deletion of a non-existent key raises a KeyError
+>>> del wombat["number_of_legs"]
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+KeyError: 'number_of_legs'
+```
 
-Inserting a new `key`:`value` pair can be done with `dict[key] = value` and the value can be retrieved by using `retrieved_value = dict[key]`.
+## Looping Through/Iterating over a Dictionary
 
-## Methods
+Looping through a dictionary using `for item in dict` or `while item` will iterate over the _keys_ by default.
+You can access _values_ within the same loop by using _square brackets_:
 
-`dicts` implement various methods to allow easy initialization, updating and viewing.
+```python
+>>> for key in bear:
+>>>     print((key, bear[key])) #this prints a tuple of (key, value)
+('name', 'Black Bear')
+('speed', 40)
+('land_animal', True)
+```
 
-Some useful `dict` methods:
+You can also use the `.items()` method, which returns (`key`, `value`) tuples:
 
-- Retrieve a value "safely" from a dictionary by using the `.get(key, [default])` method. `.get(key, [default])` returns the value for the key **or** the _default value_ if the key is not found, instead of raising a `KeyError`. This works well in situations where you would rather not have extra error handling but cannot trust that a looked-for key will be present.
-- Retrieve a value "safely" or insert a default _value_ if the key is not found using the `.setdefault(key, [default])` method. `setdefault(key, [default])` will insert the default value in the dictionary **only** if the key is not found, then it will retrieve either the **newly inserted** default value if the key was not found or the **unchanged** existing value if the key was found.
-- Return various _iterable_ views of your `dict` with `.keys()`, `.values()`, `.items()` (_an iterable of (key, value) `tuples`_).
+```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, `.keys()` will return the `keys` and `.values()` will return the `values`.
 
 For a detailed explanation of dictionaries in Python, the [official documentation][dicts-docs] is an excellent starting place, or you can also check out the [W3-Schools][how-to-dicts] tutorial.
 
-## Extending Dictionaries: The collections module
 
-The [`collections`][collections-docs] module adds more functionality to Python's standard collection-based datatypes (`dictionary`, `set`, `list`, `tuple`). A popular `dict`-oriented member of this module is the [`Counter`][counter-dicts], which automatically counts items and returns them a `dict` with the items as keys and their counts as values. There is also the [`OrderedDict`][ordered-dicts-docs], which has methods specialized for re-arranging the order of a dictionary. Finally, there is the [`defaultdict`][default-dicts], a subclass of the built-in `dict` module that, based on a factory method, sets a default value if a key is not found when trying to retrieve or assign the value.
+## Extending Dictionary Functionality: The Collections Module
 
-[term-hashable]: https://docs.python.org/3/glossary.html#term-hashable
-[hashtable-wikipedia]: https://en.wikipedia.org/wiki/Hash_table
-[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
-[dicts-docs]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
-[how-to-dicts]: https://www.w3schools.com/python/python_dictionaries.asp
+The [`collections`][collections-docs] module adds specialized functionality to Python's standard collection-based datatypes (`dictionary`, `set`, `list`, `tuple`).
+Three of the most useful dictionary-based classes are:
+
+- [`Counter`][counter-dicts] automatically counts items and returns them in a `dict` with the items as keys and their counts as values.
+- [`OrderedDict`][ordered-dicts-docs], has methods specialized for arranging the order of dictionary entries.
+- [`defaultdict`][default-dicts] uses a factory method to set a default value if a `key` is not found when trying to retrieve or assign to a dictionary entry.
+
+[associative-array]: https://en.wikipedia.org/wiki/Associative_array#:~:text=In%20computer%20science%2C%20an%20associative,a%20function%20with%20finite%20domain.
 [collections-docs]: https://docs.python.org/3/library/collections.html
 [counter-dicts]: https://docs.python.org/3/library/collections.html#collections.Counter
-[ordered-dicts-docs]: https://docs.python.org/3/library/collections.html#collections.OrderedDict
 [default-dicts]: https://docs.python.org/2/library/collections.html#collections.defaultdict
+[dict-comprehensions]: https://www.learnbyexample.org/python-dictionary-comprehension/
+[dicts-docs]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
+[fromkeys]: https://www.w3schools.com/python/ref_dictionary_fromkeys.asp
+[hashtable-wikipedia]: https://en.wikipedia.org/wiki/Hash_table
+[how-to-dicts]: https://www.w3schools.com/python/python_dictionaries.asp
+[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
+[ordered-dicts-docs]: https://docs.python.org/3/library/collections.html#collections.OrderedDict
+[term-hashable]: https://docs.python.org/3/glossary.html#term-hashable
diff --git a/concepts/dicts/introduction.md b/concepts/dicts/introduction.md
index 9a887ccf..5c8a7724 100644
--- a/concepts/dicts/introduction.md
+++ b/concepts/dicts/introduction.md
@@ -1,15 +1,24 @@
 # 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].
 
-A dictionary (`dict`) is a [mapping type][mapping-types-dict] data structure that associates [hashable][term-hashable] `keys` to `values` -- known in other programming languages as a resizable [hash table or hashmap][hashtable-wikipedia].
-  `Keys` can include `numbers`, `str`, `tuples` (of _immutable_ values), or `frozensets`, but must be hashable and unique across the dictionary.
-  `values` can be of any or multiple data type(s) or structures, including other dictionaries, built-in types, custom types, or even objects like functions or classes.
-  Dictionaries enable the retrieval of a `value` in (on average) constant O(1) time, given the `key`.
 
-  Compared to searching for a value within a `list` or `array` (_without knowing the `index` position_), a `dict` uses significantly more space in memory, but has significantly more rapid retrieval.
- Dictionaries are especially useful in scenarios where the collection of items is large and must be accessed and/or updated frequently.
+`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.
+
+
+[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
diff --git a/concepts/sets/about.md b/concepts/sets/about.md
index dd567f07..5f272402 100644
--- a/concepts/sets/about.md
+++ b/concepts/sets/about.md
@@ -12,7 +12,7 @@ _Unlike_ sequence types (_`string`, `list` & `tuple`_), `sets` are **neither ord
 They're also used for fast membership testing, finding supersets & subsets of items, and performing "set math" (_calculating union, intersection, difference & symmetric difference between groups of items._).
 
 Checking membership in a `set` has only O(1) time complexity versus checking for membership in a `list` or `string`, which has worst-case O(n) time complexity.
-Operations such as `<set>.union()`, `<set>.intersection()`, or `<set>.diference()` have an average O(n) time complexity.
+Operations such as `<set>.union()`, `<set>.intersection()`, or `<set>.difference()` have an average O(n) time complexity.
 
 ## Construction
 
@@ -52,7 +52,7 @@ set()
 # The list is unpacked and each distinct element is added.
 >>> multiple_elements_from_list = set([2, 3, 2, 3, 3, 3, 5, 7, 11, 7, 11, 13, 13])
 >>> multiple_elements_from_set
-{2, 3, 5, 7, 11}
+{2, 3, 5, 7, 11, 13}
 ```
 
 Results when using a set constructor with a string or dictionary may be surprising:
diff --git a/concepts/string-formatting/about.md b/concepts/string-formatting/about.md
index 07306a8d..f3b2756b 100644
--- a/concepts/string-formatting/about.md
+++ b/concepts/string-formatting/about.md
@@ -2,18 +2,18 @@
 
 ## String Formatting in Python
 
+String formatting is the process of converting values to strings and inserting them into a string template.
 The [Zen of Python][zen-of-python] asserts there should be "one _obvious_ way to do something in Python".
-But when it comes to string formatting, things are a little .... _less zen_.
+But when it comes to string formatting, things are a little ... _less zen_.
 It can be surprising to find out that there are **four** main ways to perform string formatting in Python - each for a different scenario.
 Some of this is due to Python's long history and some of it is due to considerations like internationalization or input sanitation.
 We will start with the most recent additions to the string formatting toolbox and work our way backward to "old style" or "printf() style" string formatting.
 
+## literal string interpolation: The `f-string`
 
-## literal string interpolation:  The `f-string`
-
- Introduced in [Python 3.6][pep-0498], [`f-strings`][f-string] (_short for "formatted-strings"_) or [literal string interpolation][string interpolation] are a way of quickly and efficiently evaluating and formatting expressions and strings to a `str` type using the `f` (or `F`) prefix before the brackets (_like so `f'{object}'`_).
- They can be used with all enclosing string types as: single quote `'`, double quote `"` and with multi-lines and escaping triple quotes `'''` or `"""`.
- Any variables, expressions, or other types placed inside the `{}` are first evaluated, then converted to a `str`, then concatenated with any `str` outside the curly braces.
+Introduced in [Python 3.6][pep-0498], [`f-strings`][f-string] (_short for "formatted-strings"_) or [literal string interpolation][string interpolation] are a way of quickly and efficiently evaluating and formatting expressions and strings to a `str` type using the `f` (or `F`) prefix before the brackets (_like so `f'{object}'`_).
+They can be used with all enclosing string types as: single-line `'` or `"` and with multi-lines `'''` or `"""`.
+Any variables, expressions, or other types placed inside the `{}` are first evaluated, then converted to a `str`, then concatenated with any `str` outside the curly braces.
 
 In this example, we insert two variable values in the sentence: one `str` and one `float`:
 
@@ -23,8 +23,8 @@ In this example, we insert two variable values in the sentence: one `str` and on
 ...
 # The f-string, using the two values.
 # The .2f format code truncates so the value displays as 0.12.
->>> print(f'An {name} is approximately {value:.2f}.')
-'An eighth is approximately 0.12.' 
+>>> f'An {name} is approximately {value:.2f}.'
+'An eighth is approximately 0.12.'
 ```
 
 The expressions evaluated can be almost anything.
@@ -37,16 +37,16 @@ Some examples:
 >>> waves = {'water': 1, 'light': 3, 'sound': 5}
 
 # Using the name waves in an f-string.
->>> print(f'"A dict can be represented with f-string: {waves}."')
+>>> f'"A dict can be represented with f-string: {waves}."'
 '"A dict can be represented with f-string: {\'water\': 1, \'light\': 3, \'sound\': 5}."'
 
 # Here, we pull a value from the dictionary by using the key
->>> print(f'Tenfold the value of "light" is {waves["light"]*10}.')
+>>> f'Tenfold the value of "light" is {waves["light"] * 10}.'
 'Tenfold the value of "light" is 30.'
 ```
 
 Replacement fields (_the `{}` in the f-string_) support output control mechanisms such as width, alignment, precision.
- This is the same [format specification mini-language][format-mini-language] that is used by the `str.format()` method.
+This specification is started in the [format specification mini-language][format-mini-language].
 
 A more complex example of an `f-string` that includes output control:
 
@@ -61,24 +61,21 @@ A more complex example of an `f-string` that includes output control:
 
 # This example includes a function, str, a nested f-string, an arithmetic expression, 
 # precision formatting, bracket escaping and object formatting.
->>> message = f'"Have a {"NICE".lower()} day, I will {verb} you after {f"{30e8*111_000:6.{precision}e}"} light-years."{{{the_end}}}'
-...
->>> print(message)
+>>> f'"Have a {"NICE".lower()} day, I will {verb} you after {f"{30e8 * 111_000:6.{precision}e}"} light-years."{{{the_end}}}'
 '"Have a nice day, I will meet you after 3.330e+14 light-years."{[\'end\', \'of\', \'transmission\']}'
-
 ```
 
 There are a few limitations to be aware of.
-`f-string` expressions cannot be empty, they cannot contain comments, and for Python versions earlier than Python 3.7, they cannot contain `await` or `async for` clauses:
+`f-string` expressions cannot be empty, they cannot contain comments.
 
 ```python
->>> print(f"An empty expression will error: {}")
+>>> f"An empty expression will error: {}"
 SyntaxError: f-string: empty expression not allowed
 
 >>> word = 'word'
->>> print(f"""A comment in a triple quoted f-string will error: {
+>>> f"""A comment in a triple quoted f-string will error: {
     word # I chose a nice variable
-}""")
+}"""
 SyntaxError: f-string expression part cannot include '#'
 ```
 
@@ -92,17 +89,16 @@ Also keep in mind that using expressions inside the `f-string` brackets `{}` is
 ## The `str.format()` Method
 
 The [`str.format()`][str-format] method replaces placeholders within the string with values fed as arguments to the function.
- The placeholders are identified with named (`{price}`), numbered (`{0}` or indexed) or even empty (_positional_) placeholders `{}`.
+The placeholders are identified with named (`{price}`), numbered (`{0}` or indexed) or even empty (_positional_) placeholders `{}`.
 For example:
 
 ```python
 # A named placeholder and a positional placeholder.
->>> print('My text: {placeholder_1} and {}.'.format(12, placeholder_1='named placeholder'))
-...
+>>> 'My text: {placeholder_1} and {}.'.format(12, placeholder_1='named placeholder')
 'My text: named placeholder and 12.'
 ```
 
-As with `f-strings`, Pythons  `str.format()` supports a whole range of [mini language format specifier][format-mini-language] that can be used to align text, convert, etc.
+As with `f-strings`, Pythons `str.format()` supports a whole range of [mini language format specifier][format-mini-language] that can be used to align text, convert, etc.
 
 The complete formatting specifier pattern is `{[<name>][!<conversion>][:<format_specifier>]}`:
 
@@ -115,25 +111,24 @@ Example of conversions for a diacritical letter:
 
 ```python
 # Fills in the object at index zero, converted to a string.
->>> print('An e with an umlaut: {0!s}'.format('ë'))
-An e with an umlaut: ë
-...
+>>> 'An e with an umlaut: {0!s}'.format('ë')
+'An e with an umlaut: ë'
+
 
 # Fills in the object at index zero, converted to a repr.
->>> print('An e with an umlaut object representation: {0!r}'.format('ë'))
-An e with an umlaut object representation: 'ë'
+>>> 'An e with an umlaut object representation: {0!r}'.format('ë')
+"An e with an umlaut object representation: 'ë'"
 
 ...
 
 # Fills in the object at index zero, converted to ascii
->>> print('An e with an umlaut converted into ascii: {0!a}'.format('ë'))
-An e with an umlaut converted into ascii: '\xeb'
+>>> 'An e with an umlaut converted into ascii: {0!a}'.format('ë')
+"An e with an umlaut converted into ascii: '\xeb'"
 
-...
 
 # Fills in the object in the first position.
 # Then fills in the object in the second position formatted as a repr
->>> print('She said her name is not {} but {!r}.'.format('Chloe', 'Zoë'))
+>>> 'She said her name is not {} but {!r}.'.format('Chloe', 'Zoë')
 "She said her name is not Chloe but 'Zoë'."
 ```
 
@@ -142,31 +137,28 @@ Example of using format specifiers:
 ```python
 # Formats the object at index 0 as a decimal with zero places, 
 # then as a right-aligned binary number in an 8 character wide field.
->>> print("The number {0:d} has a representation in binary: '{0: >8b}'.".format(42))
-The number 42 has a representation in binary: '  101010'.
+>>> "The number {0:d} has a representation in binary: '{0: >8b}'.".format(42)
+"The number 42 has a representation in binary: '  101010'."
 ```
 
 More examples are shown at the end of [this documentation][summary-string-format].
 
-
 ## `%` Formatting, or `printf()` Style Formatting
 
 Use of the `%` operator for formatting is the oldest method of string formatting in Python.
 It comes from the C language and allows the use of positional arguments to build a `str`.
 
 This method has been superseded by both `f-strings` and `str.format()`, which is why the nickname for `%` formatting is _'Old Style'_.
-It can be still found in python 2 and/or legacy code.
+It can be still found in Python 2 and/or legacy code.
 While using this method will work in Python 3.x, `%` formatting is usually avoided because it can be error-prone, is less efficient, has fewer options available, and any placeholder-argument mismatch can raise an exception.
- Using the `%` operator is similar to [`printf()`][printf-style-docs], so it is also sometimes called _printf formatting_.
-
+Using the `%` operator is similar to [`printf()`][printf-style-docs], so it is also sometimes called _printf formatting_.
 
 ```python
 # Assigning a variable.
->> name = "Anna-conda"
+>>> name = "Anna-conda"
 
 # Building a string using %
->> print("The snake's name is %s." % name)
-...
+>>> "The snake's name is %s." % name
 "The snake's name is Anna-conda."
 ```
 
@@ -179,33 +171,30 @@ If you want to add multiple variables to a string, you need to supply a [tuple][
 >>> fruit = "grapes"
 
 # Building a string using %
->>> print("Surprisingly, %ss favorite snack was %s." %(name, fruit))
-Surprisingly, Billy the Kids favorite snack was grapes.
+>>> "Surprisingly, %ss favorite snack was %s." %(name, fruit)
+"Surprisingly, Billy the Kids favorite snack was grapes."
 ```
 
-
 ## Template Strings
 
 [`string.Template()`][string.Template()] is a class from the `string` module (_as opposed to the built-in `str` type_), which is part of the Python standard library, but has to be imported for use.
 Template strings support `$`-based substitution and are much simpler and less capable than the other options mentioned here, but can be very useful for when complicated internationalization is needed, or outside inputs need to be sanitized.
 
-
 ```python
->> from string import Template
+>>> from string import Template
 
->>> snake_name = "Anna-Conda"
+>>> name = "Anna-Conda"
 
 # Creating a Template() with placeholder text
->> template_string = Template("The snake called `$snake_name` has escaped!")
+>>> template_string = Template("The snake called `$snake_name` has escaped!")
 
 # Calling .substitute() to replace the placeholder with a value.
->> template_string.substitute(snake_name=name)
+>>> template_string.substitute(snake_name=name)
 'The snake called `Anna-Conda` has escaped!'
 ```
 
 More information about `Template` string can be found in the Python [documentation][template-string].
 
-
 ## How Do You Choose which Formatting Method to Use?
 
 With all these options and mini-languages, how do you decide what to reach for when formatting Python strings?
diff --git a/config.json b/config.json
index 3e292d74..f386ef39 100644
--- a/config.json
+++ b/config.json
@@ -144,6 +144,14 @@
         "prerequisites": ["loops", "lists", "tuples"],
         "status": "beta"
       },
+      {
+        "slug": "mecha-munch-management",
+        "name": "Mecha Munch Management",
+        "uuid": "5ac0c40c-4038-47b8-945b-8480e4a3f44c",
+        "concepts": ["dict-methods"],
+        "prerequisites": ["dicts"],
+        "status": "wip"
+      },
       {
         "slug": "locomotive-engineer",
         "name": "Locomotive Engineer",
@@ -970,6 +978,21 @@
         ],
         "difficulty": 3
       },
+      {
+        "slug": "resistor-color-expert",
+        "name": "Resistor Color Expert",
+        "uuid": "8a738365-0efa-444f-9466-a757ddaddcdb",
+        "practices": ["list-methods"],
+        "prerequisites": [
+          "basics",
+          "bools",
+          "lists",
+          "numbers",
+          "strings",
+          "comparisons"
+        ],
+        "difficulty": 3
+      },
       {
         "slug": "matrix",
         "name": "Matrix",
diff --git a/docs/ABOUT.md b/docs/ABOUT.md
index 05c56799..f0d52389 100644
--- a/docs/ABOUT.md
+++ b/docs/ABOUT.md
@@ -22,7 +22,7 @@ The [zen of Python (PEP 20)][the zen of python] and [What is Pythonic?][what is
 
 Tests and tooling for this track currently support `3.7` - `3.10.6` (_tests_) and [`Python 3.11`][311-new-features] (_tooling_).
 It is highly recommended that students upgrade to at least `Python 3.8`, as some features used by this track may not be supported in earlier versions.
-That being said, most of the exercises will work with `Python 3.6+`, and many are compatible with `Python 2.7+`.
+That being said, most of the exercises will work with `Python 3.6+`.
 But we don't guarantee support for versions not listed under [Active Python Releases][active-python-releases].
 We will try to note when a feature is only available in a certain version.
 
diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md
index 8bf42a04..c8eb68ca 100644
--- a/docs/INSTALLATION.md
+++ b/docs/INSTALLATION.md
@@ -6,7 +6,7 @@ Real Python also offers a [nice guide][helpful guide] to installation on various
 Finally, these posts by Brett Cannon [A quick-and-dirty guide][quick-and-dirty] and [Why you should use `python -m pip`][python-m-pip], give very helpful advice on how to manage Python installations and packages.
 
 **Note for MacOS users:**  prior to MacOS Monterey (12.3), `Python 2.7` came pre-installed with the operating system.
-Using `Python 2.7` with Exercism or most other programs is not recommended.
+Using `Python 2.7` with Exercism or most other programs is not supported.
 You should instead install [Python 3][Python-three downloads] via one of the methods detailed below.
 As of MacOS Monterey (12.3), no version of Python will be pre-installed via MacOS.
 
@@ -20,7 +20,7 @@ Some quick links into the documentation by operating system:
 
 Exercism tests and tooling currently support `3.7` - `3.10.6` (_tests_) and [`Python 3.11`][311-new-features] (_tooling_).
 Exceptions to this support are noted where they occur.
-Most of the exercises will work with `Python 3.6+`, and many are compatible with `Python 2.7+`.
+Most of the exercises will work with `Python 3.6+`.
 But we don't guarantee support for versions not listed under [Active Python Releases][active-python-releases].
 
 
diff --git a/exercises/concept/black-jack/.docs/introduction.md b/exercises/concept/black-jack/.docs/introduction.md
index b79091f4..20722935 100644
--- a/exercises/concept/black-jack/.docs/introduction.md
+++ b/exercises/concept/black-jack/.docs/introduction.md
@@ -80,7 +80,7 @@ False
 Unlike numbers, strings (`str`) are compared [_lexicographically_][lexographic order], using their individual Unicode code points (_the result of passing each code point in the `str` to the built-in function [`ord()`][ord], which returns an `int`_).
 If all code points in both strings match and are _**in the same order**_, the two strings are considered equal.
 This comparison is done in a 'pair-wise' fashion - first-to-first, second-to-second, etc.
-Unlike in Python 2.x, in Python 3.x, `str` and `bytes` cannot be directly coerced/compared.
+In Python 3.x, `str` and `bytes` cannot be directly coerced/compared.
 
 ```python
 >>> 'Python' > 'Rust'
diff --git a/exercises/concept/cater-waiter/.docs/introduction.md b/exercises/concept/cater-waiter/.docs/introduction.md
index fa29f056..905504a6 100644
--- a/exercises/concept/cater-waiter/.docs/introduction.md
+++ b/exercises/concept/cater-waiter/.docs/introduction.md
@@ -50,7 +50,7 @@ set()
 # The list is unpacked and each distinct element is added.
 >>> multiple_elements_from_list = set([2, 3, 2, 3, 3, 3, 5, 7, 11, 7, 11, 13, 13])
 >>> multiple_elements_from_set
-{2, 3, 5, 7, 11}
+{2, 3, 5, 7, 11, 13}
 ```
 
 Sets can hold heterogeneous datatypes, but all `set` elements must be _hashable_:
diff --git a/exercises/concept/inventory-management/.docs/instructions.md b/exercises/concept/inventory-management/.docs/instructions.md
index e1c1806c..718b91d3 100644
--- a/exercises/concept/inventory-management/.docs/instructions.md
+++ b/exercises/concept/inventory-management/.docs/instructions.md
@@ -4,13 +4,17 @@ 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, increase the item's quantity by `1` in the inventory. Then, you will have to handle deleting items from an inventory.
+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`.
 
-To finish, you will have to implement a function which returns all the key-value pairs in an inventory as a list of `tuples`.
 
 ## 1. Create an inventory based on a list
 
-Implement the `create_inventory()` function that creates an "inventory" from a list of items. It should return a `dict` containing each item name paired with their respective quantity.
+Implement the `create_inventory(<input list>)` 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"])
@@ -19,7 +23,7 @@ Implement the `create_inventory()` function that creates an "inventory" from a l
 
 ## 2. Add items from a list to an existing dictionary
 
-Implement the `add_items()` function that adds a list of items to an inventory:
+Implement the `add_items(<inventory dict>, <item list>)` function that adds a list of items to the passed-in inventory:
 
 ```python
 >>> add_items({"coal":1}, ["wood", "iron", "coal", "wood"])
@@ -28,23 +32,26 @@ Implement the `add_items()` function that adds a list of items to an inventory:
 
 ## 3. Decrement items from the inventory
 
-Implement the `decrement_items(<items>)` function that takes a `list` of items. The function should remove one from the available count in the inventory for each time an item appears on the `list`:
+Implement the `decrement_items(<inventory dict>, <items list>)` 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 fall below 0. If the number of times an item appears on the list exceeds the count available, the quantity listed for that item should remain at 0 and additional requests for removing counts should be ignored.
+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 item entirely from the inventory
+## 4. Remove an entry entirely from the inventory
 
-Implement the `remove_item(<inventory>, <item>)` function that removes an item and its count entirely from an inventory:
+Implement the `remove_item(<inventory dict>, <item>)` function that removes an item and its count entirely from an inventory:
 
 ```python
 >>> remove_item({"coal":2, "wood":1, "diamond":2}, "coal")
@@ -58,9 +65,10 @@ If the item is not found in the inventory, the function should return the origin
 {"coal":2, "wood":1, "diamond":2}
 ```
 
-## 5. Return the inventory content
+## 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):
+Implement the `list_inventory(<inventory dict>)` 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})
diff --git a/exercises/concept/inventory-management/.docs/introduction.md b/exercises/concept/inventory-management/.docs/introduction.md
index 1b4a15dc..2b9ef011 100644
--- a/exercises/concept/inventory-management/.docs/introduction.md
+++ b/exercises/concept/inventory-management/.docs/introduction.md
@@ -1,50 +1,79 @@
 # Introduction
 
-A _**dictionary**_ is Python's primary mapping type that associates a _hashable key_ with a value. The lookup by key is more efficient than searching through an array, but does require more memory.
+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].
 
-## Dict construction
 
-Dictionaries can be created in various ways. Two simple options are the use the `dict()` class constructor or the dict literal declaration with key-value pairs.
+`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.
 
-### Use the `dict()` constructor
+`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 `<name>=<value>` _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}
 ```
 
-### Declare a _dict_ literal
+### 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}
 ```
 
-With the dict literal declaration keep in mind that _keys_ are of _data types_ `str` and the colon `:` is used instead of an equal sign `=`.
+## Accessing Values in a Dictionary
 
-## Accessing values
-
-You can access an item in a dictionary using the _key_ of the value.
-
-### Using _square brackets_ after the dict object
+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 "<stdin>", line 1, in <module>
+KeyError: 'color'
 ```
 
-### Using `.get()`
+Accessing an entry via the `.get(<key>, <default value>)` method can avoid the `KeyError`:
 
 ```python
->>> whale.get("name")
-'Blue Whale'
+>>> bear.get("color", 'not found')
+'not found'
 ```
 
-## Changing values
+## Changing or Adding Dictionary Values
 
-You can easily change a value of an item using its _key_.
+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}
 
@@ -52,29 +81,71 @@ You can easily change a value of an item using its _key_.
 {'name': 'Blue Whale', 'speed': 25, 'land_animal': False}
 ```
 
-## Deleting values using keys
+New `key`:`value` pairs can be _added_ in the same fashion:
+
+```python
+# Adding an new "color" key with a new "tawney" value.
+>>> bear["color"] = 'tawney'
+{'name': 'Grizzly Bear', 'speed': 40, 'land_animal': True, 'color': 'tawney'}
 
-You can delete an item from a dictionary using `dict.pop(<key>)`. This will remove the (`key`, `value`) pair from the dictionary and return the `value` for use. `dict.pop(<key>)` accepts second argument, `default` that is returned if the `key` is not found  (`dict.pop(<key>, <default>)`). Otherwise, a `KeyError` will be raised for any `key` that is missing.
+>>> whale["blowholes"] = 1
+{'name': 'Blue Whale', 'speed': 25, 'land_animal': False, 'blowholes': 1}
+```
+
+## Removing (Pop-ing) Dictionary Entries
+
+You can use the `.pop(<key>)` method to delete a dictionary entry.
+`.pop()` removes the (`key`, `value`) pair and returns the `value` for use.
+Like `.get()`, `.pop(<key>)` accepts second argument (_`dict.pop(<key>, <default value>)`_) 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'
->>> bear.pop("name", "Unknown")
-'Unknown'
+
+
+#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 "<stdin>", line 1, in <module>
 KeyError: 'name'
+
+
+#Using a default argument with .pop() will prevent a KeyError from a missing key.
+>>> bear.pop("name", "Unknown")
+'Unknown'
 ```
 
-## Looping through a dictionary
+## Looping through/Iterating over a Dictionary
 
-Looping through a dictionary using `for item in dict` will iterate over the _keys_, but you can access the _values_ by using _square brackets_.
+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:
->>>     (key, bear[key])
+>>>     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
diff --git a/exercises/concept/mecha-munch-management/.docs/hints.md b/exercises/concept/mecha-munch-management/.docs/hints.md
new file mode 100644
index 00000000..9edd70ab
--- /dev/null
+++ b/exercises/concept/mecha-munch-management/.docs/hints.md
@@ -0,0 +1,56 @@
+# Hints
+
+## General
+
+Remember, this is an [MVP][mvp].
+That means you don't need to get too fancy with error handling or different "edge case" scenarios.
+It's OK to be simple and direct with the functions you are writing.
+
+The dictionary section of the [official tutorial][dicts-docs] and the mapping type [official library reference][mapping-types-dict] are excellent places to look for more help with all these methods.
+
+
+## 1. Add Item(s) to the Users Shopping Cart
+
+- You will need to iterate through each item in `items_to_add`.
+- You can avoid a `KeyError` when a key is missing by using a `dict` [method][set-default] that takes a _default value_ as one of its arguments.
+- It is also possible to accomplish the same thing manually in the `loop` by using some checking and error handling, but the `dict` method is easier.
+
+## 2. Read in Items Listed in the Users Notes App
+
+- Remember, Python's got a method for _everything_. This one is a _classmethod_ that's an easy way to [populate a `dict`][fromkeys] with keys.
+- This `dict` method returns a _new dictionary_, populated with default values. If no value is given, the default value will become `None`
+
+## 3. Update Recipe "Ideas" Section
+
+- Don't overthink this one!  This can be solved in **one** `dict` method call.
+- The key word here is .... [_update_][update].
+
+## 4. Sort the Items in the User Cart
+
+- What method would you call to get an [iterable view of items][items] in the dictionary?
+- If you had a `list` or a `tuple`, what [`built-in`][builtins] function might you use to sort them?
+- The built-in function you want is the one that returns a _copy_, and doesn't mutate the original.
+
+## 5. Send User Shopping Cart to Store for Fulfillment
+
+- Having a fresh, empty dictionary here as the `fulfillment_cart` might be handy for adding in items.
+- `Looping` through the members of the cart might be the most direct way of accessing things here.
+- What method would you call to get an [iterable view of just the keys][keys] of the dictionary?
+- Remember that you can get the `value` of a given key by using `<dict name>[<key_name>]` syntax.
+- If you had a `list` or a `tuple`, what [`built-in`][builtins] function might you use to sort them?
+- Remember that the `built-in` function can take an optional `reversed=true` argument.
+
+## 6. Update the Store Inventory to Reflect what a User Has Ordered.
+
+- There is a method that will give you an iterable view of (`key`, `value`) pairs from the dictionary.
+- You can access an item in a _nested tuple_ using _bracket notation_:  `<tuple>[<nested_tuple>][<index_of_value>]`
+- Don't forget to check if an inventory count falls to zero, you'll need to add in the "Out of Stock" message.
+
+[builtins]: https://docs.python.org/3/library/functions.html
+[dicts-docs]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
+[fromkeys]: https://docs.python.org/3/library/stdtypes.html#dict.fromkeys
+[items]: https://docs.python.org/3/library/stdtypes.html#dict.items
+[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
+[mvp]: https://en.wikipedia.org/wiki/Minimum_viable_product
+[set-default]: https://docs.python.org/3/library/stdtypes.html#dict.setdefault
+[update]: https://docs.python.org/3/library/stdtypes.html#dict.update
diff --git a/exercises/concept/mecha-munch-management/.docs/instructions.md b/exercises/concept/mecha-munch-management/.docs/instructions.md
new file mode 100644
index 00000000..f5fa6f79
--- /dev/null
+++ b/exercises/concept/mecha-munch-management/.docs/instructions.md
@@ -0,0 +1,129 @@
+# Instructions
+
+Mecha Munch™, a grocery shopping automation company has just hired you to work on their ordering app.
+Your team is tasked with building an MVP (_[minimum viable product][mvp]_) that manages all the basic shopping cart activities, allowing users to add, remove, and sort their grocery orders.
+Thankfully, a different team is handling all the money and check-out functions!
+
+## 1. Add Item(s) to the Users Shopping Cart
+
+The MVP should allow the user to add items to their shopping cart.
+This could be a single item or multiple items at once.
+Since this is an MVP, item quantity is indicated by _repeats_.
+If a user wants to add 2 Oranges, 'Oranges' will appear twice in the input iterable.
+If the user already has the item in their cart, the cart quantity should be increased by 1.
+If the item is _new_ to the cart, it should be added with a quantity of 1.
+
+Create the function `add_items(<current_cart>, <items_to_add>)` that takes a cart dictionary and any list-like iterable of items to add as arguments.
+It should return a new/updated shopping cart dictionary for the user.
+
+```python
+>>> add_items({'Banana': 3, 'Apple': 2, 'Orange': 1}, 
+              ('Apple', 'Apple', 'Orange', 'Apple', 'Banana'))
+{'Banana': 4, 'Apple': 5, 'Orange': 2}
+
+>>> add_items({'Banana': 3, 'Apple': 2, 'Orange': 1}, 
+              ['Banana', 'Orange', 'Blueberries', 'Banana'])
+{'Banana': 5, 'Apple': 2, 'Orange': 2, 'Blueberries': 1}
+```
+
+## 2. Read in Items Listed in the Users Notes App
+
+Uh-oh.
+Looks like the product team is engaging in [feature creep][feature creep].
+They want to add extra functionality to the MVP.
+The application now has to create a shopping cart by reading items off a users notes app.
+Convenient for the users, but slightly more work for the team.
+
+Create the function `read_notes(<notes>)` that can take any list-like iterable as an argument.
+The function should parse the items and create a user shopping cart/dictionary.
+Each item should be added with a quantity of 1.
+The new user cart should then be returned.
+
+```python
+>>> read_notes(('Banana','Apple', 'Orange'))
+{'Banana': 1, 'Apple': 1, 'Orange': 1}
+
+>>> read_notes(['Blueberries', 'Pear', 'Orange', 'Banana', 'Apple'])
+{'Blueberries' : 1, 'Pear' : 1, 'Orange' : 1, 'Banana' : 1, 'Apple' : 1}
+```
+
+## 3. Update Recipe "Ideas" Section
+
+The app has an "ideas" section that's filled with finished recipes from various cuisines.
+The user can select any one of these recipes and have all its ingredients added to their shopping cart automatically.
+The project manager has asked you create a way to edit these "ideas" recipes, since the content team keeps changing around ingredients and quantities.
+
+Create the function `update_recipes(<ideas>, <recipe_updates>)` that takes an "ideas" dictionary and an iterable of recipe updates as arguments.
+The function should return the new/updated "ideas" dictionary.
+
+```python
+>>> update_recipes({'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
+                    'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}},
+(('Banana Bread', {'Banana': 4,  'Walnuts': 2, 'Flour': 1, 'Eggs': 2, 'Butter': 1, 'Milk': 2, 'Eggs': 3}),))
+...
+
+{'Banana Bread' : {'Banana': 4,  'Walnuts': 2, 'Flour': 1, 'Eggs': 2, 'Butter': 1, 'Milk': 2, 'Eggs': 3},
+ 'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}}
+
+>>> update_recipes({'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
+                    'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1},
+                    'Pasta Primavera': {'Eggs': 1, 'Carrots': 1, 'Spinach': 2, 'Tomatoes': 3, 'Parmesan': 2, 'Milk': 1, 'Onion': 1}},
+[('Raspberry Pie', {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2}),
+('Pasta Primavera', {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1}),
+('Blueberry Crumble', {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3})])
+...
+
+{'Banana Bread': {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
+ 'Raspberry Pie': {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2},
+ 'Pasta Primavera': {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1},
+ 'Blueberry Crumble': {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3}}
+```
+
+## 4. Sort the Items in the User Cart
+
+Once a user has started a cart, the app allows them to sort their items alphabetically.
+This makes things easier to find, and helps when there are data-entry errors like having 'potatoes' and 'Potato' in the database.
+
+Create the function `sort_entries(<cart>)` that takes a shopping cart/dictionary as an argument and returns a new, alphabetically sorted one.
+
+```python
+>>> sort_entries({'Banana': 3, 'Apple': 2, 'Orange': 1})
+{'Apple': 2, 'Banana':3, 'Orange': 1}
+```
+
+## 5. Send User Shopping Cart to Store for Fulfillment
+
+The app needs to send a given users cart to the store for fulfillment.
+However, the shoppers in the store need to know which store isle the item can be found in and if the item needs refrigeration.
+So (_rather arbitrarily_) the "fulfillment cart" needs to be sorted in reverse alphabetical order with item quantities combined with location and refrigeration information.
+
+Create the function `send_to_store(<cart>, <isle_mapping>)` that takes a user shopping cart and a dictionary that has store isle number and a `True`/`False` for refrigeration needed for each item.
+The function should `return` a combined "fulfillment cart" that has (quantity, isle, and refrigeration) for each item the customer is ordering.
+Items should appear in _reverse_ alphabetical order.
+
+```python
+>>> send_to_store({'Banana': 3, 'Apple': 2, 'Orange': 1, 'Milk': 2}, 
+                  {'Banana': ['Isle 5', False], 'Apple': ['Isle 4', False], 'Orange': ['Isle 4', False], 'Milk': ['Isle 2', True]})
+{'Orange': [1, 'Isle 4', False], 'Milk': [2, 'Isle 2', True], 'Banana': [3, 'Isle 5', False], 'Apple': [2, 'Isle 4', False]}
+```
+
+## 6. Update the Store Inventory to Reflect what a User Has Ordered.
+
+The app can't just place customer orders endlessly.
+Eventually, the store is going to run out of various products.
+So your app MVP needs to update the store inventory every time a user sends their order to the store.
+Otherwise, customers will order products that aren't actually available.
+
+Create the function `update_store_inventory(<fulfillment_cart>, <store_inventory>)` that takes a "fulfillment cart" and a store inventory.
+The function should reduce the store inventory amounts by the number "ordered" in the "fulfillment cart" and then return the updated store inventory.
+Where a store item count falls to 0, the count should be replaced by the message 'Out of Stock'.
+
+```python
+>>> update_store_inventory({'Orange': [1, 'Isle 4', False], 'Milk': [2, 'Isle 2', True], 'Banana': [3, 'Isle 5', False], 'Apple': [2, 'Isle 4', False]}, 
+{'Banana': [15, 'Isle 5', False], 'Apple': [12, 'Isle 4', False], 'Orange': [1, 'Isle 4', False], 'Milk': [4, 'Isle 2', True]})
+
+{'Banana': [12, 'Isle 5', False], 'Apple': [10, 'Isle 4', False], 'Orange': ['Out of Stock', 'Isle 4', False], 'Milk': [2, 'Isle 2', True]}
+```
+
+[feature creep]: https://en.wikipedia.org/wiki/Feature_creep
+[mvp]: https://en.wikipedia.org/wiki/Minimum_viable_product
diff --git a/exercises/concept/mecha-munch-management/.docs/introduction.md b/exercises/concept/mecha-munch-management/.docs/introduction.md
new file mode 100644
index 00000000..f1c5744e
--- /dev/null
+++ b/exercises/concept/mecha-munch-management/.docs/introduction.md
@@ -0,0 +1,221 @@
+# Dictionary Methods in Python
+
+The `dict` class in Python provides many useful [methods][dict-methods] for working with dictionaries.
+Some were introduced in the concept for `dicts`.
+Here we cover a few more - along with some techniques for iterating through and manipulating dictionaries.
+
+### Use `setdefault()` for Error-Free Insertion
+
+The dictionary concept previously covered that `.get(key, <default value>)` returns an existing `value` or the `default value` if a `key` is not found in a dictionary, thereby avoiding a `KeyError`.
+This works well in situations where you would rather not have extra error handling but cannot trust that a looked-for `key` will be present.
+
+For a similarly "safe" (_without KeyError_) insertion operation, there is the `.setdefault(key, <default value>)` method.
+`setdefault(key, <default value>)` will return the `value` if the `key` is found in the dictionary.
+If the key is **not** found, it will _insert_ the (`key`, `default value`) pair and return the `default value` for use.
+
+```python
+>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
+
+# Looking for the value associated with key "Rock Brown".
+# The key does not exist, so it is added with the default value, and the value is returned.
+>>> palette.setdefault('Rock Brown', '#694605')
+'#694605'
+
+# The (key, default value) pair has now been added to the dictionary.
+>>> palette_I
+{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Rock Brown': '#694605'}
+```
+
+## Use `fromkeys()` to Populate a Dictionary from an Iterable
+
+To quickly populate a dictionary with various `keys` and default values, the _class method_ [`fromkeys(iterable, <default value>)`][fromkeys] will iterate through an iterable of `keys` and create a new `dict`.
+All `values` will be set to the `default value` provided:
+
+```python
+>>> new_dict = dict.fromkeys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'], 'fill in hex color here')
+
+{'Grassy Green': 'fill in hex color here',
+ 'Purple Mountains Majesty': 'fill in hex color here',
+ 'Misty Mountain Pink': 'fill in hex color here'}
+```
+
+## Iterating Over Entries in a Dictionary Via Views
+
+The `.keys()`, `.values()`, and `.items()` methods return [_iterable views_][dict-views] of a dictionary.
+
+These views can be used to easily loop over entries without altering them.
+Views are also _dynamic_ -- when underlying dictionary data changes, the associated `view object` will reflect the change:
+
+```python
+>>> palette_I = {'Grassy Green': '#9bc400',
+                 'Purple Mountains Majesty': '#8076a3',
+                  'Misty Mountain Pink': '#f9c5bd'}
+
+# Using .keys() returns a list of keys.
+>>> palette_I.keys()
+dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'])
+
+# Using .values() returns a list of values.
+>>> palette_I.values()
+dict_values(['#9bc400', '#8076a3', '#f9c5bd'])
+
+# Using .items() returns a list of (key, value) tuples.
+>>> palette_I.items()
+dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', '#8076a3'), ('Misty Mountain Pink', '#f9c5bd')])
+
+# Views are dynamic.  Changing values in the dict changes all of the associated views.
+>>> palette_I['Purple Mountains Majesty'] = (128, 118, 163)
+>>> palette_I['Deep Red'] = '#932432'
+
+>>> palette_I.values()
+dict_values(['#9bc400', (128, 118, 163), '#f9c5bd', '#932432'])
+
+>>> palette_I.keys()
+dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink', 'Deep Red'])
+
+>>> palette_I.items()
+dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', (128, 118, 163)), ('Misty Mountain Pink', '#f9c5bd'), ('Deep Red', '#932432')])
+```
+
+## More on `.keys()`, `.values()`, and `.items()`
+
+In Python 3.7+, `dicts` preserve the order in which entries are inserted allowing First-in, First-out (_`FIFO`_),  iteration when using `.keys()`, `.values()`, or `.items()`.
+
+In Python 3.8+, views are also _reversible_.
+This allows keys, values, or (`key`, `value`) pairs to be iterated over in Last-in, First-out (`LIFO`) order by using `reversed(<dict>.keys())`, `reversed(<dict>.values())`, or `reversed(<dict>.items())`:
+
+```python
+>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
+
+# Iterating in insertion order 
+>>> for item in palette_II.items():
+...     print(item)
+...
+('Factory Stone Purple', '#7c677f')
+('Green Treeline', '#478559')
+('Purple baseline', '#161748')
+
+
+# Iterating in the reverse direction.
+>>> for item in reversed(palette_II.items()):
+...    print (item)
+...
+('Purple baseline', '#161748')
+('Green Treeline', '#478559')
+('Factory Stone Purple', '#7c677f')
+```
+
+## Sorting a Dictionary
+
+Dictionaries do not have a built-in sorting method.
+However, it is possible to sort a `dict` _view_ using the built-in function `sorted()` with `.items()`.
+The sorted view can then be used to create a new dictionary.
+Like iteration, the default sort is over dictionary `keys`.
+
+```python
+# Default ordering for a dictionary is last in, first out (LIFO).
+>>> color_palette = {'Grassy Green': '#9bc400', 
+                    'Purple Mountains Majesty': '#8076a3', 
+                    'Misty Mountain Pink': '#f9c5bd', 
+                    'Factory Stone Purple': '#7c677f', 
+                    'Green Treeline': '#478559', 
+                    'Purple baseline': '#161748'}
+ 
+ 
+# The default sort order for a dictionary uses the keys.
+>>> sorted_palette = dict(sorted(color_palette.items()))
+>>> sorted_palette
+{'Factory Stone Purple': '#7c677f',
+ 'Grassy Green': '#9bc400',
+ 'Green Treeline': '#478559',
+ 'Misty Mountain Pink': '#f9c5bd',
+ 'Purple Mountains Majesty': '#8076a3',
+ 'Purple baseline': '#161748'}
+```
+
+## Combining Dictionaries with `.update()`
+
+`<dict_one>.update(<dict_two>)` can be used to _combine_ two dictionaries.
+This method will take the (`key`,`value`) pairs of `<dict_two>` and write them into `<dict_one>`:
+
+```python
+>>> palette_I = {'Grassy Green': '#9bc400',
+                 'Purple Mountains Majesty': '#8076a3',
+                  'Misty Mountain Pink': '#f9c5bd'}
+>>> palette_II = {'Factory Stone Purple': '#7c677f',
+                  'Green Treeline': '#478559',
+                  'Purple Baseline': '#161748'}
+
+>>> palette_I.update(palette_II)
+
+# Note that new items from palette_II are added.
+>>> palette_I
+{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple Baseline': '#161748'}
+```
+
+Where keys in the two dictionaries _overlap_, the `value` in `dict_one` will be _overwritten_ by the corresponding `value` from `dict_two`:
+
+```python
+>>> palette_I =   {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 
+                   'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
+>>> palette_III = {'Grassy Green': (155, 196, 0), 'Purple Mountains Majesty': (128, 118, 163),
+                   'Misty Mountain Pink': (249, 197, 189)}
+>>> palette_I.update(palette_III)
+
+# Overlapping values in palette_I are replaced with values from palette_III
+>>> palette_I
+{'Grassy Green': (155, 196, 0),
+  'Purple Mountains Majesty': (128, 118, 163), 
+  'Misty Mountain Pink': (249, 197, 189), 
+  'Factory Stone Purple': '#7c677f', 
+  'Green Treeline': '#478559', 'Purple baseline': '#161748'}
+```
+
+## Merge or Update Dictionaries Via the Union (`|`) Operators
+
+Python 3.9 introduces a different means of merging `dicts`: the `union` operators.
+`dict_one | dict_two` will create a **new dictionary**, made up of the (`key`, `value`) pairs of `dict_one` and `dict_two`.
+When both dictionaries share keys, `dict_two` values take precedence.
+
+```python
+>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
+>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
+>>> new_dict = palette_I | palette_II
+>>> new_dict
+...
+{'Grassy Green': '#9bc400',
+ 'Purple Mountains Majesty': '#8076a3',
+ 'Misty Mountain Pink': '#f9c5bd',
+ 'Factory Stone Purple': '#7c677f',
+ 'Green Treeline': '#478559',
+ 'Purple baseline': '#161748'}
+```
+
+`dict_one |= other` behaves similar to `<dict_one>.update(<dict_two>)`, but in this case, `other` can be either a `dict` or an iterable of (`key`, `value`) pairs:
+
+```python
+>>> palette_III = {'Grassy Green': (155, 196, 0),
+                   'Purple Mountains Majesty': (128, 118, 163),
+                   'Misty Mountain Pink': (249, 197, 189)}
+>>> new_dict |= palette_III
+>>> new_dict
+...
+{'Grassy Green': (155, 196, 0),
+'Purple Mountains Majesty': (128, 118, 163),
+'Misty Mountain Pink': (249, 197, 189),
+'Factory Stone Purple': '#7c677f',
+'Green Treeline': '#478559',
+'Purple baseline': '#161748'}
+```
+
+For a detailed explanation of dictionaries and methods for working with them, the [official tutorial][dicts-docs] and the [official library reference][mapping-types-dict] are excellent starting places.
+
+[Real Python][how-to-dicts] and [Finxter][fi-dict-guide] also have very thorough articles on Python dictionaries.
+
+[dict-methods]: https://docs.python.org/3/library/stdtypes.html#dict
+[dict-views]: https://docs.python.org/3/library/stdtypes.html#dict-views
+[dicts-docs]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
+[fi-dict-guide]: https://blog.finxter.com/python-dictionary
+[fromkeys]: https://docs.python.org/3/library/stdtypes.html#dict.fromkeys
+[how-to-dicts]: https://www.w3schools.com/python/python_dictionaries.asp
+[mapping-types-dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
diff --git a/exercises/concept/mecha-munch-management/.meta/config.json b/exercises/concept/mecha-munch-management/.meta/config.json
new file mode 100644
index 00000000..f09d0f29
--- /dev/null
+++ b/exercises/concept/mecha-munch-management/.meta/config.json
@@ -0,0 +1,21 @@
+{
+  "authors": [
+    "meatball133",
+    "BethanyG"
+  ],
+  "contributors": [
+  ],
+  "files": {
+    "solution": [
+      "dict_methods.py"
+    ],
+    "test": [
+      "dict_methods_test.py"
+    ],
+    "exemplar": [
+      ".meta/exemplar.py"
+    ]
+  },
+  "icon": "gross-store",
+  "blurb": "Learn about dictionary methods by building a shopping cart MVP for the Mecha Munch grocery app."
+}
diff --git a/exercises/concept/mecha-munch-management/.meta/design.md b/exercises/concept/mecha-munch-management/.meta/design.md
new file mode 100644
index 00000000..4c3c52a0
--- /dev/null
+++ b/exercises/concept/mecha-munch-management/.meta/design.md
@@ -0,0 +1,59 @@
+## Learning objectives
+
+Cover useful `dict` methods and a few techniques for operating on/manipulating `dicts`.
+
+- `dict.setdefault()` for automatically adding keys when needed.
+- `dict.fromkeys(iterable, <default value>)` for creating a new `dict` from any number of iterables.
+- `dict.keys()`, `dict.values()`, and `dict.items()` for convenient iterators.
+- `reversed(dict.keys())`, `reversed(dict.values())`, or `reversed(dict.items())` for reversed views.
+- `sorted()` with `dict.items()`. for re-ordering entries in a `dict`.
+- `dict_one.update(<dict_two>)` for updating one `dict` with overlapping values from another `dict`.
+- `dict | other_dict` and `dict |= other_dict` for merging or updating two `dict`s via operators.
+- `dict.popitem()` for removing and returning a key, value pair.
+
+- Working more with  the `dict` views `items()` , `keys()` or `values()`.  (e.g, by sorting information using `sorted()` or by swapping `keys` and `values`, etc.)
+- Knowing that Dictionaries can be _nested_, _-- e.g._ ' a dictionary of dictionaries'.
+- Considerations when `updating()` or using `union` with dictionaries.
+
+## Out of scope
+
+Please take a look at the `dicts` concept exercise [design.md file](https://github.com/exercism/python/edit/main/exercises/concept/inventory-management/.meta/design.md) for `dict` features  taught thus far.
+While those methods can be used for solutions to this exercise, it  isn't necessary to cover them again in detail.  Additionally, the following is out of scope:
+
+- Dictionary comprehensions
+- Built-in functions as they relate to this data structure (*e.g.* `len()`, or `enumerate()`
+- Considerations of Mutability
+- `copy()` vs `deepcopy()`
+- Memory and performance characteristics.
+- Related `collections` module with `Counter()` and `defaultdict()`
+
+## Concepts
+
+- `dicts`
+- `dict-methods`
+
+## Prerequisites
+
+These are the concepts/concept exercises the student needs to complete/understand before solving this concept exercise.
+
+- `basics`
+- `bools`
+- `conditionals`
+- `comparisons`
+- `dicts`
+- `lists`
+- `loops`
+- `numbers`
+- `strings`
+- `tuples`
+
+
+## Resources to refer to
+
+- [Python docs:  Tutorial - Dictionaries](https://docs.python.org/3/tutorial/datastructures.html#dictionaries)
+- [Python docs:  Mapping Type `dict`](https://docs.python.org/3/library/stdtypes.html#mapping-types-dict)
+- [Real Python:  Dicts](https://realpython.com/python-dicts/)
+- [Digital Ocean:  Understanding dictionaries in python 3](https://www.digitalocean.com/community/tutorials/understanding-dictionaries-in-python-3)
+- [Stack Overflow: exchanging keys with values in a `dict` in Python](https://stackoverflow.com/questions/1031851/how-do-i-exchange-keys-with-values-in-a-dictionary)
+- [kite:  how to sort a dictionary by key in python](https://www.kite.com/python/answers/how-to-sort-a-dictionary-by-key-in-python)
+- [medium:  16 Python Dictionary Tips](https://medium.com/python-in-plain-english/16-intermediate-level-python-dictionary-tips-tricks-and-shortcuts-1376859e1adc)  _**note:** this is a good resource for ideas and writing this exericse, but is a subscription-based service, so not the best for linking to_
\ No newline at end of file
diff --git a/exercises/concept/mecha-munch-management/.meta/exemplar.py b/exercises/concept/mecha-munch-management/.meta/exemplar.py
new file mode 100644
index 00000000..0390944d
--- /dev/null
+++ b/exercises/concept/mecha-munch-management/.meta/exemplar.py
@@ -0,0 +1,79 @@
+"""Functions to manage a users shopping cart items."""
+
+
+def add_item(current_cart, items_to_add):
+    """Add items to shopping cart.
+
+    :param current_cart: dict - the current shopping cart.
+    :param items_to_add: iterable - items to add to the cart.
+    :return: dict - the updated user cart dictionary.
+    """
+
+    for item in items_to_add:
+        current_cart.setdefault(item, 0)
+        current_cart[item] += 1
+
+    return current_cart
+
+
+def read_notes(notes):
+    """Create user cart from an iterable notes entry.
+
+    :param notes: iterable of items to add to cart.
+    :return: dict - a user shopping cart dictionary.
+    """
+
+    return dict.fromkeys(notes, 1)
+
+
+def update_recipes(ideas, recipe_updates):
+    """Update the recipe ideas dictionary.
+
+    :param ideas: dict - The "recipe ideas" dict.
+    :param recipe_updates: dict - dictionary with updates for the ideas section.
+    :return: dict - updated "recipe ideas" dict.
+    """
+
+    ideas.update(recipe_updates)
+    return ideas
+
+
+def sort_entries(cart):
+    """Sort a users shopping cart in alphabetically order.
+
+    :param cart: dict - a users shopping cart dictionary.
+    :return: dict - users shopping cart sorted in alphabetical order.
+    """
+
+    return dict(sorted(cart.items()))
+
+
+def send_to_store(cart, isle_mapping):
+    """Combine users order to isle and refrigeration information.
+
+    :param cart: dict - users shopping cart dictionary.
+    :param isle_mapping: dict - isle and refrigeration information dictionary.
+    :return: dict - fulfillment dictionary ready to send to store.
+    """
+    fulfillment_cart = {}
+
+    for key in cart.keys():
+        fulfillment_cart[key] = [cart[key]] + isle_mapping[key]
+
+    return dict(sorted(fulfillment_cart.items(), reverse=True))
+
+
+def update_store_inventory(fulfillment_cart, store_inventory):
+    """Update store inventory levels with user order.
+
+    :param fulfillment cart: dict - fulfillment cart to send to store.
+    :param store_inventory: dict - store available inventory
+    :return: dict - store_inventory updated.
+    """
+
+    for key, values in fulfillment_cart.items():
+        store_inventory[key][0] = store_inventory[key][0] - values[0]
+        if store_inventory[key][0] == 0:
+            store_inventory[key][0] = 'Out of Stock'
+
+    return store_inventory
diff --git a/exercises/concept/mecha-munch-management/dict_methods.py b/exercises/concept/mecha-munch-management/dict_methods.py
new file mode 100644
index 00000000..d443c8bc
--- /dev/null
+++ b/exercises/concept/mecha-munch-management/dict_methods.py
@@ -0,0 +1,65 @@
+"""Functions to manage a users shopping cart items."""
+
+
+def add_item(current_cart, items_to_add):
+    """Add items to shopping cart.
+
+    :param current_cart: dict - the current shopping cart.
+    :param items_to_add: iterable - items to add to the cart.
+    :return: dict - the updated user cart dictionary.
+    """
+
+    pass
+
+
+def read_notes(notes):
+    """Create user cart from an iterable notes entry.
+
+    :param notes: iterable of items to add to cart.
+    :return: dict - a user shopping cart dictionary.
+    """
+
+    pass
+
+
+def update_recipes(ideas, recipe_updates):
+    """Update the recipe ideas dictionary.
+
+    :param ideas: dict - The "recipe ideas" dict.
+    :param recipe_updates: dict - dictionary with updates for the ideas section.
+    :return: dict - updated "recipe ideas" dict.
+    """
+
+    pass
+
+
+def sort_entries(cart):
+    """Sort a users shopping cart in alphabetically order.
+
+    :param cart: dict - a users shopping cart dictionary.
+    :return: dict - users shopping cart sorted in alphabetical order.
+    """
+
+    pass
+
+
+def send_to_store(cart, isle_mapping):
+    """Combine users order to isle and refrigeration information.
+
+    :param cart: dict - users shopping cart dictionary.
+    :param isle_mapping: dict - isle and refrigeration information dictionary.
+    :return: dict - fulfillment dictionary ready to send to store.
+    """
+
+    pass
+
+
+def update_store_inventory(fulfillment_cart, store_inventory):
+    """Update store inventory levels with user order.
+
+    :param fulfillment cart: dict - fulfillment cart to send to store.
+    :param store_inventory: dict - store available inventory
+    :return: dict - store_inventory updated.
+    """
+
+    pass
diff --git a/exercises/practice/circular-buffer/.meta/example.py b/exercises/practice/circular-buffer/.meta/example.py
index 8438b983..538cc7bc 100644
--- a/exercises/practice/circular-buffer/.meta/example.py
+++ b/exercises/practice/circular-buffer/.meta/example.py
@@ -25,7 +25,7 @@ class CircularBuffer:
         self.read_point = 0
         self.write_point = 0
 
-    # (protected) helper method to support python 2/3
+    # (protected) helper method
     def _update_buffer(self, data):
         try:
             self.buffer[self.write_point] = data
diff --git a/exercises/practice/pythagorean-triplet/.meta/template.j2 b/exercises/practice/pythagorean-triplet/.meta/template.j2
index b3836a54..e52cda4e 100644
--- a/exercises/practice/pythagorean-triplet/.meta/template.j2
+++ b/exercises/practice/pythagorean-triplet/.meta/template.j2
@@ -2,9 +2,6 @@
 
 {{ macros.header() }}
 
-# Python 2/3 compatibility
-if not hasattr(unittest.TestCase, 'assertCountEqual'):
-    unittest.TestCase.assertCountEqual = unittest.TestCase.assertItemsEqual
 
 class {{ exercise | camel_case }}Test(unittest.TestCase):
     {% for case in cases -%}
diff --git a/exercises/practice/resistor-color-expert/.docs/instructions.md b/exercises/practice/resistor-color-expert/.docs/instructions.md
new file mode 100644
index 00000000..f0880164
--- /dev/null
+++ b/exercises/practice/resistor-color-expert/.docs/instructions.md
@@ -0,0 +1,76 @@
+# Instructions
+
+In this exercise, you are going to create a helpful program so that you don't have to remember the values of the bands.
+The program will take 1, 4, or 5 colors as input, and outputs the correct value, in ohms.
+The color bands are encoded as follows:
+
+- Black: 0
+- Brown: 1
+- Red: 2
+- Orange: 3
+- Yellow: 4
+- Green: 5
+- Blue: 6
+- Violet: 7
+- Grey: 8
+- White: 9
+
+In `resistor-color trio` you decoded the first three colors.
+For instance: orange-orange-brown translated to the main value `330`.
+In this exercise you will need to add _tolerance_ to the mix.
+Tolerance is the maximum amount that a value can be above or below the main value.
+For example, if the last band is green, the maximum tolerance will be ±0.5%.
+
+The tolerance band will have one of these values:
+
+- Grey - 0.05%
+- Violet - 0.1%
+- Blue - 0.25%
+- Green - 0.5%
+- Brown - 1%
+- Red - 2%
+- Gold - 5%
+- Silver - 10%
+
+The four-band resistor is built up like this:
+
+| Band_1  | Band_2  | Band_3     | band_4    |
+| ------- | ------- | ---------- | --------- |
+| Value_1 | Value_2 | Multiplier | Tolerance |
+
+Meaning
+
+- orange-orange-brown-green would be 330 ohms with a ±0.5% tolerance.
+- orange-orange-red would-grey would be 3300 ohms with ±0.005% tolerance.
+The difference between a four and five-band resistor is that the five-band resistor has an extra band to indicate a more precise value.
+
+| Band_1  | Band_2  | Band_3  | Band_4     | band_5    |
+| ------- | ------- | ------- | ---------- | --------- |
+| Value_1 | Value_2 | Value_3 | Multiplier | Tolerance |
+
+Meaning
+
+- orange-orange-orange-black-green would be 330 ohms with a ±0.5% tolerance.
+There are also one band resistors.
+This type of resistor only has the color black and has a value of 0.
+
+This exercise is about translating the resistor band colors into a label:
+
+"... ohms ...%"
+
+So an input of "orange", "orange", "black, green" should return:
+
+"33 ohms ±0.5%"
+
+When there are more than a thousand ohms, we say "kiloohms".
+ That's similar to saying "kilometer" for 1000 meters, and "kilograms" for 1000 grams.
+
+So an input of "orange", "orange", "orange", grey should return:
+
+"33 kiloohms ±0.05%"
+
+When there are more than a million ohms, we say "megaohms".
+
+So an input of "orange", "orange", "orange", "red" should return:
+
+"33 megaohms ±2%"
diff --git a/exercises/practice/resistor-color-expert/.docs/introduction.md b/exercises/practice/resistor-color-expert/.docs/introduction.md
new file mode 100644
index 00000000..fd9e05ef
--- /dev/null
+++ b/exercises/practice/resistor-color-expert/.docs/introduction.md
@@ -0,0 +1,10 @@
+# Introduction
+
+If you want to build something using a Raspberry Pi, you'll probably use _resistors_.
+Like the previous `Resistor Color Duo` and `Resistor Color Trio` exercises, you will be translating resistor color bands to human-readable labels.
+
+- Each resistor has a resistance value.
+- Resistors are small - so small in fact that if you printed the resistance value on them, it would be hard to read.
+  To get around this problem, manufacturers print color-coded bands onto the resistors to denote their resistance values.
+- Each band acts as a digit of a number.
+  For example, if they printed a brown band (value 1) followed by a green band (value 5), it would translate to the number 15.
diff --git a/exercises/practice/resistor-color-expert/.meta/config.json b/exercises/practice/resistor-color-expert/.meta/config.json
new file mode 100644
index 00000000..edf50b4a
--- /dev/null
+++ b/exercises/practice/resistor-color-expert/.meta/config.json
@@ -0,0 +1,20 @@
+{
+  "authors": [
+    "meatball133",
+    "bethanyg"
+  ],
+  "files": {
+    "solution": [
+      "resistor_color_expert.py"
+    ],
+    "test": [
+      "resistor_color_expert_test.py"
+    ],
+    "example": [
+      ".meta/example.py"
+    ]
+  },
+  "blurb": "Convert color codes as used on resistors with different bands to a human-readable label.",
+  "source": "Based on earlier resistor color exercises made by Erik Schierboom and Maud de Vries",
+  "source_url": "https://github.com/exercism/problem-specifications/issues/1464"
+}
diff --git a/exercises/practice/resistor-color-expert/.meta/example.py b/exercises/practice/resistor-color-expert/.meta/example.py
new file mode 100644
index 00000000..0fd6e42f
--- /dev/null
+++ b/exercises/practice/resistor-color-expert/.meta/example.py
@@ -0,0 +1,49 @@
+COLORS = [
+    'black',
+    'brown',
+    'red',
+    'orange',
+    'yellow',
+    'green',
+    'blue',
+    'violet',
+    'grey',
+    'white'
+]
+
+COLORS_TOLERANCE = {
+    'brown': 1,
+    'red': 2,
+    'green': 0.5,
+    'blue': 0.25,
+    'violet': 0.1,
+    'grey': 0.05,
+    'gold': 5,
+    'silver': 10
+}
+
+
+def resistor_label(colors):
+    if len(colors) == 1:
+        return f'0 ohms'
+    elif len(colors) == 4:
+        value = 10 * COLORS.index(colors[0]) + COLORS.index(colors[1])
+        value *= 10 ** COLORS.index(colors[2])
+        value, unit = color_code(value)
+        value = int(value) if value.is_integer() else value
+        return f'{value} {unit} ±{COLORS_TOLERANCE[colors[3]]}%'
+    else:
+        value = 100 * COLORS.index(colors[0]) + 10 * COLORS.index(colors[1]) + COLORS.index(colors[2])
+        value *= 10 ** COLORS.index(colors[3])
+        value, unit = color_code(value)
+        value = int(value) if value.is_integer() else value
+        return f'{value} {unit} ±{COLORS_TOLERANCE[colors[4]]}%'
+
+
+def color_code(color):
+    if color < 1000:
+        return color / 1, 'ohms'
+    elif color < 1000000:
+        return color / 1000, 'kiloohms'
+    else:
+        return color / 1000000, 'megaohms'
\ No newline at end of file
diff --git a/exercises/practice/resistor-color-expert/resistor_color_expert.py b/exercises/practice/resistor-color-expert/resistor_color_expert.py
new file mode 100644
index 00000000..f36881c5
--- /dev/null
+++ b/exercises/practice/resistor-color-expert/resistor_color_expert.py
@@ -0,0 +1,2 @@
+def resistor_label(colors):
+    pass
diff --git a/exercises/practice/sublist/.approaches/config.json b/exercises/practice/sublist/.approaches/config.json
new file mode 100644
index 00000000..ce54db9c
--- /dev/null
+++ b/exercises/practice/sublist/.approaches/config.json
@@ -0,0 +1,21 @@
+{
+  "introduction": {
+    "authors": ["safwansamsudeen"]
+  },
+  "approaches": [
+    {
+      "uuid": "db47397a-4551-49e8-8775-7e7aad79a38b",
+      "slug": "list-manipulation",
+      "title": "List manipulation",
+      "blurb": "Manipulate and check lists to solve the exercise",
+      "authors": ["safwansamsudeen"]
+    },
+    {
+      "uuid": "61366160-c859-4d16-9085-171428209b8d",
+      "slug": "using-strings",
+      "title": "Using strings",
+      "blurb": "Convert the lists to string and use string manipulation to solve the exercise",
+      "authors": ["safwansamsudeen"]
+    }
+  ]
+}
diff --git a/exercises/practice/sublist/.approaches/introduction.md b/exercises/practice/sublist/.approaches/introduction.md
new file mode 100644
index 00000000..42f991ef
--- /dev/null
+++ b/exercises/practice/sublist/.approaches/introduction.md
@@ -0,0 +1,59 @@
+# Introduction
+There are two broad ways to solve Sublist. 
+
+## General guidance
+To write the code, you need to branch out (probably with `if`) into the four different possible conditions, and return the appropriate name of the category. 
+
+## Approach: list manipulation
+The direct approach would be to manipulate and check the given lists to solve this.
+This solution uses a helper function, which simplifies things, but the approach can be implemented without it.
+
+```python
+SUBLIST = 1
+SUPERLIST = 2
+EQUAL = 3
+UNEQUAL = 4
+
+def check_sub_sequences(list_one, list_two):
+    n1 = len(list_one)
+    n2 = len(list_two)
+    return any(list_two[i:i+n1] == list_one for i in range(n2 - n1 + 1))
+    
+def sublist(list_one, list_two):
+    if list_one == list_two:
+        return EQUAL
+    if check_sub_sequences(list_one, list_two):
+        return SUBLIST
+    if check_sub_sequences(list_two, list_one):
+        return SUPERLIST
+    return UNEQUAL
+```
+
+Read more on the [detail of this approach][approach-list-manipulation].
+
+## Approach: using strings
+Another seemingly clever approach is to convert the lists to strings and then 
+use the `in` operator to check for sub-sequences.
+**However, this does not work.**
+```python
+SUBLIST = 1
+SUPERLIST = 2
+EQUAL = 3
+UNEQUAL = 4
+
+def sublist(list_one, list_two):
+    list_one_check = (str(list_one).strip("[]") + ",")
+    list_two_check = (str(list_two).strip("[]") + ",")
+
+    if list_one_check == list_two_check:
+        return EQUAL
+    elif list_one_check in list_two_check:
+        return SUBLIST
+    elif list_two_check in list_one_check:
+        return SUPERLIST
+    return UNEQUAL
+```
+To understand more about this approach and **why it fails**, [read here][approach-using-strings].
+
+[approach-list-manipulation]: https://exercism.org/tracks/python/exercises/sublist/approaches/list-manipulation
+[approach-using-strings]: https://exercism.org/tracks/python/exercises/sublist/approaches/using-strings
diff --git a/exercises/practice/sublist/.approaches/list-manipulation/content.md b/exercises/practice/sublist/.approaches/list-manipulation/content.md
new file mode 100644
index 00000000..ac374b73
--- /dev/null
+++ b/exercises/practice/sublist/.approaches/list-manipulation/content.md
@@ -0,0 +1,38 @@
+# List manipulation
+The direct approach would be to manipulate and check the given lists to solve this.
+This solution uses a helper function, which simplifies things, but the approach can be implemented without it.
+
+```python
+SUBLIST = 1
+SUPERLIST = 2
+EQUAL = 3
+UNEQUAL = 4
+
+def check_sub_sequences(list_one, list_two):
+    n1 = len(list_one)
+    n2 = len(list_two)
+    return any(list_two[i:i+n1] == list_one for i in range(n2 - n1 + 1))
+    
+def sublist(list_one, list_two):
+    if list_one == list_two:
+        return EQUAL
+    if check_sub_sequences(list_one, list_two):
+        return SUBLIST
+    if check_sub_sequences(list_two, list_one):
+        return SUPERLIST
+    return UNEQUAL
+```
+
+We first check for equality using the `==` operator, if so, then we return `EQUAL`. 
+A common way to do this differently would be to return `1` directly, but this is better practice as we  [remove magic values][magic values].
+
+After that we call `check_sub_sequences` passing in `list_one` and `list_two`.
+In the helper function, we check if `any` of the possible sub-sequences in `list_two` of length `n1` (the length of the first list) are equal to the first list.
+If so, then we conclude that `list_one` is a `SUBLIST` of `list_two`. 
+
+To find whether `list_one` is a `SUPERLIST` of `list_two`, we just reverse this process - pass in the lists in the opposite order.
+Thus, we check if `any` of the possible sub-sequences in `list_one` of length `n2` (the length of the second list) are equal to the second list.
+
+If none of the above conditions are true, we conclude that the two lists are unequal.
+
+[magic values]: https://stackoverflow.com/questions/47882/what-is-a-magic-number-and-why-is-it-bad
\ No newline at end of file
diff --git a/exercises/practice/sublist/.approaches/list-manipulation/snippet.txt b/exercises/practice/sublist/.approaches/list-manipulation/snippet.txt
new file mode 100644
index 00000000..290f8cdd
--- /dev/null
+++ b/exercises/practice/sublist/.approaches/list-manipulation/snippet.txt
@@ -0,0 +1,8 @@
+def sublist(list_one, list_two):
+    if list_one == list_two:
+        return EQUAL
+    if check_sub_sequences(list_one, list_two):
+        return SUBLIST
+    if check_sub_sequences(list_two, list_one):
+        return SUPERLIST
+    return UNEQUAL
\ No newline at end of file
diff --git a/exercises/practice/sublist/.approaches/using-strings/content.md b/exercises/practice/sublist/.approaches/using-strings/content.md
new file mode 100644
index 00000000..ff960902
--- /dev/null
+++ b/exercises/practice/sublist/.approaches/using-strings/content.md
@@ -0,0 +1,47 @@
+# Using strings
+~~~~exercism/caution
+**This approach does not work, and this document exists to explain that.** 
+Please do not use it in your code.
+~~~~
+
+Another seemingly clever solution is to convert the lists to strings and then 
+use the `in` operator to check for sub-sequences.
+Note that this approach, even if it worked, is not as performant as the 
+previous one.
+```python
+SUBLIST = 1
+SUPERLIST = 2
+EQUAL = 3
+UNEQUAL = 4
+
+def sublist(list_one, list_two):
+    list_one_check = str(list_one).strip("[]")
+    list_two_check = str(list_two).strip("[]")
+
+    if list_one_check == list_two_check:
+        return EQUAL
+    elif list_one_check in list_two_check:
+        return SUBLIST
+    elif list_two_check in list_one_check:
+        return SUPERLIST
+    return UNEQUAL
+```
+Let's parse the code to see what it does.
+In this approach, we convert the lists to strings, so `[1, 2, 3]` becomes `"[1, 2, 3]"`, remove the brackets `"1, 2, 3"`, and add a comma `"1, 2, 3,"`. 
+We check equality and then use the `in` operator to check for `SUBLIST` or `SUPERLIST`, and finally return `UNEQUAL`.
+
+We add a comma because, say, we call `sublist` with `[1, 2]` and `[1, 22]`. `"1, 2" in "1, 22"` evaluates to `True`, so 
+the **function would wrongly mark it as `SUBLIST`**. 
+
+This test can be overridden by changing the code like this:
+```python
+list_one_check = str(list_one).strip("[]") + ','
+list_two_check = str(list_two).strip("[]") + ','
+```
+Yet, the test case (which doesn't exist in the Exercism test suite) `["1", "2"]` and `["5", "'1', '2',", "7"]` would 
+fail.
+
+Students can add any arbitrary string into the representation to try to "defeat" this test - `list_one_check = str
+(list_one) + TOKEN`. The test suite currently test `TOKEN = ''`, but not others.
+
+[gen-exp]: https://www.programiz.com/python-programming/generator
\ No newline at end of file
diff --git a/exercises/practice/sublist/.approaches/using-strings/snippet.txt b/exercises/practice/sublist/.approaches/using-strings/snippet.txt
new file mode 100644
index 00000000..26fc3ec0
--- /dev/null
+++ b/exercises/practice/sublist/.approaches/using-strings/snippet.txt
@@ -0,0 +1,8 @@
+# Failing approach
+def sublist(list_one, list_two):
+    list_one_check = str(list_one).strip("[]")
+    ...
+    elif list_one_check in list_two_check:
+        return SUBLIST
+    ...
+    return UNEQUAL
\ No newline at end of file
diff --git a/exercises/practice/sublist/sublist.py b/exercises/practice/sublist/sublist.py
index 428d3aa6..35410301 100644
--- a/exercises/practice/sublist/sublist.py
+++ b/exercises/practice/sublist/sublist.py
@@ -1,8 +1,7 @@
 """
 This exercise stub and the test suite contain several enumerated constants.
 
-Since Python 2 does not have the enum module, the idiomatic way to write
-enumerated constants has traditionally been a NAME assigned to an arbitrary,
+Enumerated constants can be done with a NAME assigned to an arbitrary,
 but unique value. An integer is traditionally used because it’s memory
 efficient.
 It is a common practice to export both constants and functions that work with
diff --git a/exercises/practice/two-fer/.meta/template.j2 b/exercises/practice/two-fer/.meta/template.j2
index 51634eb1..5db1d53c 100644
--- a/exercises/practice/two-fer/.meta/template.j2
+++ b/exercises/practice/two-fer/.meta/template.j2
@@ -10,5 +10,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
         self.assertEqual({{ case["property"] | to_snake }}("{{ case["input"]["name"] }}"), "{{ case["expected"] }}")
         {% endif %}
     {% endfor %}
-
-{{ macros.footer() }}
diff --git a/exercises/practice/word-count/.meta/template.j2 b/exercises/practice/word-count/.meta/template.j2
index 2c91fdf9..7e41be67 100644
--- a/exercises/practice/word-count/.meta/template.j2
+++ b/exercises/practice/word-count/.meta/template.j2
@@ -21,6 +21,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
     {{ test_case(case) }}
     {% endfor %}
     {%- endif %}
-
-
-{{ macros.footer() }}
diff --git a/exercises/practice/word-search/.meta/template.j2 b/exercises/practice/word-search/.meta/template.j2
index 309a2fc1..952da9e9 100644
--- a/exercises/practice/word-search/.meta/template.j2
+++ b/exercises/practice/word-search/.meta/template.j2
@@ -20,6 +20,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
         {%- endfor %}
 
     {% endfor %}
-
-{{ macros.footer() }}
-
diff --git a/exercises/practice/yacht/.meta/template.j2 b/exercises/practice/yacht/.meta/template.j2
index 4086f512..80eb31f7 100644
--- a/exercises/practice/yacht/.meta/template.j2
+++ b/exercises/practice/yacht/.meta/template.j2
@@ -16,5 +16,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
             {{ case["expected"] }})
 
     {% endfor %}
-
-{{ macros.footer() }}
\ No newline at end of file
diff --git a/exercises/practice/zebra-puzzle/.meta/template.j2 b/exercises/practice/zebra-puzzle/.meta/template.j2
index 6b068c7e..134ccdbf 100644
--- a/exercises/practice/zebra-puzzle/.meta/template.j2
+++ b/exercises/practice/zebra-puzzle/.meta/template.j2
@@ -6,5 +6,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
     def test_{{ case["description"] | to_snake }}(self):
         self.assertEqual({{ case["property"] | to_snake }}(), "{{ case["expected"] }}")
     {% endfor %}
-
-{{ macros.footer() }}
diff --git a/exercises/practice/zipper/.meta/template.j2 b/exercises/practice/zipper/.meta/template.j2
index 9f239bc1..4e5de995 100644
--- a/exercises/practice/zipper/.meta/template.j2
+++ b/exercises/practice/zipper/.meta/template.j2
@@ -52,5 +52,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
 {%- for case in cases %}
     {{ test_case(case) }}
 {%- endfor %}
-
-{{ macros.footer() }}
diff --git a/pylintrc b/pylintrc
index 745e6f03..09795978 100644
--- a/pylintrc
+++ b/pylintrc
@@ -341,11 +341,6 @@ known-standard-library=
 # Force import order to recognize a module as part of a third party library.
 known-third-party=enchant, absl
 
-# Analyse import fallback blocks. This can be used to support both Python 2 and
-# 3 compatible code, which means that the block might have code that exists
-# only in one or another interpreter, leading to false positives when analysed.
-analyse-fallback-blocks=no
-
 
 [CLASSES]
 
diff --git a/reference/exercise-concepts/rna-transcription.md b/reference/exercise-concepts/rna-transcription.md
index b2b12946..004ded95 100644
--- a/reference/exercise-concepts/rna-transcription.md
+++ b/reference/exercise-concepts/rna-transcription.md
@@ -2,7 +2,7 @@
 
 ## Example implementation
 
-Modified from the existing [example.py](https://github.com/exercism/python/blob/master/exercises/rna-transcription/example.py) to remove Python 2 compatiblity noise:
+Taken from the existing [example.py](https://github.com/exercism/python/blob/main/exercises/practice/rna-transcription/.meta/example.py):
 
 ```python
 DNA_TO_RNA = str.maketrans("AGCT", "UCGA")


Test patch:
diff --git a/exercises/concept/mecha-munch-management/dict_methods_test.py b/exercises/concept/mecha-munch-management/dict_methods_test.py
new file mode 100644
index 00000000..2f5828d6
--- /dev/null
+++ b/exercises/concept/mecha-munch-management/dict_methods_test.py
@@ -0,0 +1,161 @@
+import unittest
+import pytest
+from dict_methods import (add_item,
+                          read_notes,
+                          update_recipes,
+                          sort_entries,
+                          send_to_store,
+                          update_store_inventory)
+
+
+class MechaMunchManagementTest(unittest.TestCase):
+
+    @pytest.mark.task(taskno=1)
+    def test_add_item(self):
+        input_data = [
+                      ({'Apple': 1, 'Banana': 4 }, ('Apple', 'Banana', 'Orange')),
+                      ({'Orange': 1, 'Raspberry': 1, 'Blueberries': 10}, ['Raspberry', 'Blueberries', 'Raspberry']),
+                      ({'Broccoli': 1, 'Banana': 1}, ('Broccoli', 'Kiwi', 'Kiwi', 'Kiwi', 'Melon', 'Apple', 'Banana', 'Banana'))
+                      ]
+        
+        output_data = [{'Apple': 2, 'Banana': 5, 'Orange': 1},
+                       {'Orange': 1, 'Raspberry': 3, 'Blueberries': 11},
+                       {'Broccoli': 2, 'Banana': 3, 'Kiwi': 3, 'Melon': 1, 'Apple': 1}]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different shopping cart.'
+                self.assertEqual(add_item(input_data[0], input_data[1]), output_data, msg=error_msg)
+        
+
+    @pytest.mark.task(taskno=2)
+    def test_read_notes(self):
+        input_data = [('Apple', "Banana"), ('Orange', 'Raspberry', 'Blueberries'),
+                      ['Broccoli', 'Kiwi', 'Melon', 'Apple', 'Banana']]
+
+        output_data = [{'Apple': 1, 'Banana': 1}, {'Orange': 1, 'Raspberry': 1, 'Blueberries': 1},
+                       {'Broccoli': 1, 'Kiwi': 1, 'Melon': 1, 'Apple': 1, 'Banana': 1}]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different shopping cart.'
+                self.assertEqual(read_notes(input_data), output_data, msg=error_msg)
+
+    @pytest.mark.task(taskno=3)
+    def test_update_recipes(self):
+        input_data = [
+                        ({'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
+                          'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}},
+                        (('Banana Bread', {'Banana': 4,  'Walnuts': 2, 'Flour': 1, 'Eggs': 2, 'Butter': 1, 'Milk': 2, 'Eggs': 3}),)),
+
+                        ({'Apple Pie': {'Apple': 1, 'Pie Crust': 1, 'Cream Custard': 1},
+                          'Blueberry Pie': {'Blueberries': 1, 'Pie Crust': 1, 'Cream Custard': 1}},
+                        (('Blueberry Pie', {'Blueberries': 2, 'Pie Crust': 1, 'Cream Custard': 1}),
+                         ('Apple Pie', {'Apple': 1, 'Pie Crust': 1, 'Cream Custard': 1}))),
+
+                        ({'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
+                          'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1},
+                          'Pasta Primavera': {'Eggs': 1, 'Carrots': 1, 'Spinach': 2, 'Tomatoes': 3, 'Parmesan': 2, 'Milk': 1, 'Onion': 1}},
+                        (('Raspberry Pie', {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2}),
+                         ('Pasta Primavera', {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1}),
+                         ('Blueberry Crumble', {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3})))
+                     ]
+
+        output_data = [
+                        {'Banana Bread': {'Banana': 4,  'Walnuts': 2, 'Flour': 1, 'Eggs': 2, 'Butter': 1, 'Milk': 2, 'Eggs': 3},
+                         'Raspberry Pie': {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}},
+                        {'Apple Pie': {'Apple': 1, 'Pie Crust': 1, 'Cream Custard': 1},
+                        'Blueberry Pie': {'Blueberries': 2, 'Pie Crust': 1, 'Cream Custard': 1}},
+                        {'Banana Bread': {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
+                        'Raspberry Pie': {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2},
+                        'Pasta Primavera': {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1},
+                        'Blueberry Crumble': {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3}}
+                     ]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different ideas instead.'
+                self.assertEqual(update_recipes(input_data[0], input_data[1]), output_data, msg=error_msg)
+
+    @pytest.mark.task(taskno=4)
+    def test_sort_entries(self):
+        input_data = [
+                      {'Banana': 4, 'Apple': 2, 'Orange': 1, 'Pear': 12},
+                      {'Apple': 3, 'Orange': 5, 'Banana': 1, 'Avocado': 2},
+                      {'Orange': 3, 'Banana': 2, 'Apple': 1},
+                      {'Apple': 2, 'Raspberry': 2, 'Blueberries': 5, 'Broccoli' : 2, 'Kiwi': 1, 'Melon': 4}
+                     ]
+
+        output_data = [
+                        {'Apple': 2, 'Banana': 4, 'Orange': 1, 'Pear': 12},
+                        {'Avocado': 2, 'Apple': 3, 'Banana': 1, 'Orange': 5},
+                        {'Apple': 1, 'Orange': 3, 'Banana': 2},
+                        {'Apple' : 2, 'Blueberries': 5, 'Broccoli': 2, 'Kiwi': 1, 'Melon': 4, 'Raspberry': 2}
+                      ]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different sorted list instead.'
+                self.assertEqual(sort_entries(input_data), output_data, msg=error_msg)
+
+    @pytest.mark.task(taskno=5)
+    def test_send_to_store(self):
+        input_data = [
+                        ({'Banana': 3, 'Apple': 2, 'Orange': 1, 'Milk': 2},
+                         {'Banana': ['Isle 5', False], 'Apple': ['Isle 4', False], 'Orange': ['Isle 4', False], 'Milk': ['Isle 2', True]}),
+
+                        ({'Kiwi': 3, 'Juice': 5, 'Yoghurt': 2, 'Milk': 5},
+                         {'Kiwi': ['Isle 6', False], 'Juice': ['Isle 5', False], 'Yoghurt': ['Isle 2', True], 'Milk': ['Isle 2', True]}),
+
+                        ({'Apple': 2, 'Raspberry': 2, 'Blueberries': 5, 'Broccoli' : 2, 'Kiwi': 1, 'Melon': 4},
+                         {'Apple': ['Isle 1', False], 'Raspberry': ['Isle 6', False], 'Blueberries': ['Isle 6', False],
+                          'Broccoli': ['Isle 3', False], 'Kiwi': ['Isle 6', False], 'Melon': ['Isle 6', False]})
+                      ]
+
+        output_data = [
+                        {'Orange': [1, 'Isle 4', False], 'Milk': [2, 'Isle 2', True], 'Banana': [3, 'Isle 5', False], 'Apple': [2, 'Isle 4', False]},
+                        {'Juice': [5, 'Isle 5', False], 'Yoghurt': [2, 'Isle 2', True], 'Milk': [5, 'Isle 2', True], 'Kiwi': [3, 'Isle 6', False]},
+                        {'Kiwi': [1, 'Isle 6', False], 'Melon': [4, 'Isle 6', False], 'Apple': [2, 'Isle 1', False],
+                         'Raspberry': [2, 'Isle 6', False], 'Blueberries': [5, 'Isle 6', False], 'Broccoli': [2, 'Isle 3', False]}
+                      ]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different fulfillment_cart instead.'
+                self.assertEqual(send_to_store(input_data[0], input_data[1]), output_data, msg=error_msg)
+
+    @pytest.mark.task(taskno=6)
+    def test_update_store_inventory(self):
+        input_data = [
+                        ({'Orange': [1, 'Isle 4', False], 'Milk': [2, 'Isle 2', True],
+                          'Banana': [3, 'Isle 5', False], 'Apple': [2, 'Isle 4', False]},
+                         {'Banana': [15, 'Isle 5', False], 'Apple': [12, 'Isle 4', False],
+                          'Orange': [1, 'Isle 4', False], 'Milk': [4, 'Isle 2', True]}),
+
+                        ({'Kiwi': [3, 'Isle 6', False]},{'Kiwi': [3, 'Isle 6', False], 'Juice': [5, 'Isle 5', False],
+                          'Yoghurt': [2, 'Isle 2', True], 'Milk': [5, 'Isle 2', True]}),
+
+                        ({'Kiwi': [1, 'Isle 6', False], 'Melon': [4, 'Isle 6', False], 'Apple': [2, 'Isle 1', False],
+                          'Raspberry': [2, 'Isle 6', False], 'Blueberries': [5, 'Isle 6', False],
+                          'Broccoli': [1, 'Isle 3', False]},
+                         {'Apple': [2, 'Isle 1', False], 'Raspberry': [5, 'Isle 6', False],
+                          'Blueberries': [10, 'Isle 6', False], 'Broccoli': [4, 'Isle 3', False],
+                          'Kiwi': [1, 'Isle 6', False], 'Melon': [8, 'Isle 6', False]})
+                      ]
+
+        output_data = [
+                        {'Banana': [12, 'Isle 5', False], 'Apple': [10, 'Isle 4', False],
+                         'Orange': ['Out of Stock', 'Isle 4', False], 'Milk': [2, 'Isle 2', True]},
+
+                        {'Juice': [5, 'Isle 5', False], 'Yoghurt': [2, 'Isle 2', True],
+                         'Milk': [5, 'Isle 2', True], 'Kiwi': ["Out of Stock", 'Isle 6', False]},
+
+                        {'Kiwi': ['Out of Stock', 'Isle 6', False], 'Melon': [4, 'Isle 6', False],
+                         'Apple': ['Out of Stock', 'Isle 1', False], 'Raspberry': [3, 'Isle 6', False],
+                         'Blueberries': [5, 'Isle 6', False], 'Broccoli': [3, 'Isle 3', False]}
+                      ]
+
+        for variant, (input_data, output_data) in enumerate(zip(input_data, output_data), start=1):
+            with self.subTest(f'variation #{variant}', input_data=input_data, output_data=output_data):
+                error_msg=f'Expected: {output_data} but got a different store inventory instead.'
+                self.assertEqual(update_store_inventory(input_data[0], input_data[1]), output_data, msg=error_msg)
diff --git a/exercises/practice/pythagorean-triplet/pythagorean_triplet_test.py b/exercises/practice/pythagorean-triplet/pythagorean_triplet_test.py
index 70d501c4..bb094c90 100644
--- a/exercises/practice/pythagorean-triplet/pythagorean_triplet_test.py
+++ b/exercises/practice/pythagorean-triplet/pythagorean_triplet_test.py
@@ -6,10 +6,6 @@ from pythagorean_triplet import (
 
 # Tests adapted from `problem-specifications//canonical-data.json`
 
-# Python 2/3 compatibility
-if not hasattr(unittest.TestCase, "assertCountEqual"):
-    unittest.TestCase.assertCountEqual = unittest.TestCase.assertItemsEqual
-
 
 class PythagoreanTripletTest(unittest.TestCase):
     def test_triplets_whose_sum_is_12(self):
diff --git a/exercises/practice/resistor-color-expert/.meta/tests.toml b/exercises/practice/resistor-color-expert/.meta/tests.toml
new file mode 100644
index 00000000..4f57723a
--- /dev/null
+++ b/exercises/practice/resistor-color-expert/.meta/tests.toml
@@ -0,0 +1,40 @@
+# This is an auto-generated file.
+#
+# Regenerating this file via `configlet sync` will:
+# - Recreate every `description` key/value pair
+# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
+# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
+# - Preserve any other key/value pair
+#
+# As user-added comments (using the # character) will be removed when this file
+# is regenerated, comments can be added via a `comment` key.
+
+[8c4f9fb6-d477-4250-bc57-b325d2be226f]
+description = "Orange, orange, black, and red"
+
+[d1d4a769-9210-43cc-9a14-6af6ce4c0b00]
+description = "Blue, grey, brown, and violet"
+
+[6af91bc3-8275-4c38-920a-185d30feb5f3]
+description = "Red, black, red, and green"
+
+[9c4630bf-0dda-4212-baca-2f5111530b4d]
+description = "Green, brown, orange, and grey"
+
+[5880ddf1-0dc6-4bd0-b9de-5626117cd2c7]
+description = "One black band"
+
+[a5cfda34-3c02-4bda-b183-726791fb43b2]
+description = "Orange, orange, yellow, black, and brown"
+
+[4f0ad96c-cdab-4c84-95dd-7074e889e001]
+description = "Red, green, yellow, yellow, and brown"
+
+[48c66841-208c-46a7-8992-1e84a2eda9e2]
+description = "Blue, grey, white, brown, and brown"
+
+[4f3aeb0c-fd9d-4cbd-b204-554e61978f73]
+description = "Violet, orange, red, and grey"
+
+[1ae3a17f-8bc0-449c-9831-fddfd2d91c5d]
+description = "Brown, red, orange, green, and blue"
diff --git a/exercises/practice/resistor-color-expert/resistor_color_expert_test.py b/exercises/practice/resistor-color-expert/resistor_color_expert_test.py
new file mode 100644
index 00000000..bcf2052c
--- /dev/null
+++ b/exercises/practice/resistor-color-expert/resistor_color_expert_test.py
@@ -0,0 +1,51 @@
+import unittest
+
+from resistor_color_expert import (
+    resistor_label,
+)
+
+# Tests adapted from `problem-specifications//canonical-data.json`
+
+
+class ResistorColorExpertTest(unittest.TestCase):
+    def test_orange_orange_black_and_red(self):
+        self.assertEqual(resistor_label(["orange", "orange", "black", "red"]), "33 ohms ±2%")
+
+    def test_blue_grey_brown_and_violet(self):
+        self.assertEqual(resistor_label(["blue", "grey", "brown", "violet"]), "680 ohms ±0.1%")
+
+    def test_red_black_red_and_green(self):
+        self.assertEqual(resistor_label(["red", "black", "red", "green"]), "2 kiloohms ±0.5%")
+
+    def test_green_brown_orange_and_grey(self):
+        self.assertEqual(
+            resistor_label(["green", "brown", "orange", "grey"]), "51 kiloohms ±0.05%"
+        )
+
+    def test_one_black_band(self):
+        self.assertEqual(resistor_label(["black"]), "0 ohms")
+
+    def test_orange_orange_yellow_black_and_brown(self):
+        self.assertEqual(
+            resistor_label(["orange", "orange", "yellow", "black", "brown"]), "334 ohms ±1%"
+        )
+
+    def test_red_green_yellow_yellow_and_brown(self):
+        self.assertEqual(
+            resistor_label(["red", "green", "yellow", "yellow", "brown"]), "2.54 megaohms ±1%"
+        )
+
+    def test_blue_grey_white_red_and_brown(self):
+        self.assertEqual(
+            resistor_label(["blue", "grey", "white", "brown", "brown"]), "6.89 kiloohms ±1%"
+        )
+
+    def test_violet_orange_red_and_grey(self):
+        self.assertEqual(
+            resistor_label(["violet", "orange", "red", "grey"]), "7.3 kiloohms ±0.05%"
+        )
+
+    def test_brown_red_orange_green_and_blue(self):
+        self.assertEqual(
+            resistor_label(["brown", "red", "orange", "green", "blue"]), "12.3 megaohms ±0.25%"
+        )
diff --git a/exercises/practice/two-fer/two_fer_test.py b/exercises/practice/two-fer/two_fer_test.py
index 540930da..ea74f116 100644
--- a/exercises/practice/two-fer/two_fer_test.py
+++ b/exercises/practice/two-fer/two_fer_test.py
@@ -16,7 +16,3 @@ class TwoFerTest(unittest.TestCase):
 
     def test_another_name_given(self):
         self.assertEqual(two_fer("Bob"), "One for Bob, one for me.")
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/exercises/practice/word-count/word_count_test.py b/exercises/practice/word-count/word_count_test.py
index b63a9eb3..329301a3 100644
--- a/exercises/practice/word-count/word_count_test.py
+++ b/exercises/practice/word-count/word_count_test.py
@@ -121,7 +121,3 @@ class WordCountTest(unittest.TestCase):
 
     def test_multiple_apostrophes_ignored(self):
         self.assertEqual(count_words("''hey''"), {"hey": 1})
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/exercises/practice/word-search/word_search_test.py b/exercises/practice/word-search/word_search_test.py
index 6ee05041..e5a32cee 100644
--- a/exercises/practice/word-search/word_search_test.py
+++ b/exercises/practice/word-search/word_search_test.py
@@ -310,7 +310,3 @@ class WordSearchTest(unittest.TestCase):
     def test_should_not_wrap_around_vertically_to_find_a_word(self):
         puzzle = WordSearch(["s", "u", "r", "a", "b", "c", "t"])
         self.assertIsNone(puzzle.search("rust"))
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/exercises/practice/yacht/yacht_test.py b/exercises/practice/yacht/yacht_test.py
index 5c262c88..32b92994 100644
--- a/exercises/practice/yacht/yacht_test.py
+++ b/exercises/practice/yacht/yacht_test.py
@@ -92,7 +92,3 @@ class YachtTest(unittest.TestCase):
 
     def test_yacht_as_choice(self):
         self.assertEqual(yacht.score([2, 2, 2, 2, 2], yacht.CHOICE), 10)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/exercises/practice/zebra-puzzle/zebra_puzzle_test.py b/exercises/practice/zebra-puzzle/zebra_puzzle_test.py
index 034d4ccc..4b35afb7 100644
--- a/exercises/practice/zebra-puzzle/zebra_puzzle_test.py
+++ b/exercises/practice/zebra-puzzle/zebra_puzzle_test.py
@@ -14,7 +14,3 @@ class ZebraPuzzleTest(unittest.TestCase):
 
     def test_resident_who_owns_zebra(self):
         self.assertEqual(owns_zebra(), "Japanese")
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/exercises/practice/zipper/zipper_test.py b/exercises/practice/zipper/zipper_test.py
index 5883e80d..d770c92b 100644
--- a/exercises/practice/zipper/zipper_test.py
+++ b/exercises/practice/zipper/zipper_test.py
@@ -315,7 +315,3 @@ class ZipperTest(unittest.TestCase):
         expected = Zipper.from_tree(final).right().to_tree()
 
         self.assertEqual(result, expected)
-
-
-if __name__ == "__main__":
-    unittest.main()