Repository: exercism/python
Pull request #2515 (2021-09-01 10:42:49)

Refreshed and Revised ABOUT.md for track.
Part of Issue #2484 


Patch:
diff --git a/docs/ABOUT.md b/docs/ABOUT.md
index 6d3ab8ae..9b53653f 100644
--- a/docs/ABOUT.md
+++ b/docs/ABOUT.md
@@ -1,17 +1,61 @@
 # About
 
-Python is a strong language for beginners.
+[Python][python docs] is a [dynamic and strongly][dynamic typing in python] typed [object-oriented][object oriented programming] programming language.
+It employs both [duck typing][duck typing] and [gradual typing][gradual typing] (via [type hints][type hints]).
+It supports multiple programming paradigms including imperative (_object-oriented, procedural_) and declarative (_functional, concurrent_) flavors.
+But do not be fooled: while programming across paradigms is fully supported, [everything in Python is an object][everythings an object].
 
-There are many resources available for programmers of all levels, the code is highly readable, and in many cases phrases are comparable to those in the English language.
 
-Code can be written and executed from the command line, in an interactive IPython session, or in a [Jupyter](http://jupyter.org) (IPython) notebook.
+Python was created by Guido van Rossum and first released in 1991.
+The [Python Software Foundation][psf] manages and directs resources for Python and CPython development and receives proposals for changes to the language from [members][psf membership] of the community via [Python Enhancement Proposals or PEPs][peps].
+It is considered a strong language for programmers [starting their journey][python for beginners], with a welcoming community and many resources available to learners of all levels and persuasions.
 
-The most common form of Python is compiled in C; this is often invisible to the beginning programmer, but if there are uses for which exceptionally fast implementation is needed then C extensions can be written to optimize Python execution.
 
-[Python is used extensively](https://www.python.org/about/apps/) in scientific computing, finance, games, networking, internet development, and in assembling pipelines of other programs.
+Python puts a strong emphasis on code readability and (_similar to Haskell_) uses [significant indentation][significant indentation] to denote function, method, and class definitions.
+Code can be written and executed from the command line, in an interactive interpreter session, in [JupyterLab][jupyter] (Jupyter notebook), or a wide variety of [code editors and IDEs][editors for python].
 
-Python was started by Guido van Rossum in 1989; its name is an homage to the comedy troupe Monty Python.
+[Python is used extensively][python is used extensively] in scientific computing, finance, games, networking, internet development, and in assembling pipelines of other programs.
 
-This track uses Python 3. It is highly recommended that students upgrade to at least Python 3.6 as some features used by this track may not be supported in earlier version of Python.
 
-Python development is shepherded by [The Python Software Foundation](https://www.python.org/about/) and there are active community-based user groups worldwide.
+The [zen of Python (PEP 20)][the zen of python] and [What is Pythonic?][what is pythonic] lay out additional philosophies and perspectives on the language.
+
+
+This track currently uses `Python 3.9.0`.
+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 exercises can be completed using Python 3.7, and many can be worked in Python 3.6.
+We will note when a feature is only available in a certain version.
+
+
+Complete documentation for the current release of Python (3.9.7) can be found at [docs.python.org][python docs].
+
+- [Python Tutorial][python tutorial]
+- [Python Library Reference][python library reference]
+- [Python Language Reference][python language reference]
+- [Python HOW TOs][python how tos]
+- [Python FAQs][python faqs]
+- [Python Glossary of Terms][python glossary of terms]
+
+
+[duck typing]: https://en.wikipedia.org/wiki/Duck_typing
+[dynamic typing in python]: https://stackoverflow.com/questions/11328920/is-python-strongly-typed
+[editors for python]: https://djangostars.com/blog/python-ide/
+[everythings an object]: https://docs.python.org/3/reference/datamodel.html
+[gradual typing]: https://en.wikipedia.org/wiki/Gradual_typing
+[jupyter]: http://jupyter.org
+[object oriented programming]: https://en.wikipedia.org/wiki/Object-oriented_programming
+[peps]: https://www.python.org/dev/peps/
+[psf membership]: https://www.python.org/psf/membership/
+[psf]: https://www.python.org/psf/
+[python docs]: https://docs.python.org/3/
+[python faqs]: https://docs.python.org/3/faq/index.html
+[python for beginners]: https://www.python.org/about/gettingstarted/
+[python glossary of terms]: https://docs.python.org/3/glossary.html
+[python how tos]: https://docs.python.org/3/howto/index.html
+[python is used extensively]: https://www.python.org/about/apps/
+[python language reference]: https://docs.python.org/3/reference/index.html
+[python library reference]: https://docs.python.org/3/library/index.html
+[python tutorial]: https://docs.python.org/3/tutorial/index.html
+[significant indentation]: https://docs.python.org/3/reference/lexical_analysis.html#indentation
+[the zen of python]: https://www.python.org/dev/peps/pep-0020/
+[type hints]: https://docs.python.org/3/library/typing.html
+[what is pythonic]: https://blog.startifact.com/posts/older/what-is-pythonic.html
diff --git a/exercises/concept/making-the-grade/.meta/exemplar.py b/exercises/concept/making-the-grade/.meta/exemplar.py
index 2b335a26..2aa9283a 100644
--- a/exercises/concept/making-the-grade/.meta/exemplar.py
+++ b/exercises/concept/making-the-grade/.meta/exemplar.py
@@ -1,4 +1,9 @@
 def round_scores(student_scores):
+    '''
+    :param student_scores: list of student exam scores as float or int.
+    :return: list of student scores *rounded* to nearest integer value.
+    '''
+
     rounded = []
     while student_scores:
         rounded.append(round(student_scores.pop()))
@@ -6,6 +11,11 @@ def round_scores(student_scores):
 
 
 def count_failed_students(student_scores):
+    '''
+    :param student_scores: list of integer student scores.
+    :return: integer count of student scores at or below 40.
+    '''
+
     non_passing = 0
     for score in student_scores:
         if score <= 40:
@@ -14,14 +24,26 @@ def count_failed_students(student_scores):
 
 
 def above_threshold(student_scores, threshold):
-    above_threshold = []
+    '''
+    :param student_scores: list of integer scores
+    :param threshold :  integer
+    :return: list of integer scores that are at or above the "best" threshold.
+    '''
+
+    above = []
+
     for score in student_scores:
         if score >= threshold:
-            above_threshold.append(score)
-    return above_threshold
+            above.append(score)
+    return above
 
 
 def letter_grades(highest):
+    '''
+   :param highest: integer of highest exam score.
+   :return: list of integer score thresholds for each F-A letter grades.
+   '''
+
     increment = round((highest - 40)/4)
     scores = []
     for score in range(41, highest, increment):
@@ -30,20 +52,31 @@ def letter_grades(highest):
 
 
 def student_ranking(student_scores, student_names):
+    '''
+     :param student_scores: list of scores in descending order.
+     :param student_names: list of names in descending order by exam score.
+     :return: list of strings in format ["<rank>. <student name>: <score>"].
+     '''
+
     results = []
     for index, name in enumerate(student_names):
         rank_string = str(index + 1) + ". " + name + ": " + str(student_scores[index])
         results.append(rank_string)
-        #results.append(f"{index + 1}. {name}: {student_scores[index]}")
+
     return results
 
 
 def perfect_score(student_info):
+    '''
+    :param student_info: list of [<student name>, <score>] lists
+    :return: First [<student name>, 100] found OR "No perfect score."
+    '''
+
     result = "No perfect score."
+
     for item in student_info:
         if item[1] == 100:
             result = item
             break
-        else:
-            continue
+
     return result
diff --git a/exercises/concept/making-the-grade/loops.py b/exercises/concept/making-the-grade/loops.py
index 7e08125a..8c60c22c 100644
--- a/exercises/concept/making-the-grade/loops.py
+++ b/exercises/concept/making-the-grade/loops.py
@@ -3,6 +3,7 @@ def round_scores(student_scores):
     :param student_scores: list of student exam scores as float or int.
     :return: list of student scores *rounded* to nearest integer value.
     '''
+
     pass
 
 def count_failed_students(student_scores):
@@ -10,6 +11,7 @@ def count_failed_students(student_scores):
     :param student_scores: list of integer student scores.
     :return: integer count of student scores at or below 40.
     '''
+
     pass
 
 def above_threshold(student_scores, threshold):
@@ -18,6 +20,7 @@ def above_threshold(student_scores, threshold):
     :param threshold :  integer
     :return: list of integer scores that are at or above the "best" threshold.
     '''
+
     pass
 
 def letter_grades(highest):
@@ -25,14 +28,18 @@ def letter_grades(highest):
     :param highest: integer of highest exam score.
     :return: list of integer score thresholds for each F-A letter grades.
     '''
+
     pass
+
 def student_ranking(student_scores, student_names):
     '''
      :param student_scores: list of scores in descending order.
      :param student_names: list of names in descending order by exam score.
      :return: list of strings in format ["<rank>. <student name>: <score>"].
      '''
+
     pass
+
 def perfect_score(student_info):
     '''
     :param student_info: list of [<student name>, <score>] lists
diff --git a/exercises/concept/meltdown-mitigation/.meta/exemplar.py b/exercises/concept/meltdown-mitigation/.meta/exemplar.py
index 96c2833f..6791002a 100644
--- a/exercises/concept/meltdown-mitigation/.meta/exemplar.py
+++ b/exercises/concept/meltdown-mitigation/.meta/exemplar.py
@@ -18,7 +18,7 @@ def is_criticality_balanced(temperature, neutrons_emitted):
         return False
 
 
-def reactor_efficency(voltage, current, theoretical_max_power):
+def reactor_efficiency(voltage, current, theoretical_max_power):
     '''
 
     :param voltage: int
@@ -26,12 +26,12 @@ def reactor_efficency(voltage, current, theoretical_max_power):
     :param theoretical_max_power: int
     :return: str one of 'green', 'orange', 'red', or 'black'
 
-    Efficency can be grouped into 4 bands:
+    Efficiency can be grouped into 4 bands:
 
-    1. green  ->   80-100% efficency
-    2. orange ->   60-79% efficency
-    3. red    ->   30-59% efficency
-    4. black  ->   <30% efficent
+    1. green  ->   80-100% efficiency
+    2. orange ->   60-79% efficiency
+    3. red    ->   30-59% efficiency
+    4. black  ->   <30% efficient
 
     These percentage ranges are calculated as
     (generated power/ theoretical max power)*100
diff --git a/exercises/concept/meltdown-mitigation/conditionals.py b/exercises/concept/meltdown-mitigation/conditionals.py
index 3ee8f789..ef0f3b85 100644
--- a/exercises/concept/meltdown-mitigation/conditionals.py
+++ b/exercises/concept/meltdown-mitigation/conditionals.py
@@ -10,10 +10,11 @@ def is_criticality_balanced(temperature, neutrons_emitted):
     - The number of neutrons emitted per second is greater than 500.
     - The product of temperature and neutrons emitted per second is less than 500000.
     '''
+
     pass
 
 
-def reactor_efficency(voltage, current, theoretical_max_power):
+def reactor_efficiency(voltage, current, theoretical_max_power):
     '''
 
     :param voltage: int
@@ -21,17 +22,18 @@ def reactor_efficency(voltage, current, theoretical_max_power):
     :param theoretical_max_power: int
     :return: str one of 'green', 'orange', 'red', or 'black'
 
-    Efficency can be grouped into 4 bands:
+    Efficiency can be grouped into 4 bands:
 
-    1. green  ->   80-100% efficency
-    2. orange ->   60-79% efficency
-    3. red    ->   30-59% efficency
-    4. black  ->   <30% efficent
+    1. green  ->   80-100% efficiency
+    2. orange ->   60-79% efficiency
+    3. red    ->   30-59% efficiency
+    4. black  ->   <30% efficient
 
     These percentage ranges are calculated as
     (generated power/ theoretical max power)*100
     where generated power = voltage * current
     '''
+
     pass
 
 
@@ -47,4 +49,5 @@ def fail_safe(temperature, neutrons_produced_per_second, threshold):
     - `temperature * neutrons per second` +/- 10% of `threshold` == 'NORMAL'
     - `temperature * neutron per second` is not in the above-stated ranges ==  'DANGER'
     '''
+
     pass
diff --git a/exercises/concept/restaurant-rozalynn/.meta/exemplar.py b/exercises/concept/restaurant-rozalynn/.meta/exemplar.py
index 7fd3ca68..6bb76639 100644
--- a/exercises/concept/restaurant-rozalynn/.meta/exemplar.py
+++ b/exercises/concept/restaurant-rozalynn/.meta/exemplar.py
@@ -1,43 +1,87 @@
+
 def new_seating_chart(size=22):
-    seats = dict()
-    for number in range(1, size+1):
-        seats[number] = None
-    return seats
+    '''
+
+    :param size: int - number if seats in the seating chart.
+    :return: dict - with number of seats specified, and placeholder values.
+    '''
+
+    return {number: None for number in range(1, size+1) }
+
 
 def arrange_reservations(guests=None):
-    if guests is None:
-        return new_seating_chart()
-    else:
-        seats = new_seating_chart()
+    '''
+
+    :param guest_list: list - list of guest names for reservations.
+    :return: dict - Default sized dictionary with guests assigned seats,
+             and placeholders for empty seats.
+    '''
+
+    seats = new_seating_chart()
+
+    if guests:
         for seat_number in range(1, len(guests)):
             seats[seat_number] = guests[seat_number]
     return seats
 
+
 def find_all_available_seats(seats):
+    '''
+
+    :param seats: dict - seating chart.
+    :return: list - list of seat numbers available for reserving..
+    '''
+
     available = []
     for seat_num, value in seats.items():
         if value is None:
             available.append(seat_num)
     return available
 
+
 def curr_empty_seat_capacity(seats):
+    '''
+
+    :param seats: dict - dictionary of reserved seats.
+    :return: int - number of seats empty.
+    '''
+
     count = 0
     for value in seats.values():
         if value is None:
             count += 1
     return count
 
+
 def accommodate_waiting_guests(seats, guests):
+    '''
+
+    :param seats: dict - seating chart dictionary.
+    :param guests: list - walk-in guests
+    :return: dict - updated seating chart with available spaces filled.
+    '''
+
     curr_empty_seats = curr_empty_seat_capacity(seats)
     empty_seat_list = find_all_available_seats(seats)
+
     if len(guests) > curr_empty_seats:
         return False
     else:
-        for index in range(len(guests)):
+        for index, item in enumerate(guests):
             seats[empty_seat_list[index]] = guests[index]
+
     return seats
 
+
 def empty_seats(seats, seat_numbers):
-   for seat in seat_numbers:
-      seats[seat] = None
-   return seats
\ No newline at end of file
+    '''
+
+    :param seats: dict - seating chart dictionary.
+    :param seat_numbers: list - list of seat numbers to free up or empty.
+    :return: updated seating chart dictionary.
+    '''
+
+    for seat in seat_numbers:
+        seats[seat] = None
+
+    return seats
\ No newline at end of file
diff --git a/exercises/concept/restaurant-rozalynn/none.py b/exercises/concept/restaurant-rozalynn/none.py
index 8f873ce2..140f2175 100644
--- a/exercises/concept/restaurant-rozalynn/none.py
+++ b/exercises/concept/restaurant-rozalynn/none.py
@@ -1,16 +1,57 @@
-def new_seating_chart():
+def new_seating_chart(size=22):
+    '''
+
+    :param size: int - number if seats in the seating chart. Default is 22.
+    :return: dict - with number of seats specified, and placeholder values.
+    '''
+
+    pass
+
+def arrange_reservations(guest_list):
+    '''
+
+    :param guest_list: list - list of guest names for reservations.
+    :return: dict - Default sized dictionary with guests assigned seats,
+             and placeholders for empty seats.
+    '''
+
+    pass
+
+def find_all_available_seats(seats):
+    '''
+
+    :param seats: dict - seating chart.
+    :return: list - list of seat numbers available for reserving..
+    '''
+
     pass
 
-def arrange_reservations():
+def current_seating_capacity(seats):
+    '''
+
+    :param seats: dict - dictionary of reserved seats.
+    :return: int - number of seats empty.
+    '''
+
     pass
 
-def find_all_available_seats():
-   pass
+def accommodate_waiting_guests(seats, guests):
+    '''
 
-def current_seating_capacity():
-   pass
+    :param seats: dict - seating chart dictionary.
+    :param guests: list - walk-in guests
+    :return: dict - updated seating chart with available spaces filled.
+    '''
 
-def accommodate_waiting_guests():
-   pass
-def empty_seats():
     pass
+
+
+def empty_seats(seats, seat_numbers):
+    '''
+
+    :param seats: dict - seating chart dictionary.
+    :param seat_numbers: list - list of seat numbers to free up or empty.
+    :return: updated seating chart dictionary.
+    '''
+
+    pass
\ No newline at end of file
diff --git a/exercises/concept/tisbury-treasure-hunt/.meta/exemplar.py b/exercises/concept/tisbury-treasure-hunt/.meta/exemplar.py
index 729e72a4..33538bbf 100644
--- a/exercises/concept/tisbury-treasure-hunt/.meta/exemplar.py
+++ b/exercises/concept/tisbury-treasure-hunt/.meta/exemplar.py
@@ -1,21 +1,58 @@
 def get_coordinate(record):
+    '''
+
+    :param record: tuple - a (treasure, coordinate) pair.
+    :return: str - the extracted map coordinate.
+    '''
+
     return record[1]
 
+
 def convert_coordinate(coordinate):
+    '''
+
+    :param coordinate: str - a string map coordinate
+    :return:  tuple - the string coordinate seperated into its individual components.
+    '''
+
     return tuple(coordinate)
 
+
 def compare_records(azara_record, rui_record):
+    '''
+
+    :param azara_record: tuple - a (treasure, coordinate) pair.
+    :param rui_record: tuple - a (location, coordinate, quadrant) trio.
+    :return: bool - True if coordinates match, False otherwise.
+    '''
+
     return convert_coordinate(azara_record[1]) in rui_record
 
+
 def create_record(azara_record, rui_record):
+    '''
+
+    :param azara_record: tuple - a (treasure, coordinate) pair.
+    :param rui_record: tuple - a (location, coordinate, quadrant) trio.
+    :return:  tuple - combined record, or "not a match" if the records are incompatible.
+    '''
+
     if compare_records(azara_record, rui_record):
         return azara_record + rui_record
     else:
         return "not a match"
 
+
 def clean_up(combined_record_group):
+    '''
+
+    :param combined_record_group: tuple of tuples - everything from both participants.
+    :return: tuple of tuples - everything "cleaned", with excess coordinates and information removed.
+    '''
 
     report = ""
+
     for item in combined_record_group:
-       report += f"{(item[0], item[2], item[3], item[4])}\n"
+        report += f"{(item[0], item[2], item[3], item[4])}\n"
+
     return report
diff --git a/exercises/concept/tisbury-treasure-hunt/tuples.py b/exercises/concept/tisbury-treasure-hunt/tuples.py
index 9212aa06..bce55568 100644
--- a/exercises/concept/tisbury-treasure-hunt/tuples.py
+++ b/exercises/concept/tisbury-treasure-hunt/tuples.py
@@ -1,14 +1,46 @@
 def get_coordinate(record):
+    '''
+
+    :param record: tuple - a (treasure, coordinate) pair.
+    :return: str - the extracted map coordinate.
+    '''
+
     pass
 
 def convert_coordinate(coordinate):
+    '''
+
+    :param coordinate: str - a string map coordinate
+    :return:  tuple - the string coordinate seperated into its individual components.
+    '''
+
     pass
 
 def compare_records(azara_record, rui_record):
+    '''
+
+    :param azara_record: tuple - a (treasure, coordinate) pair.
+    :param rui_record: tuple - a (location, coordinate, quadrant) trio.
+    :return: bool - True if coordinates match, False otherwise.
+    '''
+
     pass
 
 def create_record(azara_record, rui_record):
+    '''
+
+    :param azara_record: tuple - a (treasure, coordinate) pair.
+    :param rui_record: tuple - a (location, coordinate, quadrant) trio.
+    :return:  tuple - combined record, or "not a match" if the records are incompatible.
+    '''
+
     pass
 
 def clean_up(combined_record_group):
+    '''
+
+    :param combined_record_group: tuple of tuples - everything from both participants.
+    :return: tuple of tuples - everything "cleaned", with excess coordinates and information removed.
+    '''
+
     pass


Test patch:
diff --git a/exercises/concept/meltdown-mitigation/conditionals_test.py b/exercises/concept/meltdown-mitigation/conditionals_test.py
index cc5bc567..abf94bc7 100644
--- a/exercises/concept/meltdown-mitigation/conditionals_test.py
+++ b/exercises/concept/meltdown-mitigation/conditionals_test.py
@@ -2,7 +2,7 @@
 import unittest
 import pytest
 from conditionals import (is_criticality_balanced,
-                          reactor_efficency,
+                          reactor_efficiency,
                           fail_safe
                           )
 
@@ -40,7 +40,7 @@ class TestConditionals(unittest.TestCase):
 
 # End of first functions testing
 
-# Test case for reactor_efficency()
+# Test case for reactor_ efficiency()
     # Checking the second condition using assertEqual
     # The values for arguments is not final and should be considered as placeholders
     # More test-cases  required for full testing
@@ -48,33 +48,33 @@ class TestConditionals(unittest.TestCase):
     # Need to verify if f-string based errors allowed
 
     @pytest.mark.task(taskno=2)
-    def test_reactor_efficency_set1(self):
+    def test_reactor_efficiency_set1(self):
 
-        test_return = reactor_efficency(
+        test_return = reactor_efficiency(
             voltage=100, current=50, theoretical_max_power=5000)
         self.assertEqual(
             test_return, 'green', msg=f"Expected green but returned {test_return}"
         )
 
     @pytest.mark.task(taskno=2)
-    def test_reactor_efficency_set2(self):
-        test_return = reactor_efficency(
+    def test_reactor_efficiency_set2(self):
+        test_return = reactor_efficiency(
             voltage=100, current=30, theoretical_max_power=5000)
         self.assertEqual(
             test_return, 'orange', msg=f"Expected orange but returned {test_return}"
         )
 
     @pytest.mark.task(taskno=2)
-    def test_reactor_efficency_set3(self):
-        test_return = reactor_efficency(
+    def test_reactor_efficiency_set3(self):
+        test_return = reactor_efficiency(
             voltage=100, current=28, theoretical_max_power=5000)
         self.assertEqual(
             test_return, 'red', msg=f"Expected red but returned {test_return}"
         )
 
     @pytest.mark.task(taskno=2)
-    def test_reactor_efficency_set4(self):
-        test_return = reactor_efficency(
+    def test_reactor_efficiency_set4(self):
+        test_return = reactor_efficiency(
             voltage=100, current=10, theoretical_max_power=5000)
         self.assertEqual(
             test_return, 'black', msg=f"Expected black but returned {test_return}"