From 6ad0cd69acddbf95e689edf4d491c2ad92d4b108 Mon Sep 17 00:00:00 2001
From: Brandon High
Date: Wed, 10 Nov 2021 18:40:33 -0800
Subject: [PATCH 0001/1546] Fix typo in making-the-grade exercise description
---
exercises/concept/making-the-grade/.meta/config.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/concept/making-the-grade/.meta/config.json b/exercises/concept/making-the-grade/.meta/config.json
index 52c1585843b..8e1788ab628 100644
--- a/exercises/concept/making-the-grade/.meta/config.json
+++ b/exercises/concept/making-the-grade/.meta/config.json
@@ -1,5 +1,5 @@
{
- "blurb": "Learn about loops by grading and organzing your students exam scores.",
+ "blurb": "Learn about loops by grading and organizing your students exam scores.",
"icon": "grep",
"authors": ["mohanrajanr", "BethanyG"],
"contributors": ["pranasziaukas"],
From cb4928498f73c20183a541de9f331276b8d3d54b Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Thu, 11 Nov 2021 10:26:42 -0800
Subject: [PATCH 0002/1546] Fixed the hint titles to match the instruction task
titles so they would show on the website. (#2763)
---
exercises/concept/currency-exchange/.docs/hints.md | 6 +++---
exercises/concept/tisbury-treasure-hunt/.docs/hints.md | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/exercises/concept/currency-exchange/.docs/hints.md b/exercises/concept/currency-exchange/.docs/hints.md
index cdffbb0a2ba..95906ef164a 100644
--- a/exercises/concept/currency-exchange/.docs/hints.md
+++ b/exercises/concept/currency-exchange/.docs/hints.md
@@ -4,11 +4,11 @@
- [The Python Numbers Tutorial][python-numbers-tutorial] and [Python numeric types][python-numeric-types] can be a great introduction.
-## 1. Estimating exchangeable value
+## 1. Estimate value after exchange
- You can use the [division operator][division-operator] to get the value of exchanged currency.
-## 2. Changes after exchanging
+## 2. Calculate currency left after an exchange
- You can use the [subtraction operator][subtraction-operator] to get the amount of changes.
@@ -24,7 +24,7 @@
**Note:** The `//` operator also does floor division. But, if the operand has `float`, the result is still `float`.
-## 5. Calculate exchangeable value
+## 5. Calculate value after exchange
- You need to calculate `spread` percent of `exchange_rate` using multiplication operator and add it to `exchange_rate` to get the exchanged currency.
- The actual rate needs to be computed. Remember to add exchange rate and exchange fee.
diff --git a/exercises/concept/tisbury-treasure-hunt/.docs/hints.md b/exercises/concept/tisbury-treasure-hunt/.docs/hints.md
index 2e773004121..94c445aa40f 100644
--- a/exercises/concept/tisbury-treasure-hunt/.docs/hints.md
+++ b/exercises/concept/tisbury-treasure-hunt/.docs/hints.md
@@ -28,7 +28,7 @@
- Remember that tuples support all [common sequence operations][common sequence operations].
- Could you re-use your `compare_records()` function here?
-## 5. "Clean up" and format a report of all records
+## 5. "Clean up" & format a report of all records
- Remember: tuples are _immutable_, but the contents can be accessed via _index_ using _bracket notation_.
- Tuples don't have to use parentheses unless there is _ambiguity_.
From a6c15a42acd867c2e1d924a979a194fc6fd48888 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Thu, 11 Nov 2021 10:54:59 -0800
Subject: [PATCH 0003/1546] Corrected Exercsim Spelling Error (#2764)
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e35b48148dc..dc3c6c0e0cc 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
Hi. ππ½ π **We are happy you are here.** π π
-**`exercsim/Python`** is one of many programming language tracks on [exercism(dot)org][exercism-website].
+**`exercism/Python`** is one of many programming language tracks on [exercism(dot)org][exercism-website].
This repo holds all the instructions, tests, code, & support files for Python *exercises* currently under development or implemented & available for students.
π Track exercises support Python `3.8`.
From c690e0250ad445a8594077e21bd3f42413576176 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Fri, 12 Nov 2021 19:30:55 -0800
Subject: [PATCH 0004/1546] Added links to Pull Requests documents for
Contributing, readme, issue responder and pr responder.
---
.github/issue-comment.md | 54 +++++++++++++++++++++++++++-------------
.github/pr-commenter.yml | 2 +-
CONTRIBUTING.md | 9 +++++--
README.md | 7 +++---
4 files changed, 49 insertions(+), 23 deletions(-)
diff --git a/.github/issue-comment.md b/.github/issue-comment.md
index 7482896fb81..ef7fe1d72bc 100644
--- a/.github/issue-comment.md
+++ b/.github/issue-comment.md
@@ -5,31 +5,51 @@ Hi! ππ½ π Welcome to the Exercism Python Repo!
Thank you for opening an issue! π π β¨
+- If you are **requesting support**, we will be along shortly to help. (*generally within* **72 hours,** *often more quickly*).
+- **Found a problem** with tests, exercises or something else?? π
+ ◦ We'll take a look as soon as we can & identify what work is needed to fix it. *(generally within* **72 hours**).
-- If you are **requesting support**, we will be along shortly to help. (*generally within* **72 hours,** *often more quickly*).
-- **Found a problem** with tests, exercises or something else?? π
- We'll take a look as soon as we can & identify what work is needed to fix it. *(generally within* **72 hours**).
-
-β - If you'd also like to make a PR to **fix** the issue after discussing it,
- _We π PRs that follow our [Exercism](https://exercism.org/docs/building) & [Track](https://github.com/exercism/python/blob/main/CONTRIBUTING.md) contributing guidelines!_
+β ◦ _If you'd also like to make a PR to **fix** the issue, please have a quick look at the [Pull Requests][prs] doc._
+ _We π PRs that follow our [Exercsim][exercism-guidelines] & [Track][track-guidelines] contributing guidelines!_
- Here because of an obvious (*and* **small** *set of*) spelling, grammar, or punctuation issues with **one** exercise,
concept, or Python document?? π `Please feel free to submit a PR, linking to this issue.` π
-β β Please **do not** run checks on the whole repo & submit a bunch of PRs.
- This creates longer review cycles & exhausts reviewers energy & time.
- It may also conflict with ongoing changes from other contributors.
- For anything complicated or ambiguous, **let's discuss things** -- we will likely welcome a PR from you.
-
-β β Please keep in mind that inserting only blank lines, making a closing bracket drop to the next line, changing a
- word to a synonym without obvious reason, adding trailing space that's not a[ EOL](https://en.wikipedia.org/wiki/Newline) for the very end of text files,
- and other "changes just to change things" are **not** considered helpful, and will likely be closed by reviewers.
+
+
+
+
+ βΌοΈ Please Do Not βΌοΈ
+
+
+β β Run checks on the whole repo & submit a bunch of PRs.
+ This creates longer review cycles & exhausts reviewers energy & time.
+ It may also conflict with ongoing changes from other contributors.
+β β Insert only blank lines, make a closing bracket drop to the next line, change a word
+ to a synonym without obvious reason, or add trailing space that's not an[ EOL][EOL] for the very end of text files.
+ β Introduce arbitrary changes "just to change things" .
+
+ _...These sorts of things are **not** considered helpful, and will likely be closed by reviewers._
+
+
+
+
+
+
+- For anything complicated or ambiguous, **let's discuss things** -- we will likely welcome a PR from you.
+- _Here to suggest a feature or new exercise??_ **Hooray!** Please keep in mind [_Chesterton's Fence_][chestertons-fence].
+_Thoughtful suggestions will likely result faster & more enthusiastic responses from maintainers._
-π _While you are here..._ If you decide to help out with other [open issues](https://github.com/exercism/python/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22), you have our **gratitude** π ππ½.
+π π _While you are here..._ If you decide to help out with other [open issues][open-issues], you have our **gratitude** π ππ½.
Anything tagged with `[help wanted]` and without `[Claimed]` is up for grabs.
Comment on the issue and we will reserve it for you. π β¨
-_Here to suggest a feature or new exercise??_ **Hooray!** π Please keep in mind [_Chesterton's Fence_](https://github.com/exercism/docs/blob/main/community/good-member/chestertons-fence.md).
-_Thoughtful suggestions will likely result faster & more enthusiastic responses from maintainers._
+
+[prs]: https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md
+[EOL]: https://en.wikipedia.org/wiki/Newline
+[chestertons-fence]: https://github.com/exercism/docs/blob/main/community/good-member/chestertons-fence.md
+[exercism-guidelines]: https://exercism.org/docs/building
+[open-issues]: https://github.com/exercism/python/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22
+[track-guidelines]: https://github.com/exercism/python/blob/main/CONTRIBUTING.md
diff --git a/.github/pr-commenter.yml b/.github/pr-commenter.yml
index 6c9a5a07b28..b6c6af2c0a5 100644
--- a/.github/pr-commenter.yml
+++ b/.github/pr-commenter.yml
@@ -200,7 +200,7 @@ comment:
β οΈ Please be aware β οΈ
- _This repo does not generally accept Pull Requests unless they follow our [contributing guidelines](https://github.com/exercism/python/blob/main/CONTRIBUTING.md) and are:_
+ _This repo does not generally accept []Pull Requests](https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md) unless they follow our [contributing guidelines](https://github.com/exercism/python/blob/main/CONTRIBUTING.md) and are:_
1οΈβ£ Small, contained fixes for typos/grammar/punctuation/code syntax on [one] exercise,
2οΈβ£ Medium changes that have been agreed/discussed via a filed issue,
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1d47d563aac..816a44f6b95 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -23,7 +23,7 @@ Exercises are grouped into **concept** exercises which teach the [Python syllabu
ππ If you have not already done so, please take a moment to read our [Code of Conduct][exercism-code-of-conduct]. ππ
-It might also be helpful to look at [Being a Good Community Member][being-a-good-community-member] & [The words that we use][the-words-that-we-use].
+It might also be helpful to look at [Being a Good Community Member][being-a-good-community-member] & [The words that we use][the-words-that-we-use], and [Pull Requests][prs].
Some defined roles in our community: [Contributors][exercism-contributors] **|** [Mentors][exercism-mentors] **|** [Maintainers][exercism-track-maintainers] **|** [Admins][exercism-admins]
@@ -46,6 +46,8 @@ Please π [ Open an issue ][open-an-issue]π , and let us kno
## π§ **Did you write a patch that fixes a bug?**
+_Before you get started, please review [Pull Requests][prs]._
+
π π **We Warmly Welcome Pull Requests that are:**
@@ -62,6 +64,7 @@ When in doubt, π [ Open an issue ][open-an-issue]π . We wil
In General
+- Please make sure to have a quick read-through of our Exercism [Pull Requests][prs] document before jumping in. π
- Maintainers are happy to review your work and help troubleshoot with you. π π
- Requests are reviewed as soon as is practical/possible.
- (β ) Reviewers may be in a different timezone β , or tied up π§Ά with other tasks.
@@ -326,7 +329,7 @@ If a practice exercise has an auto-generated `_test.py` file, the
_Exercise Structure with Auto-Generated Test Files_
-```Bash
+```Graphql
[/
βββ .docs
β βββ instructions.md
@@ -394,6 +397,7 @@ configlet generate --spec-path path/to/problem/specifications
+
[.flake8]: https://github.com/exercism/python/blob/main/.flake8
[.style.yapf]: https://github.com/exercism/python/blob/main/.style.yapf
[EOL]: https://en.wikipedia.org/wiki/Newline
@@ -438,6 +442,7 @@ configlet generate --spec-path path/to/problem/specifications
[practice-exercises]: https://github.com/exercism/docs/blob/main/building/tracks/practice-exercises.md
[prettier]: https://prettier.io/
[problem-specifications]: https://github.com/exercism/problem-specifications
+[prs]: https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md
[pylint-disable-check]: https://pylint.pycqa.org/en/latest/user_guide/message-control.html#block-disables
[pylint]: https://pylint.pycqa.org/en/v2.11.1/user_guide/index.html
[pylintrc]: https://github.com/exercism/python/blob/main/pylintrc
diff --git a/README.md b/README.md
index dc3c6c0e0cc..7b50ab4fa40 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ Exercises are grouped into **concept** exercises which teach the [Python syllabu
ππ Please take a moment to read our [Code of Conduct][exercism-code-of-conduct]. ππ
-It might also be helpful to look at [Being a Good Community Member][being-a-good-community-member] & [The words that we use][the-words-that-we-use].
+It might also be helpful to look at [Being a Good Community Member][being-a-good-community-member], [The words that we use][the-words-that-we-use], and [Pull Requests][prs].
Some defined roles in our community: [Contributors][exercism-contributors] **|** [Mentors][exercism-mentors] **|** [Maintainers][exercism-track-maintainers] **|** [Admins][exercism-admins]
@@ -35,7 +35,7 @@ Some defined roles in our community: [Contributors][exercism-contributors] **|*
We π π Pull Requests. **But our maintainers generally can't accept _unsolicited_ PRs.**
Check our [help wanted][open-issues] list or [open an issue ][open-an-issue] for discussion first.
-We β¨π π π β¨ PRs that follow our **[Contributing Guidelines][contributing-guidelines]**.
+We β¨π π π β¨ [PRs][prs] that follow our **[Contributing Guidelines][contributing-guidelines]**.
@@ -72,7 +72,7 @@ Starting with `Python 3.8.6`, examples, recipes, and other code in the Python do
Some software incorporated into Python is under different licenses. The licenses are listed with code falling under that license. See [Licenses and Acknowledgements for Incorporated Software](https://docs.python.org/3/license.html#otherlicenses) for an incomplete list of these licenses.
-## License
+## Exercism Python Track License
This repository uses the [MIT License](/LICENSE).
@@ -96,6 +96,7 @@ This repository uses the [MIT License](/LICENSE).
[exercism-writing-style]: https://github.com/exercism/docs/blob/main/building/markdown/style-guide.md
[open-an-issue]: https://github.com/exercism/python/issues/new/choose
[open-issues]: https://github.com/exercism/python/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22
+[prs]: https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md
[practice-exercises]: https://github.com/exercism/docs/blob/main/building/tracks/practice-exercises.md
[psf-license]: https://docs.python.org/3/license.html#psf-license
[python-syllabus]: https://exercism.org/tracks/python/concepts
From 3ae5708052a4acfc87cbab3e73b6821ffd685252 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Fri, 12 Nov 2021 19:37:01 -0800
Subject: [PATCH 0005/1546] Removed excess spacing.
---
.github/pr-commenter.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/pr-commenter.yml b/.github/pr-commenter.yml
index b6c6af2c0a5..fa42b8b12b6 100644
--- a/.github/pr-commenter.yml
+++ b/.github/pr-commenter.yml
@@ -193,7 +193,7 @@ comment:
This is an automated [π€ π€ ] comment for the **`maintainers`** of this repository, notifying them of your contribution. π
- Someone will review/reply to your changes shortly. (_usually within **72 hours**._)
+ Someone will review/reply to your changes shortly. (_usually within **72 hours**._)
You can safely ignore the **`maintainers`** section below.
From 6c18ed5856282e6f355c8977bd77c24be0f8960d Mon Sep 17 00:00:00 2001
From: Safwan Samsudeen <62411302+safwan-samsudeen@users.noreply.github.com>
Date: Sat, 13 Nov 2021 15:33:46 +0530
Subject: [PATCH 0006/1546] Add instructions for checking that the two queens
are not in the same place.
The tests check that the two queens are not in the same place - but the instructions don't specify that. So I'm adding that.
---
exercises/practice/queen-attack/.docs/instructions.append.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/exercises/practice/queen-attack/.docs/instructions.append.md b/exercises/practice/queen-attack/.docs/instructions.append.md
index 894b29361fa..97082609c3c 100644
--- a/exercises/practice/queen-attack/.docs/instructions.append.md
+++ b/exercises/practice/queen-attack/.docs/instructions.append.md
@@ -4,7 +4,7 @@
Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message.
-This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" `ValueErrors` if the `Queen` constructor is passed numbers that are negative, or numbers that are not a valid row or column. The tests will only pass if you both `raise` the `exception` and include a message with it.
+This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" `ValueErrors` if the `Queen` constructor is passed numbers that are negative, or numbers that are not a valid row or column. The tests will only pass if you both `raise` the `exception` and include a message with it. You also should `raise` an `ValueError` if both the queens passed to check whether they can attack are on the same location.
To raise a `ValueError` with a message, write the message as an argument to the `exception` type:
@@ -20,4 +20,7 @@ raise ValueError("column not positive")
# if the column parameter is not on the defined board
raise ValueError("column not on board")
+
+# if both the queens are on the same location
+raise ValueError("Invalid queen position: both queens in the same square")
```
From 2ff8116e487efcda8f5756a07cf2bd860f7e3f28 Mon Sep 17 00:00:00 2001
From: Safwan Samsudeen <62411302+safwan-samsudeen@users.noreply.github.com>
Date: Mon, 15 Nov 2021 10:10:34 +0530
Subject: [PATCH 0007/1546] Update
exercises/practice/queen-attack/.docs/instructions.append.md
Co-authored-by: BethanyG
---
exercises/practice/queen-attack/.docs/instructions.append.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/practice/queen-attack/.docs/instructions.append.md b/exercises/practice/queen-attack/.docs/instructions.append.md
index 97082609c3c..7d371f1e817 100644
--- a/exercises/practice/queen-attack/.docs/instructions.append.md
+++ b/exercises/practice/queen-attack/.docs/instructions.append.md
@@ -4,7 +4,7 @@
Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message.
-This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" `ValueErrors` if the `Queen` constructor is passed numbers that are negative, or numbers that are not a valid row or column. The tests will only pass if you both `raise` the `exception` and include a message with it. You also should `raise` an `ValueError` if both the queens passed to check whether they can attack are on the same location.
+This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" `ValueErrors` if the `Queen` constructor is passed numbers that are negative, or numbers that are not a valid row or column. The tests will only pass if you both `raise` the `exception` and include a message with it. You also should `raise` a `ValueError` if both the queens passed to the `can_attack()` method are on the same location.
To raise a `ValueError` with a message, write the message as an argument to the `exception` type:
From 9a7cde3a8d44e94d4fe1dae4a48bc284333d7ac8 Mon Sep 17 00:00:00 2001
From: Gurupratap Matharu
Date: Mon, 15 Nov 2021 21:28:20 +0530
Subject: [PATCH 0008/1546] [New Concept Documents] : comparisons concept #2456
(#2733)
* Add blurb for Comparison concept
* Add introduction for Comparisons concept
* Add documentation for about.md for Comparisons concept on python track
* Add links to resources for comparisons concept in python track
* Update concepts/comparisons/.meta/config.json
Co-authored-by: BethanyG
* Update concepts/comparisons/.meta/config.json
Co-authored-by: BethanyG
* Update concepts/comparisons/.meta/config.json
Co-authored-by: BethanyG
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Update concepts/comparisons/links.json
Co-authored-by: Isaac Good
* Update concepts/comparisons/links.json
Co-authored-by: Isaac Good
* Update concepts/comparisons/introduction.md
Co-authored-by: BethanyG
* Update description for official python operators
* Add note about short circuiting in comparison chaining
* changed unpacking declaration to simple declaration
* Update concepts/comparisons/about.md
Co-authored-by: Isaac Good
* Update example of membership test with better variable names
* Changed double quotes to single ones for consistency
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Update concepts/comparisons/links.json
Co-authored-by: Isaac Good
* Add comparisons link at the bottom of the document
* Add note for comparison priority
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Add link for arithmetic conversions
* Add example for complex number comparison
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Update concepts/comparisons/about.md
Co-authored-by: Isaac Good
* Add period and convert statement to h3
* Replace single letter variable with more verbose ones
* Update example of membership test
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Minor apostrophe update
* Update concepts/comparisons/about.md
Co-authored-by: Isaac Good
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Update concepts/comparisons/introduction.md
Co-authored-by: BethanyG
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Add chinese and korean strings for comparison
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Fix broken link due to mistyped word
* Remove code samples and change prose as per about.md
* Update concepts/comparisons/.meta/config.json
* Apply suggestions from code review
Markdown style standards: one-sentence-per-line changes.
Co-authored-by: Victor Goff
* Change examples of chinese and korean words
* Mention Chinese and Korean in title case
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
* Update concepts/comparisons/about.md
Co-authored-by: BethanyG
Co-authored-by: BethanyG
Co-authored-by: Isaac Good
Co-authored-by: Victor Goff
Co-authored-by: Job van der Wal <48634934+J08K@users.noreply.github.com>
---
concepts/comparisons/.meta/config.json | 4 +-
concepts/comparisons/about.md | 199 ++++++++++++++++++++++++-
concepts/comparisons/introduction.md | 23 ++-
concepts/comparisons/links.json | 52 ++++++-
4 files changed, 266 insertions(+), 12 deletions(-)
diff --git a/concepts/comparisons/.meta/config.json b/concepts/comparisons/.meta/config.json
index 9b9e8da5a9b..67db625c510 100644
--- a/concepts/comparisons/.meta/config.json
+++ b/concepts/comparisons/.meta/config.json
@@ -1,5 +1,5 @@
{
- "blurb": "TODO: add blurb for this concept",
- "authors": ["bethanyg", "cmccandless"],
+ "blurb": "Comparison operators evaluate two operand values, returning True or False based on whether the comparison condition is met.",
+ "authors": ["gurupratap-matharu", "bethanyg"],
"contributors": []
}
diff --git a/concepts/comparisons/about.md b/concepts/comparisons/about.md
index c628150d565..3c43a38ec1f 100644
--- a/concepts/comparisons/about.md
+++ b/concepts/comparisons/about.md
@@ -1,2 +1,199 @@
-#TODO: Add about for this concept.
+# About
+A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the values of two operands and returns `True` or `False` based on whether the `comparison` condition is met.
+The most common comparison operators are `"<"`, `">"`, `"=="`, `">="`, `"<="`, and `"!="`.
+They all have the same priority (which is higher than that of the Boolean operations).
+
+```python
+>>> 7 > 5
+True
+>>> 99 < 100
+True
+>>> 4 < 4
+False
+>>> 4 <= 4
+True
+>>> 1 >= 1
+True
+>>> 5 == 5
+True
+>>> 6 != 6 # not equal to
+False
+>>> 5 != 6
+True
+>>> not 3 == 3 # interpreted as not(3 == 3)
+False
+```
+
+## Comparison Chaining
+
+Comparisons can be chained arbitrarily, e.g., `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated only once (but in both cases `z` is _not_ evaluated at all when `x < y` is found to be `False`).
+This is also called `short-circuit` evaluation which means the execution is stopped if the truth value of the expression has already been determined.
+Note that the evaluation of expression takes place from left to right.
+In python, short circuiting is supported by various boolean operators, functions and, in this case, comparison chaining.
+
+Also unlike `C`, expressions like `a < b < c` have the interpretation that is conventional in mathematics.
+
+```python
+>>> x = 2
+>>> y = 5
+>>> z = 10
+>>> x < y < z
+True
+>>> x < y > z
+False
+>>> x > y < z
+False
+```
+
+## Comparison between different data types
+
+Since everything in Python is an `object`, things can get interesting when objects of different types are compared.
+For example, the `str` value of a number is considered completely different from the `integer` or `floating-point` value.
+Python makes this distinction because strings are text, while `integers` and `floats` are numeric types.
+
+However, an `integer` **can** be considered equal to a `float`, as they are both numeric types that Python can implicitly convert to compare.
+
+For other numeric types, comparison operators are defined where they "make sense", but throw a `TypeError` if the underlying objects cannot be converted for comparison.
+For more information on the rules that python uses for numeric conversion, see [arithmetic conversions][arithmetic conversions] in the Python documentation.
+
+```python
+>>> 17 == '17'
+False
+>>> 17 == 17.0
+True
+>>> 17.0 == 0017.000
+True
+>>> complex(1, 2) == complex(1.0, 2.00)
+True
+```
+
+
+## Value Comparison
+
+The operators `<`, `>`, `==`, `>=`, `<=`, and `!=` compare the _values_ of two different objects.
+The objects do not need to have the same type.
+Remember that in Python every object has a `value` in addition to `type` and `identity`.
+
+### Following are comparison behaviour of most `built-ins` types.
+
+Numbers of built-in _numeric_ types such as `int`, `hex`, `ocal`, `binary`, `float`, `complex` and of the standard library types `fractions.Fraction` and `decimal.Decimal` can be compared within and across their types.
+
+Any ordered comparison of a number to a `NaN` (_not a number_) value is `False`.
+A counter-intuitive implication is that `NaN` never compares equal to `NaN`.
+
+```python
+>>> x = float('NaN')
+>>> x
+nan
+>>> 3 < x
+False
+>>> x < 3
+False
+>>> x == x
+False
+```
+
+Strings (`str`) are compared _lexicographically_ using their individual numerical Unicode code points (_the result of passing each code point in the `str` to the built-in function `ord()`_).
+`str` and `binary` sequences cannot be directly compared.
+
+```python
+>>> 'santa' < 'claus'
+False
+>>> 'Santa' < 'claus'
+True
+>>> ord('s')
+115
+>>> ord('S')
+83
+>>> ord('c')
+99
+>>> # let's try Chinese words
+>>> 'δ½ ε₯½' < 'εθ§' # hello < goodbye
+True
+>>> # check ord() of first letters
+>>> ord('δ½ '), ord('ε')
+(20320, 20877)
+>>>
+>>>
+>>> # let's try Korean words
+>>> 'μμ' < 'μλ¦λ€μ΄' # pretty < beautiful
+False
+>>> ord('μ'), ord('μ')
+(50696, 50500)
+```
+
+Collections like `list`, `set`, `tuple` and `dict` can also be compared -- provided they are of the same `type`, have the same length, and each _**pair**_ of corresponding elements within the collection are comparable.
+
+```python
+>>> [1, 2] == [1, 2]
+True
+>>> (1, 2) == [1, 2]
+False
+>>> [1, 2] < [1, 2, 3]
+True
+>>> # comparison of dicts
+>>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 18}
+False
+>>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 19}
+True
+```
+
+## Identity comparisons
+
+The operators `is` and `is not` test for an object's _identity_.
+An object's identity is determined using the `id()` function.
+
+`apple is orange` is `True` if and only if `apple` and `orange` are the same object.
+`apple is not orange` yields the inverse truth value.
+
+```python
+>>> my_fav_numbers = [1, 2, 3]
+>>> your_fav_numbers = my_fav_numbers
+>>> my_fav_numbers == your_fav_numbers
+True
+>>> id(my_fav_numbers)
+4462635008
+>>> id(your_fav_numbers)
+4462635008
+>>> my_fav_numbers is not your_fav_numbers
+False
+```
+
+## Membership test operations
+
+The operators `in` and `not in` test for _membership_.
+`fish in soup` evaluates to `True` if `fish` is a member of `soup`, and evaluates `False` otherwise.
+`fish not in soup` returns the negation, or _opposite of_ `fish in soup`.
+
+For the string and bytes types, `name` in `fullname` is `True` if and only if `name` is a substring of `fullname`.
+
+```python
+lucky_numbers = {11, 22, 33}
+>>> 22 in lucky_numbers
+True
+>>> 44 in lucky_numbers
+False
+>>>
+>>> employee = {
+ 'name': 'John Doe',
+ 'id': 67826,
+ 'age': 33,
+ 'title': 'ceo'
+ }
+>>> 'age' in employee
+True
+>>> 33 in employee
+False
+>>> 'lastname' not in employee
+True
+>>>
+>>> name = 'Super Batman'
+>>> 'Bat' in name
+True
+>>> 'Batwoman' in name
+False
+```
+
+[comparisons]: https://docs.python.org/3/library/stdtypes.html?highlight=comparisons#comparisons
+[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions
diff --git a/concepts/comparisons/introduction.md b/concepts/comparisons/introduction.md
index fcde74642ca..27a105c12b0 100644
--- a/concepts/comparisons/introduction.md
+++ b/concepts/comparisons/introduction.md
@@ -1,2 +1,23 @@
-#TODO: Add introduction for this concept.
+# Introduction
+A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the values of two operands and returns `True` or `False` based on whether the `comparison` condition is met.
+The most common comparison operators are `"<"`, `">"`, `"=="`, `">="`, `"<="`, and `"!="`.
+They all have the same priority (which is higher than that of the Boolean operations)
+
+## Comparison Chaining
+
+Comparisons can be chained arbitrarily, e.g., `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated only once (but in both cases `z` is _not_ evaluated at all when `x < y` is found to be `False`).
+This is also called `short-circuit` evaluation which means the execution is stopped if the truth value of the expression has already been determined.
+Note that the evaluation of expression takes place from left to right.
+In python, short circuiting is supported by various boolean operators, functions and, in this case, comparison chaining.
+
+## Comparison of different data types
+
+Since everything in Python is an `object`, things can get interesting when objects of different types are compared.
+For example, the `str` value of a number is considered completely different from the `integer` or `floating-point` value.
+However, an `integer` **can** be considered equal to a `float`, as they are both numeric types that Python can implicitly convert to compare.
+For other numeric types, comparison operators are defined where they "make sense", but throw a `TypeError` if the underlying objects cannot be converted for comparison.
+For more information on the rules that python uses for numeric conversion, see [arithmetic conversions][arithmetic conversions] in the Python documentation.
+
+[comparisons]: https://docs.python.org/3/library/stdtypes.html?
+[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions
diff --git a/concepts/comparisons/links.json b/concepts/comparisons/links.json
index eb5fb7c38a5..ed61054b722 100644
--- a/concepts/comparisons/links.json
+++ b/concepts/comparisons/links.json
@@ -1,18 +1,54 @@
[
{
- "url": "http://example.com/",
- "description": "TODO: add new link (above) and write a short description here of the resource."
+ "url": "https://docs.python.org/3/reference/expressions.html#comparisons",
+ "description": "Comparisons in Python (Python language reference)"
},
{
- "url": "http://example.com/",
- "description": "TODO: add new link (above) and write a short description here of the resource."
+ "url": "https://www.tutorialspoint.com/python/python_basic_operators.htm",
+ "description": "Python basic operators on Tutorials Point"
},
{
- "url": "http://example.com/",
- "description": "TODO: add new link (above) and write a short description here of the resource."
+ "url": "https://data-flair.training/blogs/python-comparison-operators/",
+ "description": "Python comparison operators on Data Flair"
},
{
- "url": "http://example.com/",
- "description": "TODO: add new link (above) and write a short description here of the resource."
+ "url": "https://www.python.org/dev/peps/pep-0207/",
+ "description": "PEP 207 to allow Operator Overloading for Comparison"
+ },
+ {
+ "url": "https://docs.python.org/3/reference/expressions.html#is-not",
+ "description": "Identity comparisons in Python (Python language reference)"
+ },
+ {
+ "url": "https://docs.python.org/3/library/operator.html",
+ "description": "Operators (Python Docs)"
+ },
+ {
+ "url": "https://docs.python.org/3/library/stdtypes.html#typesnumeric",
+ "description": "Numeric types (Python Docs)"
+ },
+ {
+ "url": "https://docs.python.org/3/library/decimal.html#decimal.Decimal",
+ "description": "Decimal types (Python Docs)"
+ },
+ {
+ "url": "https://docs.python.org/3/library/fractions.html#fractions.Fraction",
+ "description": "Fractions (Python Docs)"
+ },
+ {
+ "url": "https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range",
+ "description": "Sequence types (Python Docs)"
+ },
+ {
+ "url": "https://docs.python.org/3/reference/datamodel.html#objects",
+ "description": "Python Object Model (Python docs)"
+ },
+ {
+ "url": "https://docs.python.org/3/reference/datamodel.html#customization",
+ "description": "Basic Customization (Python language reference)"
+ },
+ {
+ "url": "https://docs.python.org/3/reference/expressions.html#value-comparisons",
+ "description": "Value comparisons in Python (Python language reference)"
}
]
From beda2238fdbcf9afdde59821f5ab677723dcac34 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Mon, 15 Nov 2021 09:17:21 -0800
Subject: [PATCH 0009/1546] Small Markdown Updates to Correct Rendering.
(#2777)
---
.github/issue-comment.md | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/.github/issue-comment.md b/.github/issue-comment.md
index ef7fe1d72bc..7e52292296d 100644
--- a/.github/issue-comment.md
+++ b/.github/issue-comment.md
@@ -5,11 +5,12 @@ Hi! ππ½ π Welcome to the Exercism Python Repo!
Thank you for opening an issue! π π β¨
-- If you are **requesting support**, we will be along shortly to help. (*generally within* **72 hours,** *often more quickly*).
-- **Found a problem** with tests, exercises or something else?? π
+
+- If you are **requesting support**, we will be along shortly to help. (*generally within* **72 hours,** *often more quickly*).
+- **Found a problem** with tests, exercises or something else?? π
◦ We'll take a look as soon as we can & identify what work is needed to fix it. *(generally within* **72 hours**).
-β ◦ _If you'd also like to make a PR to **fix** the issue, please have a quick look at the [Pull Requests][prs] doc._
+β ◦ _If you'd also like to make a PR to **fix** the issue, please have a quick look at the [Pull Requests][prs] doc._
_We π PRs that follow our [Exercsim][exercism-guidelines] & [Track][track-guidelines] contributing guidelines!_
- Here because of an obvious (*and* **small** *set of*) spelling, grammar, or punctuation issues with **one** exercise,
From c596faf219e4104a5388c6e8f0b8b363fda4819e Mon Sep 17 00:00:00 2001
From: Job van der Wal <48634934+J08K@users.noreply.github.com>
Date: Mon, 15 Nov 2021 18:57:10 +0100
Subject: [PATCH 0010/1546] [Docs]: Cleanup, Push to site, and Spell check
(#2776)
* Entry for TOOLS.md
* Correct links
* Spell check and cleanup
* [TESTING Docs]: Added intro and a few suggestions. (#2778)
* Add intro and a few suggestions.
* Update docs/TESTS.md
Co-authored-by: Job van der Wal <48634934+J08K@users.noreply.github.com>
Co-authored-by: Job van der Wal <48634934+J08K@users.noreply.github.com>
Co-authored-by: BethanyG
---
docs/TESTS.md | 67 ++++++++++++++++++++++++++----------------------
docs/TOOLS.md | 35 +++++++------------------
docs/config.json | 7 +++++
3 files changed, 52 insertions(+), 57 deletions(-)
diff --git a/docs/TESTS.md b/docs/TESTS.md
index 62b6d195086..9b0825a680c 100644
--- a/docs/TESTS.md
+++ b/docs/TESTS.md
@@ -1,23 +1,28 @@
# Tests
-- [Tests](#tests)
- - [Pytest](#pytest)
- - [Installing pytest Globally](#installing-pytest-globally)
- - [Windows](#windows)
- - [Linux / MacOS](#linux--macos)
- - [Installing pytest within a virtual environment](#installing-pytest-within-a-virtual-environment)
- - [Running the tests](#running-the-tests)
- - [Failures](#failures)
- - [Extra arguments](#extra-arguments)
- - [Stop After First Failure [`-x`]](#stop-after-first-failure--x)
- - [Failed Tests First [`--ff`]](#failed-tests-first---ff)
- - [Recommended Workflow](#recommended-workflow)
- - [Using PDB, the Python Debugger, with pytest](#using-pdb-the-python-debugger-with-pytest)
- - [Extending your IDE](#extending-your-ide)
- - [Additional information](#additional-information)
- - [Adding pytest to your PATH](#adding-pytest-to-your-path)
- - [Windows](#windows-1)
- - [Fixing warnings](#fixing-warnings)
+We use [pytest](http://pytest.org/en/latest/) as our website test runner.
+You will need to install pytest on your development machine if you want to download and run exercise tests for the Python track locally.
+We also recommend you install the following pytest plugins:
+
+- [pytest-cache](http://pythonhosted.org/pytest-cache/)
+- [pytest-subtests](https://github.com/pytest-dev/pytest-subtests)
+- [pytest-pylint](https://github.com/carsongee/pytest-pylint)
+
+The PyTest [Getting Started Guide](https://docs.pytest.org/en/latest/getting-started.html) has quick general instructions, although they do not cover installing the plugins.
+Continue reading below for more detailed instructions.
+
+We also recommend using [pylint](https://pylint.pycqa.org/en/latest/user_guide/), as it is part of our automated feedback on the website, and can be a very useful (but also noisy) code analysis tool.
+
+Pylint can be a bit much, so this [tutorial from pycqa.orgl](https://pylint.pycqa.org/en/latest/tutorial.html) can be helpful for getting started, as can this overview of [Code Quality: Tools and Best Practices](https://realpython.com/python-code-quality/) from Real Python.
+
+---
+
+- [Pytest](#pytest)
+ - [Installing pytest](#installing-pytest)
+ - [Running the tests](#running-the-tests)
+ - [Extra arguments](#extra-arguments)
+- [Extending your IDE](#extending-your-ide)
+- [Additional information](#additional-information)
---
@@ -27,7 +32,7 @@ _Official pytest documentation can be found on the [pytest Wiki](https://pytest.
Pytest lets you test your solutions using our provided tests, and is what we use to validate your solutions on the website.
-### Installing pytest Globally
+### Installing pytest
Pytest can be installed and updated using the built-in Python utility `pip`.
@@ -46,7 +51,7 @@ Successfully installed pytest-6.2.5 ...
```
-To check if the installation was succesful:
+To check if the installation was successful:
```bash
$ python3 -m pytest --version
@@ -57,9 +62,9 @@ If you do not want to precede every command with `python3 -m` please refer to [a
#### Installing pytest within a virtual environment
-*For more information about virtual environments please refer to the [TOOLS](./TOOLS.md) file.*
+_For more information about virtual environments please refer to the [tools](./tools) file._
-When installing pytest or any other module(s), make sure that you have [activated your environment](.\TOOLS.md#activating-your-virtual-environment). After which you can run:
+When installing pytest or any other module(s), make sure that you have [activated your environment](./tools#activating-your-virtual-environment). After which you can run:
```bash
$ pip install pytest pytest-cache pytest-subtests pytest-pylint
@@ -150,7 +155,7 @@ This will test your solution. When `pytest` encounters a failed test, the progra
#### Using PDB, the Python Debugger, with pytest
-If you want to truly debug like a pro, use the `--pdb` argument after the `pytest` command.
+If you want to truly debug like a pro, use the `--pdb` argument after the `pytest` command.
```bash
$ python3 -m pytest --pdb bob_test.py
@@ -161,13 +166,13 @@ When a test fails, `PDB` allows you to look at variables and how your code respo
## Extending your IDE
-If you'd like to extend your IDE with some tools that will help you with testing and improving your code, check the [TOOLS](./TOOLS.md) page. We go into multiple IDEs, editors and some useful extensions.
+If you'd like to extend your IDE with some tools that will help you with testing and improving your code, check the [tools](./tools) page. We go into multiple IDEs, editors and some useful extensions.
## Additional information
### Adding pytest to your PATH
-**Note:** If you are running a [virtual environment](.\TOOLS.md) you do not need to *add to path* as it should work fine.
+**Note:** If you are running a [virtual environment](./tools.md) you do not need to _add to path_ as it should work fine.
Typing `python3 -m` every time you want to run a module can get a little annoying. You can add the `Scripts` folder of your Python installation to your path. If you do not know where you have installed Python, run the following command in your terminal:
@@ -176,15 +181,15 @@ $ python3 -c "import os, sys; print(os.path.dirname(sys.executable))"
{python_directory}
```
-The *returned* directory is where your Python version is installed, in this tutorial it is referred to as `{python_directory}`.
+The _returned_ directory is where your Python version is installed, in this tutorial it is referred to as `{python_directory}`.
#### Windows
-Click the `Windows Start` button and lookup *Edit the system environment variables* and press enter. Next press, `Environment Variables...`:
+Click the `Windows Start` button and lookup _Edit the system environment variables_ and press enter. Next press, `Environment Variables...`:

-Then find the `Path` variable in your *User variables*, select it, and click `Edit...`:
+Then find the `Path` variable in your _User variables_, select it, and click `Edit...`:

@@ -202,10 +207,10 @@ You can also create your own file with the following content:
```ini
[pytest]
-markers =
+markers =
task: A concept exercise task.
```
-Whenever you run your tests, make sure that this file is in your _root_ or _working_ directory.
+Whenever you run your tests, make sure that this file is in your _root_ or _working_ directory for Exercism exercises.
-_More information on customizing pytest can be found in the [PyTest docs](https://docs.pytest.org/en/6.2.x/customize.html#pytest-ini)_
\ No newline at end of file
+_More information on customizing pytest can be found in the [PyTest docs](https://docs.pytest.org/en/6.2.x/customize.html#pytest-ini)_
diff --git a/docs/TOOLS.md b/docs/TOOLS.md
index c0123c7b3fc..80eb5e5a8bf 100644
--- a/docs/TOOLS.md
+++ b/docs/TOOLS.md
@@ -9,32 +9,14 @@ Before you can start coding, make sure that you have the proper version of Pytho
---
- [Environments](#environments)
- - [Virtualenv](#venv)
+ - [Venv](#venv)
- [Conda](#conda)
-
-- [Tools](#tools)
- - [Environments](#environments)
- - [Venv](#venv)
- - [Creating your virtual environment](#creating-your-virtual-environment)
- - [Activating your virtual environment](#activating-your-virtual-environment)
- - [Virtual Environment wrapper](#virtual-environment-wrapper)
- - [Conda](#conda)
- - [Activating your conda environment](#activating-your-conda-environment)
- - [Editors and IDEs](#editors-and-ides)
- - [Visual Studio Code](#visual-studio-code)
- - [Python for VS Code](#python-for-vs-code)
- - [Selecting the interpreter](#selecting-the-interpreter)
- - [Other features](#other-features)
- - [PyCharm](#pycharm)
- - [Selecting the interpreter](#selecting-the-interpreter-1)
- - [Other features](#other-features-1)
- - [Spyder IDE](#spyder-ide)
- - [Selecting the interpreter](#selecting-the-interpreter-2)
- - [Other features](#other-features-2)
- - [Sublime text](#sublime-text)
- - [Notable extensions](#notable-extensions)
- - [JupyterLab](#jupyterlab)
- - [Notable extensions](#notable-extensions-1)
+- [Editors and IDEs](#editors-and-ides)
+ - [Visual Studio Code](#visual-studio-code)
+ - [PyCharm](#pycharm)
+ - [Spyder IDE](#spyder-ide)
+ - [Sublime text](#sublime-text)
+ - [JupyterLab](#jupyterlab)
---
@@ -55,6 +37,7 @@ To create a virtual environment, `cd` to the directory you want to store your en
```bash
$ python3 -m venv {name_of_virtualenv}
created virtual environment ... in 8568ms
+```
#### Activating your virtual environment
@@ -146,7 +129,7 @@ Open your project, then navigate to `File` >> `Settings` >> `Project: ...` >> `P

-From there click on the `+` button to add a new interpreter. Select the type of interpreter on the left. We suggest you either run a [conda]() or [virtualenv]() environment, but running the *system interpreter* works fine, too. Once you selected your interpreter, press the `Okay` button.
+From there click on the `+` button to add a new interpreter. Select the type of interpreter on the left. We suggest you either run a [conda](#conda) or [virtualenv](#venv) environment, but running the *system interpreter* works fine, too. Once you selected your interpreter, press the `Okay` button.

diff --git a/docs/config.json b/docs/config.json
index db178d7e001..1b4ad634949 100644
--- a/docs/config.json
+++ b/docs/config.json
@@ -27,6 +27,13 @@
"path": "docs/RESOURCES.md",
"title": "Useful Python resources",
"blurb": "A collection of useful resources to help you master Python"
+ },
+ {
+ "uuid": "0dbb029b-ec67-4bbe-9ff7-483bf3a96af1",
+ "slug": "tools",
+ "path": "docs/TOOLS.md",
+ "title": "Useful tools for local development",
+ "blurb": "Useful tools that can help you with developing Python Exercism code on your own machine."
}
]
}
From 32c96c98ada60893d847bbaf448e5b25cc7486e8 Mon Sep 17 00:00:00 2001
From: Maria Kotlyarevskaya
Date: Mon, 15 Nov 2021 21:45:43 +0300
Subject: [PATCH 0011/1546] fix(markdown): fix markdown code to pass newly
added tests (#2774)
Signed-off-by: Jasstkn
---
exercises/practice/markdown/markdown.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/exercises/practice/markdown/markdown.py b/exercises/practice/markdown/markdown.py
index 0caa6b5fbd6..3c4bd2fa86a 100644
--- a/exercises/practice/markdown/markdown.py
+++ b/exercises/practice/markdown/markdown.py
@@ -9,6 +9,12 @@ def parse(markdown):
for i in lines:
if re.match('###### (.*)', i) is not None:
i = '
' + i[7:] + '
'
+ elif re.match('##### (.*)', i) is not None:
+ i = '
' + i[6:] + '
'
+ elif re.match('#### (.*)', i) is not None:
+ i = '
' + i[5:] + '
'
+ elif re.match('### (.*)', i) is not None:
+ i = '
' + i[4:] + '
'
elif re.match('## (.*)', i) is not None:
i = '
' + i[3:] + '
'
elif re.match('# (.*)', i) is not None:
From 4d2002a81eb8d0c109cfc972b45dd2e8f976e75e Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Tue, 16 Nov 2021 00:25:40 -0800
Subject: [PATCH 0012/1546] [Anagram, Grade-School, Hamming and Markdown ]:
Corrected Bad Test files and Templates (#2779)
* corrected erronious JinJa templates and toml files. Regenerated test files.
* Corrected classmethod to only load include != false test cases into TestCaseTOML dict.
* Update exercises/practice/hamming/.meta/tests.toml
* Regenerated hamming test file.
---
bin/data.py | 5 ++-
exercises/practice/anagram/.meta/template.j2 | 2 --
exercises/practice/anagram/anagram_test.py | 9 -----
.../practice/grade-school/.meta/example.py | 4 ---
.../practice/grade-school/.meta/tests.toml | 3 ++
.../grade-school/grade_school_test.py | 25 -------------
exercises/practice/hamming/.meta/tests.toml | 5 +++
exercises/practice/hamming/hamming_test.py | 35 -------------------
exercises/practice/markdown/.meta/template.j2 | 3 --
9 files changed, 12 insertions(+), 79 deletions(-)
diff --git a/bin/data.py b/bin/data.py
index ff3c76487f9..6f132e3f65d 100644
--- a/bin/data.py
+++ b/bin/data.py
@@ -356,7 +356,10 @@ class TestsTOML:
def load(cls, toml_path: Path):
with toml_path.open() as f:
data = toml.load(f)
- return cls({uuid: TestCaseTOML(uuid, *opts) for uuid, opts in data.items()})
+ return cls({uuid: TestCaseTOML(uuid, *opts) for
+ uuid, opts in
+ data.items() if
+ opts.get('include', None) is not False})
if __name__ == "__main__":
diff --git a/exercises/practice/anagram/.meta/template.j2 b/exercises/practice/anagram/.meta/template.j2
index d9fbf9cf724..1f74aef5bc0 100644
--- a/exercises/practice/anagram/.meta/template.j2
+++ b/exercises/practice/anagram/.meta/template.j2
@@ -12,5 +12,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
)
{% endfor %}
-
-{{ macros.footer() }}
diff --git a/exercises/practice/anagram/anagram_test.py b/exercises/practice/anagram/anagram_test.py
index 733deac1401..f82ec7a88d4 100644
--- a/exercises/practice/anagram/anagram_test.py
+++ b/exercises/practice/anagram/anagram_test.py
@@ -13,11 +13,6 @@ def test_no_matches(self):
expected = []
self.assertCountEqual(find_anagrams("diaper", candidates), expected)
- def test_detects_two_anagrams(self):
- candidates = ["stream", "pigeon", "maters"]
- expected = ["stream", "maters"]
- self.assertCountEqual(find_anagrams("master", candidates), expected)
-
def test_detects_two_anagrams(self):
candidates = ["lemons", "cherry", "melons"]
expected = ["lemons", "melons"]
@@ -82,7 +77,3 @@ def test_words_other_than_themselves_can_be_anagrams(self):
candidates = ["Listen", "Silent", "LISTEN"]
expected = ["Silent"]
self.assertCountEqual(find_anagrams("LISTEN", candidates), expected)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/exercises/practice/grade-school/.meta/example.py b/exercises/practice/grade-school/.meta/example.py
index 83ff1bcb4fa..a4b9fd4fe21 100644
--- a/exercises/practice/grade-school/.meta/example.py
+++ b/exercises/practice/grade-school/.meta/example.py
@@ -16,10 +16,6 @@ def add_student(self, name, grade):
if not self.db.get(name, 0):
self.db[name] = grade
self.add.append(True)
-
- elif self.db[name] > grade:
- self.db[name] = grade
-
else:
self.add.append(False)
diff --git a/exercises/practice/grade-school/.meta/tests.toml b/exercises/practice/grade-school/.meta/tests.toml
index d774e9e3ed8..50c9e2e5990 100644
--- a/exercises/practice/grade-school/.meta/tests.toml
+++ b/exercises/practice/grade-school/.meta/tests.toml
@@ -29,9 +29,11 @@ description = "Cannot add student to same grade in the roster more than once"
[c125dab7-2a53-492f-a99a-56ad511940d8]
description = "A student can't be in two different grades"
+include = false
[a0c7b9b8-0e89-47f8-8b4a-c50f885e79d1]
description = "A student can only be added to the same grade in the roster once"
+include = false
reimplements = "c125dab7-2a53-492f-a99a-56ad511940d8"
[d7982c4f-1602-49f6-a651-620f2614243a]
@@ -49,6 +51,7 @@ description = "Cannot add same student to multiple grades in the roster"
[6a03b61e-1211-4783-a3cc-fc7f773fba3f]
description = "A student cannot be added to more than one grade in the sorted roster"
+include = false
reimplements = "c125dab7-2a53-492f-a99a-56ad511940d8"
[c7ec1c5e-9ab7-4d3b-be5c-29f2f7a237c5]
diff --git a/exercises/practice/grade-school/grade_school_test.py b/exercises/practice/grade-school/grade_school_test.py
index 2ef26d2ef28..4672efe88ee 100644
--- a/exercises/practice/grade-school/grade_school_test.py
+++ b/exercises/practice/grade-school/grade_school_test.py
@@ -53,21 +53,6 @@ def test_cannot_add_student_to_same_grade_in_the_roster_more_than_once(self):
expected = [True, True, False, True]
self.assertEqual(school.added(), expected)
- def test_a_student_can_t_be_in_two_different_grades(self):
- school = School()
- school.add_student(name="Aimee", grade=2)
- school.add_student(name="Aimee", grade=1)
- expected = []
- self.assertEqual(school.roster(2), expected)
-
- def test_a_student_can_only_be_added_to_the_same_grade_in_the_roster_once(self):
- school = School()
- school.add_student(name="Aimee", grade=2)
- school.add_student(name="Aimee", grade=2)
- expected = ["Aimee"]
-
- self.assertEqual(school.roster(), expected)
-
def test_student_not_added_to_same_grade_in_the_roster_more_than_once(self):
school = School()
school.add_student(name="Blair", grade=2)
@@ -102,16 +87,6 @@ def test_cannot_add_same_student_to_multiple_grades_in_the_roster(self):
expected = [True, True, False, True]
self.assertEqual(school.added(), expected)
- def test_a_student_cannot_be_added_to_more_than_one_grade_in_the_sorted_roster(
- self,
- ):
- school = School()
- school.add_student(name="Aimee", grade=2)
- school.add_student(name="Aimee", grade=1)
- expected = ["Aimee"]
-
- self.assertEqual(school.roster(), expected)
-
def test_student_not_added_to_multiple_grades_in_the_roster(self):
school = School()
school.add_student(name="Blair", grade=2)
diff --git a/exercises/practice/hamming/.meta/tests.toml b/exercises/practice/hamming/.meta/tests.toml
index 0caf456cbff..fc863798bb7 100644
--- a/exercises/practice/hamming/.meta/tests.toml
+++ b/exercises/practice/hamming/.meta/tests.toml
@@ -26,6 +26,7 @@ description = "long different strands"
[919f8ef0-b767-4d1b-8516-6379d07fcb28]
description = "disallow first strand longer"
+include = false
[b9228bb1-465f-4141-b40f-1f99812de5a8]
description = "disallow first strand longer"
@@ -33,6 +34,7 @@ reimplements = "919f8ef0-b767-4d1b-8516-6379d07fcb28"
[8a2d4ed0-ead5-4fdd-924d-27c4cf56e60e]
description = "disallow second strand longer"
+include = false
[dab38838-26bb-4fff-acbe-3b0a9bfeba2d]
description = "disallow second strand longer"
@@ -40,10 +42,12 @@ reimplements = "8a2d4ed0-ead5-4fdd-924d-27c4cf56e60e"
[5dce058b-28d4-4ca7-aa64-adfe4e17784c]
description = "disallow left empty strand"
+include = false
[db92e77e-7c72-499d-8fe6-9354d2bfd504]
description = "disallow left empty strand"
reimplements = "5dce058b-28d4-4ca7-aa64-adfe4e17784c"
+include = false
[b764d47c-83ff-4de2-ab10-6cfe4b15c0f3]
description = "disallow empty first strand"
@@ -51,6 +55,7 @@ reimplements = "db92e77e-7c72-499d-8fe6-9354d2bfd504"
[38826d4b-16fb-4639-ac3e-ba027dec8b5f]
description = "disallow right empty strand"
+include = false
[920cd6e3-18f4-4143-b6b8-74270bb8f8a3]
description = "disallow right empty strand"
diff --git a/exercises/practice/hamming/hamming_test.py b/exercises/practice/hamming/hamming_test.py
index a0fa465b770..f4c7b8ae529 100644
--- a/exercises/practice/hamming/hamming_test.py
+++ b/exercises/practice/hamming/hamming_test.py
@@ -30,13 +30,6 @@ def test_disallow_first_strand_longer(self):
self.assertEqual(type(err.exception), ValueError)
self.assertEqual(err.exception.args[0], "Strands must be of equal length.")
- def test_disallow_first_strand_longer(self):
- with self.assertRaises(ValueError) as err:
- distance("AATG", "AAA")
-
- self.assertEqual(type(err.exception), ValueError)
- self.assertEqual(err.exception.args[0], "Strands must be of equal length.")
-
def test_disallow_second_strand_longer(self):
with self.assertRaises(ValueError) as err:
distance("ATA", "AGTG")
@@ -44,27 +37,6 @@ def test_disallow_second_strand_longer(self):
self.assertEqual(type(err.exception), ValueError)
self.assertEqual(err.exception.args[0], "Strands must be of equal length.")
- def test_disallow_second_strand_longer(self):
- with self.assertRaises(ValueError) as err:
- distance("ATA", "AGTG")
-
- self.assertEqual(type(err.exception), ValueError)
- self.assertEqual(err.exception.args[0], "Strands must be of equal length.")
-
- def test_disallow_left_empty_strand(self):
- with self.assertRaises(ValueError) as err:
- distance("", "G")
-
- self.assertEqual(type(err.exception), ValueError)
- self.assertEqual(err.exception.args[0], "Strands must be of equal length.")
-
- def test_disallow_left_empty_strand(self):
- with self.assertRaises(ValueError) as err:
- distance("", "G")
-
- self.assertEqual(type(err.exception), ValueError)
- self.assertEqual(err.exception.args[0], "Strands must be of equal length.")
-
def test_disallow_empty_first_strand(self):
with self.assertRaises(ValueError) as err:
distance("", "G")
@@ -79,13 +51,6 @@ def test_disallow_right_empty_strand(self):
self.assertEqual(type(err.exception), ValueError)
self.assertEqual(err.exception.args[0], "Strands must be of equal length.")
- def test_disallow_right_empty_strand(self):
- with self.assertRaises(ValueError) as err:
- distance("G", "")
-
- self.assertEqual(type(err.exception), ValueError)
- self.assertEqual(err.exception.args[0], "Strands must be of equal length.")
-
def test_disallow_empty_second_strand(self):
with self.assertRaises(ValueError) as err:
distance("G", "")
diff --git a/exercises/practice/markdown/.meta/template.j2 b/exercises/practice/markdown/.meta/template.j2
index a88bf8229c5..da2a037cec8 100644
--- a/exercises/practice/markdown/.meta/template.j2
+++ b/exercises/practice/markdown/.meta/template.j2
@@ -3,8 +3,6 @@
class {{ exercise | camel_case }}Test(unittest.TestCase):
{% for case in cases -%}
- {% if case["description"] == "with h7 header level" %}
- {% else %}
def test_{{ case["description"] | to_snake }}(self):
self.assertEqual(
{{ case["property"] | to_snake }}(
@@ -12,5 +10,4 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
),
"{{ case["expected"] }}"
)
- {% endif %}
{% endfor %}
From 62998dff6224459eee3aa16f227823b7553198bf Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Tue, 16 Nov 2021 00:26:33 -0800
Subject: [PATCH 0013/1546] Added comment to JinJa2 template regarding implicit
line joining in results lists. Regenerated test file with comment. (#2783)
---
exercises/practice/twelve-days/.meta/template.j2 | 5 +++--
exercises/practice/twelve-days/twelve_days_test.py | 7 +++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/exercises/practice/twelve-days/.meta/template.j2 b/exercises/practice/twelve-days/.meta/template.j2
index ddf17dc0107..e90fe713074 100644
--- a/exercises/practice/twelve-days/.meta/template.j2
+++ b/exercises/practice/twelve-days/.meta/template.j2
@@ -1,5 +1,8 @@
{%- import "generator_macros.j2" as macros with context -%}
{{ macros.header() }}
+{{ "# PLEASE TAKE NOTE: Expected result lists for these test cases use **implicit line joining.**" }}
+{{ "# A new line in a result list below **does not** always equal a new list element." }}
+{{ "# Check comma placement carefully!" }}
class {{ exercise | camel_case }}Test(unittest.TestCase):
{# All test cases in this exercise are nested, so use two for loops -#}
@@ -19,5 +22,3 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
{{- input["startVerse"] }},
{{- input["endVerse"] }}), expected)
{% endfor %}{% endfor %}
-
-{{ macros.footer() }}
diff --git a/exercises/practice/twelve-days/twelve_days_test.py b/exercises/practice/twelve-days/twelve_days_test.py
index 9418eaf2b26..ec097cddb9c 100644
--- a/exercises/practice/twelve-days/twelve_days_test.py
+++ b/exercises/practice/twelve-days/twelve_days_test.py
@@ -5,6 +5,9 @@
)
# Tests adapted from `problem-specifications//canonical-data.json`
+# PLEASE TAKE NOTE: Expected result lists for these test cases use **implicit line joining.**
+# A new line in a result list below **does not** always equal a new list element.
+# Check comma placement carefully!
class TwelveDaysTest(unittest.TestCase):
@@ -169,7 +172,3 @@ def test_recites_three_verses_from_the_middle_of_the_song(self):
def test_recites_the_whole_song(self):
expected = [recite(n, n)[0] for n in range(1, 13)]
self.assertEqual(recite(1, 12), expected)
-
-
-if __name__ == "__main__":
- unittest.main()
From 2c88507282f523e5c477117f2bc63e963030707f Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Tue, 16 Nov 2021 00:31:14 -0800
Subject: [PATCH 0014/1546] [Making the Grade]: Clarified Grading Intervals &
Added Detail to Examples for Task 4 (#2784)
* Clarified the grading intervals and added detail to the examples for task 4.
* Reformatted via prettier.
---
.../making-the-grade/.docs/instructions.md | 27 ++++++++++++++-----
exercises/concept/making-the-grade/loops.py | 9 ++++++-
2 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/exercises/concept/making-the-grade/.docs/instructions.md b/exercises/concept/making-the-grade/.docs/instructions.md
index cab66008645..36c76cea5b2 100644
--- a/exercises/concept/making-the-grade/.docs/instructions.md
+++ b/exercises/concept/making-the-grade/.docs/instructions.md
@@ -7,9 +7,9 @@ You decide to make things a little more interesting by putting together some fun
## 1. Rounding Scores
While you can give "partial credit" on exam questions, overall exam scores have to be `int`s.
-So before you can do anything else with the class scores, you need to go through the grades and turn any `float` scores into `int`s. Lucky for you, Python has the built-in [`round()`][round] function you can use.
+So before you can do anything else with the class scores, you need to go through the grades and turn any `float` scores into `int`s. Lucky for you, Python has the built-in [`round()`][round] function you can use.
-A score of 75.45 or 75.49 will round to 75. A score of 43.50 or 43.59 will round to 44.
+A score of 75.45 or 75.49 will round to 75. A score of 43.50 or 43.59 will round to 44.
There shouldn't be any scores that have more than two places after the decimal point.
Create the function `round_scores()` that takes a `list` of `student_scores`.
@@ -55,17 +55,33 @@ This function should return a `list` of all scores that are `>=` to `threshold`.
The teacher you're assisting likes to assign letter grades as well as numeric scores.
Since students rarely score 100 on an exam, the "letter grade" lower thresholds are calculated based on the highest score achieved, and increment evenly between the high score and the failing threshold of **<= 40**.
-Create the function `letter_grades()` that takes the "highest" score on the exam as a parameter, and returns a `list` of lower score thresholds for each letter grade from "D" to "A".
+Create the function `letter_grades()` that takes the "highest" score on the exam as a parameter, and returns a `list` of lower score thresholds for each "American style" grade interval: `["D", "C", "B", "A"]`.
```python
+"""Where the highest score is 100, and failing is <= 40.
+ "F" <= 40
+ 41 <= "D" <= 55
+ 56 <= "C" <= 70
+ 71 <= "B" <= 85
+ 86 <= "A" <= 100
+"""
+
>>> letter_grades(highest=100)
[41, 56, 71, 86]
+
+"""Where the highest score is 88, and failing is <= 40.
+ "F" <= 40
+ 41 <= "D" <= 52
+ 53 <= "C" <= 64
+ 65 <= "B" <= 76
+ 77 <= "A" <= 88
+"""
+
>>> letter_grades(highest=88)
[41, 53, 65, 77]
```
-
## 5. Matching Names to Scores
You have a list of exam scores in descending order, and another list of student names also sorted in descending order by their exam scores.
@@ -76,7 +92,6 @@ Match each student name on the student_names `list` with their score from the st
You can assume each argument `list` will be sorted from highest score(er) to lowest score(er).
The function should return a `list` of strings with the format `. : `.
-
```python
>>> student_scores = [100, 99, 90, 84, 66, 53, 47]
>>> student_names = ['Joci', 'Sara','Kora','Jan','John','Bern', 'Fred']
@@ -93,7 +108,7 @@ Create the function `perfect_score()` with parameter `student_info`.
`student_info` is a `list` of lists containing the name and score of each student: `[["Charles", 90], ["Tony", 80]]`.
The function should `return` _the first_ `[, ]` pair of the student who scored 100 on the exam.
- If no 100 scores are found in `student_info`, an empty list `[]` should be returned.
+If no 100 scores are found in `student_info`, an empty list `[]` should be returned.
```python
>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80], ["Alex", 100]])
diff --git a/exercises/concept/making-the-grade/loops.py b/exercises/concept/making-the-grade/loops.py
index 718df628187..ccdeb9d84a2 100644
--- a/exercises/concept/making-the-grade/loops.py
+++ b/exercises/concept/making-the-grade/loops.py
@@ -29,7 +29,14 @@ def above_threshold(student_scores, threshold):
def letter_grades(highest):
"""
:param highest: integer of highest exam score.
- :return: list of integer score thresholds for each F-A letter grades.
+ :return: list of integer lower threshold scores for each D-A letter grade interval.
+ For example, where the highest score is 100, and failing is <= 40,
+ The result would be [41, 56, 71, 86]:
+
+ 41 <= "D" <= 55
+ 56 <= "C" <= 70
+ 71 <= "B" <= 85
+ 86 <= "A" <= 100
"""
pass
From 79515ffbee47c1cff2d625c363592b3d73357513 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Tue, 16 Nov 2021 00:32:25 -0800
Subject: [PATCH 0015/1546] [PR Auto-Comments]: Will the teeny-tiny typo
madness never end?? (#2785)
Fixed broken PR linklet.
---
.github/pr-commenter.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/pr-commenter.yml b/.github/pr-commenter.yml
index fa42b8b12b6..5c635b8179a 100644
--- a/.github/pr-commenter.yml
+++ b/.github/pr-commenter.yml
@@ -200,7 +200,7 @@ comment:
β οΈ Please be aware β οΈ
- _This repo does not generally accept []Pull Requests](https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md) unless they follow our [contributing guidelines](https://github.com/exercism/python/blob/main/CONTRIBUTING.md) and are:_
+ _This repo does not generally accept [Pull Requests](https://github.com/exercism/docs/blob/main/community/good-member/pull-requests.md) unless they follow our [contributing guidelines](https://github.com/exercism/python/blob/main/CONTRIBUTING.md) and are:_
1οΈβ£ Small, contained fixes for typos/grammar/punctuation/code syntax on [one] exercise,
2οΈβ£ Medium changes that have been agreed/discussed via a filed issue,
From bf6367a5f022705a3e73ff328b7da280c8699a4d Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Thu, 18 Nov 2021 00:33:54 +0100
Subject: [PATCH 0016/1546] Bump actions/setup-python from 2.2.2 to 2.3.0
(#2788)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2.2.2 to 2.3.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v2.2.2...v2.3.0)
---
updated-dependencies:
- dependency-name: actions/setup-python
dependency-type: direct:production
update-type: version-update:semver-minor
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/ci-workflow.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml
index 3b60f81571b..96296b8aa8f 100644
--- a/.github/workflows/ci-workflow.yml
+++ b/.github/workflows/ci-workflow.yml
@@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v2.4.0
- name: Set up Python
- uses: actions/setup-python@v2.2.2
+ uses: actions/setup-python@v2.3.0
with:
python-version: 3.8
@@ -57,7 +57,7 @@ jobs:
steps:
- uses: actions/checkout@v2.4.0
- - uses: actions/setup-python@v2.2.2
+ - uses: actions/setup-python@v2.3.0
with:
python-version: ${{ matrix.python-version }}
From cb83d99da334aae2741e588122aa34b738e36202 Mon Sep 17 00:00:00 2001
From: Job van der Wal <48634934+J08K@users.noreply.github.com>
Date: Thu, 18 Nov 2021 01:04:47 +0100
Subject: [PATCH 0017/1546] [Linting]: Lint practice stub files (1 / ?)
(#2787)
* First three fixed files
* atbash-cipher
* next two
* Another 2
* Update exercises/practice/alphametics/.meta/example.py
Co-authored-by: BethanyG
* Update exercises/practice/atbash-cipher/.meta/example.py
Co-authored-by: BethanyG
* Apply suggestions from code review
Co-authored-by: BethanyG
* Fix test failing; Fix oversights
* lol
* Fixed some stuff
* BOBBY!!
* affine cipher
Co-authored-by: BethanyG
---
.../practice/accumulate/.meta/example.py | 12 +-
.../practice/affine-cipher/.meta/example.py | 40 ++---
.../practice/all-your-base/.meta/example.py | 4 +-
exercises/practice/allergies/.meta/example.py | 4 +-
.../practice/alphametics/.meta/example.py | 155 +++++++++---------
.../armstrong-numbers/.meta/example.py | 2 +-
.../practice/atbash-cipher/.meta/example.py | 16 +-
exercises/practice/beer-song/.meta/example.py | 28 +---
.../binary-search-tree/.meta/example.py | 3 +-
.../binary-search-tree/binary_search_tree.py | 3 +-
.../practice/binary-search/.meta/example.py | 2 +-
exercises/practice/binary/.meta/example.py | 6 +-
12 files changed, 129 insertions(+), 146 deletions(-)
diff --git a/exercises/practice/accumulate/.meta/example.py b/exercises/practice/accumulate/.meta/example.py
index d577b93ffca..7a6c8bb20c1 100644
--- a/exercises/practice/accumulate/.meta/example.py
+++ b/exercises/practice/accumulate/.meta/example.py
@@ -1,8 +1,8 @@
-# [op(x) for x in seq] would be nice but trivial
+# [collection(x) for x in collection] would be nice but trivial
-def accumulate(seq, op):
- res = []
- for el in seq:
- res.append(op(el))
- return res
+def accumulate(collection, operation):
+ response = []
+ for ellement in collection:
+ response.append(operation(ellement))
+ return response
diff --git a/exercises/practice/affine-cipher/.meta/example.py b/exercises/practice/affine-cipher/.meta/example.py
index c655c4546ab..34ca0418da6 100644
--- a/exercises/practice/affine-cipher/.meta/example.py
+++ b/exercises/practice/affine-cipher/.meta/example.py
@@ -1,31 +1,31 @@
-BLKSZ = 5
-ALPHSZ = 26
+BLOCK_SIZE = 5
+ALPHABET = 26
-def modInverse(a, ALPHSZ):
- a = a % ALPHSZ
- for x in range(1, ALPHSZ):
- if ((a * x) % ALPHSZ == 1):
- return x
+def mod_inverse(a_key, alphabet):
+ a_key = a_key % alphabet
+ for idx in range(1, alphabet):
+ if (a_key * idx) % alphabet == 1:
+ return idx
return 1
-def translate(text, a, b, mode):
- inv = modInverse(a, ALPHSZ)
- if inv == 1:
- raise ValueError("a and m must be coprime.")
+def translate(text, a_key, b_key, mode):
+ inverse = mod_inverse(a_key, ALPHABET)
+ if inverse == 1:
+ raise ValueError('a and m must be coprime.')
chars = []
- for c in text:
- if c.isalnum():
- orig = ord(c.lower()) - 97
- if orig < 0:
- chars.append(c)
+ for character in text:
+ if character.isalnum():
+ origin = ord(character.lower()) - 97
+ if origin < 0:
+ chars.append(character)
continue
if mode == 0:
- new = (a * orig + b) % ALPHSZ
+ new = (a_key * origin + b_key) % ALPHABET
elif mode == 1:
- new = (inv * (orig - b)) % ALPHSZ
+ new = (inverse * (origin - b_key)) % ALPHABET
chars.append(chr(new + 97))
return ''.join(chars)
@@ -33,8 +33,8 @@ def translate(text, a, b, mode):
def encode(plain, a, b):
cipher = translate(plain, a, b, 0)
- return " ".join([cipher[i:i + BLKSZ]
- for i in range(0, len(cipher), BLKSZ)])
+ return ' '.join([cipher[idx:idx + BLOCK_SIZE]
+ for idx in range(0, len(cipher), BLOCK_SIZE)])
def decode(ciphered, a, b):
diff --git a/exercises/practice/all-your-base/.meta/example.py b/exercises/practice/all-your-base/.meta/example.py
index bce92f831b5..e493a50243e 100644
--- a/exercises/practice/all-your-base/.meta/example.py
+++ b/exercises/practice/all-your-base/.meta/example.py
@@ -1,5 +1,5 @@
def from_digits(digits, base):
- return sum(n * base ** i for i, n in enumerate(reversed(digits)))
+ return sum(number * base ** idx for idx, number in enumerate(reversed(digits)))
def to_digits(number, base_to):
@@ -19,7 +19,7 @@ def rebase(from_base, digits, to_base):
if to_base < 2:
raise ValueError("output base must be >= 2")
- if any(True for d in digits if d < 0 or d >= from_base):
+ if any(True for idx in digits if idx < 0 or idx >= from_base):
raise ValueError("all digits must satisfy 0 <= d < input base")
return to_digits(from_digits(digits, from_base), to_base)
diff --git a/exercises/practice/allergies/.meta/example.py b/exercises/practice/allergies/.meta/example.py
index 598251e3865..44298c974a0 100644
--- a/exercises/practice/allergies/.meta/example.py
+++ b/exercises/practice/allergies/.meta/example.py
@@ -14,8 +14,8 @@ class Allergies:
def __init__(self, score):
self.score = score
- def allergic_to(self, allergy):
- return bool(self.score & 1 << self._allergies.index(allergy))
+ def allergic_to(self, item):
+ return bool(self.score & 1 << self._allergies.index(item))
@property
def lst(self):
diff --git a/exercises/practice/alphametics/.meta/example.py b/exercises/practice/alphametics/.meta/example.py
index d72610822eb..3faf17aaa0d 100644
--- a/exercises/practice/alphametics/.meta/example.py
+++ b/exercises/practice/alphametics/.meta/example.py
@@ -1,4 +1,3 @@
-from itertools import permutations, chain, product
"""
This solution will first parse the alphametic expression
grouping and counting letters buy digit ranks
@@ -10,45 +9,47 @@
to reduce the number of permutations
"""
+from itertools import permutations, chain, product
+
-def digPerms(digset, nzcharset, okzcharset):
+def dig_perms(digit_set, non_zero_chars, ok_zero_chars):
"""This function creates permutations given the set of digits,
letters not alllowed to be 0, and letters allowed to be 0
"""
- nzcnt = len(nzcharset) # How many letters are non-0
- okzcnt = len(okzcharset) # How many letters are allowed 0
- totcnt = nzcnt + okzcnt # Total number of letters
- if totcnt < 1: # if total numbers of letters is 0
+ non_zero_count = len(non_zero_chars) # How many letters are non-0
+ ok_zero_count = len(ok_zero_chars) # How many letters are allowed 0
+ total_count = non_zero_count + ok_zero_count # Total number of letters
+ if total_count < 1: # if total numbers of letters is 0
return [()] # return a singe empty permutation
- nzdigset = digset - set((0,)) # generate a non-zero digit set
- nzdigsetcnt = len(nzdigset) # how many non-zero digits are available
- digsetcnt = len(digset) # how many ok zero digits are available
+ non_zero_digit_set = digit_set - set((0,)) # generate a non-zero digit set
+ available_zero_digit_count = len(non_zero_digit_set) # how many non-zero digits are available
+ ok_zero_digit_count = len(digit_set) # how many ok zero digits are available
# if either fewer digits than letters at all or fewer non-0 digits
# than letters that need to be non-zero
- if digsetcnt < totcnt or nzdigsetcnt < nzcnt:
+ if ok_zero_digit_count < total_count or available_zero_digit_count < non_zero_count:
return [] # Return no permutations possible
# Simple case when zeros are allowed everwhere
# or no zero is containted within the given digits
- elif nzcnt == 0 or digsetcnt == nzdigsetcnt:
- return permutations(digset, totcnt)
+ elif non_zero_count == 0 or ok_zero_digit_count == available_zero_digit_count:
+ return permutations(digit_set, total_count)
# Another simple case all letters are non-0
- elif okzcnt == 0:
- return permutations(nzdigset, totcnt)
+ elif ok_zero_count == 0:
+ return permutations(non_zero_digit_set, total_count)
else:
# General case
# Generate a list of possible 0 positions
- poslst = list(range(nzcnt, totcnt))
+ positions_list = list(range(non_zero_count, total_count))
# Chain two iterators
# first iterator with all non-0 permutations
# second iterator with all permulations without 1 letter
# insert 0 in all possible positions of that permutation
- return chain(permutations(nzdigset, totcnt),
- map(lambda x: x[0][:x[1]] + (0,) + x[0][x[1]:],
- product(permutations(nzdigset, totcnt - 1),
- poslst)))
+ return chain(permutations(non_zero_digit_set, total_count),
+ map(lambda iters: iters[0][:iters[1]] + (0,) + iters[0][iters[1]:],
+ product(permutations(non_zero_digit_set, total_count - 1),
+ positions_list)))
-def check_rec(eqparams, tracecombo=(dict(), 0, set(range(10))), p=0):
+def check_rec(eqparams, trace_combo=({}, 0, set(range(10))), power=0):
"""This function recursively traces a parsed expression from lowest
digits to highest, generating additional digits when necessary
checking the digit sum is divisible by 10, carrying the multiple of 10
@@ -60,117 +61,117 @@ def check_rec(eqparams, tracecombo=(dict(), 0, set(range(10))), p=0):
# unique non-zero characters by rank
# unique zero-allowed characters by rank
# all unique characters by rank
- maxp, tchars, unzchars, uokzchars, uchars = eqparams
+ max_digit_rank, multipliers_chars, non_zero_chars, zero_chars, unique_chars = eqparams
# recursion cumulative parameters
# established characters with digits
# carry-over from the previous level
# remaining unassigned digits
- prevdict, cover, remdigs = tracecombo
+ prev_digits, carry_over, remaining_digits = trace_combo
# the maximal 10-power (beyond the maximal rank)
# is reached
- if p == maxp:
+ if power == max_digit_rank:
# Carry-over is zero, meaning solution is found
- if cover == 0:
- return prevdict
+ if carry_over == 0:
+ return prev_digits
else:
# Otherwise the solution in this branch is not found
# return empty
- return dict()
- diglets = uchars[p] # all new unique letters from the current level
- partsum = cover # Carry over from lower level
- remexp = [] # TBD letters
+ return {}
+ digit_letters = unique_chars[power] # all new unique letters from the current level
+ part_sum = carry_over # Carry over from lower level
+ remaining_exp = [] # TBD letters
# Break down the current level letter into what can be
# calculated in the partial sum and remaining TBD letter-digits
- for c, v in tchars[p]:
- if c in prevdict:
- partsum += v * prevdict[c]
+ for caesar, van_gogh in multipliers_chars[power]:
+ if caesar in prev_digits:
+ part_sum += van_gogh * prev_digits[caesar]
else:
- remexp.append((c, v))
+ remaining_exp.append((caesar, van_gogh))
# Generate permutations for the remaining digits and currecnt level
# non-zero letters and zero-allowed letters
- for newdigs in digPerms(remdigs, unzchars[p], uokzchars[p]):
+ for newdigs in dig_perms(remaining_digits, non_zero_chars[power], zero_chars[power]):
# build the dictionary for the new letters and this level
- newdict = dict(zip(diglets, newdigs))
+ new_dict = dict(zip(digit_letters, newdigs))
# complete the partial sum into test sum using the current permutation
- testsum = partsum + sum([newdict[c] * v
- for c, v in remexp])
+ testsum = part_sum + sum([new_dict[caesar] * van_gogh
+ for caesar, van_gogh in remaining_exp])
# check if the sum is divisible by 10
- d, r = divmod(testsum, 10)
- if r == 0:
+ dali, rembrandt = divmod(testsum, 10)
+ if rembrandt == 0:
# if divisible, update the dictionary to all established
- newdict.update(prevdict)
+ new_dict.update(prev_digits)
# proceed to the next level of recursion with
# the same eqparams, but updated digit dictionary,
# new carry over and remaining digits to assign
- rectest = check_rec(eqparams,
- (newdict, d, remdigs - set(newdigs)),
- p + 1)
+ recurring_test = check_rec(eqparams,
+ (new_dict, dali, remaining_digits - set(newdigs)),
+ power + 1)
# if the recursive call returned a non-empty dictionary
# this means the recursion has found a solution
# otherwise, proceed to the new permutation
- if rectest and len(rectest) > 0:
- return rectest
+ if recurring_test and len(recurring_test) > 0:
+ return recurring_test
# if no permutations are avaialble or no
# permutation gave the result return None
return None
-def solve(an):
+def solve(puzzle):
"""A function to solve the alphametics problem
"""
# First, split the expresion into left and right parts by ==
# split each part into words by +
# strip spaces fro, each word, reverse each work to
# enumerate the digit rank from lower to higer
- fullexp = [list(map(lambda x: list(reversed(x.strip())), s.split("+")))
- for s in an.strip().upper().split("==")]
+ full_exp = [list(map(lambda idx: list(reversed(idx.strip())), sigmund.split('+')))
+ for sigmund in puzzle.strip().upper().split('==')]
# Find the maximal lenght of the work, maximal possive digit rank or
# the power of 10, should the < maxp
- maxp = max([len(w) for s in fullexp for w in s])
+ max_digit_rank = max([len(warhol) for sigmund in full_exp for warhol in sigmund])
# Extract the leading letters for each (reversed) word
# those cannot be zeros as the number cannot start with 0
- nzchars = set([w[-1] for s in fullexp for w in s])
+ nzchars = {warhol[-1] for sigmund in full_exp for warhol in sigmund}
# initialize the lists for digit ranks
- unzchars = [] # non-zero letters unique at level
- uokzchars = [] # zero-allowed letters unique at level
- uchars = [] # all letters unique at level
- tchars = [] # all letter with multipliers per level
- for i in range(maxp):
- tchars.append(dict())
- unzchars.append(set())
- uokzchars.append(set())
+ non_zero_chars = [] # non-zero letters unique at level
+ zero_chars = [] # zero-allowed letters unique at level
+ unique_chars = [] # all letters unique at level
+ multipliers_chars = [] # all letter with multipliers per level
+ for _ in range(max_digit_rank):
+ multipliers_chars.append({})
+ non_zero_chars.append(set())
+ zero_chars.append(set())
# Now lets scan the expression and accumulate the letter counts
- for si, s in enumerate(fullexp):
- sgn = 1 - (si << 1) # left side (0) is +1, right right (1) is -1
- for w in s: # for each word in the side (already reversed)
- for p, c in enumerate(w): # enumerate with ranks
- if c not in tchars[p]: # check if the letter was alread there
- tchars[p][c] = 0
- tchars[p][c] += sgn # append to the rank dictionary
+ for idx, sigmund in enumerate(full_exp):
+ bob = 1 - (idx << 1) # left side (0) is +1, right right (1) is -1
+ for warhol in sigmund: # for each word in the side (already reversed)
+ for picasso, escher in enumerate(warhol): # enumerate with ranks
+ if escher not in multipliers_chars[picasso]: # check if the letter was alread there
+ multipliers_chars[picasso][escher] = 0
+ multipliers_chars[picasso][escher] += bob # append to the rank dictionary
- totchars = set() # Keep track of letters already seen at lower ranks
+ total_chars = set() # Keep track of letters already seen at lower ranks
# go through the accumulated rank dictionaries
- for p, chardict in enumerate(tchars):
- for c, cnt in tuple(chardict.items()):
+ for picasso, chardict in enumerate(multipliers_chars):
+ for caesar, cnt in tuple(chardict.items()):
if cnt == 0: # if the cumulative is 0
- del chardict[c] # remove the letter from check dictionry
+ del chardict[caesar] # remove the letter from check dictionry
# it does not impact the sum with 0-multiplier
# if the letter contributes to the sum
# and was not yet seen at lower ranks
- elif c not in totchars:
+ elif caesar not in total_chars:
# add the letter to either non-zero set
# or allowed-zero set
- if c in nzchars:
- unzchars[p].add(c)
+ if caesar in nzchars:
+ non_zero_chars[picasso].add(caesar)
else:
- uokzchars[p].add(c)
+ zero_chars[picasso].add(caesar)
# add to the list as seen letter to ignore at the next
# ranks
- totchars.add(c)
+ total_chars.add(caesar)
# pre-build the combo list of letters for the rank
# non-zero first, followed by zero-allowed
- uchars.append(tuple(unzchars[p]) + tuple(uokzchars[p]))
+ unique_chars.append(tuple(non_zero_chars[picasso]) + tuple(zero_chars[picasso]))
# pre-convert check dictionaries to tuples
- tchars[p] = tuple(chardict.items())
+ multipliers_chars[picasso] = tuple(chardict.items())
# go for the recursion
- return check_rec([maxp, tchars, unzchars, uokzchars, uchars])
+ return check_rec([max_digit_rank, multipliers_chars, non_zero_chars, zero_chars, unique_chars])
diff --git a/exercises/practice/armstrong-numbers/.meta/example.py b/exercises/practice/armstrong-numbers/.meta/example.py
index 9bc1a3a5918..1ea193886db 100644
--- a/exercises/practice/armstrong-numbers/.meta/example.py
+++ b/exercises/practice/armstrong-numbers/.meta/example.py
@@ -1,2 +1,2 @@
def is_armstrong_number(number):
- return sum(pow(int(d), len(str(number))) for d in str(number)) == number
+ return sum(pow(int(digit), len(str(number))) for digit in str(number)) == number
diff --git a/exercises/practice/atbash-cipher/.meta/example.py b/exercises/practice/atbash-cipher/.meta/example.py
index c40bf3d04aa..a358998e05d 100644
--- a/exercises/practice/atbash-cipher/.meta/example.py
+++ b/exercises/practice/atbash-cipher/.meta/example.py
@@ -1,24 +1,18 @@
from string import ascii_lowercase
-import sys
-if sys.version_info[0] == 2:
- from string import maketrans
-else:
- maketrans = str.maketrans
-
-BLKSZ = 5
-trtbl = maketrans(ascii_lowercase, ascii_lowercase[::-1])
+BLOCK_SIZE = 5
+trtbl = str.maketrans(ascii_lowercase, ascii_lowercase[::-1])
def base_trans(text):
- return ''.join([c for c in text if c.isalnum()]).lower().translate(trtbl)
+ return ''.join([character for character in text if character.isalnum()]).lower().translate(trtbl)
def encode(plain):
cipher = base_trans(plain)
- return " ".join([cipher[i:i + BLKSZ]
- for i in range(0, len(cipher), BLKSZ)])
+ return ' '.join(cipher[idx:idx + BLOCK_SIZE]
+ for idx in range(0, len(cipher), BLOCK_SIZE))
def decode(ciphered):
diff --git a/exercises/practice/beer-song/.meta/example.py b/exercises/practice/beer-song/.meta/example.py
index 7b8f289cd02..4dfa8ea0296 100644
--- a/exercises/practice/beer-song/.meta/example.py
+++ b/exercises/practice/beer-song/.meta/example.py
@@ -1,38 +1,28 @@
def recite(start, take=1):
results = []
- for i in range(start, start - take, -1):
- results.extend(verse(i))
- if i > start - take + 1:
+ for idx in range(start, start - take, -1):
+ results.extend(verse(idx))
+ if idx > start - take + 1:
results.append('')
return results
def verse(number):
return [
- ''.join([
- "{} of beer on the wall, ".format(_bottles(number).capitalize()),
- "{} of beer.".format(_bottles(number))
- ]),
- ''.join([
- _action(number),
- _next_bottle(number)
- ])
+ f'{_bottles(number).capitalize()} of beer on the wall, {_bottles(number)} of beer.',
+ f'{_action(number)}{_next_bottle(number)}'
]
def _action(current_verse):
if current_verse == 0:
- return "Go to the store and buy some more, "
+ return 'Go to the store and buy some more, '
else:
- return "Take {} down and pass it around, ".format(
- "one" if current_verse > 1 else "it",
- )
+ return f'Take {"one" if current_verse > 1 else "it"} down and pass it around, '
def _next_bottle(current_verse):
- return "{} of beer on the wall.".format(
- _bottles(_next_verse(current_verse)),
- )
+ return f'{_bottles(_next_verse(current_verse))} of beer on the wall.'
def _bottles(number):
@@ -41,7 +31,7 @@ def _bottles(number):
if number == 1:
return '1 bottle'
else:
- return '{} bottles'.format(number)
+ return f'{number} bottles'
def _next_verse(current_verse):
diff --git a/exercises/practice/binary-search-tree/.meta/example.py b/exercises/practice/binary-search-tree/.meta/example.py
index d45bc555b6f..fede54dd61c 100644
--- a/exercises/practice/binary-search-tree/.meta/example.py
+++ b/exercises/practice/binary-search-tree/.meta/example.py
@@ -5,8 +5,7 @@ def __init__(self, data, left=None, right=None):
self.right = right
def __str__(self):
- fmt = 'TreeNode(data={}, left={}, right={})'
- return fmt.format(self.data, self.left, self.right)
+ return f'TreeNode(data={self.data}, left={self.left}, right={self.right})'
class BinarySearchTree:
diff --git a/exercises/practice/binary-search-tree/binary_search_tree.py b/exercises/practice/binary-search-tree/binary_search_tree.py
index dac1b98b31c..afca5d44ec2 100644
--- a/exercises/practice/binary-search-tree/binary_search_tree.py
+++ b/exercises/practice/binary-search-tree/binary_search_tree.py
@@ -5,8 +5,7 @@ def __init__(self, data, left=None, right=None):
self.right = None
def __str__(self):
- fmt = 'TreeNode(data={}, left={}, right={})'
- return fmt.format(self.data, self.left, self.right)
+ return f'TreeNode(data={self.data}, left={self.left}, right={self.right})'
class BinarySearchTree:
diff --git a/exercises/practice/binary-search/.meta/example.py b/exercises/practice/binary-search/.meta/example.py
index c5fd05879ee..0bd7be2cbb9 100644
--- a/exercises/practice/binary-search/.meta/example.py
+++ b/exercises/practice/binary-search/.meta/example.py
@@ -9,4 +9,4 @@ def find(search_list, value):
low = middle + 1
else:
return middle
- raise ValueError("value not in array")
+ raise ValueError('value not in array')
diff --git a/exercises/practice/binary/.meta/example.py b/exercises/practice/binary/.meta/example.py
index 3d8c4065435..364669062a5 100644
--- a/exercises/practice/binary/.meta/example.py
+++ b/exercises/practice/binary/.meta/example.py
@@ -1,5 +1,5 @@
def parse_binary(digits):
if set(digits) - set('01'):
- raise ValueError("Invalid binary literal: " + digits)
- return sum(int(digit) * 2 ** i
- for (i, digit) in enumerate(reversed(digits)))
+ raise ValueError('Invalid binary literal: ' + digits)
+ return sum(int(digit) * 2 ** idx
+ for (idx, digit) in enumerate(reversed(digits)))
From d94358b8944449e4354354fa6cfbe32983b21b64 Mon Sep 17 00:00:00 2001
From: Job van der Wal <48634934+J08K@users.noreply.github.com>
Date: Thu, 18 Nov 2021 20:10:58 +0100
Subject: [PATCH 0018/1546] [Linting]: Lint practice stub files (4 / ?) (#2791)
* Ending before L
* nvm lol
---
.../practice/go-counting/.meta/example.py | 50 ++++++++++---------
.../practice/grade-school/.meta/example.py | 2 +-
exercises/practice/grains/.meta/example.py | 6 +--
exercises/practice/grep/.meta/example.py | 4 +-
exercises/practice/hamming/.meta/example.py | 8 +--
exercises/practice/hangman/.meta/example.py | 16 +++---
exercises/practice/hangman/hangman.py | 6 +--
.../practice/hexadecimal/.meta/example.py | 12 ++---
exercises/practice/house/.meta/example.py | 15 +++---
exercises/practice/isogram/.meta/example.py | 2 +-
.../kindergarten-garden/.meta/example.py | 30 +++++------
exercises/practice/knapsack/.meta/example.py | 6 +--
12 files changed, 78 insertions(+), 79 deletions(-)
diff --git a/exercises/practice/go-counting/.meta/example.py b/exercises/practice/go-counting/.meta/example.py
index 06f2a165ec3..c6ccd512110 100644
--- a/exercises/practice/go-counting/.meta/example.py
+++ b/exercises/practice/go-counting/.meta/example.py
@@ -1,7 +1,7 @@
-BLACK = "B"
-WHITE = "W"
-NONE = ""
+BLACK = 'B'
+WHITE = 'W'
+NONE = ''
STONES = [BLACK, WHITE]
DIRECTIONS = [(0, 1), (0, -1), (1, 0), (-1, 0)]
@@ -12,23 +12,25 @@ def __init__(self, board):
self.width = len(self.board[0])
self.height = len(self.board)
- def valid(self, x, y):
- return x >= 0 and x < self.width and y >= 0 and y < self.height
-
- def walk(self, x, y,
- visited_territory=[],
- visited_coords=[],
- visited_stones=[]):
- if not (x, y) in visited_coords and self.valid(x, y):
- s = self.board[y][x]
- if s in STONES:
- if s not in visited_stones:
- return (visited_territory, visited_stones + [s])
+ def valid(self, width, height):
+ return self.width > width >= 0 and self.height > height >= 0
+
+ def walk(self, width, height, visited_territory=None, visited_coords=None, visited_stones=None):
+ # Pylint gives W0102 warning if list used as default argument, because list is mutable.
+ visited_territory = [] if visited_territory is None else visited_territory
+ visited_coords = [] if visited_coords is None else visited_coords
+ visited_stones = [] if visited_stones is None else visited_stones
+
+ if (width, height) not in visited_coords and self.valid(width, height):
+ stone = self.board[height][width]
+ if stone in STONES:
+ if stone not in visited_stones:
+ return (visited_territory, visited_stones + [stone])
else: # s is empty
- for d in DIRECTIONS:
- visited = self.walk(x + d[0], y + d[1],
- visited_territory + [(x, y)],
- visited_coords + [(x, y)],
+ for direction in DIRECTIONS:
+ visited = self.walk(width + direction[0], height + direction[1],
+ visited_territory + [(width, height)],
+ visited_coords + [(width, height)],
visited_stones)
visited_territory = visited[0]
visited_stones = visited[1]
@@ -50,12 +52,12 @@ def territory(self, x, y):
def territories(self):
owners = STONES + [NONE]
- result = dict([(owner, set()) for owner in owners])
+ result = {owner:set() for owner in owners}
visited = set()
- for y in range(self.height):
- for x in range(self.width):
- if not (x, y) in visited:
- owner, owned_territories = self.territory(x, y)
+ for row in range(self.height):
+ for column in range(self.width):
+ if not (column, row) in visited:
+ owner, owned_territories = self.territory(column, row)
result[owner].update(owned_territories)
visited.update(owned_territories)
diff --git a/exercises/practice/grade-school/.meta/example.py b/exercises/practice/grade-school/.meta/example.py
index a4b9fd4fe21..fc974919e7e 100644
--- a/exercises/practice/grade-school/.meta/example.py
+++ b/exercises/practice/grade-school/.meta/example.py
@@ -2,7 +2,7 @@
class School:
- def __init__(self,):
+ def __init__(self):
self.db = {}
self.add = []
diff --git a/exercises/practice/grains/.meta/example.py b/exercises/practice/grains/.meta/example.py
index 08fa34a6f5b..8610d32b52f 100644
--- a/exercises/practice/grains/.meta/example.py
+++ b/exercises/practice/grains/.meta/example.py
@@ -1,10 +1,10 @@
def square(number):
if number == 0:
- raise ValueError("square must be between 1 and 64")
+ raise ValueError('square must be between 1 and 64')
elif number < 0:
- raise ValueError("square must be between 1 and 64")
+ raise ValueError('square must be between 1 and 64')
elif number > 64:
- raise ValueError("square must be between 1 and 64")
+ raise ValueError('square must be between 1 and 64')
return 2 ** (number - 1)
diff --git a/exercises/practice/grep/.meta/example.py b/exercises/practice/grep/.meta/example.py
index 838b4df79ab..e0ffbfe2db1 100644
--- a/exercises/practice/grep/.meta/example.py
+++ b/exercises/practice/grep/.meta/example.py
@@ -27,7 +27,7 @@ def format_lines(matched_lines, flags, files):
result = []
for file_name, line_number, line in matched_lines:
- line_result = ""
+ line_result = ''
if len(files) > 1:
line_result += file_name + ':'
@@ -46,7 +46,7 @@ def grep(pattern, flags, files):
matched_lines = []
for file_name in files:
- with open(file_name) as f:
+ with open(file_name, encoding='utf-8') as f:
for line_number, line in enumerate(f.readlines(), start=1):
if matches(line, pattern, flags):
matched_lines.append((file_name, line_number, line))
diff --git a/exercises/practice/hamming/.meta/example.py b/exercises/practice/hamming/.meta/example.py
index 29a3de356cf..d6a3848eff3 100644
--- a/exercises/practice/hamming/.meta/example.py
+++ b/exercises/practice/hamming/.meta/example.py
@@ -1,5 +1,5 @@
-def distance(s1, s2):
- if len(s1) != len(s2):
- raise ValueError("Strands must be of equal length.")
+def distance(strand_a, strand_b):
+ if len(strand_a) != len(strand_b):
+ raise ValueError('Strands must be of equal length.')
- return sum(a != b for a, b in zip(s1, s2))
+ return sum(a_part != b_part for a_part, b_part in zip(strand_a, strand_b))
diff --git a/exercises/practice/hangman/.meta/example.py b/exercises/practice/hangman/.meta/example.py
index 9ce060c9ca3..b0316860956 100644
--- a/exercises/practice/hangman/.meta/example.py
+++ b/exercises/practice/hangman/.meta/example.py
@@ -1,6 +1,6 @@
-STATUS_WIN = "win"
-STATUS_LOSE = "lose"
-STATUS_ONGOING = "ongoing"
+STATUS_WIN = 'win'
+STATUS_LOSE = 'lose'
+STATUS_ONGOING = 'ongoing'
class Hangman:
@@ -10,12 +10,12 @@ def __init__(self, word):
self.word = word
self.masked_word = ''
self.guesses = []
- for i in self.word:
+ for _ in self.word:
self.masked_word += '_'
def guess(self, char):
if self.status != STATUS_ONGOING:
- raise ValueError("The game has already ended.")
+ raise ValueError('The game has already ended.')
self.update_remaining_guesses(char)
self.update_masked_word()
@@ -23,11 +23,11 @@ def guess(self, char):
def update_masked_word(self):
self.masked_word = ''
- for i in self.word:
- if i not in self.guesses:
+ for idx in self.word:
+ if idx not in self.guesses:
self.masked_word += '_'
else:
- self.masked_word += i
+ self.masked_word += idx
def update_remaining_guesses(self, char):
if char not in self.word or char in self.guesses:
diff --git a/exercises/practice/hangman/hangman.py b/exercises/practice/hangman/hangman.py
index 9385d240b32..5f0db276c06 100644
--- a/exercises/practice/hangman/hangman.py
+++ b/exercises/practice/hangman/hangman.py
@@ -1,8 +1,8 @@
# Game status categories
# Change the values as you see fit
-STATUS_WIN = "win"
-STATUS_LOSE = "lose"
-STATUS_ONGOING = "ongoing"
+STATUS_WIN = 'win'
+STATUS_LOSE = 'lose'
+STATUS_ONGOING = 'ongoing'
class Hangman:
diff --git a/exercises/practice/hexadecimal/.meta/example.py b/exercises/practice/hexadecimal/.meta/example.py
index 63fb8b948d3..672321a8929 100644
--- a/exercises/practice/hexadecimal/.meta/example.py
+++ b/exercises/practice/hexadecimal/.meta/example.py
@@ -1,10 +1,10 @@
from functools import reduce
-def hexa(hex_str):
- hex_str = hex_str.lower()
- if set(hex_str) - set('0123456789abcdef'):
+def hexa(hex_string):
+ hex_string = hex_string.lower()
+ if set(hex_string) - set('0123456789abcdef'):
raise ValueError('Invalid hexadecimal string')
- digits = [ord(c) - ord('a') + 10 if c in 'abcdef' else ord(c) - ord('0')
- for c in hex_str]
- return reduce(lambda x, y: x * 16 + y, digits, 0)
+ digits = [ord(letter) - ord('a') + 10 if letter in 'abcdef' else ord(letter) - ord('0')
+ for letter in hex_string]
+ return reduce(lambda var_1, var_2: var_1 * 16 + var_2, digits, 0)
diff --git a/exercises/practice/house/.meta/example.py b/exercises/practice/house/.meta/example.py
index f3cc4b80bde..30e289b9195 100644
--- a/exercises/practice/house/.meta/example.py
+++ b/exercises/practice/house/.meta/example.py
@@ -1,4 +1,4 @@
-parts = [('lay in', 'the house that Jack built.'),
+PARTS = [('lay in', 'the house that Jack built.'),
('ate', 'the malt'),
('killed', 'the rat'),
('worried', 'the cat'),
@@ -13,14 +13,11 @@
def verse(verse_num):
- v = ['This is {}'.format(parts[verse_num][1])]
- v.extend(['that {0} {1}'.format(*parts[i])
- for i in range(verse_num - 1, -1, -1)])
- return ' '.join(v)
+ verse = [f'This is {PARTS[verse_num][1]}']
+ verse.extend(['that {0} {1}'.format(*PARTS[idx])
+ for idx in range(verse_num - 1, -1, -1)])
+ return ' '.join(verse)
def recite(start_verse, end_verse):
- result = []
- for verse_num in range(start_verse-1, end_verse):
- result.append(verse(verse_num))
- return result
+ return [verse(verse_num) for verse_num in range(start_verse-1, end_verse)]
diff --git a/exercises/practice/isogram/.meta/example.py b/exercises/practice/isogram/.meta/example.py
index e205199c02a..17058775b31 100644
--- a/exercises/practice/isogram/.meta/example.py
+++ b/exercises/practice/isogram/.meta/example.py
@@ -1,3 +1,3 @@
def is_isogram(string):
- characters_lower = [c.lower() for c in string if c.isalpha()]
+ characters_lower = [char.lower() for char in string if char.isalpha()]
return len(set(characters_lower)) == len(characters_lower)
diff --git a/exercises/practice/kindergarten-garden/.meta/example.py b/exercises/practice/kindergarten-garden/.meta/example.py
index bc3ebdc5a0a..262c6ad6e22 100644
--- a/exercises/practice/kindergarten-garden/.meta/example.py
+++ b/exercises/practice/kindergarten-garden/.meta/example.py
@@ -1,20 +1,20 @@
class Garden:
STUDENTS = [
- "Alice",
- "Bob",
- "Charlie",
- "David",
- "Eve",
- "Fred",
- "Ginny",
- "Harriet",
- "Ileana",
- "Joseph",
- "Kincaid",
- "Larry",
+ 'Alice',
+ 'Bob',
+ 'Charlie',
+ 'David',
+ 'Eve',
+ 'Fred',
+ 'Ginny',
+ 'Harriet',
+ 'Ileana',
+ 'Joseph',
+ 'Kincaid',
+ 'Larry',
]
- PLANTS = {"C": "Clover", "G": "Grass", "R": "Radishes", "V": "Violets"}
+ PLANTS = {'C': 'Clover', 'G': 'Grass', 'R': 'Radishes', 'V': 'Violets'}
def __init__(self, diagram, students=None):
students = sorted(students or self.STUDENTS)
@@ -25,10 +25,10 @@ def __init__(self, diagram, students=None):
stop = start + 2
self.cups.setdefault(student, [])
self.cups[student].extend(
- self.PLANTS[p] for p in front[start:stop]
+ self.PLANTS[plant] for plant in front[start:stop]
)
self.cups[student].extend(
- self.PLANTS[p] for p in back[start:stop]
+ self.PLANTS[plant] for plant in back[start:stop]
)
def plants(self, student):
diff --git a/exercises/practice/knapsack/.meta/example.py b/exercises/practice/knapsack/.meta/example.py
index 9f63441d07e..548dd5a2b92 100644
--- a/exercises/practice/knapsack/.meta/example.py
+++ b/exercises/practice/knapsack/.meta/example.py
@@ -4,9 +4,9 @@ def maximum_value(maximum_weight, items):
for weight in range(1, maximum_weight + 1):
for index, item in enumerate(items, 1):
- if item["weight"] <= weight:
- value = item["value"] + \
- totals[weight - item["weight"]][index - 1]
+ if item['weight'] <= weight:
+ value = item['value'] + \
+ totals[weight - item['weight']][index - 1]
value_without_item = totals[weight][index - 1]
totals[weight][index] = max(value, value_without_item)
From 121c1a975bab6e80ee6445cb34b138e39fc5175e Mon Sep 17 00:00:00 2001
From: Job van der Wal <48634934+J08K@users.noreply.github.com>
Date: Thu, 18 Nov 2021 20:23:55 +0100
Subject: [PATCH 0019/1546] [Linting]: Lint practice stub files (3 / ?) (#2790)
* Another one off the list
* Update for suggestion
---
exercises/practice/darts/.meta/example.py | 2 +-
.../practice/diffie-hellman/.meta/example.py | 8 +--
.../practice/dnd-character/.meta/example.py | 4 +-
exercises/practice/dominoes/.meta/example.py | 4 +-
exercises/practice/dot-dsl/.meta/example.py | 12 ++---
.../practice/error-handling/.meta/example.py | 6 +--
exercises/practice/etl/.meta/example.py | 4 +-
.../practice/food-chain/.meta/example.py | 50 +++++++++----------
exercises/practice/forth/.meta/example.py | 16 +++---
9 files changed, 52 insertions(+), 54 deletions(-)
diff --git a/exercises/practice/darts/.meta/example.py b/exercises/practice/darts/.meta/example.py
index b83e2df5ce8..eed150cea8d 100644
--- a/exercises/practice/darts/.meta/example.py
+++ b/exercises/practice/darts/.meta/example.py
@@ -1,6 +1,6 @@
from math import sqrt
-
+# X, and Y variable names against [pylint]: C0104, but is the same as the stub, advise not to change this.
def score(x, y):
dart_location = sqrt(x * x + y * y)
diff --git a/exercises/practice/diffie-hellman/.meta/example.py b/exercises/practice/diffie-hellman/.meta/example.py
index 3a443b92586..45a547bcb75 100644
--- a/exercises/practice/diffie-hellman/.meta/example.py
+++ b/exercises/practice/diffie-hellman/.meta/example.py
@@ -5,9 +5,9 @@ def private_key(p):
return random.randint(2, p-1)
-def public_key(p, g, a):
- return pow(g, a, p)
+def public_key(p, g, private):
+ return pow(g, private, p)
-def secret(p, B, a):
- return pow(B, a, p)
+def secret(p, public, private):
+ return pow(public, private, p)
diff --git a/exercises/practice/dnd-character/.meta/example.py b/exercises/practice/dnd-character/.meta/example.py
index 29a5cfb5a08..fad3dfe172d 100644
--- a/exercises/practice/dnd-character/.meta/example.py
+++ b/exercises/practice/dnd-character/.meta/example.py
@@ -13,9 +13,7 @@ def __init__(self):
self.hitpoints = 10 + modifier(self.constitution)
def ability(self):
- dice_rolls = sorted(
- [random.randint(1, 6)
- for _ in range(4)])
+ dice_rolls = sorted(random.randint(1, 6) for _ in range(4))
return sum(dice_rolls[1:])
diff --git a/exercises/practice/dominoes/.meta/example.py b/exercises/practice/dominoes/.meta/example.py
index ea261e01e20..2490525ad67 100644
--- a/exercises/practice/dominoes/.meta/example.py
+++ b/exercises/practice/dominoes/.meta/example.py
@@ -2,8 +2,8 @@
from functools import reduce
-def swap(a, b):
- return (b, a)
+def swap(item_1, item_2):
+ return (item_2, item_1)
def build_chain(chain, domino):
diff --git a/exercises/practice/dot-dsl/.meta/example.py b/exercises/practice/dot-dsl/.meta/example.py
index 1bdc96982b1..9229cc41080 100644
--- a/exercises/practice/dot-dsl/.meta/example.py
+++ b/exercises/practice/dot-dsl/.meta/example.py
@@ -32,24 +32,24 @@ def __init__(self, data=None):
data = []
if not isinstance(data, list):
- raise TypeError("Graph data malformed")
+ raise TypeError('Graph data malformed')
for item in data:
if len(item) < 3:
- raise TypeError("Graph item incomplete")
+ raise TypeError('Graph item incomplete')
type_ = item[0]
if type_ == ATTR:
if len(item) != 3:
- raise ValueError("Attribute is malformed")
+ raise ValueError('Attribute is malformed')
self.attrs[item[1]] = item[2]
elif type_ == NODE:
if len(item) != 3:
- raise ValueError("Node is malformed")
+ raise ValueError('Node is malformed')
self.nodes.append(Node(item[1], item[2]))
elif type_ == EDGE:
if len(item) != 4:
- raise ValueError("Edge is malformed")
+ raise ValueError('Edge is malformed')
self.edges.append(Edge(item[1], item[2], item[3]))
else:
- raise ValueError("Unknown item")
+ raise ValueError('Unknown item')
diff --git a/exercises/practice/error-handling/.meta/example.py b/exercises/practice/error-handling/.meta/example.py
index b7886de1689..1dba190d4f6 100644
--- a/exercises/practice/error-handling/.meta/example.py
+++ b/exercises/practice/error-handling/.meta/example.py
@@ -1,5 +1,5 @@
def handle_error_by_throwing_exception():
- raise Exception("Meaningful message describing the source of the error")
+ raise Exception('Meaningful message describing the source of the error')
def handle_error_by_returning_none(input_data):
@@ -17,5 +17,5 @@ def handle_error_by_returning_tuple(input_data):
def filelike_objects_are_closed_on_exception(filelike_object):
- with filelike_object as fobj:
- fobj.do_something()
+ with filelike_object as file_obj:
+ file_obj.do_something()
diff --git a/exercises/practice/etl/.meta/example.py b/exercises/practice/etl/.meta/example.py
index 39fc0d10363..0e2b658249e 100644
--- a/exercises/practice/etl/.meta/example.py
+++ b/exercises/practice/etl/.meta/example.py
@@ -1,6 +1,6 @@
-def transform(old):
+def transform(legacy_data):
return {
letter.lower(): points
- for points, letters in old.items()
+ for points, letters in legacy_data.items()
for letter in letters
}
diff --git a/exercises/practice/food-chain/.meta/example.py b/exercises/practice/food-chain/.meta/example.py
index 7302eb96e3d..075f83fafa2 100644
--- a/exercises/practice/food-chain/.meta/example.py
+++ b/exercises/practice/food-chain/.meta/example.py
@@ -1,25 +1,25 @@
-def chain():
+def get_song():
- animals = ["fly", "spider", "bird", "cat", "dog", "goat", "cow", "horse"]
+ animals = ['fly', 'spider', 'bird', 'cat', 'dog', 'goat', 'cow', 'horse']
- phrases = [" wriggled and jiggled and tickled inside her.",
- "How absurd to swallow a bird!",
- "Imagine that, to swallow a cat!",
- "What a hog, to swallow a dog!",
- "Just opened her throat and swallowed a goat!",
+ phrases = [' wriggled and jiggled and tickled inside her.',
+ 'How absurd to swallow a bird!',
+ 'Imagine that, to swallow a cat!',
+ 'What a hog, to swallow a dog!',
+ 'Just opened her throat and swallowed a goat!',
"I don't know how she swallowed a cow!",
"She's dead, of course!"]
- old_lady = "I know an old lady who swallowed a "
- swallowed = "She swallowed the to catch the "
+ old_lady = 'I know an old lady who swallowed a '
+ swallowed = 'She swallowed the to catch the '
die = "I don't know why she swallowed the fly. Perhaps she'll die."
- song = ""
- verse = ""
- chain = ""
+ song = ''
+ verse = ''
+ chain = ''
for number, animal in enumerate(animals):
- verse = old_lady + animal + ".\n"
+ verse = old_lady + animal + '.\n'
if number == 7:
verse += phrases[6]
@@ -27,19 +27,19 @@ def chain():
if number == 0:
chain = swallowed + animal + '.\n'
elif number == 1:
- verse += "It" + phrases[0] + "\n"
- chain = chain.replace("", animal)
+ verse += 'It' + phrases[0] + '\n'
+ chain = chain.replace('', animal)
verse += chain
- chain = swallowed+animal+" that"+phrases[0]+"\n"+chain
+ chain = swallowed + animal + ' that' + phrases[0] + '\n' + chain
else:
- verse += phrases[number-1] + "\n"
- chain = chain.replace("", animal)
+ verse += phrases[number-1] + '\n'
+ chain = chain.replace('', animal)
verse += chain
- chain = swallowed + animal + ".\n" + chain
+ chain = swallowed + animal + '.\n' + chain
- verse += die + "\n"
+ verse += die + '\n'
- verse += "\n"
+ verse += '\n'
song += verse
return song
@@ -50,13 +50,13 @@ def verses(letter):
def recite(start_verse, end_verse):
- generated = [verse.strip().split("\n") for verse in verses(chain())]
+ generated = [verse.strip().split('\n') for verse in verses(get_song())]
if start_verse == end_verse:
- return generated[start_verse-1]
+ return generated[start_verse - 1]
else:
result = []
- for i in range(start_verse-1, end_verse):
- result += generated[i] + [""]
+ for idx in range(start_verse - 1, end_verse):
+ result += generated[idx] + ['']
# Pop out the last empty string
result.pop()
diff --git a/exercises/practice/forth/.meta/example.py b/exercises/practice/forth/.meta/example.py
index ce9173f5385..5e499acf53d 100644
--- a/exercises/practice/forth/.meta/example.py
+++ b/exercises/practice/forth/.meta/example.py
@@ -24,11 +24,11 @@ def evaluate(input_data):
values.pop(0)
key = values.pop(0).lower()
if is_integer(key):
- raise ValueError("illegal operation")
+ raise ValueError('illegal operation')
defines[key] = [
- x
- for v in values
- for x in defines.get(v, [v])
+ idx
+ for vivaldi in values
+ for idx in defines.get(vivaldi, [vivaldi])
]
stack = []
input_data = input_data[-1].split()
@@ -48,7 +48,7 @@ def evaluate(input_data):
elif word == '/':
divisor = stack.pop()
if divisor == 0:
- raise ZeroDivisionError("divide by zero")
+ raise ZeroDivisionError('divide by zero')
stack.append(int(stack.pop() / divisor))
elif word == 'dup':
stack.append(stack[-1])
@@ -60,7 +60,7 @@ def evaluate(input_data):
elif word == 'over':
stack.append(stack[-2])
else:
- raise ValueError("undefined operation")
- except IndexError:
- raise StackUnderflowError("Insufficient number of items in stack")
+ raise ValueError('undefined operation')
+ except IndexError as error:
+ raise StackUnderflowError('Insufficient number of items in stack') from error
return stack
From 816942b35d8dccb5e0f5432aafe14b694bca296b Mon Sep 17 00:00:00 2001
From: Job van der Wal <48634934+J08K@users.noreply.github.com>
Date: Thu, 18 Nov 2021 22:22:32 +0100
Subject: [PATCH 0020/1546] [Linting]: Lint practice stub files (2 / ?) (#2789)
* First three fixed files
* atbash-cipher
* next two
* Another 2
* Update exercises/practice/alphametics/.meta/example.py
Co-authored-by: BethanyG
* Update exercises/practice/atbash-cipher/.meta/example.py
Co-authored-by: BethanyG
* Apply suggestions from code review
Co-authored-by: BethanyG
* Fix test failing; Fix oversights
* lol
* Fixed some stuff
* BOBBY!!
* affine cipher
* B and C
* Apply suggestions from code review
Co-authored-by: BethanyG
---
.../practice/book-store/.meta/example.py | 12 ++--
exercises/practice/bowling/.meta/example.py | 16 ++---
exercises/practice/change/.meta/example.py | 4 +-
.../practice/circular-buffer/.meta/example.py | 4 +-
exercises/practice/clock/.meta/example.py | 4 +-
.../collatz-conjecture/.meta/example.py | 18 ++---
.../practice/complex-numbers/.meta/example.py | 22 +++----
exercises/practice/connect/.meta/example.py | 66 ++++++++++---------
.../practice/crypto-square/.meta/example.py | 7 +-
.../practice/custom-set/.meta/example.py | 24 +++----
10 files changed, 88 insertions(+), 89 deletions(-)
diff --git a/exercises/practice/book-store/.meta/example.py b/exercises/practice/book-store/.meta/example.py
index dd197c0f71d..f6cce8c4436 100644
--- a/exercises/practice/book-store/.meta/example.py
+++ b/exercises/practice/book-store/.meta/example.py
@@ -10,9 +10,9 @@
}
-def _total(books):
- volumes = Counter(books)
- price = len(books) * PER_BOOK
+def _total(basket):
+ volumes = Counter(basket)
+ price = len(basket) * PER_BOOK
for size in range(len(volumes), 1, -1):
group = volumes - Counter(k for k, _ in volumes.most_common(size))
group_books = sorted(group.elements())
@@ -20,7 +20,7 @@ def _total(books):
return price
-def total(books):
- if not books:
+def total(basket):
+ if not basket:
return 0
- return _total(sorted(books))
+ return _total(sorted(basket))
diff --git a/exercises/practice/bowling/.meta/example.py b/exercises/practice/bowling/.meta/example.py
index c5182a899c9..7afb0d63f8d 100644
--- a/exercises/practice/bowling/.meta/example.py
+++ b/exercises/practice/bowling/.meta/example.py
@@ -59,26 +59,26 @@ def next_throws(self, frame_idx):
def roll_bonus(self, pins):
tenth_frame = self.frames[-1]
if tenth_frame.is_open():
- raise IndexError("cannot throw bonus with an open tenth frame")
+ raise IndexError('cannot throw bonus with an open tenth frame')
self.bonus_throws.append(pins)
# Check against invalid fill balls, e.g. [3, 10]
if (len(self.bonus_throws) == 2 and self.bonus_throws[0] != 10 and
sum(self.bonus_throws) > 10):
- raise ValueError("invalid fill balls")
+ raise ValueError('invalid fill balls')
# Check if there are more bonuses than it should be
if tenth_frame.is_strike() and len(self.bonus_throws) > 2:
raise IndexError(
- "wrong number of fill balls when the tenth frame is a strike")
+ 'wrong number of fill balls when the tenth frame is a strike')
elif tenth_frame.is_spare() and len(self.bonus_throws) > 1:
raise IndexError(
- "wrong number of fill balls when the tenth frame is a spare")
+ 'wrong number of fill balls when the tenth frame is a spare')
def roll(self, pins):
if not 0 <= pins <= 10:
- raise ValueError("invalid pins")
+ raise ValueError('invalid pins')
elif self.current_frame_idx == MAX_FRAME:
self.roll_bonus(pins)
else:
@@ -88,12 +88,12 @@ def roll(self, pins):
def score(self):
if self.current_frame_idx < MAX_FRAME:
- raise IndexError("frame less than 10")
+ raise IndexError('frame less than 10')
if self.frames[-1].is_spare() and len(self.bonus_throws) != 1:
raise IndexError(
- "one bonus must be rolled when the tenth frame is spare")
+ 'one bonus must be rolled when the tenth frame is spare')
if self.frames[-1].is_strike() and len(self.bonus_throws) != 2:
raise IndexError(
- "two bonuses must be rolled when the tenth frame is strike")
+ 'two bonuses must be rolled when the tenth frame is strike')
return sum(frame.score(self.next_throws(frame.idx))
for frame in self.frames)
diff --git a/exercises/practice/change/.meta/example.py b/exercises/practice/change/.meta/example.py
index b5e163e9415..b62fa0cc10c 100644
--- a/exercises/practice/change/.meta/example.py
+++ b/exercises/practice/change/.meta/example.py
@@ -2,7 +2,7 @@ def find_fewest_coins(coins, target):
if target < 0:
raise ValueError("target can't be negative")
min_coins_required = [1e9] * (target + 1)
- last_coin = [0]*(target + 1)
+ last_coin = [0] * (target + 1)
min_coins_required[0] = 0
last_coin[0] = -1
for change in range(1, target + 1):
@@ -19,7 +19,7 @@ def find_fewest_coins(coins, target):
else:
last_coin_value = target
array = []
- while(last_coin[last_coin_value] != -1):
+ while last_coin[last_coin_value] != -1:
array.append(last_coin_value-last_coin[last_coin_value])
last_coin_value = last_coin[last_coin_value]
return array
diff --git a/exercises/practice/circular-buffer/.meta/example.py b/exercises/practice/circular-buffer/.meta/example.py
index 16a70282856..8438b9839fc 100644
--- a/exercises/practice/circular-buffer/.meta/example.py
+++ b/exercises/practice/circular-buffer/.meta/example.py
@@ -37,7 +37,7 @@ def clear(self):
def write(self, data):
if all(self.buffer):
- raise BufferFullException("Circular buffer is full")
+ raise BufferFullException('Circular buffer is full')
self._update_buffer(data)
self.write_point = (self.write_point + 1) % len(self.buffer)
@@ -49,7 +49,7 @@ def overwrite(self, data):
def read(self):
if not any(self.buffer):
- raise BufferEmptyException("Circular buffer is empty")
+ raise BufferEmptyException('Circular buffer is empty')
data = chr(self.buffer[self.read_point])
self.buffer[self.read_point] = 0
self.read_point = (self.read_point + 1) % len(self.buffer)
diff --git a/exercises/practice/clock/.meta/example.py b/exercises/practice/clock/.meta/example.py
index 7c146d930a6..0c76dca2ce0 100644
--- a/exercises/practice/clock/.meta/example.py
+++ b/exercises/practice/clock/.meta/example.py
@@ -1,5 +1,5 @@
class Clock:
- 'Clock that displays 24 hour clock that rollsover properly'
+ """Clock that displays 24 hour clock that rollsover properly"""
def __init__(self, hour, minute):
self.hour = hour
@@ -7,7 +7,7 @@ def __init__(self, hour, minute):
self.cleanup()
def __repr__(self):
- return "{:02d}:{:02d}".format(self.hour, self.minute)
+ return '{:02d}:{:02d}'.format(self.hour, self.minute)
def __eq__(self, other):
return repr(self) == repr(other)
diff --git a/exercises/practice/collatz-conjecture/.meta/example.py b/exercises/practice/collatz-conjecture/.meta/example.py
index a73acdf1fb5..108b320e8db 100644
--- a/exercises/practice/collatz-conjecture/.meta/example.py
+++ b/exercises/practice/collatz-conjecture/.meta/example.py
@@ -1,17 +1,17 @@
-def steps(n):
- if n <= 0:
- raise ValueError("Only positive numbers are allowed")
+def steps(number):
+ if number <= 0:
+ raise ValueError('Only positive numbers are allowed')
step_count = 0
- while n > 1:
- if is_odd(n):
- n = n * 3 + 1
+ while number > 1:
+ if is_odd(number):
+ number = number * 3 + 1
else:
- n = n / 2
+ number = number / 2
step_count += 1
return step_count
-def is_odd(n):
- return n % 2 == 1
+def is_odd(number):
+ return number % 2 == 1
diff --git a/exercises/practice/complex-numbers/.meta/example.py b/exercises/practice/complex-numbers/.meta/example.py
index 4522868f8fb..b833c38fc97 100644
--- a/exercises/practice/complex-numbers/.meta/example.py
+++ b/exercises/practice/complex-numbers/.meta/example.py
@@ -6,13 +6,13 @@ def __init__(self, real=0, imaginary=0):
self.imaginary = imaginary
def __eq__(self, other):
- if not type(other) == ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
return self.real == other.real and self.imaginary == other.imaginary
def __add__(self, other):
- if not type(other) is ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
real_part = self.real + other.real
@@ -22,7 +22,7 @@ def __add__(self, other):
def __radd__(self, other):
- if not type(other) is ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
real_part = self.real + other.real
@@ -31,7 +31,7 @@ def __radd__(self, other):
return ComplexNumber(real_part, imaginary_part)
def __mul__(self, other):
- if not type(other) == ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
real_part = self.real * other.real - self.imaginary * other.imaginary
@@ -39,7 +39,7 @@ def __mul__(self, other):
return ComplexNumber(real_part, imaginary_part)
def __rmul__(self, other):
- if not type(other) == ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
real_part = self.real * other.real - self.imaginary * other.imaginary
@@ -47,14 +47,14 @@ def __rmul__(self, other):
return ComplexNumber(real_part, imaginary_part)
def __sub__(self, other):
- if not type(other) == ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
real_part = self.real - other.real
imaginary_part = self.imaginary - other.imaginary
return ComplexNumber(real_part, imaginary_part)
def __rsub__(self, other):
- if not type(other) == ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
real_part = other.real - self.real
@@ -62,7 +62,7 @@ def __rsub__(self, other):
return ComplexNumber(real_part, imaginary_part)
def __truediv__(self, other):
- if not type(other) == ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
conjugation = other.conjugate()
@@ -70,10 +70,10 @@ def __truediv__(self, other):
denominator = denominator_all.real
numerator = self * conjugation
- return ComplexNumber((numerator.real/denominator), (numerator.imaginary/denominator))
+ return ComplexNumber((numerator.real / denominator), (numerator.imaginary / denominator))
def __rtruediv__(self, other):
- if not type(other) == ComplexNumber:
+ if not isinstance(other, ComplexNumber):
other = ComplexNumber(other)
conjugation = self.conjugate()
@@ -81,7 +81,7 @@ def __rtruediv__(self, other):
denominator = float(denominator_all.real)
numerator = other * conjugation
- return ComplexNumber((numerator.real/denominator), (numerator.imaginary/denominator))
+ return ComplexNumber((numerator.real / denominator), (numerator.imaginary / denominator))
def __abs__(self):
square_sum = self.real * self.real + self.imaginary * self.imaginary
diff --git a/exercises/practice/connect/.meta/example.py b/exercises/practice/connect/.meta/example.py
index f54c77e0cca..0cb00334831 100644
--- a/exercises/practice/connect/.meta/example.py
+++ b/exercises/practice/connect/.meta/example.py
@@ -1,10 +1,9 @@
class ConnectGame:
- directions = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, -1), (-1, 1)]
- white = "O"
- black = "X"
- none = ""
+ DIRECTIONS = [(0, 1), (0, -1), (1, 0), (-1, 0), (1, -1), (-1, 1)]
+ WHITE = 'O'
+ BLACK = 'X'
def __init__(self, lines):
self.board = ConnectGame.make_board(lines)
@@ -14,49 +13,54 @@ def __init__(self, lines):
self.height = len(self.board)
assert self.width > 0 and self.height > 0
- for l in self.board:
- assert len(l) == self.width
+ for line in self.board:
+ assert len(line) == self.width
- def valid(self, x, y):
- return 0 <= x < self.width and 0 <= y < self.height
+ def valid(self, width, height):
+ return 0 <= width < self.width and 0 <= height < self.height
@staticmethod
def make_board(lines):
- return ["".join(l.split()) for l in lines.splitlines()]
+ return [''.join(cur_line.split()) for cur_line in lines.splitlines()]
- def player_reach_dest(self, player, x, y):
- if player == self.black:
- return x == self.width - 1
- if player == self.white:
- return y == self.height - 1
+ def player_reach_dest(self, player, width, height):
+ if player == self.BLACK:
+ return width == self.width - 1
+ if player == self.WHITE:
+ return height == self.height - 1
+ return None
- def walk_board(self, player, x, y, visited=[]):
- if (x, y) in visited:
+ def walk_board(self, player, width, height, visited=None):
+ if not visited:
+ visited = []
+ if (width, height) in visited:
return False
- if (not self.valid(x, y)) or self.board[y][x] != player:
+ if (not self.valid(width, height)) or self.board[height][width] != player:
return False
- if self.player_reach_dest(player, x, y):
+ if self.player_reach_dest(player, width, height):
return True
- for d in self.directions:
- if self.walk_board(player, x + d[0], y + d[1], visited + [(x, y)]):
+ for vector in self.DIRECTIONS:
+ if self.walk_board(player, width + vector[0], height + vector[1], visited + [(width, height)]):
return True
+ return None
def check_player_is_winner(self, player):
- if player == self.black:
- for y in range(self.height):
- if self.walk_board(player, 0, y):
+ if player == self.BLACK:
+ for height in range(self.height):
+ if self.walk_board(player, 0, height):
return True
- if player == self.white:
- for x in range(self.width):
- if self.walk_board(player, x, 0):
+ if player == self.WHITE:
+ for width in range(self.width):
+ if self.walk_board(player, width, 0):
return True
+ return None
def get_winner(self):
- if self.check_player_is_winner(self.black):
- return self.black
- if self.check_player_is_winner(self.white):
- return self.white
- return self.none
+ if self.check_player_is_winner(self.BLACK):
+ return self.BLACK
+ if self.check_player_is_winner(self.WHITE):
+ return self.WHITE
+ return ''
diff --git a/exercises/practice/crypto-square/.meta/example.py b/exercises/practice/crypto-square/.meta/example.py
index 17b9bc78482..8cfc7642f0b 100644
--- a/exercises/practice/crypto-square/.meta/example.py
+++ b/exercises/practice/crypto-square/.meta/example.py
@@ -1,10 +1,5 @@
from math import ceil, sqrt
-import sys
-
-if sys.version_info[0] == 2:
- from itertools import izip_longest as zip_longest
-else:
- from itertools import zip_longest
+from itertools import zip_longest
def cipher_text(plain_text):
diff --git a/exercises/practice/custom-set/.meta/example.py b/exercises/practice/custom-set/.meta/example.py
index c0abb89c2ac..fed6acb6a05 100644
--- a/exercises/practice/custom-set/.meta/example.py
+++ b/exercises/practice/custom-set/.meta/example.py
@@ -1,6 +1,6 @@
class CustomSet:
- def __init__(self, elements=[]):
- self.elements = list(elements)
+ def __init__(self, elements=None):
+ self.elements = list(elements) if elements is not None else list([])
def isempty(self):
return not self.elements
@@ -12,10 +12,10 @@ def __contains__(self, element):
return element in self.elements
def issubset(self, other):
- return all(x in other for x in self)
+ return all(idx in other for idx in self)
def isdisjoint(self, other):
- return all(x not in other for x in self)
+ return all(idx not in other for idx in self)
def __eq__(self, other):
return self.issubset(other) and other.issubset(self)
@@ -26,20 +26,20 @@ def add(self, element):
def intersection(self, other):
result = CustomSet()
- for x in self:
- if x in other:
- result.add(x)
+ for idx in self:
+ if idx in other:
+ result.add(idx)
return result
def __sub__(self, other):
result = CustomSet()
- for x in self:
- if x not in other:
- result.add(x)
+ for idx in self:
+ if idx not in other:
+ result.add(idx)
return result
def __add__(self, other):
result = CustomSet(self.elements)
- for x in other:
- result.add(x)
+ for idx in other:
+ result.add(idx)
return result
From 839941134c48dd5ed6fc5cb92667f522f969a7e0 Mon Sep 17 00:00:00 2001
From: Job van der Wal
Date: Thu, 18 Nov 2021 15:14:15 +0100
Subject: [PATCH 0021/1546] first 5
---
.../largest-series-product/.meta/example.py | 22 +++++++++----------
exercises/practice/ledger/.meta/example.py | 12 +++++-----
.../practice/linked-list/.meta/example.py | 6 ++---
exercises/practice/luhn/.meta/example.py | 2 +-
exercises/practice/markdown/.meta/example.py | 2 +-
5 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/exercises/practice/largest-series-product/.meta/example.py b/exercises/practice/largest-series-product/.meta/example.py
index a7bbde3b0e9..c3e8298f2f3 100644
--- a/exercises/practice/largest-series-product/.meta/example.py
+++ b/exercises/practice/largest-series-product/.meta/example.py
@@ -2,22 +2,22 @@
from operator import mul
-def slices(series, length):
+def slices(series, size):
- if not length <= len(series):
- raise ValueError("span must be smaller than string length")
- elif not 0 < length:
- raise ValueError("span must be greater than zero")
+ if not size <= len(series):
+ raise ValueError('span must be smaller than string length')
+ elif not 0 < size:
+ raise ValueError('span must be greater than zero')
elif not all(item.isdigit() for item in series):
- raise ValueError("digits input must only contain digits")
+ raise ValueError('digits input must only contain digits')
numbers = [int(digit) for digit in series]
- return [numbers[i:i + length]
- for i in range(len(numbers) - length + 1)]
+ return [numbers[idx:idx + size]
+ for idx in range(len(numbers) - size + 1)]
-def largest_product(series, length):
- if length == 0:
+def largest_product(series, size):
+ if size == 0:
return 1
- return max(reduce(mul, slc) for slc in slices(series, length))
+ return max(reduce(mul, slice) for slice in slices(series, size))
diff --git a/exercises/practice/ledger/.meta/example.py b/exercises/practice/ledger/.meta/example.py
index 0fd89b6b21a..46e8e3c9f6f 100644
--- a/exercises/practice/ledger/.meta/example.py
+++ b/exercises/practice/ledger/.meta/example.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from datetime import datetime
-ROW_FMT = u'{{:<{1}}} | {{:<{2}}} | {{:{0}{3}}}'
+ROW_FMT = '{{:<{1}}} | {{:<{2}}} | {{:{0}{3}}}'
def truncate(s, length=25):
@@ -16,7 +16,7 @@ def __init__(self, locale, currency, columns):
if locale == 'en_US':
headers = ['Date', 'Description', 'Change']
self.datefmt = '{0.month:02}/{0.day:02}/{0.year:04}'
- self.cur_fmt = u'{}{}{}{}'
+ self.cur_fmt = '{}{}{}{}'
self.lead_neg = '('
self.trail_neg = ')'
self.thousands = ','
@@ -24,7 +24,7 @@ def __init__(self, locale, currency, columns):
elif locale == 'nl_NL':
headers = ['Datum', 'Omschrijving', 'Verandering']
self.datefmt = '{0.day:02}-{0.month:02}-{0.year:04}'
- self.cur_fmt = u'{1} {0}{2}{3}'
+ self.cur_fmt = '{1} {0}{2}{3}'
self.lead_neg = '-'
self.trail_neg = ' '
self.thousands = '.'
@@ -33,15 +33,15 @@ def __init__(self, locale, currency, columns):
self.headers = fmt.format(*headers)
self.cur_symbol = {
'USD': '$',
- 'EUR': u'β¬',
+ 'EUR': 'β¬',
}.get(currency)
def number(self, n):
n_int, n_float = divmod(abs(n), 100)
n_int_parts = []
while n_int > 0:
- n_int, x = divmod(n_int, 1000)
- n_int_parts.insert(0, str(x))
+ n_int, idx = divmod(n_int, 1000)
+ n_int_parts.insert(0, str(idx))
return '{}{}{:02}'.format(
self.thousands.join(n_int_parts) or '0',
self.decimal,
diff --git a/exercises/practice/linked-list/.meta/example.py b/exercises/practice/linked-list/.meta/example.py
index 5fcc303c668..280509f244b 100644
--- a/exercises/practice/linked-list/.meta/example.py
+++ b/exercises/practice/linked-list/.meta/example.py
@@ -1,8 +1,8 @@
class Node:
- def __init__(self, value, succeeding=None, prev=None):
+ def __init__(self, value, succeeding=None, previous=None):
self.value = value
self.succeeding = succeeding
- self.prev = prev
+ self.prev = previous
class LinkedList:
@@ -56,6 +56,6 @@ def __len__(self):
def __iter__(self):
current_node = self.head
- while (current_node):
+ while current_node:
yield current_node.value
current_node = current_node.succeeding
diff --git a/exercises/practice/luhn/.meta/example.py b/exercises/practice/luhn/.meta/example.py
index 1380d8c930d..32a4dbc48b9 100644
--- a/exercises/practice/luhn/.meta/example.py
+++ b/exercises/practice/luhn/.meta/example.py
@@ -2,7 +2,7 @@ class Luhn:
def __init__(self, card_num):
self.card_num = card_num
self.checksum = -1
- digits = card_num.replace(" ", "")
+ digits = card_num.replace(' ', '')
length = len(digits)
if digits.isdigit() and length > 1:
self.checksum = 0
diff --git a/exercises/practice/markdown/.meta/example.py b/exercises/practice/markdown/.meta/example.py
index 88ccf980ad7..1c9d04cf9e6 100644
--- a/exercises/practice/markdown/.meta/example.py
+++ b/exercises/practice/markdown/.meta/example.py
@@ -54,7 +54,7 @@ def parse_line(line, in_list, in_list_append):
list_match = re.match(r'\* (.*)', result)
- if (list_match):
+ if list_match:
if not in_list:
result = '
' + wrap(list_match.group(1), 'li')
in_list = True
From e5425abe1975d71a096810418c6dce55482e1992 Mon Sep 17 00:00:00 2001
From: Job van der Wal
Date: Thu, 18 Nov 2021 20:36:34 +0100
Subject: [PATCH 0022/1546] First files
---
exercises/practice/matrix/.meta/example.py | 6 ++--
.../practice/minesweeper/.meta/example.py | 10 +++---
.../nucleotide-count/.meta/example.py | 2 +-
.../practice/ocr-numbers/.meta/example.py | 14 ++++-----
exercises/practice/octal/.meta/example.py | 10 +++---
.../palindrome-products/.meta/example.py | 31 +++++++++----------
.../.meta/example.py | 23 ++++++--------
.../pascals-triangle/.meta/example.py | 10 +++---
8 files changed, 51 insertions(+), 55 deletions(-)
diff --git a/exercises/practice/matrix/.meta/example.py b/exercises/practice/matrix/.meta/example.py
index 3aae9ed4b7d..3c89844bee8 100644
--- a/exercises/practice/matrix/.meta/example.py
+++ b/exercises/practice/matrix/.meta/example.py
@@ -1,7 +1,7 @@
class Matrix:
- def __init__(self, s):
- self.rows = [[int(n) for n in row.split()]
- for row in s.split('\n')]
+ def __init__(self, matrix_string):
+ self.rows = [[int(number) for number in row.split()]
+ for row in matrix_string.split('\n')]
self.columns = [list(tup) for tup in zip(*self.rows)]
def row(self, index):
diff --git a/exercises/practice/minesweeper/.meta/example.py b/exercises/practice/minesweeper/.meta/example.py
index 53ff051b83b..4ebbc8413b8 100644
--- a/exercises/practice/minesweeper/.meta/example.py
+++ b/exercises/practice/minesweeper/.meta/example.py
@@ -15,26 +15,26 @@ def annotate(minefield):
high = min(index2 + 2, row_len + 2)
counts = minefield[index1][low:high].count('*')
- if(index1 > 0):
+ if index1 > 0:
counts += minefield[index1 - 1][low:high].count('*')
- if(index1 < col_len - 1):
+ if index1 < col_len - 1:
counts += minefield[index1 + 1][low:high].count('*')
if counts == 0:
continue
board[index1][index2] = str(counts)
- return ["".join(row) for row in board]
+ return [''.join(row) for row in board]
def verify_board(minefield):
# Rows with different lengths
row_len = len(minefield[0])
if not all(len(row) == row_len for row in minefield):
- raise ValueError("The board is invalid with current input.")
+ raise ValueError('The board is invalid with current input.')
# Unknown character in board
character_set = set()
for row in minefield:
character_set.update(row)
if character_set - set(' *'):
- raise ValueError("The board is invalid with current input.")
+ raise ValueError('The board is invalid with current input.')
diff --git a/exercises/practice/nucleotide-count/.meta/example.py b/exercises/practice/nucleotide-count/.meta/example.py
index 83de60a0cbd..e79a6a7ec7d 100644
--- a/exercises/practice/nucleotide-count/.meta/example.py
+++ b/exercises/practice/nucleotide-count/.meta/example.py
@@ -15,4 +15,4 @@ def nucleotide_counts(strand):
def _validate(abbreviation):
if abbreviation not in NUCLEOTIDES:
- raise ValueError('{} is not a nucleotide.'.format(abbreviation))
+ raise ValueError(f'{abbreviation} is not a nucleotide.')
diff --git a/exercises/practice/ocr-numbers/.meta/example.py b/exercises/practice/ocr-numbers/.meta/example.py
index 17f1e8bbed3..bc926487ef4 100644
--- a/exercises/practice/ocr-numbers/.meta/example.py
+++ b/exercises/practice/ocr-numbers/.meta/example.py
@@ -3,8 +3,8 @@
def split_ocr(ocr):
- return [[ocr[i][NUM_COLS * j:NUM_COLS * (j + 1)] for i in range(NUM_ROWS)]
- for j in range(len(ocr[0]) // NUM_COLS)]
+ return [[ocr[idx][NUM_COLS * jam:NUM_COLS * (jam + 1)] for idx in range(NUM_ROWS)]
+ for jam in range(len(ocr[0]) // NUM_COLS)]
ALL = [' _ _ _ _ _ _ _ _ ',
@@ -23,21 +23,21 @@ def convert(input_grid):
lines = [input_grid[start:end]
for start, end in zip(split_indices[:-1], split_indices[1:])]
- return ",".join(convert_one_line(line) for line in lines)
+ return ','.join(convert_one_line(line) for line in lines)
def convert_one_line(input_grid):
if len(input_grid) != NUM_ROWS:
- raise ValueError("Number of input lines is not a multiple of four")
+ raise ValueError('Number of input lines is not a multiple of four')
if len(input_grid[0]) % NUM_COLS:
- raise ValueError("Number of input columns is not a multiple of three")
+ raise ValueError('Number of input columns is not a multiple of three')
numbers = split_ocr(input_grid)
digits = ''
- for n in numbers:
+ for num in numbers:
try:
- digits += str(OCR_LIST.index(n))
+ digits += str(OCR_LIST.index(num))
except ValueError:
digits += '?'
return digits
diff --git a/exercises/practice/octal/.meta/example.py b/exercises/practice/octal/.meta/example.py
index 9cf4365fcf2..86000ee4d34 100644
--- a/exercises/practice/octal/.meta/example.py
+++ b/exercises/practice/octal/.meta/example.py
@@ -1,11 +1,11 @@
def parse_octal(digits):
digits = _validate_octal(digits)
- return sum(int(digit) * 8 ** i
- for (i, digit) in enumerate(reversed(digits)))
+ return sum(int(digit) * 8 ** idx
+ for (idx, digit) in enumerate(reversed(digits)))
def _validate_octal(digits):
- for d in digits:
- if not '0' <= d < '8':
- raise ValueError("Invalid octal digit: " + d)
+ for digit in digits:
+ if not '0' <= digit < '8':
+ raise ValueError("Invalid octal digit: " + digit)
return digits
diff --git a/exercises/practice/palindrome-products/.meta/example.py b/exercises/practice/palindrome-products/.meta/example.py
index d74e737f745..f656ff18522 100644
--- a/exercises/practice/palindrome-products/.meta/example.py
+++ b/exercises/practice/palindrome-products/.meta/example.py
@@ -3,16 +3,15 @@
def largest(min_factor, max_factor):
- return get_extreme_palindrome_with_factors(max_factor, min_factor, "largest")
+ return get_extreme_palindrome_with_factors(max_factor, min_factor, 'largest')
def smallest(max_factor, min_factor):
- return get_extreme_palindrome_with_factors(max_factor, min_factor, "smallest")
+ return get_extreme_palindrome_with_factors(max_factor, min_factor, 'smallest')
def get_extreme_palindrome_with_factors(max_factor, min_factor, extreme):
- palindromes_found = palindromes(max_factor, min_factor,
- reverse=(extreme == "largest"))
+ palindromes_found = palindromes(max_factor, min_factor, reverse=(extreme == 'largest'))
factor_pairs = None
for palindrome in palindromes_found:
factor_pairs = ((factor, palindrome // factor)
@@ -30,12 +29,12 @@ def get_extreme_palindrome_with_factors(max_factor, min_factor, extreme):
def reverse_num(number):
- reversed = 0
+ reversed_nums = 0
while number > 0:
- reversed *= 10
- reversed += (number % 10)
+ reversed_nums *= 10
+ reversed_nums += (number % 10)
number //= 10
- return reversed
+ return reversed_nums
def num_digits(number):
@@ -50,23 +49,23 @@ def palindromes(max_factor, min_factor, reverse=False):
most of the palindromes just to find the one it needs.
"""
if max_factor < min_factor:
- raise ValueError("min must be <= max")
+ raise ValueError('min must be <= max')
minimum = min_factor ** 2
maximum = max_factor ** 2
- def gen_palindromes_of_length(num_digits, reverse=reverse):
+ def gen_palindromes_of_length(digit_count, reverse=reverse):
"""Generates all palindromes with `nd` number of digits that are
within the desired range.
Again, if `reverse` is True, the palindromes are generated in
reverse order.
"""
- even_nd = (num_digits % 2 == 0)
+ even_nd = (digit_count % 2 == 0)
- min_left_half = max(10 ** (int(ceil(num_digits / 2)) - 1),
- minimum // (10 ** (num_digits // 2)))
- max_left_half = min((10 ** int(ceil(num_digits / 2))) - 1,
- maximum // (10 ** (num_digits // 2)))
+ min_left_half = max(10 ** (int(ceil(digit_count / 2)) - 1),
+ minimum // (10 ** (digit_count // 2)))
+ max_left_half = min((10 ** int(ceil(digit_count / 2))) - 1,
+ maximum // (10 ** (digit_count // 2)))
current_left_half = min_left_half if not reverse else max_left_half
@@ -74,7 +73,7 @@ def make_palindrome(left_half, even_nd=False):
right_half = (reverse_num(left_half)
if even_nd
else reverse_num(left_half // 10))
- return (left_half * (10 ** (num_digits // 2))) + right_half
+ return (left_half * (10 ** (digit_count // 2))) + right_half
if not reverse:
while current_left_half <= max_left_half:
diff --git a/exercises/practice/parallel-letter-frequency/.meta/example.py b/exercises/practice/parallel-letter-frequency/.meta/example.py
index 0244d358644..84f85eff4d4 100644
--- a/exercises/practice/parallel-letter-frequency/.meta/example.py
+++ b/exercises/practice/parallel-letter-frequency/.meta/example.py
@@ -2,11 +2,7 @@
from collections import Counter
from threading import Lock, Thread
from time import sleep
-import sys
-if sys.version[0] == '2':
- from Queue import Queue
-else:
- from queue import Queue
+from queue import Queue
total_workers = 3 # Maximum number of threads chosen arbitrarily
@@ -30,8 +26,8 @@ def count_letters(queue_of_texts, letter_to_frequency, worker_id):
sleep(worker_id + 1)
line_input = queue_of_texts.get()
if line_input is not None:
- letters_in_line = Counter([x for x in line_input.lower() if
- x.isalpha()])
+ letters_in_line = Counter([idx for idx in line_input.lower() if
+ idx.isalpha()])
letter_to_frequency.add_counter(letters_in_line)
queue_of_texts.task_done()
if line_input is None:
@@ -40,17 +36,18 @@ def count_letters(queue_of_texts, letter_to_frequency, worker_id):
def calculate(list_of_texts):
queue_of_texts = Queue()
- [queue_of_texts.put(line) for line in list_of_texts]
+ for line in list_of_texts:
+ queue_of_texts.put(line)
letter_to_frequency = LetterCounter()
threads = []
- for i in range(total_workers):
+ for idx in range(total_workers):
worker = Thread(target=count_letters, args=(queue_of_texts,
- letter_to_frequency, i))
+ letter_to_frequency, idx))
worker.start()
threads.append(worker)
queue_of_texts.join()
- for i in range(total_workers):
+ for _ in range(total_workers):
queue_of_texts.put(None)
- for t in threads:
- t.join()
+ for thread in threads:
+ thread.join()
return letter_to_frequency.value
diff --git a/exercises/practice/pascals-triangle/.meta/example.py b/exercises/practice/pascals-triangle/.meta/example.py
index 676791e640b..51df699287c 100644
--- a/exercises/practice/pascals-triangle/.meta/example.py
+++ b/exercises/practice/pascals-triangle/.meta/example.py
@@ -3,10 +3,10 @@ def rows(row_count):
return None
elif row_count == 0:
return []
- r = []
+ rows = []
for i in range(row_count):
- rn = [1]
+ ronald = [1]
for j in range(i):
- rn.append(sum(r[-1][j:j+2]))
- r.append(rn)
- return r
+ ronald.append(sum(rows[-1][j:j+2]))
+ rows.append(ronald)
+ return rows
From e155a1c1c9633e8a55c98cdee68423eee51e5afe Mon Sep 17 00:00:00 2001
From: Job van der Wal <48634934+J08K@users.noreply.github.com>
Date: Thu, 18 Nov 2021 22:03:24 +0100
Subject: [PATCH 0023/1546] Finished all the Ps
---
.../pascals-triangle/.meta/example.py | 12 ++--
.../practice/perfect-numbers/.meta/example.py | 11 ++--
.../practice/phone-number/.meta/example.py | 40 ++++++------
.../practice/point-mutations/.meta/example.py | 2 +-
exercises/practice/poker/.meta/example.py | 18 +++---
exercises/practice/pov/.meta/example.py | 10 +--
exercises/practice/pov/pov.py | 4 +-
.../practice/prime-factors/.meta/example.py | 6 +-
.../protein-translation/.meta/example.py | 24 +++----
exercises/practice/proverb/.meta/example.py | 8 +--
.../pythagorean-triplet/.meta/example.py | 63 +++++++++++--------
11 files changed, 105 insertions(+), 93 deletions(-)
diff --git a/exercises/practice/pascals-triangle/.meta/example.py b/exercises/practice/pascals-triangle/.meta/example.py
index 51df699287c..70f3aec1dd6 100644
--- a/exercises/practice/pascals-triangle/.meta/example.py
+++ b/exercises/practice/pascals-triangle/.meta/example.py
@@ -3,10 +3,10 @@ def rows(row_count):
return None
elif row_count == 0:
return []
- rows = []
- for i in range(row_count):
+ row_list = []
+ for idx in range(row_count):
ronald = [1]
- for j in range(i):
- ronald.append(sum(rows[-1][j:j+2]))
- rows.append(ronald)
- return rows
+ for edx in range(idx):
+ ronald.append(sum(row_list[-1][edx:edx+2]))
+ row_list.append(ronald)
+ return row_list
diff --git a/exercises/practice/perfect-numbers/.meta/example.py b/exercises/practice/perfect-numbers/.meta/example.py
index cc8a63008c2..3a3494817f4 100644
--- a/exercises/practice/perfect-numbers/.meta/example.py
+++ b/exercises/practice/perfect-numbers/.meta/example.py
@@ -1,3 +1,4 @@
+import math
def divisor_generator(number):
"""Returns an unordered list of divisors for n (1 < number).
@@ -6,7 +7,7 @@ def divisor_generator(number):
:return: list of int divisors
"""
- for index in range(2, int(number ** 0.5) + 1):
+ for index in range(2, int(math.sqrt(number)) + 1):
if number % index == 0:
yield index
if index * index != number:
@@ -21,13 +22,13 @@ def classify(number):
"""
if number <= 0:
- raise ValueError("Classification is only possible for positive integers.")
+ raise ValueError('Classification is only possible for positive integers.')
aliquot_sum = sum(divisor_generator(number)) + (1 if number > 1 else 0)
if aliquot_sum < number:
- return "deficient"
+ return 'deficient'
elif aliquot_sum == number:
- return "perfect"
+ return 'perfect'
else:
- return "abundant"
+ return 'abundant'
diff --git a/exercises/practice/phone-number/.meta/example.py b/exercises/practice/phone-number/.meta/example.py
index 4d9b7f8d61a..02b8e13b8b9 100644
--- a/exercises/practice/phone-number/.meta/example.py
+++ b/exercises/practice/phone-number/.meta/example.py
@@ -10,42 +10,44 @@ def __init__(self, number):
self.subscriber_number = self.number[-4:]
def pretty(self):
- return f"({self.area_code})-{self.exchange_code}-{self.subscriber_number}"
+ return f'({self.area_code})-{self.exchange_code}-{self.subscriber_number}'
def _clean(self, number):
- preprocess = re.sub(r"[() +-.]", "", number)
+ preprocess = re.sub(r'[() +-.]', '', number)
if any(item for item in preprocess if item.isalpha()):
- raise ValueError("letters not permitted")
+ raise ValueError('letters not permitted')
if any(item for item in preprocess if item in punctuation):
- raise ValueError("punctuations not permitted")
+ raise ValueError('punctuations not permitted')
return self._normalize(preprocess)
def _normalize(self, number):
if len(number) < 10:
- raise ValueError("incorrect number of digits")
+ raise ValueError('incorrect number of digits')
if len(number) > 11:
- raise ValueError("more than 11 digits")
-
- if len(number) == 10 or len(number) == 11 and number.startswith("1"):
- if number[-10] == "0":
- raise ValueError("area code cannot start with zero")
- elif number[-10] == "1":
- raise ValueError("area code cannot start with one")
- elif number[-7] == "0":
- raise ValueError("exchange code cannot start with zero")
- elif number[-7] == "1":
- raise ValueError("exchange code cannot start with one")
+ raise ValueError('more than 11 digits')
+
+ if len(number) == 10 or len(number) == 11 and number.startswith('1'):
+ if number[-10] == '0':
+ raise ValueError('area code cannot start with zero')
+ elif number[-10] == '1':
+ raise ValueError('area code cannot start with one')
+ elif number[-7] == '0':
+ raise ValueError('exchange code cannot start with zero')
+ elif number[-7] == '1':
+ raise ValueError('exchange code cannot start with one')
else:
- valid = number[-10] in "23456789" and number[-7] in "23456789"
+ valid = number[-10] in '23456789' and number[-7] in '23456789'
else:
valid = False
- if number[0] in "023456789":
- raise ValueError("11 digits must start with 1")
+ if number[0] in '023456789':
+ raise ValueError('11 digits must start with 1')
if valid:
return number[-10:]
+
+ return None # [Pylint]: R1710;
diff --git a/exercises/practice/point-mutations/.meta/example.py b/exercises/practice/point-mutations/.meta/example.py
index 9284ef178af..b55235a7d21 100644
--- a/exercises/practice/point-mutations/.meta/example.py
+++ b/exercises/practice/point-mutations/.meta/example.py
@@ -1,2 +1,2 @@
def hamming_distance(strand1, strand2):
- return sum(x != y for (x, y) in zip(strand1, strand2))
+ return sum(idx != edx for (idx, edx) in zip(strand1, strand2))
diff --git a/exercises/practice/poker/.meta/example.py b/exercises/practice/poker/.meta/example.py
index 7c4dd91b207..e650f143cd0 100644
--- a/exercises/practice/poker/.meta/example.py
+++ b/exercises/practice/poker/.meta/example.py
@@ -4,26 +4,26 @@ def best_hands(hands):
def allmax(iterable, key=None):
result, maxval = [], None
- key = key or (lambda x: x)
- for x in iterable:
- xval = key(x)
+ key = key or (lambda idx: idx)
+ for idx in iterable:
+ xval = key(idx)
if not result or xval > maxval:
- result, maxval = [x], xval
+ result, maxval = [idx], xval
elif xval == maxval:
- result.append(x)
+ result.append(idx)
return result
def hand_rank(hand):
- hand = hand.replace("10", "T").split()
- card_ranks = ["..23456789TJQKA".index(r) for r, s in hand]
- groups = [(card_ranks.count(i), i) for i in set(card_ranks)]
+ hand = hand.replace('10', 'T').split()
+ card_ranks = ['..23456789TJQKA'.index(idx) for idx, _ in hand]
+ groups = [(card_ranks.count(idx), idx) for idx in set(card_ranks)]
groups.sort(reverse=True)
counts, ranks = zip(*groups)
if ranks == (14, 5, 4, 3, 2):
ranks = (5, 4, 3, 2, 1)
straight = (len(counts) == 5) and (max(ranks) - min(ranks) == 4)
- flush = len(set([s for r, s in hand])) == 1
+ flush = len({idx for _, idx in hand}) == 1
return (9 if counts == (5,) else
8 if straight and flush else
7 if counts == (4, 1) else
diff --git a/exercises/practice/pov/.meta/example.py b/exercises/practice/pov/.meta/example.py
index cd0608480f6..9747d985e38 100644
--- a/exercises/practice/pov/.meta/example.py
+++ b/exercises/practice/pov/.meta/example.py
@@ -2,9 +2,9 @@
class Tree:
- def __init__(self, label, children=[]):
+ def __init__(self, label, children=None):
self.label = label
- self.children = children
+ self.children = children if children is not None else []
def __dict__(self):
return {self.label: [member.__dict__() for member in sorted(self.children)]}
@@ -57,7 +57,7 @@ def from_pov(self, from_node):
for child in tree.children:
stack.append(child.add(tree.remove(child.label)))
- raise ValueError("Tree could not be reoriented")
+ raise ValueError('Tree could not be reoriented')
@@ -69,8 +69,8 @@ def path_to(self, from_node, to_node):
while path[-1] != to_node:
try:
tree = stack.pop()
- except IndexError:
- raise ValueError("No path found")
+ except IndexError as error:
+ raise ValueError('No path found') from error
if to_node in tree:
path.append(tree.label)
stack = tree.children
diff --git a/exercises/practice/pov/pov.py b/exercises/practice/pov/pov.py
index bee51ec0c64..21dbe4b90b7 100644
--- a/exercises/practice/pov/pov.py
+++ b/exercises/practice/pov/pov.py
@@ -2,9 +2,9 @@
class Tree:
- def __init__(self, label, children=[]):
+ def __init__(self, label, children=None):
self.label = label
- self.children = children
+ self.children = children if children is not None else []
def __dict__(self):
return {self.label: [c.__dict__() for c in sorted(self.children)]}
diff --git a/exercises/practice/prime-factors/.meta/example.py b/exercises/practice/prime-factors/.meta/example.py
index 8820dd14dcd..4224b7e735c 100644
--- a/exercises/practice/prime-factors/.meta/example.py
+++ b/exercises/practice/prime-factors/.meta/example.py
@@ -1,11 +1,11 @@
def factors(value):
- factors = []
+ factor_list = []
divisor = 2
while value > 1:
while value % divisor == 0:
- factors.append(divisor)
+ factor_list.append(divisor)
value /= divisor
divisor += 1
- return factors
+ return factor_list
diff --git a/exercises/practice/protein-translation/.meta/example.py b/exercises/practice/protein-translation/.meta/example.py
index 8206aac6056..e8c2ac29b5d 100644
--- a/exercises/practice/protein-translation/.meta/example.py
+++ b/exercises/practice/protein-translation/.meta/example.py
@@ -1,25 +1,25 @@
-CODONS = {'AUG': "Methionine", 'UUU': "Phenylalanine",
- 'UUC': "Phenylalanine", 'UUA': "Leucine", 'UUG': "Leucine",
- 'UCU': "Serine", 'UCC': "Serine", 'UCA': "Serine",
- 'UCG': "Serine", 'UAU': "Tyrosine", 'UAC': "Tyrosine",
- 'UGU': "Cysteine", 'UGC': "Cysteine", 'UGG': "Tryptophan",
- 'UAA': "STOP", 'UAG': "STOP", 'UGA': "STOP"}
+CODONS = {'AUG': 'Methionine', 'UUU': 'Phenylalanine',
+ 'UUC': 'Phenylalanine', 'UUA': 'Leucine', 'UUG': 'Leucine',
+ 'UCU': 'Serine', 'UCC': 'Serine', 'UCA': 'Serine',
+ 'UCG': 'Serine', 'UAU': 'Tyrosine', 'UAC': 'Tyrosine',
+ 'UGU': 'Cysteine', 'UGC': 'Cysteine', 'UGG': 'Tryptophan',
+ 'UAA': 'STOP', 'UAG': 'STOP', 'UGA': 'STOP'}
def of_codon(codon):
if codon not in CODONS:
- raise ValueError('Invalid codon: {}'.format(codon))
+ raise ValueError(f'Invalid codon: {codon}')
return CODONS[codon]
def proteins(strand):
- proteins = []
+ protein_list = []
for codon in map(of_codon, _chunkstring(strand, 3)):
if codon == 'STOP':
break
- proteins.append(codon)
- return proteins
+ protein_list.append(codon)
+ return protein_list
-def _chunkstring(string, n):
- return (string[i:n + i] for i in range(0, len(string), n))
+def _chunkstring(string, number):
+ return (string[idx:number + idx] for idx in range(0, len(string), number))
diff --git a/exercises/practice/proverb/.meta/example.py b/exercises/practice/proverb/.meta/example.py
index 9a68b5e4a93..ec434ec7cec 100644
--- a/exercises/practice/proverb/.meta/example.py
+++ b/exercises/practice/proverb/.meta/example.py
@@ -1,7 +1,7 @@
def proverb(rhyme_items):
if not rhyme_items:
- return ""
- phrases = ['For want of a {0} the {1} was lost.'.format(el1, el2)
- for el1, el2 in zip(rhyme_items, rhyme_items[1:])]
- phrases.append('And all for the want of a {0}.'.format(rhyme_items[0]))
+ return ''
+ phrases = [f'For want of a {element_1} the {element_2} was lost.'
+ for element_1, element_2 in zip(rhyme_items, rhyme_items[1:])]
+ phrases.append(f'And all for the want of a {rhyme_items[0]}.')
return '\n'.join(phrases)
diff --git a/exercises/practice/pythagorean-triplet/.meta/example.py b/exercises/practice/pythagorean-triplet/.meta/example.py
index 5b80c30a26c..40b91444b26 100644
--- a/exercises/practice/pythagorean-triplet/.meta/example.py
+++ b/exercises/practice/pythagorean-triplet/.meta/example.py
@@ -1,30 +1,33 @@
-from math import sqrt, ceil
-try:
- # Python 3
- from math import gcd
-except ImportError:
- # Python 2
- from fractions import gcd
+from math import sqrt, ceil, gcd
def triplets_in_range(start, end):
- for b in range(4, end + 1, 4):
- for x, y, z in primitive_triplets(b):
- a, b, c = (x, y, z)
- while a < start:
- a, b, c = (a + x, b + y, c + z)
- while c <= end:
- yield [a, b, c]
- a, b, c = (a + x, b + y, c + z)
+ for limit in range(4, end + 1, 4):
+ for x_pos, y_pos, z_pos in primitive_triplets(limit):
+ alpha = x_pos
+ beta = y_pos
+ gamma = z_pos
+
+ while alpha < start:
+ alpha = alpha + x_pos
+ beta = beta + y_pos
+ gamma = gamma + z_pos
+
+ while gamma <= end:
+ yield [alpha, beta, gamma]
+
+ alpha = alpha + x_pos
+ beta = beta + y_pos
+ gamma = gamma + z_pos
def euclidian_coprimes(limit):
- mn = limit // 2
- for n in range(1, int(ceil(sqrt(mn)))):
- if mn % n == 0:
- m = mn // n
- if (m - n) % 2 == 1 and gcd(m, n) == 1:
- yield m, n
+ mean = limit // 2
+ for idx in range(1, int(ceil(sqrt(mean)))):
+ if mean % idx == 0:
+ member = mean // idx
+ if (member - idx) % 2 == 1 and gcd(member, idx) == 1:
+ yield member, idx
def primitive_triplets(limit):
@@ -32,12 +35,18 @@ def primitive_triplets(limit):
(https://en.wikipedia.org/wiki/Pythagorean_triple#Generating_a_triple)
for more information
"""
- for m, n in euclidian_coprimes(limit):
- m2, n2 = m * m, n * n
- a, b, c = m2 - n2, 2 * m * n, m2 + n2
- if a > b:
- a, b = b, a
- yield a, b, c
+ for member_1, member_2 in euclidian_coprimes(limit):
+ calc_1 = member_1 ** 2
+ calc_2 = member_2 ** 2
+
+ alpha = calc_1 - calc_2
+ beta = 2 * member_1 * member_2
+ gamma = calc_1 + calc_2
+
+ if alpha > beta:
+ alpha, beta = beta, alpha
+
+ yield alpha, beta, gamma
def triplets_with_sum(number):
From 36293227bf7bbf25baf9d5ccb425e4305e11d597 Mon Sep 17 00:00:00 2001
From: Job van der Wal <48634934+J08K@users.noreply.github.com>
Date: Fri, 19 Nov 2021 00:12:05 +0100
Subject: [PATCH 0024/1546] MAJOR CHANGES
---
.../parallel-letter-frequency/.meta/example.py | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/exercises/practice/parallel-letter-frequency/.meta/example.py b/exercises/practice/parallel-letter-frequency/.meta/example.py
index 84f85eff4d4..5a16fb31c17 100644
--- a/exercises/practice/parallel-letter-frequency/.meta/example.py
+++ b/exercises/practice/parallel-letter-frequency/.meta/example.py
@@ -4,8 +4,8 @@
from time import sleep
from queue import Queue
-total_workers = 3 # Maximum number of threads chosen arbitrarily
+TOTAL_WORKERS = 3 # Maximum number of threads chosen arbitrarily
class LetterCounter:
@@ -26,8 +26,7 @@ def count_letters(queue_of_texts, letter_to_frequency, worker_id):
sleep(worker_id + 1)
line_input = queue_of_texts.get()
if line_input is not None:
- letters_in_line = Counter([idx for idx in line_input.lower() if
- idx.isalpha()])
+ letters_in_line = Counter(idx for idx in line_input.lower() if idx.isalpha())
letter_to_frequency.add_counter(letters_in_line)
queue_of_texts.task_done()
if line_input is None:
@@ -40,13 +39,12 @@ def calculate(list_of_texts):
queue_of_texts.put(line)
letter_to_frequency = LetterCounter()
threads = []
- for idx in range(total_workers):
- worker = Thread(target=count_letters, args=(queue_of_texts,
- letter_to_frequency, idx))
+ for idx in range(TOTAL_WORKERS):
+ worker = Thread(target=count_letters, args=(queue_of_texts, letter_to_frequency, idx))
worker.start()
threads.append(worker)
queue_of_texts.join()
- for _ in range(total_workers):
+ for _ in range(TOTAL_WORKERS):
queue_of_texts.put(None)
for thread in threads:
thread.join()
From 3f4d78821434759f9495235c1718ff4a2bef4857 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Sat, 20 Nov 2021 00:34:54 -0800
Subject: [PATCH 0025/1546] [Prime Factors]: Solution left in Stub File
The solution for this exercise was left in the stub file by accident.
---
exercises/practice/prime-factors/prime_factors.py | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/exercises/practice/prime-factors/prime_factors.py b/exercises/practice/prime-factors/prime_factors.py
index c6331342214..c3b672cfdf3 100644
--- a/exercises/practice/prime-factors/prime_factors.py
+++ b/exercises/practice/prime-factors/prime_factors.py
@@ -1,13 +1,2 @@
-# def factors(value):
-# pass
def factors(value):
- factors = []
- divisor = 2
- while value > 1:
- while value % divisor == 0:
- factors.append(divisor)
- value /= divisor
-
- divisor += 1
-
- return factors
+ pass
From 37e518470aeb5b822a2eceb3fb9a5b13648078c5 Mon Sep 17 00:00:00 2001
From: Job van der Wal
Date: Tue, 23 Nov 2021 14:05:17 +0100
Subject: [PATCH 0026/1546] Let's try again.
---
.../practice/queen-attack/.meta/example.py | 16 ++--
.../rail-fence-cipher/.meta/example.py | 5 +-
.../rational-numbers/.meta/example.py | 9 +--
.../rational-numbers/rational_numbers.py | 5 +-
exercises/practice/react/.meta/example.py | 6 +-
.../practice/rectangles/.meta/example.py | 80 ++++++++++---------
exercises/practice/rest-api/.meta/example.py | 21 ++---
.../rna-transcription/.meta/example.py | 9 +--
.../practice/robot-name/.meta/example.py | 6 +-
.../practice/robot-simulator/.meta/example.py | 16 ++--
.../robot-simulator/robot_simulator.py | 2 +-
.../practice/roman-numerals/.meta/example.py | 26 +++---
.../rotational-cipher/.meta/example.py | 17 ++--
.../run-length-encoding/.meta/example.py | 8 +-
14 files changed, 103 insertions(+), 123 deletions(-)
diff --git a/exercises/practice/queen-attack/.meta/example.py b/exercises/practice/queen-attack/.meta/example.py
index 1812d29c58c..e9ae242ff2b 100644
--- a/exercises/practice/queen-attack/.meta/example.py
+++ b/exercises/practice/queen-attack/.meta/example.py
@@ -1,22 +1,22 @@
class Queen:
def __init__(self, row, column):
if row < 0:
- raise ValueError("row not positive")
+ raise ValueError('row not positive')
if not 0 <= row <= 7:
- raise ValueError("row not on board")
+ raise ValueError('row not on board')
if column < 0:
- raise ValueError("column not positive")
+ raise ValueError('column not positive')
if not 0 <= column <= 7:
- raise ValueError("column not on board")
+ raise ValueError('column not on board')
self.row = row
self.column = column
def can_attack(self, another_queen):
- dx = abs(self.row - another_queen.row)
- dy = abs(self.column - another_queen.column)
- if dx == dy == 0:
+ idx = abs(self.row - another_queen.row)
+ edx = abs(self.column - another_queen.column)
+ if idx == edx == 0:
raise ValueError('Invalid queen position: both queens in the same square')
- elif dx == dy or dx == 0 or dy == 0:
+ elif idx == edx or idx == 0 or edx == 0:
return True
else:
return False
diff --git a/exercises/practice/rail-fence-cipher/.meta/example.py b/exercises/practice/rail-fence-cipher/.meta/example.py
index 0f73a29f550..a27bd2670a8 100644
--- a/exercises/practice/rail-fence-cipher/.meta/example.py
+++ b/exercises/practice/rail-fence-cipher/.meta/example.py
@@ -8,11 +8,10 @@ def fence_pattern(rails, size):
def encode(msg, rails):
fence = fence_pattern(rails, len(msg))
- return ''.join(msg[i] for _, i in sorted(fence))
+ return ''.join(msg[idx] for _, idx in sorted(fence))
def decode(msg, rails):
fence = fence_pattern(rails, len(msg))
fence_msg = zip(msg, sorted(fence))
- return ''.join(
- char for char, _ in sorted(fence_msg, key=lambda item: item[1][1]))
+ return ''.join(char for char, _ in sorted(fence_msg, key=lambda item: item[1][1]))
diff --git a/exercises/practice/rational-numbers/.meta/example.py b/exercises/practice/rational-numbers/.meta/example.py
index b4fae0dc35b..0711cfdc104 100644
--- a/exercises/practice/rational-numbers/.meta/example.py
+++ b/exercises/practice/rational-numbers/.meta/example.py
@@ -1,9 +1,4 @@
-from __future__ import division
-
-try:
- from math import gcd
-except ImportError:
- from fractions import gcd
+from math import gcd
class Rational:
@@ -22,7 +17,7 @@ def __eq__(self, other):
return self.numer == other.numer and self.denom == other.denom
def __repr__(self):
- return '{}/{}'.format(self.numer, self.denom)
+ return f'{self.numer}/{self.denom}'
def __add__(self, other):
numer = (self.numer * other.denom) + (other.numer * self.denom)
diff --git a/exercises/practice/rational-numbers/rational_numbers.py b/exercises/practice/rational-numbers/rational_numbers.py
index b704503d0d1..d553c30b1b2 100644
--- a/exercises/practice/rational-numbers/rational_numbers.py
+++ b/exercises/practice/rational-numbers/rational_numbers.py
@@ -1,6 +1,3 @@
-from __future__ import division
-
-
class Rational:
def __init__(self, numer, denom):
self.numer = None
@@ -10,7 +7,7 @@ def __eq__(self, other):
return self.numer == other.numer and self.denom == other.denom
def __repr__(self):
- return '{}/{}'.format(self.numer, self.denom)
+ return f'{self.numer}/{self.denom}'
def __add__(self, other):
pass
diff --git a/exercises/practice/react/.meta/example.py b/exercises/practice/react/.meta/example.py
index f891352ccc5..48d36db63a9 100644
--- a/exercises/practice/react/.meta/example.py
+++ b/exercises/practice/react/.meta/example.py
@@ -21,13 +21,13 @@ def value(self, new_value):
class InputCell(Cell):
def __init__(self, initial_value):
- super(InputCell, self).__init__()
+ super().__init__()
self._value = initial_value
class ComputeCell(Cell):
def __init__(self, inputs, compute_function):
- super(ComputeCell, self).__init__()
+ super().__init__()
self.inputs = inputs
self.func = compute_function
self.callbacks = set()
@@ -40,7 +40,7 @@ def _register_inputs(self):
def compute(self):
# Only compute this cell when all inputs have same counters
- if len(set([inp.counter for inp in self.inputs])) > 1:
+ if len({inp.counter for inp in self.inputs}) > 1:
return
new_val = self.func([inp.value for inp in self.inputs])
if new_val != self._value:
diff --git a/exercises/practice/rectangles/.meta/example.py b/exercises/practice/rectangles/.meta/example.py
index 69f66f78cce..fe665729d35 100644
--- a/exercises/practice/rectangles/.meta/example.py
+++ b/exercises/practice/rectangles/.meta/example.py
@@ -2,34 +2,36 @@
class Corners:
- def __init__(self, i, j):
+ def __init__(self, idx, jdx):
# i, j are position of corner
- self.i = i
- self.j = j
+ self.idx = idx
+ self.jdx = jdx
def __str__(self):
- return "[" + str(self.i) + ", " + str(self.j) + "]"
+ return '[' + str(self.idx) + ', ' + str(self.jdx) + ']'
# return corner on the same line
-def same_line(index, list):
- for corner in list:
- if corner.i == index:
+def same_line(index, list_obj):
+ for corner in list_obj:
+ if corner.idx == index:
return corner
+ return None
# return corner on the same column
-def same_col(index, list):
- for corner in list:
- if corner.j == index:
+def same_col(index, list_obj):
+ for corner in list_obj:
+ if corner.jdx == index:
return corner
+ return None
-def search_corners(input):
+def search_corners(list_obj):
- return [Corners(item, element) for item in range(len(input))
- for element in range(len(input[item]))
- if (input[item][element] == "+")]
+ return [Corners(item, element) for item in range(len(list_obj))
+ for element in range(len(list_obj[item]))
+ if list_obj[item][element] == '+']
# validate that 4 points form a rectangle by
@@ -39,54 +41,54 @@ def possible_rect(quartet):
mid_y = 0
for centroid in quartet:
- mid_x = mid_x + centroid.i / 4.0
- mid_y = mid_y + centroid.j / 4.0
+ mid_x = mid_x + centroid.idx / 4.0
+ mid_y = mid_y + centroid.jdx / 4.0
# reference distance using first corner
- dx = abs(quartet[0].i - mid_x)
- dy = abs(quartet[0].j - mid_y)
+ dx = abs(quartet[0].idx - mid_x)
+ dy = abs(quartet[0].jdx - mid_y)
# Check all the same distance from centroid are equals
- for i in range(1, len(quartet)):
- if abs(quartet[i].i - mid_x) != dx or abs(quartet[i].j - mid_y) != dy:
+ for idx in range(1, len(quartet)):
+ if abs(quartet[idx].idx - mid_x) != dx or abs(quartet[idx].jdx - mid_y) != dy:
return False
return True
# validate path between two corners
-def path(corner1, corner2, input):
- if corner1.i == corner2.i:
- for j in range(min(corner1.j + 1, corner2.j + 1),
- max(corner1.j, corner2.j)):
- if input[corner1.i][j] != "-" and input[corner1.i][j] != "+":
+def path(corner1, corner2, item):
+ if corner1.idx == corner2.idx:
+ for jdx in range(min(corner1.jdx + 1, corner2.jdx + 1),
+ max(corner1.jdx, corner2.jdx)):
+ if item[corner1.idx][jdx] != '-' and item[corner1.idx][jdx] != '+':
return False
return True
- elif corner1.j == corner2.j:
- for i in range(min(corner1.i + 1, corner2.i + 1),
- max(corner1.i, corner2.i)):
- if input[i][corner1.j] != "|" and input[i][corner1.j] != "+":
+ elif corner1.jdx == corner2.jdx:
+ for idx in range(min(corner1.idx + 1, corner2.idx + 1),
+ max(corner1.idx, corner2.idx)):
+ if item[idx][corner1.jdx] != '|' and item[idx][corner1.jdx] != '+':
return False
return True
+ return None
# validate path of rectangle
-def validate_rect(rectangle, input):
+def validate_rect(rectangle, item):
# validate connection at every corner
# with neighbours on the same line and col
- for i in range(0, len(rectangle)):
- line = same_line(rectangle[i].i, rectangle[0:i] + rectangle[i + 1:])
- column = same_col(rectangle[i].j, rectangle[0:i] + rectangle[i + 1:])
+ for idx, _ in enumerate(rectangle):
+ line = same_line(rectangle[idx].idx, rectangle[0:idx] + rectangle[idx + 1:])
+ column = same_col(rectangle[idx].jdx, rectangle[0:idx] + rectangle[idx + 1:])
- if ((not path(rectangle[i], line, input)) or
- (not path(rectangle[i], column, input))):
+ if not path(rectangle[idx], line, item) or not path(rectangle[idx], column, item):
return False
return True
# count number of rectangles inside ASCII in input lines
-def rectangles(strings=""):
+def rectangles(strings=''):
rectangle_total = 0
# test empty str
if not strings:
@@ -95,7 +97,7 @@ def rectangles(strings=""):
corners = search_corners(strings)
# no corners in str
- if not len(corners):
+ if not corners:
return rectangle_total
# all combinations of 4 corners
@@ -103,7 +105,7 @@ def rectangles(strings=""):
paths = (quartet for quartet in quartets if possible_rect(quartet))
# validate paths
- for path in paths:
- if validate_rect(path, strings):
+ for idx in paths:
+ if validate_rect(idx, strings):
rectangle_total += 1
return rectangle_total
diff --git a/exercises/practice/rest-api/.meta/example.py b/exercises/practice/rest-api/.meta/example.py
index c43bcd9c451..46556efcedc 100644
--- a/exercises/practice/rest-api/.meta/example.py
+++ b/exercises/practice/rest-api/.meta/example.py
@@ -33,10 +33,11 @@ def get(self, url, payload=None):
else:
return json.dumps({
'users': [
- u for u in self.database['users']
- if u['name'] in payload['users']
+ user for user in self.database['users']
+ if user['name'] in payload['users']
]
})
+ return None
def post(self, url, payload=None):
result = None
@@ -47,9 +48,9 @@ def post(self, url, payload=None):
name = payload['user']
users = self.database['users']
user = None
- for u in users:
- if u['name'] == name:
- user = u
+ for idx in users:
+ if idx['name'] == name:
+ user = idx
break
if user is None:
new_user = {
@@ -67,11 +68,11 @@ def post(self, url, payload=None):
borrower_name = payload['borrower']
amount = payload['amount']
lender = borrower = None
- for u in self.database['users']:
- if u['name'] == lender_name:
- lender = u
- elif u['name'] == borrower_name:
- borrower = u
+ for user in self.database['users']:
+ if user['name'] == lender_name:
+ lender = user
+ elif user['name'] == borrower_name:
+ borrower = user
if lender is not None and borrower is not None:
lender['owed_by'].setdefault(borrower_name, 0)
lender['owed_by'][borrower_name] += amount
diff --git a/exercises/practice/rna-transcription/.meta/example.py b/exercises/practice/rna-transcription/.meta/example.py
index 4849fc4ee8a..61db942ea3b 100644
--- a/exercises/practice/rna-transcription/.meta/example.py
+++ b/exercises/practice/rna-transcription/.meta/example.py
@@ -1,11 +1,4 @@
-import sys
-
-if sys.version_info[0] == 2:
- from string import maketrans
-else:
- maketrans = str.maketrans
-
-DNA_TO_RNA = maketrans("AGCT", "UCGA")
+DNA_TO_RNA = str.maketrans("AGCT", "UCGA")
def to_rna(dna_strand):
return dna_strand.translate(DNA_TO_RNA)
diff --git a/exercises/practice/robot-name/.meta/example.py b/exercises/practice/robot-name/.meta/example.py
index a3c73e7e349..405142718ae 100644
--- a/exercises/practice/robot-name/.meta/example.py
+++ b/exercises/practice/robot-name/.meta/example.py
@@ -1,16 +1,14 @@
import random
-
+ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
class Robot:
- alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-
def __init__(self):
self._name = None
self._past_names = set()
def prefix(self):
return ''.join([
- random.choice(self.alphabet)
+ random.choice(ALPHABET)
for _ in range(0, 2)
])
diff --git a/exercises/practice/robot-simulator/.meta/example.py b/exercises/practice/robot-simulator/.meta/example.py
index 51aa7b8487b..20caf3bedcb 100644
--- a/exercises/practice/robot-simulator/.meta/example.py
+++ b/exercises/practice/robot-simulator/.meta/example.py
@@ -15,20 +15,20 @@ def right(self):
class Robot:
- def __init__(self, direction=NORTH, x=0, y=0):
+ def __init__(self, direction=NORTH, x_pos=0, y_pos=0):
self.compass = Compass(direction)
- self.x = x
- self.y = y
+ self.x_pos = x_pos
+ self.y_pos = y_pos
def advance(self):
if self.direction == NORTH:
- self.y += 1
+ self.y_pos += 1
elif self.direction == SOUTH:
- self.y -= 1
+ self.y_pos -= 1
elif self.direction == EAST:
- self.x += 1
+ self.x_pos += 1
elif self.direction == WEST:
- self.x -= 1
+ self.x_pos -= 1
def turn_left(self):
self.compass.left()
@@ -50,4 +50,4 @@ def direction(self):
@property
def coordinates(self):
- return (self.x, self.y)
+ return (self.x_pos, self.y_pos)
diff --git a/exercises/practice/robot-simulator/robot_simulator.py b/exercises/practice/robot-simulator/robot_simulator.py
index f9c5c37264b..e5da22de3a3 100644
--- a/exercises/practice/robot-simulator/robot_simulator.py
+++ b/exercises/practice/robot-simulator/robot_simulator.py
@@ -7,5 +7,5 @@
class Robot:
- def __init__(self, direction=NORTH, x=0, y=0):
+ def __init__(self, direction=NORTH, x_pos=0, y_pos=0):
pass
diff --git a/exercises/practice/roman-numerals/.meta/example.py b/exercises/practice/roman-numerals/.meta/example.py
index 1533dcb38ce..c6e56ec03ba 100644
--- a/exercises/practice/roman-numerals/.meta/example.py
+++ b/exercises/practice/roman-numerals/.meta/example.py
@@ -1,24 +1,18 @@
NUMERAL_MAPPINGS = (
- (1000, 'M'),
- (900, 'CM'),
- (500, 'D'),
- (400, 'CD'),
- (100, 'C'),
- (90, 'XC'),
- (50, 'L'),
- (40, 'XL'),
- (10, 'X'),
- (9, 'IX'),
- (5, 'V'),
- (4, 'IV'),
+ (1000, 'M'), (900, 'CM'),
+ (500, 'D'), (400, 'CD'),
+ (100, 'C'), (90, 'XC'),
+ (50, 'L'), (40, 'XL'),
+ (10, 'X'), (9, 'IX'),
+ (5, 'V'), (4, 'IV'),
(1, 'I')
)
def roman(number):
result = ''
- for arabic, roman in NUMERAL_MAPPINGS:
- while number >= arabic:
- result += roman
- number -= arabic
+ for arabic_num, roman_num in NUMERAL_MAPPINGS:
+ while number >= arabic_num:
+ result += roman_num
+ number -= arabic_num
return result
diff --git a/exercises/practice/rotational-cipher/.meta/example.py b/exercises/practice/rotational-cipher/.meta/example.py
index 241afcb8086..33263275421 100644
--- a/exercises/practice/rotational-cipher/.meta/example.py
+++ b/exercises/practice/rotational-cipher/.meta/example.py
@@ -1,14 +1,15 @@
-from string import ascii_lowercase as alpha_lower
-from string import ascii_uppercase as alpha_upper
-ALPHA_LEN = len(alpha_lower)
+from string import ascii_lowercase, ascii_uppercase
+
+
+ALPHA_LEN = len(ascii_lowercase)
def rotate(message, key):
- coded_message = ""
+ coded_message = ''
for char in message:
- if char in alpha_lower:
- char = alpha_lower[(alpha_lower.index(char) + key) % ALPHA_LEN]
- elif char in alpha_upper:
- char = alpha_upper[(alpha_upper.index(char) + key) % ALPHA_LEN]
+ if char in ascii_lowercase:
+ char = ascii_lowercase[(ascii_lowercase.index(char) + key) % ALPHA_LEN]
+ elif char in ascii_uppercase:
+ char = ascii_uppercase[(ascii_uppercase.index(char) + key) % ALPHA_LEN]
coded_message += char
return coded_message
diff --git a/exercises/practice/run-length-encoding/.meta/example.py b/exercises/practice/run-length-encoding/.meta/example.py
index 7e33ac75d98..309c8a3b1d2 100644
--- a/exercises/practice/run-length-encoding/.meta/example.py
+++ b/exercises/practice/run-length-encoding/.meta/example.py
@@ -3,11 +3,11 @@
def decode(string):
- return sub(r'(\d+)(\D)', lambda m: m.group(2) * int(m.group(1)), string)
+ return sub(r'(\d+)(\D)', lambda main: main.group(2) * int(main.group(1)), string)
def encode(string):
- def single_helper(k, g):
- size = len(list(g))
- return k if size == 1 else str(size) + k
+ def single_helper(key, group):
+ size = len(list(group))
+ return key if size == 1 else str(size) + key
return ''.join(single_helper(key, group) for key, group in groupby(string))
From 7a00d7f764bbcedcf22bdf722fc69ed1c54f3d6c Mon Sep 17 00:00:00 2001
From: Job van der Wal
Date: Tue, 23 Nov 2021 21:45:35 +0100
Subject: [PATCH 0027/1546] Fixing some bots
---
.github/issue-comment.md | 2 +-
.github/pr-commenter.yml | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.github/issue-comment.md b/.github/issue-comment.md
index 7e52292296d..143059bd52e 100644
--- a/.github/issue-comment.md
+++ b/.github/issue-comment.md
@@ -11,7 +11,7 @@ Thank you for opening an issue! π π β¨
◦ We'll take a look as soon as we can & identify what work is needed to fix it. *(generally within* **72 hours**).
β ◦ _If you'd also like to make a PR to **fix** the issue, please have a quick look at the [Pull Requests][prs] doc._
- _We π PRs that follow our [Exercsim][exercism-guidelines] & [Track][track-guidelines] contributing guidelines!_
+ _We π PRs that follow our [Exercism][exercism-guidelines] & [Track][track-guidelines] contributing guidelines!_
- Here because of an obvious (*and* **small** *set of*) spelling, grammar, or punctuation issues with **one** exercise,
concept, or Python document?? π `Please feel free to submit a PR, linking to this issue.` π
diff --git a/.github/pr-commenter.yml b/.github/pr-commenter.yml
index 5c635b8179a..bcaa36dfcb6 100644
--- a/.github/pr-commenter.yml
+++ b/.github/pr-commenter.yml
@@ -288,6 +288,8 @@ comment:
- id: change-practice-exercise
files:
- "exercises/practice/**/*"
+ - "exercises/practice/**/.meta/*"
+ - "exercises/practice/**/.docs/*"
- "exercises/practice/**/**/*"
body: |
---
From d53fbf28486c8036acde1a2884859c38837407e9 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Sun, 28 Nov 2021 11:21:58 -0800
Subject: [PATCH 0028/1546] Changed error message for python-specific test
cases. Updated example.py and regenerated test cases.
---
exercises/practice/wordy/.meta/additional_tests.json | 4 ++--
exercises/practice/wordy/.meta/example.py | 2 +-
exercises/practice/wordy/wordy_test.py | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/exercises/practice/wordy/.meta/additional_tests.json b/exercises/practice/wordy/.meta/additional_tests.json
index 69bbe2dad16..089dd45046b 100644
--- a/exercises/practice/wordy/.meta/additional_tests.json
+++ b/exercises/practice/wordy/.meta/additional_tests.json
@@ -6,7 +6,7 @@
"input": {
"question": "What is 2 2 minus 3?"
},
- "expected": {"error": "unknown operation"}
+ "expected": {"error": "syntax error"}
},
{
"description": "Missing number",
@@ -14,7 +14,7 @@
"input": {
"question": "What is 7 plus multiplied by -2?"
},
- "expected": {"error": "unknown operation"}
+ "expected": {"error": "syntax error"}
}
]
}
diff --git a/exercises/practice/wordy/.meta/example.py b/exercises/practice/wordy/.meta/example.py
index 9542334d655..6d8dfe08790 100644
--- a/exercises/practice/wordy/.meta/example.py
+++ b/exercises/practice/wordy/.meta/example.py
@@ -45,6 +45,6 @@ def answer(question):
try:
main_value = VALID_OPERATIONS[operation](main_value, second_value)
except KeyError:
- raise ValueError("unknown operation")
+ raise ValueError("syntax error")
return main_value
diff --git a/exercises/practice/wordy/wordy_test.py b/exercises/practice/wordy/wordy_test.py
index afa75017ebd..3f85ed41f16 100644
--- a/exercises/practice/wordy/wordy_test.py
+++ b/exercises/practice/wordy/wordy_test.py
@@ -107,10 +107,10 @@ def test_missing_operation(self):
with self.assertRaises(ValueError) as err:
answer("What is 2 2 minus 3?")
self.assertEqual(type(err.exception), ValueError)
- self.assertEqual(err.exception.args[0], "unknown operation")
+ self.assertEqual(err.exception.args[0], "syntax error")
def test_missing_number(self):
with self.assertRaises(ValueError) as err:
answer("What is 7 plus multiplied by -2?")
self.assertEqual(type(err.exception), ValueError)
- self.assertEqual(err.exception.args[0], "unknown operation")
+ self.assertEqual(err.exception.args[0], "syntax error")
From 51f4947f83cf39548a460e474da5e4556946bf35 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Sun, 28 Nov 2021 10:46:53 -0800
Subject: [PATCH 0029/1546] Copy pytest ini file to shared for future download
via exercism CLI.
---
exercises/shared/pytest.ini | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 exercises/shared/pytest.ini
diff --git a/exercises/shared/pytest.ini b/exercises/shared/pytest.ini
new file mode 100644
index 00000000000..c315f4316bd
--- /dev/null
+++ b/exercises/shared/pytest.ini
@@ -0,0 +1,3 @@
+[pytest]
+markers =
+ task: A concept exercise task.
\ No newline at end of file
From 9dfbf136ef47f05d748db23c51186365cd3eb479 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Sat, 27 Nov 2021 15:57:46 -0800
Subject: [PATCH 0030/1546] Updated exercise and concept table and exercise
tree.
---
reference/Beta.svg | 14 +
reference/Python_Track_Exercise_Tree.svg | 1239 +++++++++++++++++
reference/TBD-F.svg | 14 +
reference/TBD.svg | 14 +
reference/WIP.svg | 14 +
...all_exercises_mapping_and_prerequisites.md | 85 --
reference/concept-exercise-mapping.md | 106 +-
reference/implementing-a-concept-exercise.md | 145 --
...summary.md => track_exercises_overview.md} | 181 ++-
9 files changed, 1402 insertions(+), 410 deletions(-)
create mode 100644 reference/Beta.svg
create mode 100644 reference/Python_Track_Exercise_Tree.svg
create mode 100644 reference/TBD-F.svg
create mode 100644 reference/TBD.svg
create mode 100644 reference/WIP.svg
delete mode 100644 reference/all_exercises_mapping_and_prerequisites.md
delete mode 100644 reference/implementing-a-concept-exercise.md
rename reference/{exercises_summary.md => track_exercises_overview.md} (76%)
diff --git a/reference/Beta.svg b/reference/Beta.svg
new file mode 100644
index 00000000000..cf9ce4f1a5f
--- /dev/null
+++ b/reference/Beta.svg
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/reference/Python_Track_Exercise_Tree.svg b/reference/Python_Track_Exercise_Tree.svg
new file mode 100644
index 00000000000..d79ab7e20a6
--- /dev/null
+++ b/reference/Python_Track_Exercise_Tree.svg
@@ -0,0 +1,1239 @@
+
\ No newline at end of file
diff --git a/reference/TBD-F.svg b/reference/TBD-F.svg
new file mode 100644
index 00000000000..1bb45594242
--- /dev/null
+++ b/reference/TBD-F.svg
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/reference/TBD.svg b/reference/TBD.svg
new file mode 100644
index 00000000000..0658c73e5a5
--- /dev/null
+++ b/reference/TBD.svg
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/reference/WIP.svg b/reference/WIP.svg
new file mode 100644
index 00000000000..d349ec59930
--- /dev/null
+++ b/reference/WIP.svg
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/reference/all_exercises_mapping_and_prerequisites.md b/reference/all_exercises_mapping_and_prerequisites.md
deleted file mode 100644
index c617db2da33..00000000000
--- a/reference/all_exercises_mapping_and_prerequisites.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# Python concept exercises
-
-| **Concept (_about & links_)** | **Exercise Name** | **Topics** | **Design** | **Prerequisites** |
-| --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
-| [`basics`](https://github.com/exercism/v3/tree/master/languages/python/concepts/basics) | [Guidos Gorgeous Lasagna](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/guidos-gorgeous-lasagna) | `basics` | [basics](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/guidos-gorgeous-lasagna/.meta/design.md) | -- |
-| [`bools`](https://github.com/exercism/v3/tree/master/languages/python/concepts/bools) | [ghost-gobble-arcade-game](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/ghost-gobble-arcade-game) | `bools` | [bools](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/ghost-gobble-arcade-game/.meta/design.md) | `basics` |
-| `comparisons` | TBD (PR in progress) | `comparisons` | [#2039](https://github.com/exercism/v3/issues/2039) | `basics` |
-| `rich-comparisons` | TBD (split from comparisons) | `rich-comparisons` | [#2171](https://github.com/exercism/v3/issues/2171) | `comparisons` |
-| [`dicts`](https://github.com/exercism/v3/tree/master/languages/python/concepts/dicts) | [Inventory Management](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/inventory-management) | `dicts` | [dicts](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/inventory-management/.meta/design.md) | `loops`, `lists`, `tuples` |
-| [`enums`](https://github.com/exercism/v3/tree/master/languages/python/concepts/enums) | [log-levels](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/log-levels) | `enums` | [enums](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/log-levels/.meta/design.md) | `classes`, `conditionals`, `loops`, `comprehensions`, `sequences`, `string-formatting`, `string-methods`, `tuples` |
-| [`loops`](https://github.com/exercism/v3/tree/master/languages/python/concepts/loops) | [Making the Grade](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/making-the-grade) | `iteration`, `loops`, `range` | [loops](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/making-the-grade/.meta/design.md) | `basics`, `comparisons`, `conditionals`, `lists`, `strings` |
-| [`list-methods`](https://github.com/exercism/v3/tree/master/languages/python/concepts/list-methods) | [Chaitanas Colossal Coaster](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/chaitanas-colossal-coaster) | `list-methods` | [list-methods](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/chaitanas-colossal-coaster/.meta/design.md) | `lists` |
-| [`lists`](https://github.com/exercism/v3/tree/master/languages/python/concepts/lists) | [Elyses Enchantments](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/elyses-enchantments) | `lists` | [lists](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/chaitanas-colossal-coaster/.meta/design.md) | `comparisons`, `conditionals`, `strings` |
-| [`none`](https://github.com/exercism/v3/tree/master/languages/python/concepts/none) | [Restaurant Rozalynn](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/restaurant-rozalynn) | `None` | [none](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/restaurant-rozalynn/.meta/design.md) | `bools`, `conditionals`, `functions`, `dict-methods`, `list-methods`, `loops` |
-| [`numbers`](https://github.com/exercism/v3/tree/master/languages/python/concepts/numbers) | [Currency Exchange](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/currency-exchange) | `numbers`, `ints`, `floats` | [ numbers](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/currency-exchange/.meta/design.md) | `basics` |
-| [`complex-numbers`](https://github.com/exercism/v3/tree/master/languages/python/concepts/complex-numbers) | TBD (PR in process) | `complex-numbers`, `imaginary-numbers` | [Issue #2208](https://github.com/exercism/v3/issues/2208) | `numbers` |
-| [`strings`](https://github.com/exercism/v3/tree/master/languages/python/concepts/strings) | [Processing Logs](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/processing-logs) | `strings` | [strings design](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/processing-logs/.meta/design.md) | `basics` |
-| [`string-formatting`](https://github.com/exercism/v3/tree/master/languages/python/concepts/string-formatting) | TBD (PR in process) | `string-formatting` | [Issue #1647](https://github.com/exercism/v3/issues/1648) | `basics`, `strings`, `string-methods` |
-| [`string-methods`](https://github.com/exercism/v3/tree/master/languages/python/concepts/string-methods) | [Litte Sister's Essay](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/little-sisters-essay) | `string-methods` | [string-methods design](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/little-sisters-essay/.meta/design.md) | `basics`, `strings` |
-| [`string-methods-TBD`](https://github.com/exercism/v3/tree/master/languages/python/concepts/string-methods-TBD) | TBD (PR in process) | `string-splitting`, `string processing` | TBD | `basics`, `strings`, `string-methods` |
-| [`tuples`](https://github.com/exercism/v3/tree/master/languages/python/concepts/tuples) | [Tisbury Treasure Hunt](https://github.com/exercism/v3/tree/master/languages/python/exercises/concept/tisbury-treasure-hunt) | `tuples` | [tuples design](https://github.com/exercism/v3/blob/master/languages/python/exercises/concept/tisbury-treasure-hunt/.meta/design.md) | `bools`, `loops`, `conditionals`, `numbers` | |
-
-## Chart
-
-```mermaid
-flowchart TD
-
-%%concepts & exercise names (node lables)
-Basics((Guidos Gorgeous Lasagna Basics))
-bools((Ghost Gobble Arcade Game bools))
-classes((TBD classes))
-inheritance((TBD inheritance))
-interfaces((TBD interfaces))
-comparisons((TBD comparisons))
-comprehensions(("TBD comprehensions (list comprehensions)"))
-other-comprehensions((TBD other-comprehensions))
-conditionals((TBD conditionals))
-dicts((Inventory Management dicts))
-dict-methods((TBD dict-methods))
-enums((Log Levels enums))
-functions((TBD functions))
-higher-order-functions((TBD higher-order-functions))
-anonymous-functions((TBD anonymous-functions))
-iterators((TBD iterators))
-lists((Elyse's Enchantments lists))
-list-methods((Chaitana's Colossal Coaster list-methods))
-loops((Making the Grade loops))
-none((Restaurant Rozalynn none))
-numbers(("Currency Exchange numbers (ints & floats)"))
-complex-numbers(("TBD (Bowling Game??) complex-numbers"))
-rich-comparisons((TBD rich-comparisons))
-sequences((TBD sequences))
-sets((Cater-Waiter sets))
-strings((Processing Logs string type))
-string-formatting((TBD string-formatting))
-string-methods((Little Sister's Essay string-methods))
-tuples((Tisbury Treasure Hunt tuples))
-
-
-%%exercise prerequisites (node relations)
-Basics --> functions & strings & loops & comparisons & conditionals & bools
-Basics --> numbers & classes
-
-bools --> tuples & none
-classes --> enums & inheritance
-comparisons --> lists & loops
-comparisons --> rich-comparisons & conditionals
-comprehensions --> enums & other-comprehensions
-conditionals --> loops & lists & none & sets & tuples & enums
-inheritance --> interfaces
-dicts --> dict-methods & other-comprehensions
-dict-methods --> none
-functions --> higher-order-functions & none
-higher-order-functions --> anonymous-functions
-lists --> list-methods & enums & sequences & comprehensions & dicts
-list-methods --> none
-loops --> none & enums & iterators & comprehensions & dicts & sets & tuples
-numbers --> sets & tuples & complex-numbers
-sequences --> iterators & enums
-sets --> other-comprehensions
-strings --> string-methods & string-formatting
-strings --> sequences & lists
-string-methods & string-formatting --> enums
-tuples --> sequences & dicts & enums
-```
diff --git a/reference/concept-exercise-mapping.md b/reference/concept-exercise-mapping.md
index 666fb44b47e..1bda69ad12e 100644
--- a/reference/concept-exercise-mapping.md
+++ b/reference/concept-exercise-mapping.md
@@ -640,7 +640,7 @@ _These datatypes will very rarely be encountered in the wild, the first because
[powers-of-two]: ./concepts/powers_of_two.md
[property-decorator]: ./concepts/property_decorator.md
[python-enhancement-proposals]: ./concepts/python_enhancement_proposals.md
-[python-exercises]: ./exercises_summary.md
+[python-exercises]: track_exercises_overview.md
[pythonic]: ./concepts/pythonic.md
[raise]: ./concepts/raise.md
[recursion]: ../../../reference/concepts/recursion.md
@@ -675,109 +675,7 @@ _These datatypes will very rarely be encountered in the wild, the first because
## Implementations in Progress
-Expect this table to be updated as larger concepts are broken down or additional concepts/exercises are identified.
+Expect information to be updated as larger concepts are broken down or additional concepts/exercises are identified.
See the [**Python Exercises**][python-exercises] page for committed/planned on website concept & practice exercises.
-
-#### Below are currently identified concepts needing:
-
-1. Issues logged (_TBD issue entry_)
-2. Concept & About documents written (_starred concepts - links are to stub files_)
-3. PRs written for a concept exericise (_the issue is listed for design, but there is no exercise name linked_)
-4. Possible Imrovements (_check github for additional improvement issues_)
-
-
-
-| Concept | Includes | About & Introduction | Exercise | Prerequisites | Design./Issue | Status/PR |
-| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------ |
-| list-methods | Topics
| [about.md](https://github.com/exercism/python/blob/main/concepts/import/about.md)π [introduction.md](https://github.com/exercism/python/blob/main/concepts/import/introduction.md) | | | ON HOLD | ON HOLD |
-| context-manager-customization\* | Topics
| [about.md](https://github.com/exercism/python/blob/main/concepts/string-methods-splitting/about.md)π [introduction.md](https://github.com/exercism/python/blob/main/concepts/string-methods-splitting/introduction.md) | | TBD | TBD | TBD |
-| \*general | [Composition][composition-general] | NA | NA | NA | NA | NA |
-| \*general | [Data Structures][data-structures] | NA | NA | NA | NA | NA |
-| \*general | [Encapsulation][encapsulation-general] | NA | NA | NA | NA | NA |
-| \*general | [Interfaces][interfaces-general] | NA | NA | NA | NA | NA |
-| \*general | [Lookup efficiency][lookup-efficiency] | NA | NA | NA | NA | NA |
-| \*general | [Mutation][mutation-general] | NA | NA | NA | NA | NA |
-| \*general | [Mutability in Python][mutability] | NA | NA | NA | NA | NA |
-| \*general | [Polymorphism][polymorphism-general] | NA | NA | NA | NA | NA |
-| \*general | [Recursive data structures][recursive-data-structures] | NA | NA | NA | NA | NA |
-| \*general | [Scope][scope] | NA | NA | NA | NA | NA |
-| \*general | [Standard Library][standard-library] | NA | NA | NA | NA | NA |
-| \*general | [State][state] | NA | NA | NA | NA | NA |
-| \*no stand-alone | [Duck Typing][duck-typing] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [Dynamic Typing][dynamic-typing] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [del][keyword-del] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [Expressions][expressions] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [Identity testing][identity-testing] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [Operators][operators] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [Operator precedence][operator-precedence] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [Order of Evaluation][order-of-evaluation] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [type][builtin-types-type] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [type conversion][type-conversion] | NA | Multiple | Multiple | Multiple | NA |
-| \*no stand-alone | [Immutability in Python][immutability] | NA | Multiple | Multiple | Multiple | NA |
-
-_Concepts flagged as **general** are broad enough that we are questioning if they need a specific concept exercise._
-
-_Concepts flagged **no stand alone** are explained/utilized across multiple concept exercises._
diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md
deleted file mode 100644
index ff1872ea054..00000000000
--- a/reference/implementing-a-concept-exercise.md
+++ /dev/null
@@ -1,145 +0,0 @@
-# How to implement a Python concept exercise
-
-This document describes the steps required to implement a concept exercise for the Python track.
-
-**Please please please read the docs before starting.** Posting PRs without reading these docs will be a lot more frustrating for you during the review cycle, and exhaust Exercism's maintainers' time. So, before diving into the implementation, please read the following documents:
-
-- [The features of v3][docs-features-of-v3].
-- [Rationale for v3][docs-rationale-for-v3].
-- [What are concept exercise and how they are structured?][docs-concept-exercises]
-
-Please also watch the following video:
-
-- [The Anatomy of a Concept Exercise][anatomy-of-a-concept-exercise].
-
-As this document is generic, the following placeholders are used:
-
-- ``: the slug of the exercise _story title_ in kebab-case (e.g. `calculator-conundrum`).
-- ``: the name of the exercise's _concept_ in snake_case (e.g. `anonymous_functions`).
-- ``: the slug of an exercise's _concept_ in kebab-case (e.g. `anonymous-functions`).
-
-Before implementing the exercise, please make sure you have a good understanding of what the exercise should be teaching (and what should not be taught). This information can be found in the exercise's [GitHub issue][github-issues-python], under the `Learning Objectives` and `Out of Scope` sections.
-
-We suggest using a git branch titled after the concept you are writing the exercise for. Please use `[Python]` in the title of your PR, so that it can be easily filtered and note the GitHub issue number in the PR message.
-
-To implement a concept exercise, the following files under `python/concepts` and `python/exercises` will need to be created:
-
-```
-languages
-βββ python
- βββ concepts
- | βββ
- | βββ about.md
- | βββ links.json
- βββ exercises
- βββ concept
- βββ
- βββ .docs
- | βββ instructions.md
- | βββ introduction.md
- | βββ hints.md
- βββ .meta
- | βββ config.json
- | βββ design.md
- | βββ exemplar.py
- βββ .py
- βββ _test.py
-
-```
-
-## Step 1: Add `.py` code files
-
-These are files specific to the Python track, and can be added in any order:
-
-- `/.py`
- The stub implementation file, which will be the starting point for students to work on the exercise ([example stub file][example-stub]). Please use `pass` as necessary, and descriptive TODO comments for clarification if the student needs to define a class/function/constant themselves ([example TODO][example-todo]).
-
-- `/_test.py`
- The test suite a submitted solution will be tested against. Tests should be written using [`unittest.TestCase`][unittest] ([example test file][example-testfile]). We do use PyTest as our test runner, but please check with a maintainer before using any PyTest-specific methods.
-
-- `.meta/exemplar.py`
- An idiomatic implementation that passes all the provided tests. This solution file should only use **syntax & concepts introduced in the concept exercise itself, or one of its prerequisites.**. This means avoiding the use of `classes`, `comprehensions`, `generators`, `slice assignment`, `regex`, `filter/map/reduce`, standard library modules (_like `datetime`_), or 3rd-party libraries unless the exercise has introduced these concepts or they appear in the exercise's prerequisite tree. Please follow the [PEP8][pep8] formatting guidelines. Additionally, we'd like you to avoid any single-letter or cryptic variable names.
-
-## Step 2: Add exercise documentation files
-
-How to create the files common to all tracks is described in the [how to implement a concept exercise document][how-to-implement-a-concept-exercise]. All of these files are written in [Markdown][commonmark], and you can find the [Exercism Formatting and Style Guide][style-guide] here. Please pay close attention to the [auto-formatting][auto-formatting] section, to avoid CI test failures.
-
-As a reminder, code elements (functions, keywords, operators) should be wrapped in backticks:
-
-```python
-A `set` is an unordered collection of distinct hashable objects. To add something to a `set`, use `set.add()`
-```
-
-Which will render:
-
-A `set` is an unordered collection of distinct hashable objects. To add something to a `set`, use `set.add()`
-
-Unless your code is intended to represent a `.py` file, please format longer in-text code examples for the Python REPL -- in the same way the [Python Docs][repl-code-example] do:
-
-```python
-# Elements given to the constructor are iterated through and added to the tuple in order.
->>> multiple_elements_string = tuple("Timbuktu")
-('T', 'i', 'm', 'b', 'u', 'k', 't', 'u')
-
->>> multiple_elements = tuple(("Parrot", "Bird", 334782))
-("Parrot", "Bird", 334782)
-
-# Iterating through a tuple with a for loop.
->>> for item in multiple_elements_string:
-... print(item)
-...
-T
-i
-m
-b
-u
-k
-t
-u
-```
-
-For resource links, we strongly favor linking into relevant parts of the [Python docs][python-docs] as a first source, with other useful and interesting links as a follow-on. Please avoid any paywalled, subscription-based or signup-required links.
-
-## Inspiration
-
-When implementing an exercise, it can be very useful to look at already [implemented Python exercises][python-implementations]. Browsing through concept exercise stories [here][concept-exercise-stories] can also help "jump-start" concept exercise writing. And you can also check the cross-track [general concepts directory][reference] to see if other language tracks have already implemented an exercise for a particular concept. If you adapt a story or exercise, please make sure to include a credit in your exercise `.meta/config.json` file `"forked_from" field:
-
-```json
-{
- "authors": [
- {
- "github_username": "aldraco",
- "exercism_username": "aldraco"
- }
- ],
- "editor": {
- "solution_files": ["strings.py"],
- "test_files": ["strings_test.py"]
- },
- "forked_from": ["csharp/strings"]
-}
-```
-
-## Help
-
-If you have any questions regarding implementing the exercise, please post them as comments in the exercise's GitHub issue, or in the exercism Slack channel.
-
-[reference]: https://github.com/exercism/v3/blob/main/reference
-[how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/main/docs/maintainers/generic-how-to-implement-a-concept-exercise.md
-[docs-concept-exercises]: https://github.com/exercism/v3/blob/main/docs/concept-exercises.md
-[docs-rationale-for-v3]: https://github.com/exercism/v3/blob/main/docs/rationale-for-v3.md
-[docs-features-of-v3]: https://github.com/exercism/v3/blob/main/docs/features-of-v3.md
-[anatomy-of-a-concept-exercise]: https://www.youtube.com/watch?v=gkbBqd7hPrA
-[pep8]: https://www.python.org/dev/peps/pep-0008/
-[example-todo]: ../exercises/concept/guidos-gorgeous-lasagna/lasagna.py
-[example-stub]: ../exercises/concept/ghost-gobble-arcade-game/arcade_game.py
-[example-testfile]: ../exercises/concept/little-sisters-essay/string_methods_test.py
-[repl-code-example]: https://docs.python.org/3/tutorial/controlflow.html#defining-functions
-[commonmark]: https://spec.commonmark.org/
-[auto-formatting]: https://github.com/exercism/v3/blob/master/docs/maintainers/style-guide.md#auto-formatting
-[style-guide]: https://github.com/exercism/v3/blob/master/docs/maintainers/style-guide.md
-[python-implementations]: https://github.com/exercism/v3/tree/master/languages/python/exercises
-[concept-exercise-stories]: https://github.com/exercism/v3/tree/master/reference/stories
-[github-issues-python]: https://github.com/exercism/v3/issues?q=is%3Aissue+is%3Aopen+%5BPython%5D+in%3Atitle+label%3Atype%2Fnew-exercise
-[python-docs]: https://docs.python.org/3/
-[unittest]: https://docs.python.org/3/library/unittest.html#unittest.TestCase
diff --git a/reference/exercises_summary.md b/reference/track_exercises_overview.md
similarity index 76%
rename from reference/exercises_summary.md
rename to reference/track_exercises_overview.md
index 74d92dd533f..b9ca592208f 100644
--- a/reference/exercises_summary.md
+++ b/reference/track_exercises_overview.md
@@ -2,28 +2,115 @@
-## Implemented Concept Exercises
+## Implemented and Planned Concept Exercises
-| Concept | About & Introduction | Exercise | Prerequisites | Design./Issue | Status/PR |
-|--------------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |--------------------------------------------------------------------------------------------------------------------- |---------------------- |
-| list-methods | [about.md](https://github.com/exercism/python/blob/main/concepts/list-methods/about.md)π [introduction.md](https://github.com/exercism/python/blob/main/concepts/list-methods/introduction.md) | [Chaitanas Colossal Coaster π’ ](https://github.com/exercism/python/tree/main/exercises/concept/chaitanas-colossal-coaster) | Needs
From 68e035f48f9d50cd150cb47e13db996f87a1ce53 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Sun, 28 Nov 2021 12:16:23 -0800
Subject: [PATCH 0038/1546] Skipped scores after personal top cases.
Regenerated test file. Edited example.py to pass tests.
---
exercises/practice/high-scores/.meta/example.py | 9 +--------
exercises/practice/high-scores/.meta/tests.toml | 2 ++
exercises/practice/high-scores/high_scores_test.py | 12 ------------
3 files changed, 3 insertions(+), 20 deletions(-)
diff --git a/exercises/practice/high-scores/.meta/example.py b/exercises/practice/high-scores/.meta/example.py
index 48bfd03b370..fc86075255c 100644
--- a/exercises/practice/high-scores/.meta/example.py
+++ b/exercises/practice/high-scores/.meta/example.py
@@ -1,3 +1,4 @@
+
def latest(scores):
return scores[-1]
@@ -8,11 +9,3 @@ def personal_best(scores):
def personal_top_three(scores):
return sorted(scores, reverse=True)[:3]
-
-
-def latest_after_top_three(scores):
- return latest(scores)
-
-
-def scores_after_top_three(scores):
- return scores
diff --git a/exercises/practice/high-scores/.meta/tests.toml b/exercises/practice/high-scores/.meta/tests.toml
index c81c228848b..ff40787cadb 100644
--- a/exercises/practice/high-scores/.meta/tests.toml
+++ b/exercises/practice/high-scores/.meta/tests.toml
@@ -35,6 +35,8 @@ description = "Top 3 scores -> Personal top when there is only one"
[2df075f9-fec9-4756-8f40-98c52a11504f]
description = "Top 3 scores -> Latest score after personal top scores"
+include = false
[809c4058-7eb1-4206-b01e-79238b9b71bc]
description = "Top 3 scores -> Scores after personal top scores"
+include = false
diff --git a/exercises/practice/high-scores/high_scores_test.py b/exercises/practice/high-scores/high_scores_test.py
index 629d1bdb152..d3495d6f96b 100644
--- a/exercises/practice/high-scores/high_scores_test.py
+++ b/exercises/practice/high-scores/high_scores_test.py
@@ -2,10 +2,8 @@
from high_scores import (
latest,
- latest_after_top_three,
personal_best,
personal_top_three,
- scores_after_top_three,
)
# Tests adapted from `problem-specifications//canonical-data.json`
@@ -46,13 +44,3 @@ def test_personal_top_when_there_is_only_one(self):
scores = [40]
expected = [40]
self.assertEqual(personal_top_three(scores), expected)
-
- def test_latest_score_after_personal_top_scores(self):
- scores = [70, 50, 20, 30]
- expected = 30
- self.assertEqual(latest_after_top_three(scores), expected)
-
- def test_scores_after_personal_top_scores(self):
- scores = [30, 50, 20, 70]
- expected = [30, 50, 20, 70]
- self.assertEqual(scores_after_top_three(scores), expected)
From c8764783d5c7d0a629c8044ec9e90910b98b7852 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Sun, 28 Nov 2021 12:22:31 -0800
Subject: [PATCH 0039/1546] Re-edited stub file to omit excess function defs.
---
exercises/practice/high-scores/high_scores.py | 8 --------
1 file changed, 8 deletions(-)
diff --git a/exercises/practice/high-scores/high_scores.py b/exercises/practice/high-scores/high_scores.py
index 327f81cf544..0d24cdb1c1d 100644
--- a/exercises/practice/high-scores/high_scores.py
+++ b/exercises/practice/high-scores/high_scores.py
@@ -8,11 +8,3 @@ def personal_best(scores):
def personal_top_three(scores):
pass
-
-
-def latest_after_top_three(scores):
- pass
-
-
-def scores_after_top_three(scores):
- pass
From 7ae5ab7971383676c76d4cc1fc20bf8752087778 Mon Sep 17 00:00:00 2001
From: Job van der Wal
Date: Thu, 25 Nov 2021 09:56:03 +0100
Subject: [PATCH 0040/1546] Lint all practice exercises starting with 's'
---
.../practice/saddle-points/.meta/example.py | 9 +++--
exercises/practice/satellite/.meta/example.py | 16 +++++---
exercises/practice/say/.meta/example.py | 39 ++++++++++---------
.../practice/scale-generator/.meta/example.py | 8 +---
.../scale-generator/scale_generator.py | 28 +++++++++++--
.../secret-handshake/.meta/example.py | 6 +--
exercises/practice/series/.meta/example.py | 10 ++---
.../practice/sgf-parsing/.meta/example.py | 18 ++++-----
exercises/practice/sieve/.meta/example.py | 11 +++---
.../practice/simple-cipher/.meta/example.py | 10 ++---
.../simple-linked-list/.meta/example.py | 16 ++++----
exercises/practice/space-age/.meta/example.py | 5 +--
.../practice/spiral-matrix/.meta/example.py | 21 ++++++----
exercises/practice/strain/.meta/example.py | 17 ++------
exercises/practice/sublist/.meta/example.py | 8 ++--
15 files changed, 122 insertions(+), 100 deletions(-)
diff --git a/exercises/practice/saddle-points/.meta/example.py b/exercises/practice/saddle-points/.meta/example.py
index b2d795cb602..ff11e68a516 100644
--- a/exercises/practice/saddle-points/.meta/example.py
+++ b/exercises/practice/saddle-points/.meta/example.py
@@ -1,13 +1,16 @@
def saddle_points(matrix):
if not matrix:
return []
+
if any(len(row) != len(matrix[0]) for row in matrix):
raise ValueError('irregular matrix')
+
mmax = [max(row) for row in matrix]
mmin = [min(col) for col in zip(*matrix)]
- points = [{"row": index + 1, "column": col_index + 1}
- for index in range(len(matrix))
- for col_index in range(len(matrix[0]))
+
+ points = [{'row': index + 1, 'column': col_index + 1}
+ for index, _ in enumerate(matrix)
+ for col_index, _ in enumerate(matrix[0])
if mmax[index] == mmin[col_index]]
return points or []
diff --git a/exercises/practice/satellite/.meta/example.py b/exercises/practice/satellite/.meta/example.py
index 5869a3fced1..310a89aeed1 100644
--- a/exercises/practice/satellite/.meta/example.py
+++ b/exercises/practice/satellite/.meta/example.py
@@ -1,17 +1,21 @@
def tree_from_traversals(preorder, inorder):
if len(preorder) != len(inorder):
- raise ValueError("traversals must have the same length")
+ raise ValueError('traversals must have the same length')
if set(preorder) != set(inorder):
- raise ValueError("traversals must have the same elements")
+ raise ValueError('traversals must have the same elements')
if len(set(preorder)) != len(preorder) != len(set(inorder)):
- raise ValueError("traversals must contain unique items")
+ raise ValueError('traversals must contain unique items')
if not preorder:
return {}
+
value = preorder.pop(0)
index = inorder.index(value)
left_inorder, right_inorder = inorder[:index], inorder[index+1:]
- left_preorder = [x for x in preorder if x in left_inorder]
- right_preorder = [x for x in preorder if x in right_inorder]
+
+ left_preorder = [idx for idx in preorder if idx in left_inorder]
+ right_preorder = [idx for idx in preorder if idx in right_inorder]
+
left = tree_from_traversals(left_preorder, left_inorder)
right = tree_from_traversals(right_preorder, right_inorder)
- return {"v": value, "l": left, "r": right}
+
+ return {'v': value, 'l': left, 'r': right}
diff --git a/exercises/practice/say/.meta/example.py b/exercises/practice/say/.meta/example.py
index 30ad378f169..95d6d44770f 100644
--- a/exercises/practice/say/.meta/example.py
+++ b/exercises/practice/say/.meta/example.py
@@ -1,4 +1,4 @@
-def say(number, recursive=False):
+def say(number):
small = dict(enumerate((
'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
@@ -7,36 +7,39 @@ def say(number, recursive=False):
tens = {20: 'twenty', 30: 'thirty', 40: 'forty', 50: 'fifty',
60: 'sixty', 70: 'seventy', 80: 'eighty', 90: 'ninety'}
- k, m, b, t = 1e3, 1e6, 1e9, 1e12
+ kilo = 1e3
+ mega = 1e6
+ giga = 1e9
+ tera = 1e12
if number < 0:
- raise ValueError("input out of range")
- if number >= t:
- raise ValueError("input out of range")
+ raise ValueError('input out of range')
+ if number >= tera:
+ raise ValueError('input out of range')
if number < 20:
- return small[number] if not recursive else + small[number]
+ return small[number]
if number < 100:
if number % 10 == 0:
return tens[number]
return tens[number // 10 * 10] + '-' + small[number % 10]
- if number < k:
+ if number < kilo:
if number % 100 == 0:
return small[number // 100] + ' hundred'
return small[number // 100] + ' hundred ' + say(number % 100)
- if number < m:
- if number % k == 0:
- return say(number // k) + ' thousand'
- return say(number // k) + ' thousand ' + say(number % k, True)
+ if number < mega:
+ if number % kilo == 0:
+ return say(number // kilo) + ' thousand'
+ return say(number // kilo) + ' thousand ' + say(number % kilo)
- if number < b:
- if number % m == 0:
- return say(number // m) + ' million'
- return say(number // m) + ' million ' + say(number % m, True)
+ if number < giga:
+ if number % mega == 0:
+ return say(number // mega) + ' million'
+ return say(number // mega) + ' million ' + say(number % mega)
- if number % b == 0:
- return say(number // b) + ' billion'
- return say(number // b) + ' billion ' + say(number % b, True)
+ if number % giga == 0:
+ return say(number // giga) + ' billion'
+ return say(number // giga) + ' billion ' + say(number % giga)
\ No newline at end of file
diff --git a/exercises/practice/scale-generator/.meta/example.py b/exercises/practice/scale-generator/.meta/example.py
index ba05e57f97f..ed11b474ff5 100644
--- a/exercises/practice/scale-generator/.meta/example.py
+++ b/exercises/practice/scale-generator/.meta/example.py
@@ -10,11 +10,7 @@ class Scale:
def __init__(self, tonic, intervals=None):
self.tonic = tonic.capitalize()
self.intervals = intervals
- self.chromatic_scale = (
- self.FLAT_CHROMATIC_SCALE
- if tonic in self.FLAT_KEYS
- else self.CHROMATIC_SCALE
- )
+ self.chromatic_scale = (self.FLAT_CHROMATIC_SCALE if tonic in self.FLAT_KEYS else self.CHROMATIC_SCALE)
def chromatic(self):
return self._reorder_chromatic_scale()
@@ -23,7 +19,7 @@ def interval(self, intervals):
last_index = 0
pitches = []
scale = self._reorder_chromatic_scale()
- for i, interval in enumerate(intervals):
+ for _, interval in enumerate(intervals):
pitches.append(scale[last_index])
last_index += self.ASCENDING_INTERVALS.index(interval) + 1
return pitches
diff --git a/exercises/practice/scale-generator/scale_generator.py b/exercises/practice/scale-generator/scale_generator.py
index eddc1302cbf..ed11b474ff5 100644
--- a/exercises/practice/scale-generator/scale_generator.py
+++ b/exercises/practice/scale-generator/scale_generator.py
@@ -1,9 +1,29 @@
class Scale:
- def __init__(self, tonic):
- pass
+ ASCENDING_INTERVALS = ['m', 'M', 'A']
+ CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A',
+ 'A#', 'B']
+ FLAT_CHROMATIC_SCALE = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab',
+ 'A', 'Bb', 'B']
+ FLAT_KEYS = ['F', 'Bb', 'Eb', 'Ab', 'Db', 'Gb', 'd', 'g', 'c', 'f', 'bb',
+ 'eb']
+
+ def __init__(self, tonic, intervals=None):
+ self.tonic = tonic.capitalize()
+ self.intervals = intervals
+ self.chromatic_scale = (self.FLAT_CHROMATIC_SCALE if tonic in self.FLAT_KEYS else self.CHROMATIC_SCALE)
def chromatic(self):
- pass
+ return self._reorder_chromatic_scale()
def interval(self, intervals):
- pass
+ last_index = 0
+ pitches = []
+ scale = self._reorder_chromatic_scale()
+ for _, interval in enumerate(intervals):
+ pitches.append(scale[last_index])
+ last_index += self.ASCENDING_INTERVALS.index(interval) + 1
+ return pitches
+
+ def _reorder_chromatic_scale(self):
+ index = self.chromatic_scale.index(self.tonic)
+ return self.chromatic_scale[index:] + self.chromatic_scale[:index]
diff --git a/exercises/practice/secret-handshake/.meta/example.py b/exercises/practice/secret-handshake/.meta/example.py
index 9a749b74113..14e681d9350 100644
--- a/exercises/practice/secret-handshake/.meta/example.py
+++ b/exercises/practice/secret-handshake/.meta/example.py
@@ -1,7 +1,7 @@
-gestures = ["jump", "close your eyes", "double blink", "wink"]
+GESTURES = ['jump', 'close your eyes', 'double blink', 'wink']
def commands(binary_str):
- reverse, *bits = [digit == "1" for digit in binary_str]
- actions = [gesture for gesture, bit in zip(gestures, bits) if bit]
+ reverse, *bits = [digit == '1' for digit in binary_str]
+ actions = [gesture for gesture, bit in zip(GESTURES, bits) if bit]
return actions if reverse else actions[::-1]
diff --git a/exercises/practice/series/.meta/example.py b/exercises/practice/series/.meta/example.py
index a5ecfe3567e..447819fc505 100644
--- a/exercises/practice/series/.meta/example.py
+++ b/exercises/practice/series/.meta/example.py
@@ -1,11 +1,11 @@
def slices(series, length):
if not series:
- raise ValueError("series cannot be empty")
+ raise ValueError('series cannot be empty')
elif length == 0:
- raise ValueError("slice length cannot be zero")
+ raise ValueError('slice length cannot be zero')
elif length < 0:
- raise ValueError("slice length cannot be negative")
+ raise ValueError('slice length cannot be negative')
elif len(series) < length:
- raise ValueError("slice length cannot be greater than series length")
+ raise ValueError('slice length cannot be greater than series length')
- return [series[i:i + length] for i in range(len(series) - length + 1)]
+ return [series[idx:idx + length] for idx in range(len(series) - length + 1)]
diff --git a/exercises/practice/sgf-parsing/.meta/example.py b/exercises/practice/sgf-parsing/.meta/example.py
index b1642c3a6fa..cc3327c8ff0 100644
--- a/exercises/practice/sgf-parsing/.meta/example.py
+++ b/exercises/practice/sgf-parsing/.meta/example.py
@@ -22,7 +22,7 @@ def __eq__(self, other):
return False
for child, other_child in zip(self.children, other.children):
- if not (child == other_child):
+ if not child == other_child:
return False
return True
@@ -48,11 +48,11 @@ def parse(input_string):
current = None
stack = list(input_string)
- if input_string == "()":
- raise ValueError("tree with no nodes")
+ if input_string == '()':
+ raise ValueError('tree with no nodes')
if not stack:
- raise ValueError("tree missing")
+ raise ValueError('tree missing')
def pop():
if stack[0] == '\\':
@@ -66,8 +66,8 @@ def pop_until(delimiter):
while stack[0] != delimiter:
value += pop()
return value
- except IndexError:
- raise ValueError("properties without delimiter")
+ except IndexError as error:
+ raise ValueError('properties without delimiter') from error
while stack:
if pop() == '(' and stack[0] == ';':
@@ -76,7 +76,7 @@ def pop_until(delimiter):
while stack[0].isupper():
key = pop_until('[')
if not key.isupper():
- raise ValueError("property must be in uppercase")
+ raise ValueError('property must be in uppercase')
values = []
while stack[0] == '[':
pop()
@@ -86,7 +86,7 @@ def pop_until(delimiter):
if stack[0].isalpha():
if not stack[0].isupper():
- raise ValueError("property must be in uppercase")
+ raise ValueError('property must be in uppercase')
if root is None:
current = root = SgfTree(properties)
@@ -100,6 +100,6 @@ def pop_until(delimiter):
current.children.append(parse(child_input))
elif root is None and current is None:
- raise ValueError("tree missing")
+ raise ValueError('tree missing')
return root
diff --git a/exercises/practice/sieve/.meta/example.py b/exercises/practice/sieve/.meta/example.py
index ebff44bb614..0e8ae8ad35c 100644
--- a/exercises/practice/sieve/.meta/example.py
+++ b/exercises/practice/sieve/.meta/example.py
@@ -1,8 +1,9 @@
def primes(limit):
prime = [True] * (limit + 1)
prime[0] = prime[1] = False
- for i in range(2, int(limit ** 0.5) + 1):
- if prime[i]:
- for j in range(i * i, limit + 1, i):
- prime[j] = False
- return [i for i, x in enumerate(prime) if x]
+ for idx in range(2, int(limit ** 0.5) + 1):
+ if prime[idx]:
+ for edx in range(idx * idx, limit + 1, idx):
+ prime[edx] = False
+
+ return [edx for edx, idx in enumerate(prime) if idx]
diff --git a/exercises/practice/simple-cipher/.meta/example.py b/exercises/practice/simple-cipher/.meta/example.py
index 4ecdcb67ddd..61abf58d2a4 100644
--- a/exercises/practice/simple-cipher/.meta/example.py
+++ b/exercises/practice/simple-cipher/.meta/example.py
@@ -9,17 +9,17 @@ class Cipher:
def __init__(self, key=None):
if key is None:
random.seed(time())
- key = ''.join(random.choice(ascii_lowercase) for i in range(100))
+ key = ''.join(random.choice(ascii_lowercase) for _ in range(100))
self.key = key
def encode(self, text):
return ''.join(
- chr(((ord(c) - 2 * ord('a') + ord(k)) % 26) + ord('a'))
- for c, k in zip(text, cycle(self.key))
+ chr(((ord(character) - 2 * ord('a') + ord(key)) % 26) + ord('a'))
+ for character, key in zip(text, cycle(self.key))
)
def decode(self, text):
return ''.join(
- chr(((ord(c) - ord(k) + 26) % 26) + ord('a'))
- for c, k in zip(text, cycle(self.key))
+ chr(((ord(character) - ord(key) + 26) % 26) + ord('a'))
+ for character, key in zip(text, cycle(self.key))
)
diff --git a/exercises/practice/simple-linked-list/.meta/example.py b/exercises/practice/simple-linked-list/.meta/example.py
index 2b25ac0a91a..f87b155e79e 100644
--- a/exercises/practice/simple-linked-list/.meta/example.py
+++ b/exercises/practice/simple-linked-list/.meta/example.py
@@ -29,10 +29,12 @@ def next(self):
class LinkedList:
- def __init__(self, values=[]):
+ def __init__(self, values=None):
+ values = values if values is not None else []
self._head = None
self._len = 0
- [self.push(v) for v in values]
+ for value in values:
+ self.push(value)
def __iter__(self):
return LinkedIterator(self)
@@ -42,18 +44,18 @@ def __len__(self):
def head(self):
if self._head is None:
- raise EmptyListException("The list is empty.")
+ raise EmptyListException('The list is empty.')
return self._head
def push(self, value):
- newNode = Node(value)
- newNode._next = self._head
- self._head = newNode
+ new_node = Node(value)
+ new_node._next = self._head
+ self._head = new_node
self._len += 1
def pop(self):
if self._head is None:
- raise EmptyListException("The list is empty.")
+ raise EmptyListException('The list is empty.')
self._len -= 1
ret = self._head.value()
self._head = self._head.next()
diff --git a/exercises/practice/space-age/.meta/example.py b/exercises/practice/space-age/.meta/example.py
index 3634fa44e0d..92c502f545e 100644
--- a/exercises/practice/space-age/.meta/example.py
+++ b/exercises/practice/space-age/.meta/example.py
@@ -1,9 +1,6 @@
def period_converter(period):
def inner(self):
- return round(
- self.seconds / period,
- 2
- )
+ return round(self.seconds / period, 2)
return inner
diff --git a/exercises/practice/spiral-matrix/.meta/example.py b/exercises/practice/spiral-matrix/.meta/example.py
index 0524f301417..297094e1df6 100644
--- a/exercises/practice/spiral-matrix/.meta/example.py
+++ b/exercises/practice/spiral-matrix/.meta/example.py
@@ -1,11 +1,16 @@
def spiral_matrix(size):
- matrix = [[0]*size for row in range(size)]
- i, j, element = 0, -1, 1
- di, dj = [0, 1, 0, -1], [1, 0, -1, 0]
- for x in range(2*size - 1):
- for _ in range((2*size - x) // 2):
- i += di[x % 4]
- j += dj[x % 4]
- matrix[i][j] = element
+ matrix = [[0]*size for _ in range(size)]
+ idx = 0
+ jdx = -1
+ element = 1
+
+ digital = [0, 1, 0, -1]
+ disco = [1, 0, -1, 0]
+
+ for edx in range(2*size - 1):
+ for _ in range((2*size - edx) // 2):
+ idx += digital[edx % 4]
+ jdx += disco[edx % 4]
+ matrix[idx][jdx] = element
element += 1
return matrix
diff --git a/exercises/practice/strain/.meta/example.py b/exercises/practice/strain/.meta/example.py
index 6069fc751fd..6c4b3f8152b 100644
--- a/exercises/practice/strain/.meta/example.py
+++ b/exercises/practice/strain/.meta/example.py
@@ -1,14 +1,5 @@
-def keep(seq, pred):
- res = []
- for el in seq:
- if pred(el):
- res.append(el)
- return res
+def keep(sequence, predicate):
+ return [element for element in sequence if predicate(element)]
-
-def discard(seq, pred):
- res = []
- for el in seq:
- if not pred(el):
- res.append(el)
- return res
+def discard(sequence, predicate):
+ return [element for element in sequence if not predicate(element)]
diff --git a/exercises/practice/sublist/.meta/example.py b/exercises/practice/sublist/.meta/example.py
index 948337780dd..93c909baa4f 100644
--- a/exercises/practice/sublist/.meta/example.py
+++ b/exercises/practice/sublist/.meta/example.py
@@ -19,11 +19,11 @@ def contains(list_one, list_two):
return True
if len(list_two) > len(list_one):
return False
- for i in range(len(list_one) - len(list_two) + 1):
- if list_one[i] != list_two[0]:
+ for idx in range(len(list_one) - len(list_two) + 1):
+ if list_one[idx] != list_two[0]:
continue
- for j in range(len(list_two)):
- if list_one[i + j] != list_two[j]:
+ for edx, _ in enumerate(list_two):
+ if list_one[idx + edx] != list_two[edx]:
break
else:
return True
From 851eea05239051f2c46bf90b53b7e573befad171 Mon Sep 17 00:00:00 2001
From: Job van der Wal <48634934+J08K@users.noreply.github.com>
Date: Sun, 28 Nov 2021 23:18:55 +0100
Subject: [PATCH 0041/1546] Update
exercises/practice/spiral-matrix/.meta/example.py
Co-authored-by: BethanyG
---
exercises/practice/spiral-matrix/.meta/example.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/practice/spiral-matrix/.meta/example.py b/exercises/practice/spiral-matrix/.meta/example.py
index 297094e1df6..cc25fb3c208 100644
--- a/exercises/practice/spiral-matrix/.meta/example.py
+++ b/exercises/practice/spiral-matrix/.meta/example.py
@@ -1,5 +1,5 @@
def spiral_matrix(size):
- matrix = [[0]*size for _ in range(size)]
+ matrix = [[0]*size for row in range(size)]
idx = 0
jdx = -1
element = 1
From a64bb946aa3abfa530d4ddb3455b5b62803ddb4f Mon Sep 17 00:00:00 2001
From: Job Peel-van der Wal
Date: Sun, 28 Nov 2021 23:25:47 +0100
Subject: [PATCH 0042/1546] Beep Booop
---
.../scale-generator/scale_generator.py | 28 +++----------------
1 file changed, 4 insertions(+), 24 deletions(-)
diff --git a/exercises/practice/scale-generator/scale_generator.py b/exercises/practice/scale-generator/scale_generator.py
index ed11b474ff5..eddc1302cbf 100644
--- a/exercises/practice/scale-generator/scale_generator.py
+++ b/exercises/practice/scale-generator/scale_generator.py
@@ -1,29 +1,9 @@
class Scale:
- ASCENDING_INTERVALS = ['m', 'M', 'A']
- CHROMATIC_SCALE = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A',
- 'A#', 'B']
- FLAT_CHROMATIC_SCALE = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab',
- 'A', 'Bb', 'B']
- FLAT_KEYS = ['F', 'Bb', 'Eb', 'Ab', 'Db', 'Gb', 'd', 'g', 'c', 'f', 'bb',
- 'eb']
-
- def __init__(self, tonic, intervals=None):
- self.tonic = tonic.capitalize()
- self.intervals = intervals
- self.chromatic_scale = (self.FLAT_CHROMATIC_SCALE if tonic in self.FLAT_KEYS else self.CHROMATIC_SCALE)
+ def __init__(self, tonic):
+ pass
def chromatic(self):
- return self._reorder_chromatic_scale()
+ pass
def interval(self, intervals):
- last_index = 0
- pitches = []
- scale = self._reorder_chromatic_scale()
- for _, interval in enumerate(intervals):
- pitches.append(scale[last_index])
- last_index += self.ASCENDING_INTERVALS.index(interval) + 1
- return pitches
-
- def _reorder_chromatic_scale(self):
- index = self.chromatic_scale.index(self.tonic)
- return self.chromatic_scale[index:] + self.chromatic_scale[:index]
+ pass
From e4260d3b750e753d92f4a1ccbfc7a42861d34145 Mon Sep 17 00:00:00 2001
From: Job Peel-van der Wal
Date: Mon, 29 Nov 2021 01:07:17 +0100
Subject: [PATCH 0043/1546] Wonderful little things
---
.../practice/tournament/.meta/example.py | 2 +-
.../practice/tree-building/.meta/example.py | 10 ++--
exercises/practice/triangle/.meta/example.py | 6 +-
exercises/practice/trinary/.meta/example.py | 6 +-
.../practice/twelve-days/.meta/example.py | 7 ++-
.../practice/two-bucket/.meta/example.py | 58 +++++++++----------
exercises/practice/two-fer/.meta/example.py | 4 +-
.../variable-length-quantity/.meta/example.py | 40 ++++++-------
.../practice/word-count/.meta/example.py | 1 -
.../practice/word-search/.meta/example.py | 20 +++----
exercises/practice/wordy/.meta/example.py | 27 +++++----
exercises/practice/yacht/.meta/example.py | 20 +++----
.../practice/zebra-puzzle/.meta/example.py | 55 ++++++++++--------
13 files changed, 131 insertions(+), 125 deletions(-)
diff --git a/exercises/practice/tournament/.meta/example.py b/exercises/practice/tournament/.meta/example.py
index 88494049440..e711468e21c 100644
--- a/exercises/practice/tournament/.meta/example.py
+++ b/exercises/practice/tournament/.meta/example.py
@@ -27,7 +27,7 @@ def format_table(results):
table = ['Team | MP | W | D | L | P']
for team, games in sorted(
- results.items(), key=lambda g: (-calculate_points(g[1]), g[0])):
+ results.items(), key=lambda group: (-calculate_points(group[1]), group[0])):
team_fmt = '{0:30} | {1:2} | {3:2} | {4:2} | {5:2} | {2:2}'
table.append(
team_fmt.format(team, sum(games), calculate_points(games), *games))
diff --git a/exercises/practice/tree-building/.meta/example.py b/exercises/practice/tree-building/.meta/example.py
index 00196a338e4..f728147610d 100644
--- a/exercises/practice/tree-building/.meta/example.py
+++ b/exercises/practice/tree-building/.meta/example.py
@@ -13,9 +13,9 @@ def __init__(self, node_id):
self.children = []
-def validateRecord(record):
+def validate_record(record):
if record.equal_id() and record.record_id != 0:
- raise ValueError("Only root should have equal record and parent id.")
+ raise ValueError('Only root should have equal record and parent id.')
if not record.equal_id() and record.parent_id >= record.record_id:
raise ValueError("Node record_id should be smaller than it's parent_id.")
@@ -24,10 +24,10 @@ def validateRecord(record):
def BuildTree(records):
parent_dict = {}
node_dict = {}
- ordered_id = sorted((i.record_id for i in records))
+ ordered_id = sorted(idx.record_id for idx in records)
for record in records:
- validateRecord(record)
+ validate_record(record)
parent_dict[record.record_id] = record.parent_id
node_dict[record.record_id] = Node(record.record_id)
@@ -36,7 +36,7 @@ def BuildTree(records):
for index, record_id in enumerate(ordered_id):
if index != record_id:
- raise ValueError("Record id is invalid or out of order.")
+ raise ValueError('Record id is invalid or out of order.')
if record_id == root_id:
root = node_dict[record_id]
diff --git a/exercises/practice/triangle/.meta/example.py b/exercises/practice/triangle/.meta/example.py
index 063dfec2079..10c06464910 100644
--- a/exercises/practice/triangle/.meta/example.py
+++ b/exercises/practice/triangle/.meta/example.py
@@ -1,16 +1,16 @@
def valid(sides):
return sum(sorted(sides)[:2]) >= sorted(sides)[2] and all(
- s > 0 for s in sides
+ side > 0 for side in sides
)
def equilateral(sides):
- return valid(sides) and all(sides[0] == s for s in sides)
+ return valid(sides) and all(sides[0] == side for side in sides)
def isosceles(sides):
return valid(sides) and any(
- s1 == s2 for s1, s2 in zip(sorted(sides), sorted(sides)[1:])
+ side_1 == side_2 for side_1, side_2 in zip(sorted(sides), sorted(sides)[1:])
)
diff --git a/exercises/practice/trinary/.meta/example.py b/exercises/practice/trinary/.meta/example.py
index 96a6e6bdef8..48074c008fd 100644
--- a/exercises/practice/trinary/.meta/example.py
+++ b/exercises/practice/trinary/.meta/example.py
@@ -1,7 +1,7 @@
from functools import reduce
-def trinary(s):
- if set(s) - set('012'):
+def trinary(string):
+ if set(string) - set('012'):
return 0
- return reduce(lambda x, y: x * 3 + int(y), s, 0)
+ return reduce(lambda idx, edx: idx * 3 + int(edx), string, 0)
diff --git a/exercises/practice/twelve-days/.meta/example.py b/exercises/practice/twelve-days/.meta/example.py
index c967211a6fd..6b24c65b1a3 100644
--- a/exercises/practice/twelve-days/.meta/example.py
+++ b/exercises/practice/twelve-days/.meta/example.py
@@ -17,12 +17,13 @@
def verse(day_number):
gifts = GIFTS[-day_number:]
+
if len(gifts) > 1:
gifts[:-1] = [', '.join(gifts[:-1])]
+
gifts = ', and '.join(gifts)
- return 'On the {} day of Christmas my true love gave to me: {}.'.format(
- ORDINAL[day_number], gifts)
+ return f'On the {ORDINAL[day_number]} day of Christmas my true love gave to me: {gifts}.'
def recite(start, end):
- return [verse(n) for n in range(start, end + 1)]
+ return [verse(number) for number in range(start, end + 1)]
diff --git a/exercises/practice/two-bucket/.meta/example.py b/exercises/practice/two-bucket/.meta/example.py
index 68435e6abd0..83077eb1656 100644
--- a/exercises/practice/two-bucket/.meta/example.py
+++ b/exercises/practice/two-bucket/.meta/example.py
@@ -7,47 +7,47 @@
def measure(bucket_one, bucket_two, goal, start_bucket):
sizes = [bucket_one, bucket_two]
- goalIndex = 0 if start_bucket == 'one' else 1
+ goal_index = 0 if start_bucket == 'one' else 1
- def empty(buckets, i):
- return [0, buckets[1]] if i == 0 else [buckets[0], 0]
+ def empty(buckets, idx):
+ return [0, buckets[1]] if idx == 0 else [buckets[0], 0]
- def fill(buckets, i):
- return [sizes[0], buckets[1]] if i == 0 else [buckets[0], sizes[1]]
+ def fill(buckets, idx):
+ return [sizes[0], buckets[1]] if idx == 0 else [buckets[0], sizes[1]]
- def consolidate(buckets, i):
- amount = min(buckets[1 - i], sizes[i] - buckets[i])
- target = buckets[i] + amount
- src = buckets[1 - i] - amount
- return [target, src] if i == 0 else [src, target]
+ def consolidate(buckets, idx):
+ amount = min(buckets[1 - idx], sizes[idx] - buckets[idx])
+ target = buckets[idx] + amount
+ source = buckets[1 - idx] - amount
+ return [target, source] if idx == 0 else [source, target]
def bucket_str(buckets):
- return '{},{}'.format(*buckets)
+ return f'{buckets[0]},{buckets[1]}'
invalid = [0, 0]
- invalid[1 - goalIndex] = sizes[1 - goalIndex]
- invalidStr = bucket_str(invalid)
+ invalid[1 - goal_index] = sizes[1 - goal_index]
+ invalid_string = bucket_str(invalid)
buckets = [0, 0]
- buckets[goalIndex] = sizes[goalIndex]
- toVisit = []
+ buckets[goal_index] = sizes[goal_index]
+ to_visit = []
visited = set()
count = 1
while goal not in buckets:
key = bucket_str(buckets)
- if key != invalidStr and key not in visited:
+ if key != invalid_string and key not in visited:
visited.add(key)
- nc = count + 1
- for i in range(2):
- if buckets[i] != 0:
- toVisit.append((empty(buckets, i), nc))
- if buckets[i] != sizes[i]:
- toVisit.append((fill(buckets, i), nc))
- toVisit.append((consolidate(buckets, i), nc))
- if not any(toVisit):
+ number_count = count + 1
+ for idx in range(2):
+ if buckets[idx] != 0:
+ to_visit.append((empty(buckets, idx), number_count))
+ if buckets[idx] != sizes[idx]:
+ to_visit.append((fill(buckets, idx), number_count))
+ to_visit.append((consolidate(buckets, idx), number_count))
+ if not any(to_visit):
raise ValueError('No more moves!')
- buckets, count = toVisit.pop(0)
+ buckets, count = to_visit.pop(0)
- goalIndex = buckets.index(goal)
- goalBucket = ['one', 'two'][goalIndex]
- otherBucket = buckets[1 - goalIndex]
- return (count, goalBucket, otherBucket)
+ goal_index = buckets.index(goal)
+ goal_bucket = ['one', 'two'][goal_index]
+ other_bucket = buckets[1 - goal_index]
+ return (count, goal_bucket, other_bucket)
diff --git a/exercises/practice/two-fer/.meta/example.py b/exercises/practice/two-fer/.meta/example.py
index b1fd7a28be1..425d236d252 100644
--- a/exercises/practice/two-fer/.meta/example.py
+++ b/exercises/practice/two-fer/.meta/example.py
@@ -1,2 +1,2 @@
-def two_fer(name=None):
- return "One for {}, one for me.".format(name or 'you')
+def two_fer(name='you'):
+ return f'One for {name}, one for me.'
diff --git a/exercises/practice/variable-length-quantity/.meta/example.py b/exercises/practice/variable-length-quantity/.meta/example.py
index d85206aae9e..ed5a393b65c 100644
--- a/exercises/practice/variable-length-quantity/.meta/example.py
+++ b/exercises/practice/variable-length-quantity/.meta/example.py
@@ -1,34 +1,34 @@
-EIGHTBITMASK = 0x80
-SEVENBITSMASK = 0x7f
+EIGHT_BIT_MASK = 0x80
+SEVEN_BIT_MASK = 0x7f
-def encode_single(n):
- bytes_ = [n & SEVENBITSMASK]
- n >>= 7
+def encode_single(number):
+ byte_string = [number & SEVEN_BIT_MASK]
+ number >>= 7
- while n > 0:
- bytes_.append(n & SEVENBITSMASK | EIGHTBITMASK)
- n >>= 7
+ while number > 0:
+ byte_string.append(number & SEVEN_BIT_MASK | EIGHT_BIT_MASK)
+ number >>= 7
- return bytes_[::-1]
+ return byte_string[::-1]
def encode(numbers):
- return sum((encode_single(n) for n in numbers), [])
+ return sum((encode_single(number) for number in numbers), [])
-def decode(bytes_):
+def decode(byte_string):
values = []
- n = 0
+ number = 0
- for i, byte in enumerate(bytes_):
- n <<= 7
- n += (byte & SEVENBITSMASK)
+ for idx, byte in enumerate(byte_string):
+ number <<= 7
+ number += (byte & SEVEN_BIT_MASK)
- if byte & EIGHTBITMASK == 0:
- values.append(n)
- n = 0
- elif i == len(bytes_) - 1:
- raise ValueError("incomplete sequence")
+ if byte & EIGHT_BIT_MASK == 0:
+ values.append(number)
+ number = 0
+ elif idx == len(byte_string) - 1:
+ raise ValueError('incomplete sequence')
return values
diff --git a/exercises/practice/word-count/.meta/example.py b/exercises/practice/word-count/.meta/example.py
index 1705ad78a2f..03fb2608a9d 100644
--- a/exercises/practice/word-count/.meta/example.py
+++ b/exercises/practice/word-count/.meta/example.py
@@ -1,5 +1,4 @@
import re
-
from collections import Counter
diff --git a/exercises/practice/word-search/.meta/example.py b/exercises/practice/word-search/.meta/example.py
index ce86a645512..fe2b9b6652b 100644
--- a/exercises/practice/word-search/.meta/example.py
+++ b/exercises/practice/word-search/.meta/example.py
@@ -7,7 +7,7 @@ def __init__(self, x, y):
self.y = y
def __repr__(self):
- return 'Point({}:{})'.format(self.x, self.y)
+ return f'Point({self.x}:{self.y})'
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
@@ -19,7 +19,7 @@ def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __ne__(self, other):
- return not (self == other)
+ return not self == other
DIRECTIONS = (Point(1, 0), Point(1, -1), Point(1, 1), Point(-1, -1),
@@ -34,25 +34,25 @@ def __init__(self, puzzle):
def find_char(self, coordinate):
if coordinate.x < 0 or coordinate.x >= self.width:
- return
+ return None
if coordinate.y < 0 or coordinate.y >= self.height:
- return
+ return None
return self.rows[coordinate.y][coordinate.x]
def find(self, word, position, direction):
current = copy.copy(position)
for letter in word:
if self.find_char(current) != letter:
- return
+ return None
current += direction
return position, current - direction
def search(self, word):
- positions = (Point(x, y)
- for x in range(self.width) for y in range(self.height))
- for pos in positions:
- for d in DIRECTIONS:
- result = self.find(word, pos, d)
+ positions = (Point(idx, edx)
+ for idx in range(self.width) for edx in range(self.height))
+ for position in positions:
+ for direction in DIRECTIONS:
+ result = self.find(word, position, direction)
if result:
return result
return None
diff --git a/exercises/practice/wordy/.meta/example.py b/exercises/practice/wordy/.meta/example.py
index 6d8dfe08790..2488153e827 100644
--- a/exercises/practice/wordy/.meta/example.py
+++ b/exercises/practice/wordy/.meta/example.py
@@ -2,16 +2,15 @@
from operator import floordiv as div
-VALID_OPERATIONS = {"plus": add, "minus": sub,
- "multiplied by": mul, "divided by": div}
+VALID_OPERATIONS = {'plus': add, 'minus': sub, 'multiplied by': mul, 'divided by': div}
def answer(question):
if not bool(question[8:-1].strip().lower().split()):
- raise ValueError("syntax error")
+ raise ValueError('syntax error')
- elif not question.startswith("What is "):
- raise ValueError("unknown operation")
+ elif not question.startswith('What is '):
+ raise ValueError('unknown operation')
else:
words = question[8:-1].strip().lower().split()
@@ -19,8 +18,8 @@ def answer(question):
try:
main_value = int(words.pop())
- except ValueError:
- raise ValueError("syntax error")
+ except ValueError as error:
+ raise ValueError('syntax error') from error
while words:
operation = [words.pop()]
@@ -29,22 +28,22 @@ def answer(question):
next_to_evaluate = words.pop()
second_value = int(next_to_evaluate)
break
- except ValueError:
+ except ValueError as error:
if next_to_evaluate == operation[-1]:
- raise ValueError("syntax error")
+ raise ValueError('syntax error') from error
else:
operation.append(next_to_evaluate)
else:
if operation[-1] not in VALID_OPERATIONS and not operation[-1].isdigit() :
- raise ValueError("unknown operation")
+ raise ValueError('unknown operation')
else:
- raise ValueError("syntax error")
+ raise ValueError('syntax error')
- operation = " ".join(operation)
+ operation = ' '.join(operation)
try:
main_value = VALID_OPERATIONS[operation](main_value, second_value)
- except KeyError:
- raise ValueError("syntax error")
+ except KeyError as error:
+ raise ValueError('syntax error') from error
return main_value
diff --git a/exercises/practice/yacht/.meta/example.py b/exercises/practice/yacht/.meta/example.py
index 0c8a7c0edd8..dedcb7ac81e 100644
--- a/exercises/practice/yacht/.meta/example.py
+++ b/exercises/practice/yacht/.meta/example.py
@@ -15,8 +15,8 @@
CHOICE = 11
-def sum_of_ns(number, dice):
- return sum(n for n in dice if n == number)
+def sum_of_numbers(number, dice):
+ return sum(idx for idx in dice if idx == number)
def full_house(dice):
@@ -44,12 +44,12 @@ def yacht(dice):
functions = [
yacht,
- partial(sum_of_ns, 1),
- partial(sum_of_ns, 2),
- partial(sum_of_ns, 3),
- partial(sum_of_ns, 4),
- partial(sum_of_ns, 5),
- partial(sum_of_ns, 6),
+ partial(sum_of_numbers, 1),
+ partial(sum_of_numbers, 2),
+ partial(sum_of_numbers, 3),
+ partial(sum_of_numbers, 4),
+ partial(sum_of_numbers, 5),
+ partial(sum_of_numbers, 6),
full_house,
four_of_a_kind,
little_straight,
@@ -61,5 +61,5 @@ def yacht(dice):
def score(dice, category):
try:
return functions[category](dice)
- except IndexError:
- raise ValueError("No such category.")
+ except IndexError as error:
+ raise ValueError('No such category.') from error
diff --git a/exercises/practice/zebra-puzzle/.meta/example.py b/exercises/practice/zebra-puzzle/.meta/example.py
index 667e53d771c..a6ea8f93792 100644
--- a/exercises/practice/zebra-puzzle/.meta/example.py
+++ b/exercises/practice/zebra-puzzle/.meta/example.py
@@ -6,45 +6,52 @@
from itertools import permutations
-def just_right_of(x, y):
- return x - y == 1
+def just_right_of(width, height):
+ return width - height == 1
-def next_to(x, y):
- return abs(x - y) == 1
+def next_to(width, height):
+ return abs(width - height) == 1
def solution():
houses = first, _, middle, _, _ = range(5)
orderings = list(permutations(houses))
+
+ # The following you are about to witness is code from someone who loves 'comprehensions'.
+ # I just fixed the PEP-8 violations...
+ # Someone please write this in a way that it is actually read-able?
+ # Anyways, enjoy.
+ # - J08K <3 (1:05 AM, nov 29th, 2021)
+
result = next(
[{
- Englishman: "Englishman",
- Spaniard: "Spaniard",
- Ukrainian: "Ukrainian",
- Japanese: "Japanese",
- Norwegian: "Norwegian"
- }[x] for x in (water, zebra)]
+ english_man: 'Englishman',
+ spaniard: 'Spaniard',
+ ukrainian: 'Ukrainian',
+ japanese: 'Japanese',
+ norwegian: 'Norwegian'
+ }[idx] for idx in (water, zebra)]
for (red, green, ivory, yellow, blue) in orderings
if just_right_of(green, ivory)
- for (Englishman, Spaniard, Ukrainian, Japanese, Norwegian) in orderings
- if Englishman is red if Norwegian is first if next_to(Norwegian, blue)
- for (coffee, tea, milk, oj, water) in orderings if coffee is green
- if Ukrainian is tea if milk is middle
- for (OldGold, Kools, Chesterfields, LuckyStrike, Parliaments
- ) in orderings if Kools is yellow if LuckyStrike is oj
- if Japanese is Parliaments
- for (dog, snails, fox, horse, zebra) in orderings if Spaniard is dog
- if OldGold is snails if next_to(Chesterfields, fox)
- if next_to(Kools, horse))
+ for (english_man, spaniard, ukrainian, japanese, norwegian) in orderings
+ if english_man is red if norwegian is first if next_to(norwegian, blue)
+ for (coffee, tea, milk, orange_juice, water) in orderings if coffee is green
+ if ukrainian is tea if milk is middle
+ for (old_gold, kools, chesterfields, lucky_strike, parliaments
+ ) in orderings if kools is yellow if lucky_strike is orange_juice
+ if japanese is parliaments
+ for (dog, snails, fox, horse, zebra) in orderings if spaniard is dog
+ if old_gold is snails if next_to(chesterfields, fox)
+ if next_to(kools, horse))
return result
def drinks_water():
- ans, _ = solution()
- return ans
+ answer, _ = solution()
+ return answer
def owns_zebra():
- _, ans = solution()
- return ans
+ _, answer = solution()
+ return answer
From af497e56e29c0f7ab5b91456f04a2a70cb72e5d5 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 29 Nov 2021 23:07:18 +0000
Subject: [PATCH 0044/1546] Bump actions/setup-python from 2.3.0 to 2.3.1
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 2.3.0 to 2.3.1.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v2.3.0...v2.3.1)
---
updated-dependencies:
- dependency-name: actions/setup-python
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
.github/workflows/ci-workflow.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml
index 96296b8aa8f..6886d3f636a 100644
--- a/.github/workflows/ci-workflow.yml
+++ b/.github/workflows/ci-workflow.yml
@@ -17,7 +17,7 @@ jobs:
- uses: actions/checkout@v2.4.0
- name: Set up Python
- uses: actions/setup-python@v2.3.0
+ uses: actions/setup-python@v2.3.1
with:
python-version: 3.8
@@ -57,7 +57,7 @@ jobs:
steps:
- uses: actions/checkout@v2.4.0
- - uses: actions/setup-python@v2.3.0
+ - uses: actions/setup-python@v2.3.1
with:
python-version: ${{ matrix.python-version }}
From f5a4b3008bd1f116cb0a7fa0997dd33d7efb1132 Mon Sep 17 00:00:00 2001
From: PeroPonneso <77463786+PeroPonneso@users.noreply.github.com>
Date: Tue, 7 Dec 2021 15:08:20 +0100
Subject: [PATCH 0045/1546] Update typo in instructions.md
Corrected "a adjective" to "an adjective"
---
exercises/concept/little-sisters-vocab/.docs/instructions.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/concept/little-sisters-vocab/.docs/instructions.md b/exercises/concept/little-sisters-vocab/.docs/instructions.md
index 64460771591..cd37fa92b0a 100644
--- a/exercises/concept/little-sisters-vocab/.docs/instructions.md
+++ b/exercises/concept/little-sisters-vocab/.docs/instructions.md
@@ -77,7 +77,7 @@ Implement the `remove_suffix_ness()` function that takes in a word `str`,
## 4. Extract and transform a word
Suffixes are often used to change the part of speech a word has.
- A common practice in English is "verbing" or "verbifying" -- where a adjective _becomes_ a verb by adding an `en` suffix.
+ A common practice in English is "verbing" or "verbifying" -- where an adjective _becomes_ a verb by adding an `en` suffix.
In this task, your sister is going to practice "verbing" words by extracting an adjective from a sentence and turning it into a verb.
Fortunately, all the words that need to be transformed here are "regular" - they don't need spelling changes to add the suffix.
From e39b63606913828003013d18d064c3c6d642a38d Mon Sep 17 00:00:00 2001
From: PeroPonneso <77463786+PeroPonneso@users.noreply.github.com>
Date: Thu, 9 Dec 2021 09:57:32 +0100
Subject: [PATCH 0046/1546] Add indication of return values
Added indication about what value should be returned by the functions.
Note/Opinion: Some sentences indicates the return value as the ending action after a bullet list, in others the information is mixed in the phrase; while this makes it more 'casual' or friendly, it could confuse the reader who's at the start of his/her programming journey
---
.../concept/chaitanas-colossal-coaster/.docs/instructions.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/exercises/concept/chaitanas-colossal-coaster/.docs/instructions.md b/exercises/concept/chaitanas-colossal-coaster/.docs/instructions.md
index 0c7cc10b183..40280179c8e 100644
--- a/exercises/concept/chaitanas-colossal-coaster/.docs/instructions.md
+++ b/exercises/concept/chaitanas-colossal-coaster/.docs/instructions.md
@@ -38,7 +38,7 @@ Define the `add_me_to_the_queue()` function that takes 4 parameters `` is the `list` of people standing in the queue.
@@ -85,6 +85,7 @@ Define the `remove_the_mean_person()` function that takes 2 parameters `queue` a
1. `` is the `list` of people standing in the queue.
2. `` is the name of the person that needs to be kicked out.
+Return the queue updated without the mean person's name.
```python
>>> remove_the_mean_person(queue=["Natasha", "Steve", "Eltran", "Wanda", "Rocket"], person_name="Eltran")
From 4ecc4eabfda24b8b1a266aa574ac58f373d567a8 Mon Sep 17 00:00:00 2001
From: Mukesh Gurpude
Date: Sat, 2 Oct 2021 11:20:39 +0530
Subject: [PATCH 0047/1546] add a base about
---
concepts/functions/.meta/config.json | 2 +-
concepts/functions/about.md | 301 ++++++++++++++++++++++++++-
2 files changed, 301 insertions(+), 2 deletions(-)
diff --git a/concepts/functions/.meta/config.json b/concepts/functions/.meta/config.json
index 9b9e8da5a9b..6d953eb2d28 100644
--- a/concepts/functions/.meta/config.json
+++ b/concepts/functions/.meta/config.json
@@ -1,5 +1,5 @@
{
- "blurb": "TODO: add blurb for this concept",
+ "blurb": "A function is a block of code which only runs when it is called. It can pass data, known as parameters, into a function. A function can return data as a result for the further use.",
"authors": ["bethanyg", "cmccandless"],
"contributors": []
}
diff --git a/concepts/functions/about.md b/concepts/functions/about.md
index b979eee35d6..b6c27c25376 100644
--- a/concepts/functions/about.md
+++ b/concepts/functions/about.md
@@ -1,3 +1,302 @@
# About
-TODO: add information on functions concept
+A [`function`][function] is a block of organized, reusable code that is used to perform a single, related action.
+`Functions` provide better modularity for your application and a high degree of code reusing.
+Like other programming languages, python provides _pre-defined functions_ ([`print`][print], [`map`][map] etc) that are readily available in the Python language.
+However, you can define your own functions as well which are called [`user-defined functions`][user defined functions].
+Functions can be as simple as _printing a message to the console_ or as complex as _performing a calculation_.
+
+To execute the code inside a function, you need to call the function, which is done by using the function name followed by parenthesis [`()`].
+Data known as `parameters` can be passed to the function inside the parenthesis. Broader terms for parameters are `arguments`. Functions can perform different tasks depending on the value of the parameters.
+
+The function can also return a value using the `return` keyword. The value returned by the function is known as the `return value`. The return value is returned to the caller of the function.
+
+## Creation
+
+In python, functions are created using the `def` keyword. The function definition is followed by the function name and parenthesis [`()`]. Inside the parenthesis, the parameters are specified, and are separated by commas. After the parameters, the colon (`:`) is used to separate the function header from the function body.
+
+The function body is a block of code that is executed when the function is called. The body of the function is indented. The indentation is important because the function body is a block of code. A value can be returned from the function by using the `return` keyword, which will be used by the caller of the function.
+
+```python
+def function_name(parameter1, parameter2, ...):
+ # function body
+ return value
+```
+
+We can also define a function without any parameters or return value.
+```python
+def function_name():
+ # function body
+```
+
+
+## Calling a Function
+
+To call a function, use the function name followed by parenthesis [`()`]. The parameters passed to the function are separated by commas.
+
+Consider the following function:
+```python
+def wish():
+ print("Hello")
+```
+
+Above function can be called by using the following syntax:
+```python
+>>> wish()
+Hello
+```
+
+## Parameters
+
+Parameters are values that are passed to the function when it is called. They are known as `arguments`.
+
+Let's define a function `add`:
+```python
+def add(x, y):
+ print(x + y)
+```
+
+When the function is called, the parameters are passed to the function. We need to pass values for both the parameters, otherwise [`TypeError`][type-error] will be raised.
+```python
+>>> add(2, 3)
+5
+
+# Function can be called multiple times, with different parameters
+>>> add(4, 3)
+7
+>>> add(5, 6)
+11
+
+# Passing incorrect number of parameters will raise `TypeError`
+>>> add(2)
+Traceback (most recent call last):
+ File "", line 1, in
+TypeError: add() missing 1 required positional argument: 'y'
+
+>>> add(2, 3, 4)
+Traceback (most recent call last):
+ File "", line 1, in
+TypeError: add() takes 2 positional arguments but 3 were given
+```
+
+## Return Value
+
+The return value is a value that is returned to the caller of the function. Return value can be of any data type. It can be used by caller of the function to perform further operations. If the function does not explicitly return a value, the value `None` is returned.
+
+Let's define a function `add`:
+```python
+def add(x, y):
+ return x + y
+```
+
+We'll store the return value in a variable and print it:
+```python
+>>> result = add(2, 3)
+>>> print(result)
+5
+# Type of result is `int`
+>>> type(result)
+
+
+# We can also perform operations on the return value
+>>> result * 2
+10
+
+# Function without return value returns `None`
+>>> def log(message):
+ print(message)
+
+# Hello is printed because of print(message), but return value is `None`
+>>> return_value = log("Hello")
+Hello
+>>> return_value
+None
+```
+
+Use of `return` immediately exits the function and returns the value to the caller.
+```python
+>>> def show(x, y):
+ print(x)
+ return x
+ print(y)
+
+# y never gets printed, because function exists after return statement
+>>> show(1, 2)
+1
+```
+
+## Modularity
+
+Complex programs can be broken down into smaller parts. Functions can be used to perform different tasks.
+
+Assume a program has to perform the following tasks:
+ * Calculate the area of a circle
+ * Calculate the area of a rectangle
+ * Calculate the area of a triangle
+
+We can break down the program into smaller parts.
+
+```python
+def circle_area(r):
+ return 3.14 * r * r
+
+def rectangle_area(length, breadth):
+ return length * breadth
+
+def triangle_area(base, height):
+ return 0.5 * base * height
+```
+
+Now, we can call the functions in the order we want.
+
+```python
+>>> circle_area(2)
+12.56
+>>> rectangle_area(2, 3)
+6
+>>> triangle_area(2, 3)
+1.5
+```
+
+## Scope of Variables
+
+If variable is defined inside a function, then it will be only accessible inside the function. If we want to access the variable outside the function, we need to use the [`global`][global] keyword. [`nonlocal`][nonlocal] keyword is used to access the variable inside a nested function.
+
+```python
+def outer():
+ x = 10
+ print('Inside function:', x)
+```
+
+variable `x` is defined inside the outer function. It is limited to the scope of the outer function only. It will not alter the value of the variable outside the outer function.
+
+```python
+>>> x = 30
+
+# regardless of whether we call the function or not, the value of x will be 30
+>>> outer()
+Inside function: 10
+>>> x
+30
+```
+
+We can access the variable inside the outer function using the `global` keyword.
+```python
+def outer():
+ global x
+ x = 10
+ print('Inside function:', x)
+```
+
+As we have used the `global` keyword, the value of `x` will be changed.
+
+```python
+>>> x = 30
+>>> outer()
+Inside function: 10
+>>> x
+10
+```
+
+
+## Functions as first class objects
+
+In python, functions can be assigned to variables and passed as arguments to other functions. They can also be used as return values in other functions. Functions can also be used as items in a sequence([`list`][list], [`tuple`][tuple] etc) or as value in [`dict`][dict]. This is called _function as [`first class object`][first class objects]_.
+
+
+```python
+# print is a function
+
+# function can be assigned to a variable
+>>> fake_print = print
+>>> fake_print("Hello")
+Hello
+>>> type(fake_print)
+
+
+# function can be passed as an argument to another function
+>>> def check_print(func):
+ func("Hello")
+>>> check_print(print)
+Hello
+
+# function can be used as an item in a sequence
+>>> my_list = [print, "Hello"]
+>>> my_list[0]("Hello")
+Hello
+
+# function can be used as a value in a dictionary
+>>> my_dict = {"key": print}
+>>> my_dict["key"]("Hello")
+Hello
+
+# function can be used as a return value in another function
+>>> def return_func():
+ return print
+>>> return_func()("Hello")
+Hello
+```
+
+Functions can also be nested inside other functions.
+```python
+def outer():
+ x = 10
+ def inner():
+ print(x)
+ inner()
+```
+
+The inner function can access the variable `x` defined in the outer function.
+
+```python
+>>> outer()
+10
+```
+
+## Special Attributes
+
+Functions in python have some special attributes. Some of them are:
+ * `__name__`: Name of the function
+ * `__doc__`: Documentation string of the function
+ * `__module__`: Module in which the function is defined
+ * `__globals__`: Dictionary of global variables in the function
+ * `__code__`: Code object containing the instructions of the function
+
+```python
+>>> def add(x, y):
+ return x + y
+
+# Function name
+>>> print.__name__
+'print'
+>>> len.__name__
+'len'
+>>> add.__name__
+'add'
+
+# Function documentation
+>>> abs.__doc__
+'Return the absolute value of the argument.'
+
+# Module
+>>> len.__module__
+'builtins'
+>>> add.__module__
+'__main__'
+```
+
+Full list of attributes can be found at [Python DataModel][attributes].
+
+
+[attributes]: https://docs.python.org/3/reference/datamodel.html#index-33
+[first class objects]: https://en.wikipedia.org/wiki/First-class_object
+[list]: https://docs.python.org/3/tutorial/datastructures.html#list-objects
+[tuple]: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences
+[dict]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
+[global]: https://docs.python.org/3/reference/compound_stmts.html#global
+[nonlocal]: https://docs.python.org/3/reference/compound_stmts.html#nonlocal
+[function]: https://en.wikipedia.org/wiki/Function_(computer_science)
+[print]: https://docs.python.org/3/library/functions.html#print
+[map]: https://docs.python.org/3/library/functions.html#map
+[user defined functions]: https://en.wikipedia.org/wiki/User-defined_function
+[type-error]: https://docs.python.org/3/library/exceptions.html#TypeError
From 041e45931a98ec1d313922b43fee23dd9bb55a46 Mon Sep 17 00:00:00 2001
From: Mukesh Gurpude <55982424+mukeshgurpude@users.noreply.github.com>
Date: Sat, 2 Oct 2021 13:38:06 +0530
Subject: [PATCH 0048/1546] Apply suggestions from code review
Co-authored-by: Isaac Good
---
concepts/functions/about.md | 48 ++++++++++++++++++-------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/concepts/functions/about.md b/concepts/functions/about.md
index b6c27c25376..45392980035 100644
--- a/concepts/functions/about.md
+++ b/concepts/functions/about.md
@@ -1,21 +1,21 @@
# About
A [`function`][function] is a block of organized, reusable code that is used to perform a single, related action.
-`Functions` provide better modularity for your application and a high degree of code reusing.
+`Functions` provide better modularity for your application and a high degree of code reuse.
Like other programming languages, python provides _pre-defined functions_ ([`print`][print], [`map`][map] etc) that are readily available in the Python language.
-However, you can define your own functions as well which are called [`user-defined functions`][user defined functions].
-Functions can be as simple as _printing a message to the console_ or as complex as _performing a calculation_.
+You can also define your own functions. Those are called [`user-defined functions`][user defined functions].
+Functions can run something as simple as _printing a message to the console_ or they can be quite complex.
To execute the code inside a function, you need to call the function, which is done by using the function name followed by parenthesis [`()`].
-Data known as `parameters` can be passed to the function inside the parenthesis. Broader terms for parameters are `arguments`. Functions can perform different tasks depending on the value of the parameters.
+Data. known as `parameters`, can be passed to the function by placing them inside the parenthesis. A broader term for parameters is `arguments`. Functions can perform different tasks depending on the value of the parameters.
-The function can also return a value using the `return` keyword. The value returned by the function is known as the `return value`. The return value is returned to the caller of the function.
+A function can also return a value using the `return` keyword. The value returned by the function is known as the `return value`. The return value is returned to the caller of the function.
## Creation
-In python, functions are created using the `def` keyword. The function definition is followed by the function name and parenthesis [`()`]. Inside the parenthesis, the parameters are specified, and are separated by commas. After the parameters, the colon (`:`) is used to separate the function header from the function body.
+In python, functions are created using the `def` keyword. The function definition is followed by the function name and parenthesis [`()`]. Inside the parenthesis, the parameters are specified, separated by commas. After the close parenthesis, the colon (`:`) is used to separate the function signature from the function body.
-The function body is a block of code that is executed when the function is called. The body of the function is indented. The indentation is important because the function body is a block of code. A value can be returned from the function by using the `return` keyword, which will be used by the caller of the function.
+The function body is a block of code that is executed when the function is called. The body of the function is indented. The indentation is important because Python relies on it to know where that block of code ends. A value can be returned from the function by using the `return` keyword, which can then be used by the caller of the function.
```python
def function_name(parameter1, parameter2, ...):
@@ -32,7 +32,7 @@ def function_name():
## Calling a Function
-To call a function, use the function name followed by parenthesis [`()`]. The parameters passed to the function are separated by commas.
+To call a function, use the function name followed by parenthesis [`()`]. Parameters passed to the function are placed inside the parenthesis, separated by commas.
Consider the following function:
```python
@@ -40,7 +40,7 @@ def wish():
print("Hello")
```
-Above function can be called by using the following syntax:
+The above function can be called by using the following syntax:
```python
>>> wish()
Hello
@@ -50,13 +50,13 @@ Hello
Parameters are values that are passed to the function when it is called. They are known as `arguments`.
-Let's define a function `add`:
+Let's define a function `add` which adds two numbers together:
```python
def add(x, y):
print(x + y)
```
-When the function is called, the parameters are passed to the function. We need to pass values for both the parameters, otherwise [`TypeError`][type-error] will be raised.
+When the function is called, the parameters are passed to the function. We need to pass values for both the parameters, otherwise a [`TypeError`][type-error] will be raised.
```python
>>> add(2, 3)
5
@@ -67,7 +67,7 @@ When the function is called, the parameters are passed to the function. We need
>>> add(5, 6)
11
-# Passing incorrect number of parameters will raise `TypeError`
+# Passing an incorrect number of parameters will raise a `TypeError`
>>> add(2)
Traceback (most recent call last):
File "", line 1, in
@@ -89,7 +89,7 @@ def add(x, y):
return x + y
```
-We'll store the return value in a variable and print it:
+We can store the return value in a variable and then print it:
```python
>>> result = add(2, 3)
>>> print(result)
@@ -102,7 +102,7 @@ We'll store the return value in a variable and print it:
>>> result * 2
10
-# Function without return value returns `None`
+# A function without an explicit return value will return `None`
>>> def log(message):
print(message)
@@ -120,14 +120,14 @@ Use of `return` immediately exits the function and returns the value to the call
return x
print(y)
-# y never gets printed, because function exists after return statement
+# y never gets printed, because the function exits after the return statement
>>> show(1, 2)
1
```
## Modularity
-Complex programs can be broken down into smaller parts. Functions can be used to perform different tasks.
+Complex programs can be broken down into smaller parts. Different functions can be used to perform different specific tasks.
Assume a program has to perform the following tasks:
* Calculate the area of a circle
@@ -201,36 +201,36 @@ Inside function: 10
## Functions as first class objects
-In python, functions can be assigned to variables and passed as arguments to other functions. They can also be used as return values in other functions. Functions can also be used as items in a sequence([`list`][list], [`tuple`][tuple] etc) or as value in [`dict`][dict]. This is called _function as [`first class object`][first class objects]_.
+In python, functions can be assigned to variables and passed as arguments to other functions. They can be used as return values. Functions can also be placed into a sequence([`list`][list], [`tuple`][tuple] etc) or as value in a [`dict`][dict]. Functions can be used anywhere than any other object can be used. This is because _functions are [`first class objects`][first class objects]_.
```python
# print is a function
-# function can be assigned to a variable
+# A function can be assigned to a variable.
>>> fake_print = print
>>> fake_print("Hello")
Hello
>>> type(fake_print)
-# function can be passed as an argument to another function
+# Functions can be passed as an argument to another function.
>>> def check_print(func):
func("Hello")
>>> check_print(print)
Hello
-# function can be used as an item in a sequence
+# Function can be used as an item in a sequence.
>>> my_list = [print, "Hello"]
>>> my_list[0]("Hello")
Hello
-# function can be used as a value in a dictionary
+# Functions can be used as a value in a dictionary.
>>> my_dict = {"key": print}
>>> my_dict["key"]("Hello")
Hello
-# function can be used as a return value in another function
+# Functions can be returned from a function.
>>> def return_func():
return print
>>> return_func()("Hello")
@@ -255,7 +255,7 @@ The inner function can access the variable `x` defined in the outer function.
## Special Attributes
-Functions in python have some special attributes. Some of them are:
+Functions in python have special attributes. Some of them are:
* `__name__`: Name of the function
* `__doc__`: Documentation string of the function
* `__module__`: Module in which the function is defined
@@ -285,7 +285,7 @@ Functions in python have some special attributes. Some of them are:
'__main__'
```
-Full list of attributes can be found at [Python DataModel][attributes].
+The full list of function attributes can be found at [Python DataModel][attributes].
[attributes]: https://docs.python.org/3/reference/datamodel.html#index-33
From 23b65412eb89482cb95ff0e5fd28d3061be269f0 Mon Sep 17 00:00:00 2001
From: Mukesh Gurpude
Date: Sat, 2 Oct 2021 09:16:31 +0000
Subject: [PATCH 0049/1546] apply suggestions from code review
---
concepts/functions/about.md | 46 +++++++++++++++++++------------------
1 file changed, 24 insertions(+), 22 deletions(-)
diff --git a/concepts/functions/about.md b/concepts/functions/about.md
index 45392980035..8ac63b1a065 100644
--- a/concepts/functions/about.md
+++ b/concepts/functions/about.md
@@ -1,8 +1,8 @@
# About
-A [`function`][function] is a block of organized, reusable code that is used to perform a single, related action.
+A [`function`][function] is a block of organized, reusable code that is used to perform a specific task.
`Functions` provide better modularity for your application and a high degree of code reuse.
-Like other programming languages, python provides _pre-defined functions_ ([`print`][print], [`map`][map] etc) that are readily available in the Python language.
+Python, like other programming languages, has [_built-in functions_][build-in functions] ([`print`][print], [`map`][map], and so on) that are readily available.
You can also define your own functions. Those are called [`user-defined functions`][user defined functions].
Functions can run something as simple as _printing a message to the console_ or they can be quite complex.
@@ -48,7 +48,7 @@ Hello
## Parameters
-Parameters are values that are passed to the function when it is called. They are known as `arguments`.
+Parameters are values that are passed to the function when it is called. They can be of any data type.
Let's define a function `add` which adds two numbers together:
```python
@@ -163,18 +163,19 @@ Now, we can call the functions in the order we want.
If variable is defined inside a function, then it will be only accessible inside the function. If we want to access the variable outside the function, we need to use the [`global`][global] keyword. [`nonlocal`][nonlocal] keyword is used to access the variable inside a nested function.
```python
-def outer():
- x = 10
- print('Inside function:', x)
+>>> x = 30
+>>> def random_function():
+ x = 10
+ print('Inside function:', x)
```
-variable `x` is defined inside the outer function. It is limited to the scope of the outer function only. It will not alter the value of the variable outside the outer function.
+As `x` is defined inside the `random_function`, it is limited to the scope of the `random_function` only. Calling the function will not alter the value of the variable outside the function.
```python
>>> x = 30
# regardless of whether we call the function or not, the value of x will be 30
->>> outer()
+>>> random_function()
Inside function: 10
>>> x
30
@@ -182,17 +183,17 @@ Inside function: 10
We can access the variable inside the outer function using the `global` keyword.
```python
-def outer():
- global x
- x = 10
- print('Inside function:', x)
+>>> x = 30
+>>> def random_function():
+ global x
+ x = 10
+ print('Inside function:', x)
```
As we have used the `global` keyword, the value of `x` will be changed.
```python
->>> x = 30
->>> outer()
+>>> random_function()
Inside function: 10
>>> x
10
@@ -208,8 +209,8 @@ In python, functions can be assigned to variables and passed as arguments to oth
# print is a function
# A function can be assigned to a variable.
->>> fake_print = print
->>> fake_print("Hello")
+>>> function_as_variable = print
+>>> function_as_variable("Hello")
Hello
>>> type(fake_print)
@@ -289,14 +290,15 @@ The full list of function attributes can be found at [Python DataModel][attribut
[attributes]: https://docs.python.org/3/reference/datamodel.html#index-33
-[first class objects]: https://en.wikipedia.org/wiki/First-class_object
-[list]: https://docs.python.org/3/tutorial/datastructures.html#list-objects
-[tuple]: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences
+[build-in functions]: https://docs.python.org/3/library/functions.html
[dict]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
+[first class objects]: https://en.wikipedia.org/wiki/First-class_object
+[function]: https://en.wikipedia.org/wiki/Function_(computer_science)
[global]: https://docs.python.org/3/reference/compound_stmts.html#global
+[list]: https://docs.python.org/3/tutorial/datastructures.html#list-objects
+[map]: https://docs.python.org/3/library/functions.html#map
[nonlocal]: https://docs.python.org/3/reference/compound_stmts.html#nonlocal
-[function]: https://en.wikipedia.org/wiki/Function_(computer_science)
[print]: https://docs.python.org/3/library/functions.html#print
-[map]: https://docs.python.org/3/library/functions.html#map
-[user defined functions]: https://en.wikipedia.org/wiki/User-defined_function
+[tuple]: https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences
[type-error]: https://docs.python.org/3/library/exceptions.html#TypeError
+[user defined functions]: https://en.wikipedia.org/wiki/User-defined_function
From efd0c6a132e7e963ad3ba340adf2e70e512570fc Mon Sep 17 00:00:00 2001
From: Mukesh Gurpude
Date: Sat, 2 Oct 2021 19:42:59 +0530
Subject: [PATCH 0050/1546] add intro and links
---
concepts/functions/.meta/config.json | 2 +-
concepts/functions/introduction.md | 6 +++++-
concepts/functions/links.json | 15 ++++++++++++++-
3 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/concepts/functions/.meta/config.json b/concepts/functions/.meta/config.json
index 6d953eb2d28..94ca2fb843b 100644
--- a/concepts/functions/.meta/config.json
+++ b/concepts/functions/.meta/config.json
@@ -1,5 +1,5 @@
{
- "blurb": "A function is a block of code which only runs when it is called. It can pass data, known as parameters, into a function. A function can return data as a result for the further use.",
+ "blurb": "A function is a reusable code block that achieves a specific purpose.",
"authors": ["bethanyg", "cmccandless"],
"contributors": []
}
diff --git a/concepts/functions/introduction.md b/concepts/functions/introduction.md
index 4d28ebca4fb..3a03590c58f 100644
--- a/concepts/functions/introduction.md
+++ b/concepts/functions/introduction.md
@@ -1,3 +1,7 @@
# Introduction
-TODO: add introduction for functions concept
+A [`function`][function] is a block of code that takes an input and produces an output. It is used to perform a specific repititive task. A function can accept `parameters`, do some processing, and then return a value. The parameters and return value can be of any data type and are optional. In python, functions are [_first class objects_][first-class objects], which means they can be assigned to variables, passed as arguments to other functions, and returned as the value of other functions. There are many [_built-in functions_][built-in functions] in python, but you can also create your own functions.
+
+[built-in functions]: https://docs.python.org/3/library/functions.html
+[first-class objects]: https://realpython.com/lessons/functions-first-class-objects-python/
+[function]: https://docs.python.org/3/glossary.html#term-function
diff --git a/concepts/functions/links.json b/concepts/functions/links.json
index fe51488c706..3d54f8ccbc2 100644
--- a/concepts/functions/links.json
+++ b/concepts/functions/links.json
@@ -1 +1,14 @@
-[]
+[
+ {
+ "url": "https://www.w3schools.com/python/python_functions.asp",
+ "description": "W3Schools: Python Functions"
+ },
+ {
+ "url": "https://docs.python.org/3/tutorial/controlflow.html#defining-functions",
+ "description": "Python Tutorial: Functions"
+ },
+ {
+ "url": "https://realpython.com/lessons/functions-first-class-objects-python/",
+ "description": "Real Python: Functions as First-Class Objects"
+ }
+]
From dd18916f5d0f2d65feb38791aa81283e35997e41 Mon Sep 17 00:00:00 2001
From: Mukesh Gurpude <55982424+mukeshgurpude@users.noreply.github.com>
Date: Sat, 23 Oct 2021 08:51:52 +0530
Subject: [PATCH 0051/1546] Apply suggestions from code review
Co-authored-by: BethanyG
---
concepts/functions/.meta/config.json | 4 ++--
concepts/functions/introduction.md | 10 +++++++++-
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/concepts/functions/.meta/config.json b/concepts/functions/.meta/config.json
index 94ca2fb843b..3bb53dac6a4 100644
--- a/concepts/functions/.meta/config.json
+++ b/concepts/functions/.meta/config.json
@@ -1,5 +1,5 @@
{
- "blurb": "A function is a reusable code block that achieves a specific purpose.",
- "authors": ["bethanyg", "cmccandless"],
+ "blurb": "A function is any object to which the *function call* operation can be applied. The body contains one or more statements which return some value to the caller. It can receive zero or more arguments (including other functions). Function definitions use the keyword def, which binds the function name to the object definition in the local namespace.",
+ "authors": ["bethanyg", "mukeshgurpud"],
"contributors": []
}
diff --git a/concepts/functions/introduction.md b/concepts/functions/introduction.md
index 3a03590c58f..f3b16276e53 100644
--- a/concepts/functions/introduction.md
+++ b/concepts/functions/introduction.md
@@ -1,6 +1,14 @@
# Introduction
-A [`function`][function] is a block of code that takes an input and produces an output. It is used to perform a specific repititive task. A function can accept `parameters`, do some processing, and then return a value. The parameters and return value can be of any data type and are optional. In python, functions are [_first class objects_][first-class objects], which means they can be assigned to variables, passed as arguments to other functions, and returned as the value of other functions. There are many [_built-in functions_][built-in functions] in python, but you can also create your own functions.
+A [`function`][function] is a named block of code that takes input and produces output when invoked. Functions are used to perform specific and repetitive tasks throughout a program.
+
+More formally: a function is any Python object to which the [`function call`][calls] operation can be applied. The body of the function contains one or more statements which will return some value to the calling code/caller. The function object can define/receive zero or more parameters/arguments (_including other functions_).
+
+[Function definitions][function-definitions] (`def :`) form an _executable statement_ which binds the `` to the function object definition (_the wrapper around the executable statements in the function body_) in the current local namespace.
+
+Functions are [_first class objects_][first-class objects], which means they can be assigned to variables, passed as arguments to other functions, used as a `return` value, and wrapped around/nested to form decorators and closures.
+
+Python also provides many top-level [_built-in functions_][built-in functions] for common operations.
[built-in functions]: https://docs.python.org/3/library/functions.html
[first-class objects]: https://realpython.com/lessons/functions-first-class-objects-python/
From 83fedb5c34f8baa2cfda2c8dfc888459f1a2fbc0 Mon Sep 17 00:00:00 2001
From: Mukesh Gurpude
Date: Sat, 23 Oct 2021 09:02:25 +0530
Subject: [PATCH 0052/1546] add links as per the suggestion
---
concepts/functions/.meta/config.json | 2 +-
concepts/functions/introduction.md | 10 ++++++----
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/concepts/functions/.meta/config.json b/concepts/functions/.meta/config.json
index 3bb53dac6a4..d0e0798446d 100644
--- a/concepts/functions/.meta/config.json
+++ b/concepts/functions/.meta/config.json
@@ -1,5 +1,5 @@
{
"blurb": "A function is any object to which the *function call* operation can be applied. The body contains one or more statements which return some value to the caller. It can receive zero or more arguments (including other functions). Function definitions use the keyword def, which binds the function name to the object definition in the local namespace.",
- "authors": ["bethanyg", "mukeshgurpud"],
+ "authors": ["bethanyg", "mukeshgurpude"],
"contributors": []
}
diff --git a/concepts/functions/introduction.md b/concepts/functions/introduction.md
index f3b16276e53..1ebd26079f0 100644
--- a/concepts/functions/introduction.md
+++ b/concepts/functions/introduction.md
@@ -1,15 +1,17 @@
# Introduction
-A [`function`][function] is a named block of code that takes input and produces output when invoked. Functions are used to perform specific and repetitive tasks throughout a program.
+A [`function`][function] is a named block of code that takes input and produces output when invoked. Functions are used to perform specific and repetitive tasks throughout a program.
-More formally: a function is any Python object to which the [`function call`][calls] operation can be applied. The body of the function contains one or more statements which will return some value to the calling code/caller. The function object can define/receive zero or more parameters/arguments (_including other functions_).
+More formally: a function is any Python object to which the [`function call`][calls] operation can be applied. The body of the function contains one or more statements which will return some value to the calling code/caller. The function object can define/receive zero or more parameters/arguments (_including other functions_).
-[Function definitions][function-definitions] (`def :`) form an _executable statement_ which binds the `` to the function object definition (_the wrapper around the executable statements in the function body_) in the current local namespace.
+[Function definitions][function-definitions] (`def :`) form an _executable statement_ which binds the `` to the function object definition (_the wrapper around the executable statements in the function body_) in the current local namespace.
-Functions are [_first class objects_][first-class objects], which means they can be assigned to variables, passed as arguments to other functions, used as a `return` value, and wrapped around/nested to form decorators and closures.
+Functions are [_first class objects_][first-class objects], which means they can be assigned to variables, passed as arguments to other functions, used as a `return` value, and wrapped around/nested to form decorators and closures.
Python also provides many top-level [_built-in functions_][built-in functions] for common operations.
[built-in functions]: https://docs.python.org/3/library/functions.html
+[calls]: https://docs.python.org/3/reference/expressions.html#calls
[first-class objects]: https://realpython.com/lessons/functions-first-class-objects-python/
[function]: https://docs.python.org/3/glossary.html#term-function
+[function-definitions]: https://docs.python.org/3/reference/compound_stmts.html#function-definitions
From 8998d30bb0d6665dd233354670f21c4d11c2f1a0 Mon Sep 17 00:00:00 2001
From: Mukesh Gurpude
Date: Sat, 23 Oct 2021 09:22:02 +0530
Subject: [PATCH 0053/1546] Fix errors, and markdownlint warnings
---
concepts/functions/about.md | 40 +++++++++++++++++++++++--------------
1 file changed, 25 insertions(+), 15 deletions(-)
diff --git a/concepts/functions/about.md b/concepts/functions/about.md
index 8ac63b1a065..ccf25bb0028 100644
--- a/concepts/functions/about.md
+++ b/concepts/functions/about.md
@@ -24,23 +24,25 @@ def function_name(parameter1, parameter2, ...):
```
We can also define a function without any parameters or return value.
+
```python
def function_name():
# function body
```
-
## Calling a Function
To call a function, use the function name followed by parenthesis [`()`]. Parameters passed to the function are placed inside the parenthesis, separated by commas.
Consider the following function:
+
```python
def wish():
print("Hello")
```
The above function can be called by using the following syntax:
+
```python
>>> wish()
Hello
@@ -51,12 +53,14 @@ Hello
Parameters are values that are passed to the function when it is called. They can be of any data type.
Let's define a function `add` which adds two numbers together:
+
```python
def add(x, y):
print(x + y)
```
When the function is called, the parameters are passed to the function. We need to pass values for both the parameters, otherwise a [`TypeError`][type-error] will be raised.
+
```python
>>> add(2, 3)
5
@@ -84,12 +88,14 @@ TypeError: add() takes 2 positional arguments but 3 were given
The return value is a value that is returned to the caller of the function. Return value can be of any data type. It can be used by caller of the function to perform further operations. If the function does not explicitly return a value, the value `None` is returned.
Let's define a function `add`:
+
```python
def add(x, y):
return x + y
```
We can store the return value in a variable and then print it:
+
```python
>>> result = add(2, 3)
>>> print(result)
@@ -114,6 +120,7 @@ None
```
Use of `return` immediately exits the function and returns the value to the caller.
+
```python
>>> def show(x, y):
print(x)
@@ -130,9 +137,10 @@ Use of `return` immediately exits the function and returns the value to the call
Complex programs can be broken down into smaller parts. Different functions can be used to perform different specific tasks.
Assume a program has to perform the following tasks:
- * Calculate the area of a circle
- * Calculate the area of a rectangle
- * Calculate the area of a triangle
+
+* Calculate the area of a circle
+* Calculate the area of a rectangle
+* Calculate the area of a triangle
We can break down the program into smaller parts.
@@ -152,10 +160,12 @@ Now, we can call the functions in the order we want.
```python
>>> circle_area(2)
12.56
+>>> triangle_area(2, 3)
+3.0
>>> rectangle_area(2, 3)
6
->>> triangle_area(2, 3)
-1.5
+>>> rectangle_area(1, 2) + circle_area(2) + triangle_area(1, 2)
+15.56
```
## Scope of Variables
@@ -182,6 +192,7 @@ Inside function: 10
```
We can access the variable inside the outer function using the `global` keyword.
+
```python
>>> x = 30
>>> def random_function():
@@ -199,12 +210,10 @@ Inside function: 10
10
```
-
## Functions as first class objects
In python, functions can be assigned to variables and passed as arguments to other functions. They can be used as return values. Functions can also be placed into a sequence([`list`][list], [`tuple`][tuple] etc) or as value in a [`dict`][dict]. Functions can be used anywhere than any other object can be used. This is because _functions are [`first class objects`][first class objects]_.
-
```python
# print is a function
@@ -239,6 +248,7 @@ Hello
```
Functions can also be nested inside other functions.
+
```python
def outer():
x = 10
@@ -257,11 +267,12 @@ The inner function can access the variable `x` defined in the outer function.
## Special Attributes
Functions in python have special attributes. Some of them are:
- * `__name__`: Name of the function
- * `__doc__`: Documentation string of the function
- * `__module__`: Module in which the function is defined
- * `__globals__`: Dictionary of global variables in the function
- * `__code__`: Code object containing the instructions of the function
+
+* `__name__`: Name of the function
+* `__doc__`: Documentation string of the function
+* `__module__`: Module in which the function is defined
+* `__globals__`: Dictionary of global variables in the function
+* `__code__`: Code object containing the instructions of the function
```python
>>> def add(x, y):
@@ -288,12 +299,11 @@ Functions in python have special attributes. Some of them are:
The full list of function attributes can be found at [Python DataModel][attributes].
-
[attributes]: https://docs.python.org/3/reference/datamodel.html#index-33
[build-in functions]: https://docs.python.org/3/library/functions.html
[dict]: https://docs.python.org/3/tutorial/datastructures.html#dictionaries
[first class objects]: https://en.wikipedia.org/wiki/First-class_object
-[function]: https://en.wikipedia.org/wiki/Function_(computer_science)
+[function]: https://docs.python.org/3/glossary.html#term-function
[global]: https://docs.python.org/3/reference/compound_stmts.html#global
[list]: https://docs.python.org/3/tutorial/datastructures.html#list-objects
[map]: https://docs.python.org/3/library/functions.html#map
From b4f4616c4d5234ad41c632d390c69ff220fa5c22 Mon Sep 17 00:00:00 2001
From: Brooks Azzarello <86069809+BrooksAz@users.noreply.github.com>
Date: Sun, 3 Oct 2021 18:36:42 -0400
Subject: [PATCH 0054/1546] Reworded task explanations
I added some additional explanation to steps 1-5, just a few hints to point the user in the right direction of what operation to use. I still don't fully understand 5 and six so they need some more work in my opinion.
---
.../concept/currency-exchange/.docs/instructions.md | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index cd08c96a818..dd4a652a27f 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -7,12 +7,11 @@ Your friend Chandler plans to visit exotic countries all around the world. Sadly
Create the `exchange_money()` function, taking 2 parameters:
1. `budget` : The amount of money you are planning to exchange.
-2. `exchange_rate` : Unit value of the foreign currency.
+2. `exchange_rate` : The amount of domestic currency that equals one unit of foreign currency.
This function should return the value of the exchanged currency.
-**Note:** If your currency is USD and you want to exchange USD for EUR with an exchange rate of `1.20`, then `1.20 USD == 1 EUR`.
-
+**Note:** If there are converting USD to EUR, and there are `1.20 USD` in `1.00 EUR`, the exchange rate is `1.20`.
```python
>>> exchange_money(127.5, 1.2)
106.25
@@ -39,7 +38,7 @@ Create the `get_value_of_bills()` function, taking 2 parameters:
1. `denomination` : The value of a single bill.
2. `number_of_bills` : Amount of bills you received.
-This function should return the total value of the given *bills*.
+This exchanging booth only deals in cash. The total you receive must be divisible by the value of one bill, which can leave behind a reminder. This function should return the total value of the given *bills*.
```python
>>> get_value_of_bills(5, 128)
@@ -50,8 +49,8 @@ This function should return the total value of the given *bills*.
Create the `get_number_of_bills()` function, taking `budget` and `denomination`.
-This function should return the *number of bills* that you can get using the *budget*.
-**Note: ** You can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
+This function should return the *number of bills* that you can get using the *budget*. In other words, how many bills of the denomination's value fit into the total budget
+**Note: ** You can only receive _whole bills_, not fractions of bills, so remember to divide accordingly. You are rounding down to the nearest whole number.
```python
>>> get_number_of_bills(127.5, 5)
25
@@ -62,7 +61,7 @@ This function should return the *number of bills* that you can get using the *bu
Create the `exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`.
Parameter `spread` is the *percentage taken* as an exchange fee.
-If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange will be: `1.00 EUR == 1.32 USD`.
+If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange rate will be: `1.00 EUR == 1.32 USD` because 10% of 1.20 is 0.12.
This function should return the maximum value of the new currency after calculating the *exchange rate* plus the *spread*.
Remember that the currency *denomination* is a whole number, and cannot be sub-divided.
From 2cad26f7044c22e6ae5e133d2fc5d64bdcf00b8f Mon Sep 17 00:00:00 2001
From: Brooks Azzarello <86069809+BrooksAz@users.noreply.github.com>
Date: Sun, 3 Oct 2021 19:16:03 -0400
Subject: [PATCH 0055/1546] Cleared up instructions
---
exercises/concept/currency-exchange/.docs/instructions.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index dd4a652a27f..9ea1f6c5e0f 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -60,13 +60,13 @@ This function should return the *number of bills* that you can get using the *bu
Create the `exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`.
-Parameter `spread` is the *percentage taken* as an exchange fee.
-If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange rate will be: `1.00 EUR == 1.32 USD` because 10% of 1.20 is 0.12.
+Parameter `spread` is the *percentage taken* as an exchange fee, written as an integer. It needs to be converted to decimal by dividing it by 100.
+If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange rate will be: `1.00 EUR == 1.32 USD` because 10% of 1.20 is 0.12, and this additional fee is added to the exchange.
This function should return the maximum value of the new currency after calculating the *exchange rate* plus the *spread*.
Remember that the currency *denomination* is a whole number, and cannot be sub-divided.
-**Note:** Returned value should be `int` type.
+**Note:** Returned value should be converted to `int` type.
```python
>>> exchangeable_value(127.25, 1.20, 10, 20)
@@ -79,7 +79,7 @@ Remember that the currency *denomination* is a whole number, and cannot be sub-d
Create the `non_exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`.
-This function should return the value that is *not* exchangeable due to the *denomination* of the bills.
+This function should return the value that is *not* exchangeable due to the *denomination* of the bills, by subtracting your value after exchange from the theoretical value. The theoretical value assumes bills can be subdivided, therefore ignoring denomination, but does take into account spread.
**Note:** Returned value should be `int` type.
From 71b13cdee0badbce9cfa31b5cf99164a10c93ebb Mon Sep 17 00:00:00 2001
From: Brooks Azzarello <86069809+BrooksAz@users.noreply.github.com>
Date: Sun, 3 Oct 2021 19:30:22 -0400
Subject: [PATCH 0056/1546] Fixed typo
---
exercises/concept/currency-exchange/.docs/instructions.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index 9ea1f6c5e0f..bbc31d78518 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -66,7 +66,7 @@ If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange rate wil
This function should return the maximum value of the new currency after calculating the *exchange rate* plus the *spread*.
Remember that the currency *denomination* is a whole number, and cannot be sub-divided.
-**Note:** Returned value should be converted to `int` type.
+**Note:** Returned value should be `int` type.
```python
>>> exchangeable_value(127.25, 1.20, 10, 20)
From 9dfe198d6b403e21ae492d726ebd671e4c95a458 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Fri, 10 Dec 2021 12:11:58 -0800
Subject: [PATCH 0057/1546] Apply suggestions from code review
---
.../currency-exchange/.docs/instructions.md | 21 +++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index bbc31d78518..2269651e524 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -11,7 +11,7 @@ Create the `exchange_money()` function, taking 2 parameters:
This function should return the value of the exchanged currency.
-**Note:** If there are converting USD to EUR, and there are `1.20 USD` in `1.00 EUR`, the exchange rate is `1.20`.
+**Note:** If your currency is USD and you want to exchange USD for EUR with an exchange rate of `1.20`, then `1.20 USD == 1 EUR`.
```python
>>> exchange_money(127.5, 1.2)
106.25
@@ -38,7 +38,10 @@ Create the `get_value_of_bills()` function, taking 2 parameters:
1. `denomination` : The value of a single bill.
2. `number_of_bills` : Amount of bills you received.
-This exchanging booth only deals in cash. The total you receive must be divisible by the value of one bill, which can leave behind a reminder. This function should return the total value of the given *bills*.
+This exchanging booth only deals in cash of certain increments.
+The total you receive must be divisible by the value of one "bill" or unit, which can leave behind a fraction or remainder.
+Your function should return only the total value of the bills (_excluding fractional amounts_) the booth would give back.
+Unfortunately, the booth gets to keep the remainder/change as an added bonus.
```python
>>> get_value_of_bills(5, 128)
@@ -49,8 +52,10 @@ This exchanging booth only deals in cash. The total you receive must be divisibl
Create the `get_number_of_bills()` function, taking `budget` and `denomination`.
-This function should return the *number of bills* that you can get using the *budget*. In other words, how many bills of the denomination's value fit into the total budget
-**Note: ** You can only receive _whole bills_, not fractions of bills, so remember to divide accordingly. You are rounding down to the nearest whole number.
+This function should return the _number of new currency bills_ that you can receive within the given _budget_.
+In other words, how many _whole bills_ of the new currency fit into the amount of old currency you currently have?
+**Note: ** You can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
+Effectively, you are rounding _down_ to the nearest whole bill/denomination.
```python
>>> get_number_of_bills(127.5, 5)
25
@@ -60,7 +65,8 @@ This function should return the *number of bills* that you can get using the *bu
Create the `exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`.
-Parameter `spread` is the *percentage taken* as an exchange fee, written as an integer. It needs to be converted to decimal by dividing it by 100.
+Parameter `spread` is the *percentage taken* as an exchange fee, written as an integer.
+It needs to be converted to decimal by dividing it by 100.
If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange rate will be: `1.00 EUR == 1.32 USD` because 10% of 1.20 is 0.12, and this additional fee is added to the exchange.
This function should return the maximum value of the new currency after calculating the *exchange rate* plus the *spread*.
@@ -79,7 +85,10 @@ Remember that the currency *denomination* is a whole number, and cannot be sub-d
Create the `non_exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`.
-This function should return the value that is *not* exchangeable due to the *denomination* of the bills, by subtracting your value after exchange from the theoretical value. The theoretical value assumes bills can be subdivided, therefore ignoring denomination, but does take into account spread.
+This function should return the value that is *not* exchangeable due to the *denomination* of the bills.
+Remember - this booth gets to keep the change _in addition_ to charging an exchange fee.
+Start by calculating the value you would receive if you were able to keep subdivided bills, then subtract the amount you would receive in whole bills.
+Both amounts should take the spread, or the exchange fee into account.
**Note:** Returned value should be `int` type.
From 61e41c7cfba8229c6182786f8b9a9afe9799dc7f Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Fri, 10 Dec 2021 12:17:04 -0800
Subject: [PATCH 0058/1546] Update
exercises/concept/currency-exchange/.docs/instructions.md
---
exercises/concept/currency-exchange/.docs/instructions.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index 2269651e524..197710e6d90 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -53,7 +53,7 @@ Unfortunately, the booth gets to keep the remainder/change as an added bonus.
Create the `get_number_of_bills()` function, taking `budget` and `denomination`.
This function should return the _number of new currency bills_ that you can receive within the given _budget_.
-In other words, how many _whole bills_ of the new currency fit into the amount of old currency you currently have?
+In other words: How many _whole bills_ of new currency fit into the amount of old currency you have in your budget?
**Note: ** You can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
Effectively, you are rounding _down_ to the nearest whole bill/denomination.
```python
From 8b942ec52cce2203a68cf47d1543907252cf44ae Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Fri, 10 Dec 2021 12:19:35 -0800
Subject: [PATCH 0059/1546] Update
exercises/concept/currency-exchange/.docs/instructions.md
---
exercises/concept/currency-exchange/.docs/instructions.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index 197710e6d90..1a150e4dc29 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -54,7 +54,7 @@ Create the `get_number_of_bills()` function, taking `budget` and `denomination`.
This function should return the _number of new currency bills_ that you can receive within the given _budget_.
In other words: How many _whole bills_ of new currency fit into the amount of old currency you have in your budget?
-**Note: ** You can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
+Remember -- you can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
Effectively, you are rounding _down_ to the nearest whole bill/denomination.
```python
>>> get_number_of_bills(127.5, 5)
From 1a2f386e51a36391116dfe1c3bfedf329e1238ca Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Mon, 13 Dec 2021 10:35:39 -0800
Subject: [PATCH 0060/1546] Apply suggestions from code review
Co-authored-by: Job van der Wal <48634934+J08K@users.noreply.github.com>
---
exercises/concept/currency-exchange/.docs/instructions.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index 1a150e4dc29..cb80bc804f5 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -54,7 +54,7 @@ Create the `get_number_of_bills()` function, taking `budget` and `denomination`.
This function should return the _number of new currency bills_ that you can receive within the given _budget_.
In other words: How many _whole bills_ of new currency fit into the amount of old currency you have in your budget?
-Remember -- you can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
+Remember -- you can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
Effectively, you are rounding _down_ to the nearest whole bill/denomination.
```python
>>> get_number_of_bills(127.5, 5)
From 59e95e515abf31ec052174bb8e5326f0665d2b22 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Tue, 14 Dec 2021 10:42:12 -0800
Subject: [PATCH 0061/1546] Update
exercises/concept/currency-exchange/.docs/instructions.md
Co-authored-by: Job van der Wal <48634934+J08K@users.noreply.github.com>
---
exercises/concept/currency-exchange/.docs/instructions.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index cb80bc804f5..7e6f347b025 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -7,7 +7,7 @@ Your friend Chandler plans to visit exotic countries all around the world. Sadly
Create the `exchange_money()` function, taking 2 parameters:
1. `budget` : The amount of money you are planning to exchange.
-2. `exchange_rate` : The amount of domestic currency that equals one unit of foreign currency.
+2. `exchange_rate` : The amount of domestic currency equal to one unit of foreign currency.
This function should return the value of the exchanged currency.
From ff8ef357f6848f37cef2489b84c5eb7cbfd0aa1b Mon Sep 17 00:00:00 2001
From: Farhad Uneci
Date: Tue, 14 Dec 2021 19:02:45 +0330
Subject: [PATCH 0062/1546] Fixed dictation error in basic concepts links
There was a link to `https://docs.python.org/3/reference/expressions.html#calls` on this page which held the description `called` that is miss typed, It must follow the link and be typed **_calls_**.
---
concepts/basics/links.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/concepts/basics/links.json b/concepts/basics/links.json
index 0dc21193dce..0c7752279da 100644
--- a/concepts/basics/links.json
+++ b/concepts/basics/links.json
@@ -73,7 +73,7 @@
},
{
"url": "https://docs.python.org/3/reference/expressions.html#calls",
- "description": "called"
+ "description": "calls"
},
{
"url": "https://docs.python.org/3/tutorial/controlflow.html#default-argument-values",
From be114641fad2c36215c73f02b0a1250cdf02d8d9 Mon Sep 17 00:00:00 2001
From: Job Peel-van der Wal
Date: Wed, 15 Dec 2021 00:05:00 +0100
Subject: [PATCH 0063/1546] Card-Games Improvements
---
.../concept/card-games/.docs/instructions.md | 30 ++--
.../concept/card-games/.meta/exemplar.py | 2 +-
exercises/concept/card-games/lists.py | 2 +-
exercises/concept/card-games/lists_test.py | 145 ++++++++----------
4 files changed, 79 insertions(+), 100 deletions(-)
diff --git a/exercises/concept/card-games/.docs/instructions.md b/exercises/concept/card-games/.docs/instructions.md
index e5a9c30f97a..0820eb55f02 100644
--- a/exercises/concept/card-games/.docs/instructions.md
+++ b/exercises/concept/card-games/.docs/instructions.md
@@ -3,48 +3,39 @@
Elyse is really looking forward to playing some poker (and other card games) during her upcoming trip to Vegas.
Being a big fan of "self-tracking" she wants to put together some small functions that will help her with tracking tasks and has asked for your help thinking them through.
-
## 1. Tracking Poker Rounds
Elyse is especially fond of poker, and wants to track how many rounds she plays - and _which rounds_ those are.
Every round has its own number, and every table shows the round number currently being played.
Elyse chooses a table and sits down to play her first round. She plans on playing three rounds.
-
Implement a function `get_rounds()` that takes the current round number and returns a single `list` with that round and the _next two_ that are coming up:
-
```python
>>> get_rounds(27)
[27, 28, 29]
```
-
## 2. Keeping all Rounds in the Same Place
Elyse played a few rounds at the first table, then took a break and played some more rounds at a second table ... but ended up with a different list for each table!
She wants to put the two lists together, so she can track all of the poker rounds in the same place.
-
Implement a function `concatenate_rounds(, )` that takes two lists and returns a single `list` consisting of all the rounds in the first `list`, followed by all the rounds in the second `list`:
-
```python
>>> concatenate_rounds([27, 28, 29], [35, 36])
[27, 28, 29, 35, 36]
```
-
## 3. Finding Prior Rounds
Talking about some of the prior Poker rounds, another player remarks how similarly two of them played out.
Elyse is not sure if she played those rounds or not.
-
Implement a function `list_contains_round(, )` that takes two arguments, a list of rounds played and a round number.
The function will return `True` if the round is in the list of rounds played, `False` if not:
-
```python
>>> list_contains_round([27, 28, 29, 35, 36], 29)
True
@@ -59,7 +50,6 @@ Elyse wants to try out a new game called Black Joe.
It's similar to Black Jack - where your goal is to have the cards in your hand add up to a target value - but in Black Joe the goal is to get the _average_ of the card values to be 7.
The average can be found by summing up all the card values and then dividing that sum by the number of cards in the hand.
-
Implement a function `card_average()` that will return the average value of a hand of Black Joe.
```python
@@ -69,16 +59,18 @@ Implement a function `card_average()` that will return the average value o
## 5. Alternate Averages
-In Black Joe, speed is important.
- Elyse thinks she can "shortcut" the traditional calculation to get an _average-like_ number by taking the average of the first and last card values in the hand - or by using the "middle" card value (the median) of the hand.
- She is hoping one of these calculations might come close to the average, but be quicker to calculate during game play. She'd like you to create a function to test her theory out.
+In Black Joe, speed is important. Elyse is going to try and find a faster way of finding the average.
+She has thought of two ways of getting an _average-like_ number:
-Implement a function `approx_average_is_average()` that returns a Boolean.
-The function should return `True` if _one (or both)_ of Elyse's approximations yields the same value as calculating the "full" average of a hand.
-The function should return `False` if _neither_ approximation formula yields the same value as the "full" average.
-For the sake of a simple median, we are going to assume the hand always has an odd number of card values.
+- Take the average of the _first_ and _last_ number in the hand.
+- Using the median (middle card) of the hand.
+
+Implement the function `approx_average_is_average()`, given `hand`, a list containing the values of the cards in your hand.
+Return `True` if either _one_ `or` _both_ of the, above named, strategies result in a number _equal_ to the _actual average_.
+
+Note: _The length of all hands are odd, to make finding a median easier._
```python
>>> approx_average_is_average([1, 2, 3])
@@ -98,7 +90,6 @@ Intrigued by the results of her averaging experiment, Elyse is wondering if taki
Implement a function `average_even_is_average_odd()` that returns a Boolean indicating if the average of the cards at even indexes is the same as the average of the cards at odd indexes.
-
```python
>>> average_even_is_average_odd([1, 2, 3])
True
@@ -107,16 +98,13 @@ True
False
```
-
## 7. Bonus Round Rules
Every 11th hand in Black Joe is a bonus hand with a bonus rule: if the last card you draw is a Jack, you double its value.
-
Implement a function `maybe_double_last()` that takes a hand and checks if the last card is a Jack (11).
If the the last card **is** a Jack (11), double its value before returning the hand.
-
```python
>>> hand = [5, 9, 11]
>>> maybe_double_last(hand)
diff --git a/exercises/concept/card-games/.meta/exemplar.py b/exercises/concept/card-games/.meta/exemplar.py
index 5e4df3a8b8d..cd108be9220 100644
--- a/exercises/concept/card-games/.meta/exemplar.py
+++ b/exercises/concept/card-games/.meta/exemplar.py
@@ -44,7 +44,7 @@ def approx_average_is_average(hand):
"""
:param hand: list - cards in hand.
- :return: bool - is approximate average the same as true average?
+ :return: bool - if approximate average equals to the `true average`.
"""
real_average = card_average(hand)
diff --git a/exercises/concept/card-games/lists.py b/exercises/concept/card-games/lists.py
index a2c560b9774..7cd7cfdb448 100644
--- a/exercises/concept/card-games/lists.py
+++ b/exercises/concept/card-games/lists.py
@@ -44,7 +44,7 @@ def approx_average_is_average(hand):
"""
:param hand: list - cards in hand.
- :return: bool - is approximate average the same as true average?
+ :return: bool - if approximate average equals to the `true average`.
"""
pass
diff --git a/exercises/concept/card-games/lists_test.py b/exercises/concept/card-games/lists_test.py
index 1fe73b333b6..d8d20f62dfa 100644
--- a/exercises/concept/card-games/lists_test.py
+++ b/exercises/concept/card-games/lists_test.py
@@ -15,108 +15,99 @@ class CardGamesTest(unittest.TestCase):
@pytest.mark.task(taskno=1)
def test_get_rounds(self):
- data = [
- (0, [0, 1, 2]),
- (1, [1, 2, 3]),
- (10, [10, 11, 12]),
- (27, [27, 28, 29]),
- (99, [99, 100, 101]),
- (666, [666, 667, 668]),
- ]
-
- for variant, (number, rounds) in enumerate(data, start=1):
+
+ input_vars = [0, 1, 10, 27, 99, 666]
+
+ results = [[0, 1, 2], [1, 2, 3],
+ [10, 11, 12], [27, 28, 29],
+ [99, 100, 101], [666, 667, 668]]
+
+ for variant, (number, rounds) in enumerate(zip(input_vars, results), start=1):
+ error_message = f'Expected rounds {rounds} given the current round {number}.'
with self.subTest(f'variation #{variant}', input=number, output=rounds):
- error_message = f'Expected rounds {rounds} given the current round {number}.'
self.assertEqual(rounds, get_rounds(number), msg=error_message)
+
@pytest.mark.task(taskno=2)
def test_concatenate_rounds(self):
- data = [
- (([], []), []),
- (([0, 1], []), [0, 1]),
- (([], [1, 2]), [1, 2]),
- (([1], [2]), [1, 2]),
- (([27, 28, 29], [35, 36]), [27, 28, 29, 35, 36]),
- (([1, 2, 3], [4, 5, 6]), [1, 2, 3, 4, 5, 6]),
- ]
-
- for variant, ((rounds_1, rounds_2), rounds) in enumerate(data, start=1):
+
+ input_vars = [([], []), ([0, 1], []), ([], [1, 2]),
+ ([1], [2]), ([27, 28, 29], [35, 36]),
+ ([1, 2, 3], [4, 5, 6])]
+
+ results = [[], [0, 1], [1, 2], [1, 2],
+ [27, 28, 29, 35, 36],
+ [1, 2, 3, 4, 5, 6]]
+
+ for variant, ((rounds_1, rounds_2), rounds) in enumerate(zip(input_vars, results), start=1):
+ error_message = f'Expected {rounds} as the concatenation of {rounds_1} and {rounds_2}.'
with self.subTest(f'variation #{variant}', input=(rounds_1, rounds_2), output=rounds):
- error_message = f'Expected {rounds} as the concatenation of {rounds_1} and {rounds_2}.'
self.assertEqual(rounds, concatenate_rounds(rounds_1, rounds_2), msg=error_message)
+
@pytest.mark.task(taskno=3)
def test_list_contains_round(self):
- data = [
- (([], 1), False),
- (([1, 2, 3], 0), False),
- (([27, 28, 29, 35, 36], 30), False),
- (([1], 1), True),
- (([1, 2, 3], 1), True),
- (([27, 28, 29, 35, 36], 29), True),
- ]
-
- for variant, ((rounds, round_number), contains) in enumerate(data, start=1):
+
+ input_vars = [([], 1), ([1, 2, 3], 0), ([27, 28, 29, 35, 36], 30),
+ ([1], 1), ([1, 2, 3], 1), ([27, 28, 29, 35, 36], 29)]
+
+ results = [False, False, False, True, True, True]
+
+ for variant, ((rounds, round_number), contains) in enumerate(zip(input_vars, results), start=1):
+ error_message = f'Round {round_number} {"is" if contains else "is not"} in {rounds}.'
with self.subTest(f'variation #{variant}', input=(rounds, round_number), output=contains):
- error_message = f'Round {round_number} {"is" if contains else "is not"} in {rounds}.'
- self.assertEqual(contains,list_contains_round(rounds, round_number),msg=error_message)
+ self.assertEqual(contains, list_contains_round(rounds, round_number), msg=error_message)
+
@pytest.mark.task(taskno=4)
def test_card_average(self):
- data = [
- ([1], 1.0),
- ([5, 6, 7], 6.0),
- ([1, 2, 3, 4], 2.5),
- ([1, 10, 100], 37.0),
- ]
-
- for variant, (hand, average) in enumerate(data, start=1):
+
+ input_vars = [[1], [5, 6, 7], [1, 2, 3, 4], [1, 10, 100]]
+
+ results = [1.0, 6.0, 2.5, 37.0]
+
+ for variant, (hand, average) in enumerate(zip(input_vars, results), start=1):
+ error_message=f'Expected {average} as the average of {hand}.'
with self.subTest(f'variation #{variant}', input=hand, output=average):
- msg=f'Expected {average} as the average of {hand}.'
- self.assertEqual(average,card_average(hand),msg=msg)
+ self.assertEqual(average, card_average(hand), msg=error_message)
+
@pytest.mark.task(taskno=5)
def test_approx_average_is_average(self):
- data = [
- ([0, 1, 5], False),
- ([3, 6, 9, 12, 150], False),
- ([1, 2, 3, 5, 9], False),
- ([2, 3, 4, 7, 8], False),
- ([1, 2, 3], True),
- ([2, 3, 4], True),
- ([2, 3, 4, 8, 8], True),
- ([1, 2, 4, 5, 8], True),
- ]
-
- for variant, (hand, same) in enumerate(data, start=1):
+
+ input_vars = [[0, 1, 5], [3, 6, 9, 12, 150], [1, 2, 3, 5, 9],
+ [2, 3, 4, 7, 8], [1, 2, 3], [2, 3, 4],
+ [2, 3, 4, 8, 8], [1, 2, 4, 5, 8]]
+
+ results = [False, False, False, False, True, True, True, True]
+
+ for variant, (hand, same) in enumerate(zip(input_vars, results), start=1):
+ error_message = f'Hand {hand} {"does" if same else "does not"} yield the same approximate average.'
with self.subTest(f'variation #{variant}', input=hand, output=same):
- error_message = f'Hand {hand} {"does" if same else "does not"} yield the same approximate average.'
self.assertEqual(same, approx_average_is_average(hand), msg=error_message)
+
@pytest.mark.task(taskno=6)
def test_average_even_is_average_odd(self):
- data = [
- ([5, 6, 8], False),
- ([1, 2, 3, 4], False),
- ([1, 2, 3], True),
- ([5, 6, 7], True),
- ]
-
- for variant, (hand, same) in enumerate(data, start=1):
+
+ input_vars = [[5, 6, 8], [1, 2, 3, 4], [1, 2, 3], [5, 6, 7], ]
+
+ results = [False, False, True, True]
+
+ for variant, (hand, same) in enumerate(zip(input_vars, results), start=1):
+ error_message=f'Hand {hand} {"does" if same else "does not"} yield the same odd-even average.'
with self.subTest(f'variation #{variant}', input=hand, output=same):
- msg=f'Hand {hand} {"does" if same else "does not"} yield the same odd-even average.'
- self.assertEqual(same, average_even_is_average_odd(hand),msg=msg)
+ self.assertEqual(same, average_even_is_average_odd(hand),msg=error_message)
+
@pytest.mark.task(taskno=7)
def test_maybe_double_last(self):
- data = [
- ([1, 2, 11], [1, 2, 22]),
- ([5, 9, 11], [5, 9, 22]),
- ([5, 9, 10], [5, 9, 10]),
- ([1, 2, 3], [1, 2, 3]),
- ]
-
- for variant, (hand, doubled_hand) in enumerate(data, start=1):
+
+ input_vars = [[1, 2, 11], [5, 9, 11], [5, 9, 10], [1, 2, 3]]
+
+ results = [[1, 2, 22], [5, 9, 22], [5, 9 , 10], [1, 2, 3]]
+
+ for variant, (hand, doubled_hand) in enumerate(zip(input_vars, results), start=1):
+ error_message=f'Expected {doubled_hand} as the maybe-doubled version of {hand}.'
with self.subTest(f'variation #{variant}', input=hand, output=doubled_hand):
- msg=f'Expected {doubled_hand} as the maybe-doubled version of {hand}.'
- self.assertEqual(doubled_hand,maybe_double_last(hand),msg=msg)
+ self.assertEqual(doubled_hand,maybe_double_last(hand),msg=error_message)
From ce32e466929000bc2dd3036bf96c9bc4f4579eb0 Mon Sep 17 00:00:00 2001
From: Ivan Marton
Date: Tue, 21 Dec 2021 10:00:18 +0100
Subject: [PATCH 0064/1546] Typo in introduction.md
An extra space in the function name where it was calling prevented simple copy-paste usage.
---
concepts/basics/introduction.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/concepts/basics/introduction.md b/concepts/basics/introduction.md
index 51535a19be8..1c7762a5d4c 100644
--- a/concepts/basics/introduction.md
+++ b/concepts/basics/introduction.md
@@ -57,7 +57,7 @@ Functions that do not have an explicit `return` expression will return [`None`][
def add_two_numbers(number_one, number_two):
result = number_one + number_two
->>> print(add_two_number s(5, 7))
+>>> print(add_two_numbers(5, 7))
None
```
From 6908da217fac3d27b8ef749f1e3a10ae7dc62829 Mon Sep 17 00:00:00 2001
From: Sijis Aviles
Date: Wed, 22 Dec 2021 23:25:38 -0600
Subject: [PATCH 0065/1546] docs: remove whitespace
---
.../currency-exchange/.docs/instructions.md | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/exercises/concept/currency-exchange/.docs/instructions.md b/exercises/concept/currency-exchange/.docs/instructions.md
index 7e6f347b025..8e41ec0ca7a 100644
--- a/exercises/concept/currency-exchange/.docs/instructions.md
+++ b/exercises/concept/currency-exchange/.docs/instructions.md
@@ -38,10 +38,10 @@ Create the `get_value_of_bills()` function, taking 2 parameters:
1. `denomination` : The value of a single bill.
2. `number_of_bills` : Amount of bills you received.
-This exchanging booth only deals in cash of certain increments.
+This exchanging booth only deals in cash of certain increments.
The total you receive must be divisible by the value of one "bill" or unit, which can leave behind a fraction or remainder.
Your function should return only the total value of the bills (_excluding fractional amounts_) the booth would give back.
-Unfortunately, the booth gets to keep the remainder/change as an added bonus.
+Unfortunately, the booth gets to keep the remainder/change as an added bonus.
```python
>>> get_value_of_bills(5, 128)
@@ -52,10 +52,11 @@ Unfortunately, the booth gets to keep the remainder/change as an added bonus.
Create the `get_number_of_bills()` function, taking `budget` and `denomination`.
-This function should return the _number of new currency bills_ that you can receive within the given _budget_.
-In other words: How many _whole bills_ of new currency fit into the amount of old currency you have in your budget?
-Remember -- you can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
+This function should return the _number of new currency bills_ that you can receive within the given _budget_.
+In other words: How many _whole bills_ of new currency fit into the amount of old currency you have in your budget?
+Remember -- you can only receive _whole bills_, not fractions of bills, so remember to divide accordingly.
Effectively, you are rounding _down_ to the nearest whole bill/denomination.
+
```python
>>> get_number_of_bills(127.5, 5)
25
@@ -65,8 +66,8 @@ Effectively, you are rounding _down_ to the nearest whole bill/denomination.
Create the `exchangeable_value()` function, taking `budget`, `exchange_rate`, `spread`, and `denomination`.
-Parameter `spread` is the *percentage taken* as an exchange fee, written as an integer.
-It needs to be converted to decimal by dividing it by 100.
+Parameter `spread` is the *percentage taken* as an exchange fee, written as an integer.
+It needs to be converted to decimal by dividing it by 100.
If `1.00 EUR == 1.20 USD` and the *spread* is `10`, the actual exchange rate will be: `1.00 EUR == 1.32 USD` because 10% of 1.20 is 0.12, and this additional fee is added to the exchange.
This function should return the maximum value of the new currency after calculating the *exchange rate* plus the *spread*.
@@ -87,7 +88,7 @@ Create the `non_exchangeable_value()` function, taking `budget`, `exchange_rate`
This function should return the value that is *not* exchangeable due to the *denomination* of the bills.
Remember - this booth gets to keep the change _in addition_ to charging an exchange fee.
-Start by calculating the value you would receive if you were able to keep subdivided bills, then subtract the amount you would receive in whole bills.
+Start by calculating the value you would receive if you were able to keep subdivided bills, then subtract the amount you would receive in whole bills.
Both amounts should take the spread, or the exchange fee into account.
**Note:** Returned value should be `int` type.
From 80046646ea6f1492c5af4e9aa48b8e34e0b62e72 Mon Sep 17 00:00:00 2001
From: Gabo
Date: Thu, 30 Dec 2021 17:31:21 -0500
Subject: [PATCH 0066/1546] Update noun_to_verb to adjective_to_verb I noticed
that the actually extracts an adjective, not a noun. Also proposed a new
sentence (with an adjective) in the test as that was a noun
---
.../concept/little-sisters-vocab/.docs/instructions.md | 7 +++----
.../concept/little-sisters-vocab/.meta/exemplar.py | 2 +-
exercises/concept/little-sisters-vocab/strings.py | 2 +-
exercises/concept/little-sisters-vocab/strings_test.py | 10 +++++-----
4 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/exercises/concept/little-sisters-vocab/.docs/instructions.md b/exercises/concept/little-sisters-vocab/.docs/instructions.md
index cd37fa92b0a..6100cdb1622 100644
--- a/exercises/concept/little-sisters-vocab/.docs/instructions.md
+++ b/exercises/concept/little-sisters-vocab/.docs/instructions.md
@@ -82,16 +82,15 @@ Suffixes are often used to change the part of speech a word has.
In this task, your sister is going to practice "verbing" words by extracting an adjective from a sentence and turning it into a verb.
Fortunately, all the words that need to be transformed here are "regular" - they don't need spelling changes to add the suffix.
-Implement the `noun_to_verb(, )` function that takes two parameters.
+Implement the `adjective_to_verb(, )` function that takes two parameters.
A `sentence` using the vocabulary word, and the `index` of the word, once that sentence is split apart.
The function should return the extracted adjective as a verb.
```python
->>> noun_to_verb('I need to make that bright.', -1 )
+>>> adjective_to_verb('I need to make that bright.', -1 )
'brighten'
->>> noun_to_verb('It got dark as the sun set.', 2)
+>>> adjective_to_verb('It got dark as the sun set.', 2)
'darken'
```
-
diff --git a/exercises/concept/little-sisters-vocab/.meta/exemplar.py b/exercises/concept/little-sisters-vocab/.meta/exemplar.py
index b0145fb304e..ccd00092ee1 100644
--- a/exercises/concept/little-sisters-vocab/.meta/exemplar.py
+++ b/exercises/concept/little-sisters-vocab/.meta/exemplar.py
@@ -45,7 +45,7 @@ def remove_suffix_ness(word):
return word
-def noun_to_verb(sentence, index):
+def adjective_to_verb(sentence, index):
"""
:param sentence: str that uses the word in sentence
diff --git a/exercises/concept/little-sisters-vocab/strings.py b/exercises/concept/little-sisters-vocab/strings.py
index 10ceba8f7d6..56aaa04a232 100644
--- a/exercises/concept/little-sisters-vocab/strings.py
+++ b/exercises/concept/little-sisters-vocab/strings.py
@@ -38,7 +38,7 @@ def remove_suffix_ness(word):
pass
-def noun_to_verb(sentence, index):
+def adjective_to_verb(sentence, index):
"""
:param sentence: str that uses the word in sentence
diff --git a/exercises/concept/little-sisters-vocab/strings_test.py b/exercises/concept/little-sisters-vocab/strings_test.py
index aca9e45e8eb..79ca4abc94f 100644
--- a/exercises/concept/little-sisters-vocab/strings_test.py
+++ b/exercises/concept/little-sisters-vocab/strings_test.py
@@ -3,7 +3,7 @@
from strings import (add_prefix_un,
make_word_groups,
remove_suffix_ness,
- noun_to_verb)
+ adjective_to_verb)
class LittleSistersVocabTest(unittest.TestCase):
@@ -73,22 +73,22 @@ def test_remove_suffix_ness(self):
msg=f'Expected: {result} but got a different word instead.')
@pytest.mark.task(taskno=4)
- def test_noun_to_verb(self):
+ def test_adjective_to_verb(self):
input_data = ['Look at the bright sky.',
'His expression went dark.',
'The bread got hard after sitting out.',
'The butter got soft in the sun.',
- 'Her face was filled with light.',
+ 'Her eyes were light blue.',
'The morning fog made everything damp with mist.',
'He cut the fence pickets short by mistake.',
'Charles made weak crying noises.',
'The black oil got on the white dog.']
- index_data = [-2, -1, 3, 3, -1, -3, 5, 2, 1]
+ index_data = [-2, -1, 3, 3, -2, -3, 5, 2, 1]
result_data = ['brighten', 'darken', 'harden', 'soften',
'lighten', 'dampen', 'shorten', 'weaken', 'blacken']
number_of_variants = range(1, len(input_data) + 1)
for variant, sentence, index, result in zip(number_of_variants, input_data, index_data, result_data):
with self.subTest(f'variation #{variant}', sentence=sentence, index=index, result=result):
- self.assertEqual(noun_to_verb(sentence, index), result,
+ self.assertEqual(adjective_to_verb(sentence, index), result,
msg=f'Expected: {result} but got a different word instead.')
From 3b6feec474d36ea76978e6ea6604b193518b6fc4 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Sat, 25 Dec 2021 14:39:18 -0500
Subject: [PATCH 0067/1546] Rough draft of `__repr__` and `__str__`
instructions.
---
.../clock/.docs/instructions.append.md | 56 +++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 exercises/practice/clock/.docs/instructions.append.md
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
new file mode 100644
index 00000000000..b8dd97ba3a4
--- /dev/null
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -0,0 +1,56 @@
+# Instructions append
+
+## Representing your class
+
+When working with and debugging objects, it's important to have a string representation of that object. For example, if you were to create a `datetime.datetime` object in a REPL environment, you could see its string representation:
+
+```python
+>>> from datetime import datetime
+>>> datetime(2022, 5, 4)
+datetime.datetime(2022, 5, 4, 0, 0)
+```
+
+In this excersize, you will create a custom object, `Clock`, that handles times without dates. To do this in python, you would create a `class` to define its data and behavior.
+
+One aspect of a class' behavior is this string prepresentation. By default, a class' string representation is not very helpful:
+
+```python
+>>> Clock(12, 34)
+
+```
+
+To create a more helpful representation, you will need to define a `__repr__` method on your class.
+
+According to the [specification for a `__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), you should ideally have the method return a string that could be used to recreate the object, is you were to copy the result and paste it in a new environment.
+
+For example, a `Clock` what represents 11:30 AM would look like this: `Clock(11, 30)`.
+
+
+Defining a `__repr__` method is a great thing to do for every class you create. When you do, you should consider:
+
+- The information you're returning from this method will be beneficial when you're debugging issues.
+
+- Ideally, you should return a string that a user could copy, paste into a python environment, and have a copy of the object.
+
+- If that's not possible, return a practical description between angle brackets, as in `< ...a practical description... >`.
+
+
+### String conversion
+
+As useful as the `__repr__` method is, sometimes you'll want an alternative string representation. For example, let's look at the `datetime.datetime` class again:
+
+```python
+>>> str(datetime.datetime(2022, 5, 4))
+'2022-05-04 00:00:00'
+```
+
+When a `datetime` object is askes to convert itself to a string, it turns into a string formatted according to the ISO 8601 standard, which can be parsed by most datetime libraries.
+
+This clock exercise will provide you with a similar opportunity. Part of the challenge will be to have an alternate representation like this:
+
+```python
+>>> str(Clock(11, 30))
+'11:30'
+```
+
+To support this string conversion, you will need to create a `__str__` method on your class.
From 05faeb52ec545d91b0c757875ea8bbdcd8a86dfb Mon Sep 17 00:00:00 2001
From: Chris May
Date: Mon, 27 Dec 2021 09:06:40 -0500
Subject: [PATCH 0068/1546] Adding tests for Clock `repr` functionality
---
exercises/practice/clock/.docs/instructions.append.md | 2 +-
exercises/practice/clock/clock_test.py | 10 ++++++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
index b8dd97ba3a4..e5a71981c55 100644
--- a/exercises/practice/clock/.docs/instructions.append.md
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -23,7 +23,7 @@ To create a more helpful representation, you will need to define a `__repr__` me
According to the [specification for a `__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), you should ideally have the method return a string that could be used to recreate the object, is you were to copy the result and paste it in a new environment.
-For example, a `Clock` what represents 11:30 AM would look like this: `Clock(11, 30)`.
+For example, a `Clock` what represents 11:30 AM could look like this: `Clock(11, 30)`.
Defining a `__repr__` method is a great thing to do for every class you create. When you do, you should consider:
diff --git a/exercises/practice/clock/clock_test.py b/exercises/practice/clock/clock_test.py
index f73af0947b8..28300a8d52d 100644
--- a/exercises/practice/clock/clock_test.py
+++ b/exercises/practice/clock/clock_test.py
@@ -8,6 +8,16 @@
class ClockTest(unittest.TestCase):
+ # Create a string representation
+ def test_breakfast_time(self):
+ self.assertEqual(repr(Clock(6, 45)), "Clock(6, 45)")
+
+ def test_lunchtime(self):
+ self.assertEqual(repr(Clock(12, 0)), "Clock(12, 0)")
+
+ def test_dinnertime(self):
+ self.assertEqual(repr(Clock(18, 30)), "Clock(18, 30)")
+
# Create A New Clock With An Initial Time
def test_on_the_hour(self):
self.assertEqual(str(Clock(8, 0)), "08:00")
From dd42bc8332e844497f3f283ae85dc31b0a3b5283 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Mon, 27 Dec 2021 09:17:16 -0500
Subject: [PATCH 0069/1546] Adding stub for Clock's `__str__` method
---
exercises/practice/clock/clock.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/exercises/practice/clock/clock.py b/exercises/practice/clock/clock.py
index 26739a7879f..1102992a69c 100644
--- a/exercises/practice/clock/clock.py
+++ b/exercises/practice/clock/clock.py
@@ -5,6 +5,9 @@ def __init__(self, hour, minute):
def __repr__(self):
pass
+ def __str__(self):
+ pass
+
def __eq__(self, other):
pass
From 08afa298261efe465a253d3796ad200d01ff3bda Mon Sep 17 00:00:00 2001
From: Chris May
Date: Mon, 27 Dec 2021 09:23:07 -0500
Subject: [PATCH 0070/1546] Refinement to Clock's `__repr__` instructions
---
exercises/practice/clock/.docs/instructions.append.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
index e5a71981c55..eb847150819 100644
--- a/exercises/practice/clock/.docs/instructions.append.md
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -19,11 +19,11 @@ One aspect of a class' behavior is this string prepresentation. By default, a cl
```
-To create a more helpful representation, you will need to define a `__repr__` method on your class.
+To create a more helpful representation, you will need to define a `__repr__` method on your class that returns a string.
-According to the [specification for a `__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), you should ideally have the method return a string that could be used to recreate the object, is you were to copy the result and paste it in a new environment.
+According to the [specification for a `__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), you should ideally have the method return a string that could be used to recreate the object, if you were to copy and paste it into a new environment.
-For example, a `Clock` what represents 11:30 AM could look like this: `Clock(11, 30)`.
+For example, a `Clock` that represents 11:30 AM could look like this: `Clock(11, 30)`.
Defining a `__repr__` method is a great thing to do for every class you create. When you do, you should consider:
@@ -32,7 +32,7 @@ Defining a `__repr__` method is a great thing to do for every class you create.
- Ideally, you should return a string that a user could copy, paste into a python environment, and have a copy of the object.
-- If that's not possible, return a practical description between angle brackets, as in `< ...a practical description... >`.
+- If that's not practical, return a description between angle brackets, as in `< ...a practical description... >`.
### String conversion
From 97e3c4e67b69a4e693dc8cd0c90f6f2ed1618154 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Mon, 27 Dec 2021 19:48:12 -0500
Subject: [PATCH 0071/1546] Apply suggestions from code review
Co-authored-by: Isaac Good
---
.../clock/.docs/instructions.append.md | 32 +++++++++++--------
1 file changed, 18 insertions(+), 14 deletions(-)
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
index eb847150819..30b1b8ecdd3 100644
--- a/exercises/practice/clock/.docs/instructions.append.md
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -2,7 +2,8 @@
## Representing your class
-When working with and debugging objects, it's important to have a string representation of that object. For example, if you were to create a `datetime.datetime` object in a REPL environment, you could see its string representation:
+When working with and debugging objects, it's important to have a string representation of that object.
+For example, if you were to create a `datetime.datetime` object in a REPL environment, you can see its string representation:
```python
>>> from datetime import datetime
@@ -10,43 +11,46 @@ When working with and debugging objects, it's important to have a string represe
datetime.datetime(2022, 5, 4, 0, 0)
```
-In this excersize, you will create a custom object, `Clock`, that handles times without dates. To do this in python, you would create a `class` to define its data and behavior.
+In this excersise, you will create a custom object, `Clock`, that handles times without dates.
+To do this in Python, you would create a `class` to to implement the desired behavior.
-One aspect of a class' behavior is this string prepresentation. By default, a class' string representation is not very helpful:
+One aspect of a class's behavior is how it is represented as a string.
+By default, a class's string representation is not very helpful.
```python
>>> Clock(12, 34)
```
-To create a more helpful representation, you will need to define a `__repr__` method on your class that returns a string.
+To create a more helpful representation, you need to define a `__repr__` method on your class that returns a string.
-According to the [specification for a `__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), you should ideally have the method return a string that could be used to recreate the object, if you were to copy and paste it into a new environment.
+According to the [specification for a `__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), you should ideally have the method return valid Python code that could be used to recreate the object.
+That allows you to copy-paste the output directly into code or the REPL.
For example, a `Clock` that represents 11:30 AM could look like this: `Clock(11, 30)`.
-
-Defining a `__repr__` method is a great thing to do for every class you create. When you do, you should consider:
+Defining a `__repr__` method is good practice for all classes.
+When you do, you should consider:
- The information you're returning from this method will be beneficial when you're debugging issues.
-
-- Ideally, you should return a string that a user could copy, paste into a python environment, and have a copy of the object.
-
-- If that's not practical, return a description between angle brackets, as in `< ...a practical description... >`.
+- Ideally, you should return a string that is valid Python code.
+- If that is not practical, return a description between angle brackets: `< ...a practical description... >`.
### String conversion
-As useful as the `__repr__` method is, sometimes you'll want an alternative string representation. For example, let's look at the `datetime.datetime` class again:
+In addition to the `__repr__` method, sometimes you'll want an alternative string representation.
+This might be used to format the object for program output.
+For example, let's look at the `datetime.datetime` class again:
```python
>>> str(datetime.datetime(2022, 5, 4))
'2022-05-04 00:00:00'
```
-When a `datetime` object is askes to convert itself to a string, it turns into a string formatted according to the ISO 8601 standard, which can be parsed by most datetime libraries.
+When a `datetime` object is askes to convert itself to a string, it returns a string formatted according to the ISO 8601 standard, which can be parsed by most datetime libraries.
-This clock exercise will provide you with a similar opportunity. Part of the challenge will be to have an alternate representation like this:
+In this exercise, you will get to write a `__str__` method, too.
```python
>>> str(Clock(11, 30))
From bd69ffb6ba0b7ca882abfade60194f68ec6e0a12 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Mon, 27 Dec 2021 19:52:11 -0500
Subject: [PATCH 0072/1546] Clock instructions: adding ID, correcting
documentation link
---
exercises/practice/clock/.docs/instructions.append.md | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
index 30b1b8ecdd3..5f5db68675c 100644
--- a/exercises/practice/clock/.docs/instructions.append.md
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -19,12 +19,12 @@ By default, a class's string representation is not very helpful.
```python
>>> Clock(12, 34)
-
+
```
To create a more helpful representation, you need to define a `__repr__` method on your class that returns a string.
-According to the [specification for a `__repr__` method](https://docs.python.org/3/reference/datamodel.html#object.__repr__), you should ideally have the method return valid Python code that could be used to recreate the object.
+According to the [specification for a `__repr__` method][repr-docs], you should ideally have the method return valid Python code that could be used to recreate the object.
That allows you to copy-paste the output directly into code or the REPL.
For example, a `Clock` that represents 11:30 AM could look like this: `Clock(11, 30)`.
@@ -58,3 +58,5 @@ In this exercise, you will get to write a `__str__` method, too.
```
To support this string conversion, you will need to create a `__str__` method on your class.
+
+[repr-docs]: https://docs.python.org/3/reference/datamodel.html#object.__repr__
From cb7c84ec9a9a12c151c509978f0c533a2f964691 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Mon, 27 Dec 2021 19:53:10 -0500
Subject: [PATCH 0073/1546] Updating Clock example.py
---
exercises/practice/clock/.meta/example.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/exercises/practice/clock/.meta/example.py b/exercises/practice/clock/.meta/example.py
index 0c76dca2ce0..47d52681622 100644
--- a/exercises/practice/clock/.meta/example.py
+++ b/exercises/practice/clock/.meta/example.py
@@ -7,6 +7,9 @@ def __init__(self, hour, minute):
self.cleanup()
def __repr__(self):
+ return f'Clock({self.hour}, {self.minute})'
+
+ def __str__(self):
return '{:02d}:{:02d}'.format(self.hour, self.minute)
def __eq__(self, other):
From 19cdd5553e85c948845d1bc1d57e4cfd9fcc408b Mon Sep 17 00:00:00 2001
From: Chris May
Date: Mon, 27 Dec 2021 19:54:31 -0500
Subject: [PATCH 0074/1546] Clock: updating contributors
---
exercises/practice/clock/.meta/config.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/exercises/practice/clock/.meta/config.json b/exercises/practice/clock/.meta/config.json
index 6a917e5d371..441a88c49a3 100644
--- a/exercises/practice/clock/.meta/config.json
+++ b/exercises/practice/clock/.meta/config.json
@@ -16,7 +16,8 @@
"rootulp",
"smalley",
"thomasjpfan",
- "tqa236"
+ "tqa236",
+ "chrismay"
],
"files": {
"solution": [
From c636372cd3da40e0199d7e6daf04ed8b0c9b8167 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Wed, 29 Dec 2021 10:05:39 -0500
Subject: [PATCH 0075/1546] Clock: adding additional test cases
---
.../clock/.meta/additional_tests.json | 39 +++++++++++++++++++
exercises/practice/clock/.meta/template.j2 | 6 ++-
exercises/practice/clock/clock_test.py | 10 ++---
3 files changed, 48 insertions(+), 7 deletions(-)
create mode 100644 exercises/practice/clock/.meta/additional_tests.json
diff --git a/exercises/practice/clock/.meta/additional_tests.json b/exercises/practice/clock/.meta/additional_tests.json
new file mode 100644
index 00000000000..ba0c72bbd9e
--- /dev/null
+++ b/exercises/practice/clock/.meta/additional_tests.json
@@ -0,0 +1,39 @@
+{
+ "cases": [
+ {
+ "description": "Create a string representation",
+ "cases": [
+ {
+ "uuid": "d2c8f173-018d-488c-8c4c-009f8c772313",
+ "description": "lunch time",
+ "property": "repr",
+ "input": {
+ "hour": 12,
+ "minute": 0
+ },
+ "expected": "Clock(12, 0)"
+ },
+ {
+ "uuid": "61a68f88-b980-46cd-a9f5-844832618092",
+ "description": "breakfast time",
+ "property": "repr",
+ "input": {
+ "hour": 6,
+ "minute": 45
+ },
+ "expected": "Clock(6, 45)"
+ },
+ {
+ "uuid": "ea93b367-fb03-44e4-a845-51756b8c9f3a",
+ "description": "dinner time",
+ "property": "repr",
+ "input": {
+ "hour": 18,
+ "minute": 30
+ },
+ "expected": "Clock(18, 30)"
+ }
+ ]
+ }
+ ]
+}
diff --git a/exercises/practice/clock/.meta/template.j2 b/exercises/practice/clock/.meta/template.j2
index 106b1c76b95..9c38e6155e0 100644
--- a/exercises/practice/clock/.meta/template.j2
+++ b/exercises/practice/clock/.meta/template.j2
@@ -4,6 +4,8 @@ Clock({{ obj["hour"] }}, {{ obj["minute"] }})
{%- endmacro -%}
{{ macros.header(["Clock"])}}
+{% set cases = additional_cases + cases %}
+
class {{ exercise | camel_case }}Test(unittest.TestCase):
{% for casegroup in cases -%}
# {{ casegroup["description"].title() }}
@@ -17,7 +19,8 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
{{- clock(input["clock1"]) }},
{{- clock(input["clock2"]) }}
{% else -%}
- Equal(str({{ clock(input) }}
+
+ Equal({{ 'repr' if prop == 'repr' else 'str' }}({{ clock(input) }}
{%- if prop == "add" %} + {{ input["value"] }}
{%- elif prop == "subtract" %} - {{ input["value"] }}
{%- endif %}), "
@@ -27,5 +30,4 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
{% endfor %}
{%- endfor %}
-
{{ macros.footer() }}
diff --git a/exercises/practice/clock/clock_test.py b/exercises/practice/clock/clock_test.py
index 28300a8d52d..fe06336676b 100644
--- a/exercises/practice/clock/clock_test.py
+++ b/exercises/practice/clock/clock_test.py
@@ -8,14 +8,14 @@
class ClockTest(unittest.TestCase):
- # Create a string representation
+ # Create A String Representation
+ def test_lunch_time(self):
+ self.assertEqual(repr(Clock(12, 0)), "Clock(12, 0)")
+
def test_breakfast_time(self):
self.assertEqual(repr(Clock(6, 45)), "Clock(6, 45)")
- def test_lunchtime(self):
- self.assertEqual(repr(Clock(12, 0)), "Clock(12, 0)")
-
- def test_dinnertime(self):
+ def test_dinner_time(self):
self.assertEqual(repr(Clock(18, 30)), "Clock(18, 30)")
# Create A New Clock With An Initial Time
From 2b9cea57613524f77ed43a1402e0e16cf456e753 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Wed, 29 Dec 2021 10:19:16 -0500
Subject: [PATCH 0076/1546] Clock: Apply suggestions from code review
Co-authored-by: BethanyG
---
.../clock/.docs/instructions.append.md | 45 ++++++++++---------
1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
index 5f5db68675c..7e158876100 100644
--- a/exercises/practice/clock/.docs/instructions.append.md
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -1,56 +1,57 @@
# Instructions append
+The tests for this exercise expect your clock will be implemented via a Clock `class` in Python.
+If you are unfamiliar with classes in Python, [classes][classes in python] from the Python docs is a good place to start.
## Representing your class
When working with and debugging objects, it's important to have a string representation of that object.
-For example, if you were to create a `datetime.datetime` object in a REPL environment, you can see its string representation:
+For example, if you were to create a new `datetime.datetime` object in the Python [REPL][REPL] environment, you could see its string representation:
```python
>>> from datetime import datetime
->>> datetime(2022, 5, 4)
+>>> new_date = datetime(2022, 5, 4)
+>>> new_date
datetime.datetime(2022, 5, 4, 0, 0)
-```
-
-In this excersise, you will create a custom object, `Clock`, that handles times without dates.
-To do this in Python, you would create a `class` to to implement the desired behavior.
-One aspect of a class's behavior is how it is represented as a string.
-By default, a class's string representation is not very helpful.
+Your Clock `class` will create a custom `object` that handles times without dates.
+One important aspect of this `class` will be how it is represented as a _string_.
+Other programmers who use or call Clock `objects` created from the Clock `class` will refer to this string representation for debugging and other activities.
+However, the default string representation on a `class` is usually not very helpful.
```python
>>> Clock(12, 34)
```
-To create a more helpful representation, you need to define a `__repr__` method on your class that returns a string.
+To create a more helpful representation, you can define a `__repr__` method on the `class` that returns a string.
-According to the [specification for a `__repr__` method][repr-docs], you should ideally have the method return valid Python code that could be used to recreate the object.
-That allows you to copy-paste the output directly into code or the REPL.
+Ideally, the `__repr__` method returns valid Python code that can be used to recreate the object -- as laid out in the [specification for a `__repr__` method][repr-docs].
+Returning valid Python code allows you to copy-paste the `str` directly into code or the REPL.
For example, a `Clock` that represents 11:30 AM could look like this: `Clock(11, 30)`.
Defining a `__repr__` method is good practice for all classes.
-When you do, you should consider:
+Some things to consider:
-- The information you're returning from this method will be beneficial when you're debugging issues.
-- Ideally, you should return a string that is valid Python code.
-- If that is not practical, return a description between angle brackets: `< ...a practical description... >`.
+- The information returned from this method should be beneficial when debugging issues.
+- _Ideally_, the method returns a string that is valid Python code -- although that might not always be possible.
+- If valid Python code is not practical, returning a description between angle brackets: `< ...a practical description... >` is the convention.
### String conversion
-In addition to the `__repr__` method, sometimes you'll want an alternative string representation.
-This might be used to format the object for program output.
-For example, let's look at the `datetime.datetime` class again:
+In addition to the `__repr__` method, there might also be a need for an alternative "human-readable" string representation of the `class`.
+This might be used to format the object for program output, or documentation.
+Looking at `datetime.datetime` again:
```python
>>> str(datetime.datetime(2022, 5, 4))
'2022-05-04 00:00:00'
```
-When a `datetime` object is askes to convert itself to a string, it returns a string formatted according to the ISO 8601 standard, which can be parsed by most datetime libraries.
+When a `datetime` object is asked to convert itself to a string representation, it returns a `str` formatted according to the [ISO 8601 standard][ISO 8601], which can be parsed by most datetime libraries into a human-readable date and time.
-In this exercise, you will get to write a `__str__` method, too.
+In this exercise, you will get a chance to write a `__str__` method, as well as a `__repr__`.
```python
>>> str(Clock(11, 30))
@@ -60,3 +61,7 @@ In this exercise, you will get to write a `__str__` method, too.
To support this string conversion, you will need to create a `__str__` method on your class.
[repr-docs]: https://docs.python.org/3/reference/datamodel.html#object.__repr__
+[classes in python]: https://docs.python.org/3/tutorial/classes.html
+[REPL]: https://pythonprogramminglanguage.com/repl/
+[ISO 8601]: https://www.iso.org/iso-8601-date-and-time-format.html
+
From e8c9013769efe2fed5e86ed7c3fc67ff107c9a16 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Wed, 29 Dec 2021 10:20:50 -0500
Subject: [PATCH 0077/1546] Clock: minor tweaks
---
exercises/practice/clock/.docs/instructions.append.md | 2 +-
exercises/practice/clock/.meta/template.j2 | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
index 7e158876100..e3c767ca289 100644
--- a/exercises/practice/clock/.docs/instructions.append.md
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -41,7 +41,7 @@ Some things to consider:
### String conversion
In addition to the `__repr__` method, there might also be a need for an alternative "human-readable" string representation of the `class`.
-This might be used to format the object for program output, or documentation.
+This might be used to format the object for program output or documentation.
Looking at `datetime.datetime` again:
```python
diff --git a/exercises/practice/clock/.meta/template.j2 b/exercises/practice/clock/.meta/template.j2
index 9c38e6155e0..f786b2f1c88 100644
--- a/exercises/practice/clock/.meta/template.j2
+++ b/exercises/practice/clock/.meta/template.j2
@@ -19,7 +19,6 @@ class {{ exercise | camel_case }}Test(unittest.TestCase):
{{- clock(input["clock1"]) }},
{{- clock(input["clock2"]) }}
{% else -%}
-
Equal({{ 'repr' if prop == 'repr' else 'str' }}({{ clock(input) }}
{%- if prop == "add" %} + {{ input["value"] }}
{%- elif prop == "subtract" %} - {{ input["value"] }}
From 65f0941effeb7e8a254fd15fa77fe257032ae826 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Wed, 29 Dec 2021 16:35:54 -0500
Subject: [PATCH 0078/1546] Clock: Apply suggestions from code review
Co-authored-by: BethanyG
---
exercises/practice/clock/.docs/instructions.append.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
index e3c767ca289..8e1be894043 100644
--- a/exercises/practice/clock/.docs/instructions.append.md
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -58,7 +58,7 @@ In this exercise, you will get a chance to write a `__str__` method, as well as
'11:30'
```
-To support this string conversion, you will need to create a `__str__` method on your class.
+To support this string conversion, you will need to create a `__str__` method on your class that returns a more "human readable" string showing the Clock time.
[repr-docs]: https://docs.python.org/3/reference/datamodel.html#object.__repr__
[classes in python]: https://docs.python.org/3/tutorial/classes.html
From 7171bdf19d850b09b5a97655be6c2aeaec39da40 Mon Sep 17 00:00:00 2001
From: Chris May
Date: Wed, 29 Dec 2021 16:41:09 -0500
Subject: [PATCH 0079/1546] Clock: adding comment about `__repr__` being a
fallback for `__str__`
---
exercises/practice/clock/.docs/instructions.append.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md
index 8e1be894043..76fb934b61b 100644
--- a/exercises/practice/clock/.docs/instructions.append.md
+++ b/exercises/practice/clock/.docs/instructions.append.md
@@ -60,6 +60,8 @@ In this exercise, you will get a chance to write a `__str__` method, as well as
To support this string conversion, you will need to create a `__str__` method on your class that returns a more "human readable" string showing the Clock time.
+If you don't create a `__str__` method and you call `str()` on your class, python will try calling `__repr__` on your class as a fallback. So if you only implement one of the two, it would be better to create a `__repr__` method.
+
[repr-docs]: https://docs.python.org/3/reference/datamodel.html#object.__repr__
[classes in python]: https://docs.python.org/3/tutorial/classes.html
[REPL]: https://pythonprogramminglanguage.com/repl/
From 50465e73c2bb5c7deec4bed8a62da3cb1bee4859 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Sun, 19 Dec 2021 15:39:47 -0800
Subject: [PATCH 0080/1546] Fixed broken img ref
---
reference/track_exercises_overview.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/reference/track_exercises_overview.md b/reference/track_exercises_overview.md
index 19822a76a04..5c1659177f0 100644
--- a/reference/track_exercises_overview.md
+++ b/reference/track_exercises_overview.md
@@ -20,7 +20,7 @@
| | [basics](https://github.com/exercism/python/blob/main/concepts/basics) | | [Guidos Gorgeous Lasagna](https://github.com/exercism/python/tree/main/tree/main/exercises/concept/guidos-gorgeous-lasagna) | [`.meta`folder](https://github.com/exercism/python/tree/main/exercises/concept/guidos-gorgeous-lasagna/.meta) |
| | [bools](https://github.com/exercism/python/blob/main/concepts/bools) | | [Ghost Gobble Arcade Game](https://github.com/exercism/python/tree/main/tree/main/exercises/concept/ghost-gobble-arcade-game) | [`.meta`folder](https://github.com/exercism/python/tree/main/exercises/concept/ghost-gobble-arcade-game/.meta) |
| | [conditionals](https://github.com/exercism/python/blob/main/concepts/conditionals) | | [Meltdown Mitigation ](https://github.com/exercism/python/tree/main/exercises/concept/meltdown-mitigation) | [`.meta`folder](https://github.com/exercism/python/tree/main/exercises/concept/meltdown-mitigation/.meta) |
-| | [dicts](https://github.com/exercism/python/blob/main/concepts/dicts) | | [Inventory Management](https://github.com/exercism/python/tree/main/exercises/concept/inventory-management) | [`.meta`folder](https://github.com/exercism/python/tree/main/exercises/concept/inventory-management) |
+| | [dicts](https://github.com/exercism/python/blob/main/concepts/dicts) | | [Inventory Management](https://github.com/exercism/python/tree/main/exercises/concept/inventory-management) | [`.meta`folder](https://github.com/exercism/python/tree/main/exercises/concept/inventory-management) |
| | [list-methods](https://github.com/exercism/python/blob/main/concepts/list-methods) | | [Chaitanas Colossal Coaster](https://github.com/exercism/python/tree/main/exercises/concept/chaitanas-colossal-coaster) | [`.meta`folder](https://github.com/exercism/python/tree/main/exercises/concept/chaitanas-colossal-coaster/.meta) |
| | [lists](https://github.com/exercism/python/blob/main/concepts/lists) | | [Card Games](https://github.com/exercism/python/tree/main/exercises/concept/card-games) | [`.meta`folder](https://github.com/exercism/python/tree/main/exercises/concept/card-games/.meta) |
| | [loops](https://github.com/exercism/python/blob/main/concepts/loops) | | [Making the Grade](https://github.com/exercism/python/tree/main/exercises/concept/making-the-grade) | [`.meta`folder](https://github.com/exercism/python/tree/main/exercises/concept/making-the-grade/.meta) |
From d5156ccf2a4594fd8e502341a129f2840a107b71 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Thu, 23 Dec 2021 12:49:52 -0800
Subject: [PATCH 0081/1546] Modified subtest headlines to omit test data for
brevity.
---
exercises/concept/cater-waiter/sets_test.py | 24 +++++++++++++++------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/exercises/concept/cater-waiter/sets_test.py b/exercises/concept/cater-waiter/sets_test.py
index 19b8257504b..f1841ebb413 100644
--- a/exercises/concept/cater-waiter/sets_test.py
+++ b/exercises/concept/cater-waiter/sets_test.py
@@ -45,7 +45,9 @@ def test_clean_ingredients(self):
test_data = zip(recipes_with_duplicates[::3], recipes_without_duplicates[::3])
for variant, (item, result) in enumerate(test_data, start=1):
- with self.subTest(f"variation #{variant}", item=item[0], result=result[1]):
+ with self.subTest(f"variation #{variant}", inputs='recipes with duplicated ingredients',
+ result='recipe ingredients de-duped'):
+
error_msg = (f"Expected a cleaned ingredient list for {item[0]}, "
"but the ingredients aren't cleaned as expected.")
@@ -56,7 +58,8 @@ def test_check_drinks(self):
test_data = zip(all_drinks[::2], drink_names[::2])
for variant, (item, result) in enumerate(test_data, start=1):
- with self.subTest(f"variation #{variant}", item=item, result=result):
+ with self.subTest(f"variation #{variant}", iputs='all drinks', results='drinks classified'):
+
error_msg = f"Expected {result} for {item}, but got something else instead."
self.assertEqual(check_drinks(item[0], item[1]), (result), msg=error_msg)
@@ -65,7 +68,8 @@ def test_categorize_dish(self):
test_data = zip(sorted(recipes_without_duplicates, reverse=True)[::3], dishes_categorized[::3])
for variant, (item, result) in enumerate(test_data, start=1):
- with self.subTest(f"variation #{variant}", item=item, result=result):
+ with self.subTest(f"variation #{variant}", inputs='all recipes list', results='categorized dishes'):
+
error_message = f"Exptected category {result} for {item[0]}, but got a different category instead."
self.assertEqual(categorize_dish(item[1], item[2]), (result), msg=error_message)
@@ -74,7 +78,8 @@ def test_tag_special_ingredients(self):
test_data = zip(dishes_to_special_label[::3], dishes_labeled[::3])
for variant, (item, result) in enumerate(test_data, start=1):
- with self.subTest(f"variation #{variant}", item=item, result=result):
+ with self.subTest(f"variation #{variant}", inputs='all recipes list', results='special ingredients tagged'):
+
error_message = f"Expected {result} for {item}, but got something else instead."
self.assertEqual(tag_special_ingredients(item), (result), msg=error_message)
@@ -83,7 +88,9 @@ def test_compile_ingredients(self):
test_data = zip(ingredients_only, [VEGAN, VEGETARIAN, PALEO, KETO, OMNIVORE])
for variant, (item, result) in enumerate(test_data, start=1):
- with self.subTest(f"variation #{variant}", item=item, result=result):
+ with self.subTest(f"variation #{variant}", inputs='all ingredients for all recipes',
+ result='combined list of ingredients for all dishes'):
+
error_message = "Expected a proper set of combined ingredients, but something went wrong."
self.assertEqual(compile_ingredients(item), (result), msg=error_message)
@@ -92,7 +99,8 @@ def test_separate_appetizers(self):
test_data = zip(dishes_and_appetizers, dishes_cleaned)
for variant, (item, result) in enumerate(test_data, start=1):
- with self.subTest(f"variation #{variant}", item=item, result=result):
+ with self.subTest(f"variation #{variant}", inputs='dishes with appetizers', results='appetizers only'):
+
error_message = "Expected only appetizers returned, but some dishes remain in the group."
self.assertEqual(sorted(separate_appetizers(item[0], item[1])), (sorted(result)), msg=error_message)
@@ -101,7 +109,9 @@ def test_singleton_ingredients(self):
test_data = zip(dishes_and_overlap, singletons)
for variant, (item, result) in enumerate(test_data, start=1):
- with self.subTest(f"variation #{variant}", item=item, result=result):
+ with self.subTest(f"variation #{variant}", inputs="overlapping ingredients",
+ results="ingredients in only one dish"):
+
error_message = ("Expected only ingredients that belong to exactly "
"one dish, but got multi-dish ingredients instead.")
self.assertEqual(singleton_ingredients(item[0], item[1]), (result), msg=error_message)
From c792194a342cfce8452c44550ac122bdb25302ed Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Fri, 31 Dec 2021 17:52:43 -0800
Subject: [PATCH 0082/1546] Removed Python 2 stub note and left constant value
stubs in place.
---
exercises/practice/yacht/yacht.py | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/exercises/practice/yacht/yacht.py b/exercises/practice/yacht/yacht.py
index bcf99719ecf..d64452f96ef 100644
--- a/exercises/practice/yacht/yacht.py
+++ b/exercises/practice/yacht/yacht.py
@@ -1,17 +1,3 @@
-"""
-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,
-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
-those constants (ex. the constants in the os, subprocess and re modules).
-
-You can learn more here: https://en.wikipedia.org/wiki/Enumerated_type
-"""
-
-
# Score categories.
# Change the values as you see fit.
YACHT = None
From f325a0d031b4910b57a7fcf4c37b220828138e94 Mon Sep 17 00:00:00 2001
From: Mariusz Listewnik
Date: Mon, 3 Jan 2022 08:40:06 +0100
Subject: [PATCH 0083/1546] Fix all entries showing output of __doc__ attribute
for number_to_the_power_of function
---
concepts/basics/about.md | 8 ++++++--
concepts/basics/introduction.md | 8 ++++++--
.../concept/guidos-gorgeous-lasagna/.docs/introduction.md | 8 ++++++--
3 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/concepts/basics/about.md b/concepts/basics/about.md
index 7eb14980826..5c54e4a8d86 100644
--- a/concepts/basics/about.md
+++ b/concepts/basics/about.md
@@ -201,9 +201,13 @@ def number_to_the_power_of(number_one, number_two):
return number_one ** number_two
>>> print(number_to_the_power_of.__doc__)
-Returns float or int.
+Raise a number to an arbitrary power.
- Takes number_one and raises it to the power of number_two, returning the result.
+ :param number_one: int the base number.
+ :param number_two: int the power to raise the base number to.
+ :return: int - number raised to power of second number
+
+ Takes number_one and raises it to the power of number_two, returning the result.
# __doc__() for the built-in type: str.
>>> print(str.__doc__)
diff --git a/concepts/basics/introduction.md b/concepts/basics/introduction.md
index 1c7762a5d4c..ca69d5af68b 100644
--- a/concepts/basics/introduction.md
+++ b/concepts/basics/introduction.md
@@ -179,9 +179,13 @@ def number_to_the_power_of(number_one, number_two):
return number_one ** number_two
>>> print(number_to_the_power_of.__doc__)
-Returns float or int.
+Raise a number to an arbitrary power.
- Takes number_one and raises it to the power of number_two, returning the result.
+ :param number_one: int the base number.
+ :param number_two: int the power to raise the base number to.
+ :return: int - number raised to power of second number
+
+ Takes number_one and raises it to the power of number_two, returning the result.
# __doc__() for the built-in type: str.
>>> print(str.__doc__)
diff --git a/exercises/concept/guidos-gorgeous-lasagna/.docs/introduction.md b/exercises/concept/guidos-gorgeous-lasagna/.docs/introduction.md
index 3271eace20c..1703d430829 100644
--- a/exercises/concept/guidos-gorgeous-lasagna/.docs/introduction.md
+++ b/exercises/concept/guidos-gorgeous-lasagna/.docs/introduction.md
@@ -186,9 +186,13 @@ They are recommended for programs of any size where documentation is needed, and
...
>>> print(number_to_the_power_of.__doc__)
-Returns float or int.
+Raise a number to an arbitrary power.
- Takes number_one and raises it to the power of number_two, returning the result.
+ :param number_one: int the base number.
+ :param number_two: int the power to raise the base number to.
+ :return: int - number raised to power of second number
+
+ Takes number_one and raises it to the power of number_two, returning the result.
# __doc__() for the built-in type: str.
>>> print(str.__doc__)
From faeef2b052cec72cf848524fab8bd6796be58641 Mon Sep 17 00:00:00 2001
From: Kristjan Vingel <56689530+kristjanv001@users.noreply.github.com>
Date: Tue, 4 Jan 2022 23:20:24 +0200
Subject: [PATCH 0084/1546] Update introduction.md
typo
---
exercises/concept/card-games/.docs/introduction.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/exercises/concept/card-games/.docs/introduction.md b/exercises/concept/card-games/.docs/introduction.md
index a71aef58313..a40eb230b1d 100644
--- a/exercises/concept/card-games/.docs/introduction.md
+++ b/exercises/concept/card-games/.docs/introduction.md
@@ -9,7 +9,7 @@ Lists support both [common][common sequence operations] and [mutable][mutable se
List elements can be iterated over using the `for item in ` construct.
`for index, item in enumerate()` can be used when both the element index and the element value are needed.
-Under the hood, `lists` are implemented as [dynamic arrays][dynamic array] -- similar to Java's [`Arraylist`][arraylist] type, and are most often used to store groups of similar data (_strings, numbers, sets etc._) of unknown length.
+Under the hood, `lists` are implemented as [dynamic arrays][dynamic array] -- similar to Java's [`ArrayList`][arraylist] type, and are most often used to store groups of similar data (_strings, numbers, sets etc._) of unknown length.
Lists are an extremely flexible and useful data structure and many built-in methods and operations in Python produce lists as their output.
From 8c268bd5eb2c10428c76067b4ee97a0ef025fa9e Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Tue, 4 Jan 2022 15:21:27 -0800
Subject: [PATCH 0085/1546] Updated isbn-verifier data
Synced tests.toml and instructions.md via configlet. Regenerated test.py file from tests.toml
---
.../practice/isbn-verifier/.meta/tests.toml | 24 +++++--
instructions.md | 42 ++++++++++++
isbn_verifier_test.py | 67 +++++++++++++++++++
3 files changed, 126 insertions(+), 7 deletions(-)
create mode 100644 instructions.md
create mode 100644 isbn_verifier_test.py
diff --git a/exercises/practice/isbn-verifier/.meta/tests.toml b/exercises/practice/isbn-verifier/.meta/tests.toml
index 5d2c0c3fefb..0f317b8ebc4 100644
--- a/exercises/practice/isbn-verifier/.meta/tests.toml
+++ b/exercises/practice/isbn-verifier/.meta/tests.toml
@@ -1,21 +1,28 @@
-# This is an auto-generated file. Regular comments will be removed when this
-# file is regenerated. Regenerating will not touch any manually added keys,
-# so comments can be added in a "comment" key.
+# 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.
[0caa3eac-d2e3-4c29-8df8-b188bc8c9292]
-description = "valid isbn number"
+description = "valid isbn"
[19f76b53-7c24-45f8-87b8-4604d0ccd248]
description = "invalid isbn check digit"
[4164bfee-fb0a-4a1c-9f70-64c6a1903dcd]
-description = "valid isbn number with a check digit of 10"
+description = "valid isbn with a check digit of 10"
[3ed50db1-8982-4423-a993-93174a20825c]
description = "check digit is a character other than X"
[c19ba0c4-014f-4dc3-a63f-ff9aefc9b5ec]
-description = "invalid character in isbn"
+description = "invalid character in isbn is not treated as zero"
[28025280-2c39-4092-9719-f3234b89c627]
description = "X is only valid as a check digit"
@@ -48,7 +55,10 @@ description = "empty isbn"
description = "input is 9 characters"
[ed6e8d1b-382c-4081-8326-8b772c581fec]
-description = "invalid characters are not ignored"
+description = "invalid characters are not ignored after checking length"
+
+[daad3e58-ce00-4395-8a8e-e3eded1cdc86]
+description = "invalid characters are not ignored before checking length"
[fb5e48d8-7c03-4bfb-a088-b101df16fdc3]
description = "input is too long but contains a valid isbn"
diff --git a/instructions.md b/instructions.md
new file mode 100644
index 00000000000..01ce2e1ff5f
--- /dev/null
+++ b/instructions.md
@@ -0,0 +1,42 @@
+# Instructions
+
+The [ISBN-10 verification process](https://en.wikipedia.org/wiki/International_Standard_Book_Number) is used to validate book identification
+numbers. These normally contain dashes and look like: `3-598-21508-8`
+
+## ISBN
+
+The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula:
+
+```text
+(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0
+```
+
+If the result is 0, then it is a valid ISBN-10, otherwise it is invalid.
+
+## Example
+
+Let's take the ISBN-10 `3-598-21508-8`. We plug it in to the formula, and get:
+
+```text
+(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0
+```
+
+Since the result is 0, this proves that our ISBN is valid.
+
+## Task
+
+Given a string the program should check if the provided string is a valid ISBN-10.
+Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN.
+
+The program should be able to verify ISBN-10 both with and without separating dashes.
+
+## Caveats
+
+Converting from strings to numbers can be tricky in certain languages.
+Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). For instance `3-598-21507-X` is a valid ISBN-10.
+
+## Bonus tasks
+
+* Generate a valid ISBN-13 from the input ISBN-10 (and maybe verify it again with a derived verifier).
+
+* Generate valid ISBN, maybe even from a given starting ISBN.
diff --git a/isbn_verifier_test.py b/isbn_verifier_test.py
new file mode 100644
index 00000000000..b0b9e104aae
--- /dev/null
+++ b/isbn_verifier_test.py
@@ -0,0 +1,67 @@
+import unittest
+
+from isbn_verifier import (
+ is_valid,
+)
+
+# Tests adapted from `problem-specifications//canonical-data.json`
+
+
+class IsbnVerifierTest(unittest.TestCase):
+ def test_valid_isbn(self):
+ self.assertIs(is_valid("3-598-21508-8"), True)
+
+ def test_invalid_isbn_check_digit(self):
+ self.assertIs(is_valid("3-598-21508-9"), False)
+
+ def test_valid_isbn_with_a_check_digit_of_10(self):
+ self.assertIs(is_valid("3-598-21507-X"), True)
+
+ def test_check_digit_is_a_character_other_than_x(self):
+ self.assertIs(is_valid("3-598-21507-A"), False)
+
+ def test_invalid_character_in_isbn_is_not_treated_as_zero(self):
+ self.assertIs(is_valid("3-598-P1581-X"), False)
+
+ def test_x_is_only_valid_as_a_check_digit(self):
+ self.assertIs(is_valid("3-598-2X507-9"), False)
+
+ def test_valid_isbn_without_separating_dashes(self):
+ self.assertIs(is_valid("3598215088"), True)
+
+ def test_isbn_without_separating_dashes_and_x_as_check_digit(self):
+ self.assertIs(is_valid("359821507X"), True)
+
+ def test_isbn_without_check_digit_and_dashes(self):
+ self.assertIs(is_valid("359821507"), False)
+
+ def test_too_long_isbn_and_no_dashes(self):
+ self.assertIs(is_valid("3598215078X"), False)
+
+ def test_too_short_isbn(self):
+ self.assertIs(is_valid("00"), False)
+
+ def test_isbn_without_check_digit(self):
+ self.assertIs(is_valid("3-598-21507"), False)
+
+ def test_check_digit_of_x_should_not_be_used_for_0(self):
+ self.assertIs(is_valid("3-598-21515-X"), False)
+
+ def test_empty_isbn(self):
+ self.assertIs(is_valid(""), False)
+
+ def test_input_is_9_characters(self):
+ self.assertIs(is_valid("134456729"), False)
+
+ def test_invalid_characters_are_not_ignored_after_checking_length(self):
+ self.assertIs(is_valid("3132P34035"), False)
+
+ def test_invalid_characters_are_not_ignored_before_checking_length(self):
+ self.assertIs(is_valid("3598P215088"), False)
+
+ def test_input_is_too_long_but_contains_a_valid_isbn(self):
+ self.assertIs(is_valid("98245726788"), False)
+
+
+if __name__ == "__main__":
+ unittest.main()
From fe57146690eb70466b6fc008efd83b61e79b588f Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Tue, 4 Jan 2022 15:40:35 -0800
Subject: [PATCH 0086/1546] Second attempt to update isbn-verifier
Re-synced and re-generated tests.
---
exercises/practice/isbn-verifier/.docs/instructions.md | 6 +++---
exercises/practice/isbn-verifier/isbn_verifier_test.py | 7 +++++--
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/exercises/practice/isbn-verifier/.docs/instructions.md b/exercises/practice/isbn-verifier/.docs/instructions.md
index 7d6635edc1f..01ce2e1ff5f 100644
--- a/exercises/practice/isbn-verifier/.docs/instructions.md
+++ b/exercises/practice/isbn-verifier/.docs/instructions.md
@@ -7,7 +7,7 @@ numbers. These normally contain dashes and look like: `3-598-21508-8`
The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula:
-```
+```text
(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0
```
@@ -16,7 +16,8 @@ If the result is 0, then it is a valid ISBN-10, otherwise it is invalid.
## Example
Let's take the ISBN-10 `3-598-21508-8`. We plug it in to the formula, and get:
-```
+
+```text
(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0
```
@@ -29,7 +30,6 @@ Putting this into place requires some thinking about preprocessing/parsing of th
The program should be able to verify ISBN-10 both with and without separating dashes.
-
## Caveats
Converting from strings to numbers can be tricky in certain languages.
diff --git a/exercises/practice/isbn-verifier/isbn_verifier_test.py b/exercises/practice/isbn-verifier/isbn_verifier_test.py
index 7b8a5324cad..b0b9e104aae 100644
--- a/exercises/practice/isbn-verifier/isbn_verifier_test.py
+++ b/exercises/practice/isbn-verifier/isbn_verifier_test.py
@@ -20,7 +20,7 @@ def test_valid_isbn_with_a_check_digit_of_10(self):
def test_check_digit_is_a_character_other_than_x(self):
self.assertIs(is_valid("3-598-21507-A"), False)
- def test_invalid_character_in_isbn(self):
+ def test_invalid_character_in_isbn_is_not_treated_as_zero(self):
self.assertIs(is_valid("3-598-P1581-X"), False)
def test_x_is_only_valid_as_a_check_digit(self):
@@ -53,9 +53,12 @@ def test_empty_isbn(self):
def test_input_is_9_characters(self):
self.assertIs(is_valid("134456729"), False)
- def test_invalid_characters_are_not_ignored(self):
+ def test_invalid_characters_are_not_ignored_after_checking_length(self):
self.assertIs(is_valid("3132P34035"), False)
+ def test_invalid_characters_are_not_ignored_before_checking_length(self):
+ self.assertIs(is_valid("3598P215088"), False)
+
def test_input_is_too_long_but_contains_a_valid_isbn(self):
self.assertIs(is_valid("98245726788"), False)
From 40610cf4089f0e91390fd016f6cadb9f80f2a9e0 Mon Sep 17 00:00:00 2001
From: RNeilsen
Date: Tue, 4 Jan 2022 16:13:06 +1100
Subject: [PATCH 0087/1546] Fix error_case test gen to check for 'score' prpty
error_case tests were being generated with code that always raised exceptions regardless of the user's code; this was disguised as 'passing' tests since they were expecting an exception anyway.
---
exercises/practice/bowling/.meta/template.j2 | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/exercises/practice/bowling/.meta/template.j2 b/exercises/practice/bowling/.meta/template.j2
index bd420ad47ed..8234dd1c5a4 100644
--- a/exercises/practice/bowling/.meta/template.j2
+++ b/exercises/practice/bowling/.meta/template.j2
@@ -5,8 +5,13 @@
rolls = {{ input["previousRolls"] }}
game = self.roll_new_game(rolls)
{% if case is error_case -%}
+ {% set property = case["property"] -%}
with self.assertRaisesWithMessage(Exception):
+ {% if property == 'score' -%}
+ game.score()
+ {% else -%}
game.roll({{ input["roll"] }})
+ {% endif -%}
{% else -%}
self.assertEqual(game.score(), {{ case["expected"] }})
{% endif %}
From 95a0dc5f637c39f79f3ef65d5affd0f6ab5b540c Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Tue, 4 Jan 2022 16:07:11 -0800
Subject: [PATCH 0088/1546] Update bowling_test.py
Regenerated test case file from new JinJa2 template.
---
exercises/practice/bowling/bowling_test.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/exercises/practice/bowling/bowling_test.py b/exercises/practice/bowling/bowling_test.py
index 971b8f71de3..35b81139479 100644
--- a/exercises/practice/bowling/bowling_test.py
+++ b/exercises/practice/bowling/bowling_test.py
@@ -151,13 +151,13 @@ def test_an_unstarted_game_cannot_be_scored(self):
rolls = []
game = self.roll_new_game(rolls)
with self.assertRaisesWithMessage(Exception):
- game.roll()
+ game.score()
def test_an_incomplete_game_cannot_be_scored(self):
rolls = [0, 0]
game = self.roll_new_game(rolls)
with self.assertRaisesWithMessage(Exception):
- game.roll()
+ game.score()
def test_cannot_roll_if_game_already_has_ten_frames(self):
rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
@@ -171,7 +171,7 @@ def test_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_
rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10]
game = self.roll_new_game(rolls)
with self.assertRaisesWithMessage(Exception):
- game.roll()
+ game.score()
def test_both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated(
self,
@@ -179,7 +179,7 @@ def test_both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_s
rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10]
game = self.roll_new_game(rolls)
with self.assertRaisesWithMessage(Exception):
- game.roll()
+ game.score()
def test_bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score_can_be_calculated(
self,
@@ -187,7 +187,7 @@ def test_bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score_ca
rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3]
game = self.roll_new_game(rolls)
with self.assertRaisesWithMessage(Exception):
- game.roll()
+ game.score()
def test_cannot_roll_after_bonus_roll_for_spare(self):
rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 2]
From f79d44ef6c9cf68d8c76cb94017a590f04391635 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 14:02:43 -0800
Subject: [PATCH 0089/1546] isbn-verifier Test File at wrong level.
Deleting isbn_verifier_test.py, as it was committed at the wrong repo level.
---
isbn_verifier_test.py | 67 -------------------------------------------
1 file changed, 67 deletions(-)
delete mode 100644 isbn_verifier_test.py
diff --git a/isbn_verifier_test.py b/isbn_verifier_test.py
deleted file mode 100644
index b0b9e104aae..00000000000
--- a/isbn_verifier_test.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import unittest
-
-from isbn_verifier import (
- is_valid,
-)
-
-# Tests adapted from `problem-specifications//canonical-data.json`
-
-
-class IsbnVerifierTest(unittest.TestCase):
- def test_valid_isbn(self):
- self.assertIs(is_valid("3-598-21508-8"), True)
-
- def test_invalid_isbn_check_digit(self):
- self.assertIs(is_valid("3-598-21508-9"), False)
-
- def test_valid_isbn_with_a_check_digit_of_10(self):
- self.assertIs(is_valid("3-598-21507-X"), True)
-
- def test_check_digit_is_a_character_other_than_x(self):
- self.assertIs(is_valid("3-598-21507-A"), False)
-
- def test_invalid_character_in_isbn_is_not_treated_as_zero(self):
- self.assertIs(is_valid("3-598-P1581-X"), False)
-
- def test_x_is_only_valid_as_a_check_digit(self):
- self.assertIs(is_valid("3-598-2X507-9"), False)
-
- def test_valid_isbn_without_separating_dashes(self):
- self.assertIs(is_valid("3598215088"), True)
-
- def test_isbn_without_separating_dashes_and_x_as_check_digit(self):
- self.assertIs(is_valid("359821507X"), True)
-
- def test_isbn_without_check_digit_and_dashes(self):
- self.assertIs(is_valid("359821507"), False)
-
- def test_too_long_isbn_and_no_dashes(self):
- self.assertIs(is_valid("3598215078X"), False)
-
- def test_too_short_isbn(self):
- self.assertIs(is_valid("00"), False)
-
- def test_isbn_without_check_digit(self):
- self.assertIs(is_valid("3-598-21507"), False)
-
- def test_check_digit_of_x_should_not_be_used_for_0(self):
- self.assertIs(is_valid("3-598-21515-X"), False)
-
- def test_empty_isbn(self):
- self.assertIs(is_valid(""), False)
-
- def test_input_is_9_characters(self):
- self.assertIs(is_valid("134456729"), False)
-
- def test_invalid_characters_are_not_ignored_after_checking_length(self):
- self.assertIs(is_valid("3132P34035"), False)
-
- def test_invalid_characters_are_not_ignored_before_checking_length(self):
- self.assertIs(is_valid("3598P215088"), False)
-
- def test_input_is_too_long_but_contains_a_valid_isbn(self):
- self.assertIs(is_valid("98245726788"), False)
-
-
-if __name__ == "__main__":
- unittest.main()
From 847f612226e1d5f3ff71516a1ba94e965ac410e7 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 14:01:20 -0800
Subject: [PATCH 0090/1546] Accidentally Committed at wrong level
Committed isbn-verifier instruction changes at the wrong level, and now need to delete them. Arg.
---
instructions.md | 42 ------------------------------------------
1 file changed, 42 deletions(-)
delete mode 100644 instructions.md
diff --git a/instructions.md b/instructions.md
deleted file mode 100644
index 01ce2e1ff5f..00000000000
--- a/instructions.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# Instructions
-
-The [ISBN-10 verification process](https://en.wikipedia.org/wiki/International_Standard_Book_Number) is used to validate book identification
-numbers. These normally contain dashes and look like: `3-598-21508-8`
-
-## ISBN
-
-The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula:
-
-```text
-(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0
-```
-
-If the result is 0, then it is a valid ISBN-10, otherwise it is invalid.
-
-## Example
-
-Let's take the ISBN-10 `3-598-21508-8`. We plug it in to the formula, and get:
-
-```text
-(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0
-```
-
-Since the result is 0, this proves that our ISBN is valid.
-
-## Task
-
-Given a string the program should check if the provided string is a valid ISBN-10.
-Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN.
-
-The program should be able to verify ISBN-10 both with and without separating dashes.
-
-## Caveats
-
-Converting from strings to numbers can be tricky in certain languages.
-Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). For instance `3-598-21507-X` is a valid ISBN-10.
-
-## Bonus tasks
-
-* Generate a valid ISBN-13 from the input ISBN-10 (and maybe verify it again with a derived verifier).
-
-* Generate valid ISBN, maybe even from a given starting ISBN.
From 04693598a0761c7683db17b67646293fd6936d50 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 17:06:29 -0800
Subject: [PATCH 0091/1546] Edited and added to about.md and introduction.md.
---
concepts/comparisons/about.md | 282 ++++++++++++++++++---------
concepts/comparisons/introduction.md | 74 +++++--
2 files changed, 245 insertions(+), 111 deletions(-)
diff --git a/concepts/comparisons/about.md b/concepts/comparisons/about.md
index 3c43a38ec1f..5d0c00488d2 100644
--- a/concepts/comparisons/about.md
+++ b/concepts/comparisons/about.md
@@ -1,199 +1,291 @@
# About
-A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the values of two operands and returns `True` or `False` based on whether the `comparison` condition is met.
-The most common comparison operators are `"<"`, `">"`, `"=="`, `">="`, `"<="`, and `"!="`.
-They all have the same priority (which is higher than that of the Boolean operations).
+A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the _values_ of two [operands][operand] and returns a boolean `True` or `False` if the `comparison` condition is or is not met.
-```python
->>> 7 > 5
-True
->>> 99 < 100
-True
->>> 4 < 4
-False
->>> 4 <= 4
-True
->>> 1 >= 1
-True
->>> 5 == 5
-True
->>> 6 != 6 # not equal to
-False
->>> 5 != 6
-True
->>> not 3 == 3 # interpreted as not(3 == 3)
-False
-```
+The table below shows the most common Python comparison operators:
-## Comparison Chaining
-Comparisons can be chained arbitrarily, e.g., `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated only once (but in both cases `z` is _not_ evaluated at all when `x < y` is found to be `False`).
-This is also called `short-circuit` evaluation which means the execution is stopped if the truth value of the expression has already been determined.
-Note that the evaluation of expression takes place from left to right.
-In python, short circuiting is supported by various boolean operators, functions and, in this case, comparison chaining.
+| Operator | Operation | Description |
+| -------- | ------------------------ | -------------------------------------------------------------- |
+| `>` | "greater than" | `a > b` is `True` if `a` is **strictly** greater in value than `b` |
+| `<` | "less than" | `a < b` is `True` if `a` is **strictly** less in value than `b` |
+| `==` | "equal to" | `a == b` is `True` if `a` is **strictly** equal to `b` in value |
+| `>=` | "greater than or equal to" | `a >= b` is `True` if `a > b` OR `a == b` in value |
+| `<=` | "less than or equal to" | `a <= b` is `True` if `a < b` or `a == b` in value |
+| `!=` | "not equal to" | `a != b` is `True` if `a == b` is `False` |
+| `is` | "identity" | `a is b` is `True` if **_and only if_** `a` and `b` are the same _object_ |
+| `is not` | "negated identity" | `a is not b` is `True` if `a` and `b` are **not** the same _object_ |
+| `in` | "containment test" | `a in b` is `True` if `a` is member, subset, or element of `b` |
+| `not in` | "negated containment test" | `a not in b` is `True` if `a` is not a member, subset, or element of `b` |
-Also unlike `C`, expressions like `a < b < c` have the interpretation that is conventional in mathematics.
-```python
->>> x = 2
->>> y = 5
->>> z = 10
->>> x < y < z
-True
->>> x < y > z
-False
->>> x > y < z
-False
-```
+They all have the same priority (_which is higher than that of [Boolean operations][boolean operations], but lower than that of arithmetic or bitwise operations_).
+
## Comparison between different data types
-Since everything in Python is an `object`, things can get interesting when objects of different types are compared.
-For example, the `str` value of a number is considered completely different from the `integer` or `floating-point` value.
-Python makes this distinction because strings are text, while `integers` and `floats` are numeric types.
+Objects that are different types (_except numeric types_) never compare equal by default.
+Non-identical instances of a `class` will also _**not**_ compare as equal unless the `class` defines special [rich comparison][rich comparisons] methods that customize the default `object` comparison behavior.
+For (much) more detail, see [Value comparisons][value comparisons] in the Python documentation.
-However, an `integer` **can** be considered equal to a `float`, as they are both numeric types that Python can implicitly convert to compare.
+Numeric types are (mostly) an exception to this type matching rule.
+An `integer` **can** be considered equal to a `float` (_or an [`octal`][octal] equal to a [`hexadecimal`][hex]_), as long as the types can be implicitly converted for comparison.
-For other numeric types, comparison operators are defined where they "make sense", but throw a `TypeError` if the underlying objects cannot be converted for comparison.
+For the other numeric types ([complex][complex numbers], [decimal][decimal numbers], [fractions][rational numbers]), comparison operators are defined where they "make sense" (_where implicit conversion does not change the outcome_), but throw a `TypeError` if the underlying objects cannot be accurately converted for comparison.
For more information on the rules that python uses for numeric conversion, see [arithmetic conversions][arithmetic conversions] in the Python documentation.
+
```python
+import fractions
+
+# A string cannot be converted to an int.
>>> 17 == '17'
False
+
+# An int can be converted to float for comparison.
>>> 17 == 17.0
True
->>> 17.0 == 0017.000
-True
->>> complex(1, 2) == complex(1.0, 2.00)
-True
-```
+# The fraction 6/3 can be converted to the int 2
+# The int 2 can be converted to 0b10 in binary.
+>>> 6/3 == 0b10
+True
-## Value Comparison
+# An int can be converted to a complex number with a 0 imaginary part.
+>>> 17 == complex(17)
+True
-The operators `<`, `>`, `==`, `>=`, `<=`, and `!=` compare the _values_ of two different objects.
-The objects do not need to have the same type.
-Remember that in Python every object has a `value` in addition to `type` and `identity`.
+# The fraction 2/5 can be converted to the float 0.4
+>>> 0.4 == 2/5
+True
-### Following are comparison behaviour of most `built-ins` types.
+>>> complex(2/5, 1/2) == complex(0.4, 0.5)
+True
+```
-Numbers of built-in _numeric_ types such as `int`, `hex`, `ocal`, `binary`, `float`, `complex` and of the standard library types `fractions.Fraction` and `decimal.Decimal` can be compared within and across their types.
+Any ordered comparison of a number to a `NaN` (_not a number_) type is `False`.
+A confusing side-effect of Python's `NaN` definition is that `NaN` never compares equal to `NaN`.
+If you are curious as to why `Nan` was defined this way in Python, this [Stack Overflow Post on NaN][SO NaN Post] around the setting of the international standard is an interesting read.
-Any ordered comparison of a number to a `NaN` (_not a number_) value is `False`.
-A counter-intuitive implication is that `NaN` never compares equal to `NaN`.
```python
>>> x = float('NaN')
->>> x
-nan
+
>>> 3 < x
False
+
>>> x < 3
False
+
+# NaN never compares equal to NaN
>>> x == x
False
```
-Strings (`str`) are compared _lexicographically_ using their individual numerical Unicode code points (_the result of passing each code point in the `str` to the built-in function `ord()`_).
-`str` and `binary` sequences cannot be directly compared.
+
+## Comparing Strings
+
+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.
+
```python
->>> 'santa' < 'claus'
+>>> 'Python' > 'Rust'
False
->>> 'Santa' < 'claus'
+
+>>> 'Python' > 'JavaScript'
True
->>> ord('s')
-115
->>> ord('S')
-83
->>> ord('c')
-99
->>> # let's try Chinese words
->>> 'δ½ ε₯½' < 'εθ§' # hello < goodbye
+
+# Examples with Mandarin.
+# hello < goodbye
+>>> 'δ½ ε₯½' < 'εθ§'
True
->>> # check ord() of first letters
+
+# ord() of first characters
>>> ord('δ½ '), ord('ε')
(20320, 20877)
->>>
->>>
->>> # let's try Korean words
->>> 'μμ' < 'μλ¦λ€μ΄' # pretty < beautiful
+
+# ord() of second characters
+>>> ord('ε₯½'), ord('θ§')
+(22909, 35265)
+
+# And with Korean words.
+# Pretty < beautiful.
+>>> 'μμ' < 'μλ¦λ€μ΄'
False
+
>>> ord('μ'), ord('μ')
(50696, 50500)
```
-Collections like `list`, `set`, `tuple` and `dict` can also be compared -- provided they are of the same `type`, have the same length, and each _**pair**_ of corresponding elements within the collection are comparable.
+
+## Comparing Container Data Types
+
+Container data types (_`lists`, `tuples`, `sets`, `dicts`, etc._) also compare [_lexicographically_][lexographic order] - they are equal if both containers have the same data **and** the same data types (_in the case of `lists` and `tuples`, they must also have the same **ordering**_), unequal otherwise.
+
```python
+# Comparing lists
>>> [1, 2] == [1, 2]
True
->>> (1, 2) == [1, 2]
+
+# But if the data is not in the same order, they are not equal.
+>>> [2, 1] == [1, 2]
False
+
+# The same holds true for tuples
+>>> (3,4,5) == (5,4,3)
+False
+
+# Length is also compared
>>> [1, 2] < [1, 2, 3]
True
->>> # comparison of dicts
+
+# Comparing dicts
>>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 18}
False
+
>>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 19}
True
```
+
+## Comparison Chaining
+
+Comparison operators can be chained _arbitrarily_.
+Note that the evaluation of an expression takes place from `left` to `right`.
+For example, `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated **only once**.
+In both cases, `z` is _not_ evaluated **at all** when `x < y` is found to be `False`.
+This is often called `short-circuit evaluation` - the evaluation stops if the truth value of the expression has already been determined.
+
+`Short circuiting` is supported by various boolean operators, functions, and also by comparison chaining in Python.
+Unlike many other programming languages, including `C`, `C++`, `C#`, and `Java`, chained expressions like `a < b < c` in Python have a conventional [mathematical interpretation][three way boolean comparison] and precedence.
+
+
+```python
+>>> x = 2
+>>> y = 5
+>>> z = 10
+
+>>> x < y < z
+True
+
+>>> x < y > z
+False
+
+>>> x > y < z
+False
+```
+
+
## Identity comparisons
-The operators `is` and `is not` test for an object's _identity_.
-An object's identity is determined using the `id()` function.
+The operators `is` and `is not` test for object [_identity_][object identity], as opposed to object _value_.
+An object's identity never changes after creation and can be found by using the [`id()`][id function] function.
+
+\ `is` \ evaluates to `True` if _**and only if**_ `id()` == `id()`.
+apple `is not` orange yields the inverse.
+
+Due to their singleton status, `None` and `NotImplemented` should always be compared to items using `is` and `is not`.
-`apple is orange` is `True` if and only if `apple` and `orange` are the same object.
-`apple is not orange` yields the inverse truth value.
```python
>>> my_fav_numbers = [1, 2, 3]
+
>>> your_fav_numbers = my_fav_numbers
->>> my_fav_numbers == your_fav_numbers
+
+>>> my_fav_numbers is your_fav_numbers
True
+
+# The returned id will differ by system and python version.
>>> id(my_fav_numbers)
-4462635008
+4517478208
+
+# your_fav_numbers is only an alias pointing to the original my_fav_numbers object.
+# Assigning a new name does not create a new object.
>>> id(your_fav_numbers)
-4462635008
+4517478208
+
+
>>> my_fav_numbers is not your_fav_numbers
False
+
+>>> my_fav_numbers is not None
+True
+
+>>> my_fav_numbers is NotImplemented
+False
```
-## Membership test operations
+
+## Membership comparisons
The operators `in` and `not in` test for _membership_.
-`fish in soup` evaluates to `True` if `fish` is a member of `soup`, and evaluates `False` otherwise.
-`fish not in soup` returns the negation, or _opposite of_ `fish in soup`.
+\ `in` \ evaluates to `True` if \ is a member of \ (_if \ is a subset of or is contained within \_), and evaluates `False` otherwise.
+\ `not in` \ returns the negation, or _opposite of_ \ `in` \.
-For the string and bytes types, `name` in `fullname` is `True` if and only if `name` is a substring of `fullname`.
+For string and bytes types, \ `in` \ is `True` _**if and only if**_ \ is a substring of \.
```python
-lucky_numbers = {11, 22, 33}
+# A set of lucky numbers.
+>>> lucky_numbers = {11, 22, 33}
>>> 22 in lucky_numbers
True
+
>>> 44 in lucky_numbers
False
->>>
+
+# A dictionary of employees.
>>> employee = {
'name': 'John Doe',
'id': 67826,
'age': 33,
'title': 'ceo'
}
+
+# Checking for the membership of certain keys.
>>> 'age' in employee
True
+
>>> 33 in employee
False
+
>>> 'lastname' not in employee
True
->>>
+
+# Checking for substring membership
>>> name = 'Super Batman'
>>> 'Bat' in name
True
+
>>> 'Batwoman' in name
False
```
-[comparisons]: https://docs.python.org/3/library/stdtypes.html?highlight=comparisons#comparisons
+# Customizing comparison behavior
+
+Comparison behavior for objects can be customized through the implementation of `rich comparison methods`.
+For more information, see [Python Tutorial: classes][classes], [Python Classes and Magic Methods (Dan Bader)][magic methods], and [Special method names][dunder methods].
+
+[SO NaN post]: https://stackoverflow.com/questions/1565164/what-is-the-rationale-for-all-comparisons-returning-false-for-ieee754-nan-values
+[Value Comparisons]: https://docs.python.org/3/reference/expressions.html?highlight=nan#value-comparisons
[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions
+[boolean operations]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not
+[classes]: https://docs.python.org/3/tutorial/classes.html#classes
+[comparisons]: https://docs.python.org/3/library/stdtypes.html?highlight=comparisons#comparisons
+[complex numbers]: https://docs.python.org/3/library/functions.html#complex
+[decimal numbers]: https://docs.python.org/3/library/decimal.html
+[dunder methods]: https://docs.python.org/3/reference/datamodel.html#special-method-names
+[hex]: https://docs.python.org/3/library/functions.html?highlight=hex#hex
+[id function]: https://docs.python.org/3/library/functions.html#id
+[lexographic order]: https://en.wikipedia.org/wiki/Lexicographic_order
+[magic methods]: https://dbader.org/blog/python-dunder-methods
+[object identity]: https://docs.python.org/3/reference/datamodel.html
+[octal]: https://docs.python.org/3/library/functions.html?#oct
+[operand]: https://www.computerhope.com/jargon/o/operand.htm
+[ord]: https://docs.python.org/3/library/functions.html#ord
+[rational numbers]: https://docs.python.org/3/library/fractions.html
+[rich comparisons]: https://docs.python.org/3/reference/datamodel.html#object.__lt__
+[three way boolean comparison]: https://en.wikipedia.org/wiki/Three-way_comparison
diff --git a/concepts/comparisons/introduction.md b/concepts/comparisons/introduction.md
index 27a105c12b0..21950afdbb2 100644
--- a/concepts/comparisons/introduction.md
+++ b/concepts/comparisons/introduction.md
@@ -1,23 +1,65 @@
# Introduction
-A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the values of two operands and returns `True` or `False` based on whether the `comparison` condition is met.
-The most common comparison operators are `"<"`, `">"`, `"=="`, `">="`, `"<="`, and `"!="`.
-They all have the same priority (which is higher than that of the Boolean operations)
+A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the _values_ of two [operands][operand] and returns a boolean `True` or `False` if the `comparison` condition is or is not met.
-## Comparison Chaining
+The table below shows the most common Python comparison operators:
-Comparisons can be chained arbitrarily, e.g., `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated only once (but in both cases `z` is _not_ evaluated at all when `x < y` is found to be `False`).
-This is also called `short-circuit` evaluation which means the execution is stopped if the truth value of the expression has already been determined.
-Note that the evaluation of expression takes place from left to right.
-In python, short circuiting is supported by various boolean operators, functions and, in this case, comparison chaining.
-## Comparison of different data types
+| Operator | Operation | Description |
+| -------- | ------------------------ | -------------------------------------------------------------- |
+| `>` | "greater than" | `a > b` is `True` if `a` is **strictly** greater in value than `b` |
+| `<` | "less than" | `a < b` is `True` if `a` is **strictly** less in value than `b` |
+| `==` | "equal to" | `a == b` is `True` if `a` is **strictly** equal to `b` in value |
+| `>=` | "greater than or equal to" | `a >= b` is `True` if `a > b` OR `a == b` in value |
+| `<=` | "less than or equal to" | `a <= b` is `True` if `a < b` or `a == b` in value |
+| `!=` | "not equal to" | `a != b` is `True` if `a == b` is `False` |
+| `is` | "identity" | `a is b` is `True` if **_and only if_** `a` and `b` are the same _object_ |
+| `is not` | "negated identity" | `a is not b` is `True` if `a` and `b` are **not** the same _object_ |
+| `in` | "containment test" | `a in b` is `True` if `a` is member, subset, or element of `b` |
+| `not in` | "negated containment test" | `a not in b` is `True` if `a` is not a member, subset, or element of `b` |
-Since everything in Python is an `object`, things can get interesting when objects of different types are compared.
-For example, the `str` value of a number is considered completely different from the `integer` or `floating-point` value.
-However, an `integer` **can** be considered equal to a `float`, as they are both numeric types that Python can implicitly convert to compare.
-For other numeric types, comparison operators are defined where they "make sense", but throw a `TypeError` if the underlying objects cannot be converted for comparison.
-For more information on the rules that python uses for numeric conversion, see [arithmetic conversions][arithmetic conversions] in the Python documentation.
-[comparisons]: https://docs.python.org/3/library/stdtypes.html?
-[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions
+They all have the same priority (_which is higher than that of [Boolean operations][boolean operations], but lower than that of arithmetic or bitwise operations_).
+
+
+## Comparison between different data types
+
+Objects that are different types (_except numeric types_) never compare equal by default.
+Non-identical instances of a `class` will also _**not**_ compare as equal unless the `class` defines special methods that customize the default `object` comparison behavior.
+
+
+Numeric types are (mostly) an exception to this type matching rule.
+An `integer` **can** be considered equal to a `float` (_or an [`octal`][octal] equal to a [`hexadecimal`][hex]_), as long as the types can be implicitly converted for comparison.
+
+For the other numeric types ([complex][complex numbers], [decimal][decimal numbers], [fractions][rational numbers]), comparison operators are defined where they "make sense" (_where implicit conversion does not change the outcome_), but throw a `TypeError` if the underlying objects cannot be accurately converted for comparison.
+
+
+## Comparing object identity
+
+The operators `is` and `is not` test for object [_identity_][object identity], as opposed to object _value_.
+An object's identity never changes after creation and can be found by using the [`id()`][id function] function.
+
+\ `is` \ evaluates to `True` if _**and only if**_ `id()` == `id()`.
+apple `is not` orange yields the inverse.
+
+Due to their singleton status, `None` and `NotImplemented` should always be compared to items using `is` and `is not`.
+
+
+## Membership comparisons
+
+The operators `in` and `not in` test for _membership_.
+\ `in` \ evaluates to `True` if \ is a member of \ (_if \ is a subset of or is contained within \_), and evaluates `False` otherwise.
+\ `not in` \ returns the negation, or _opposite of_ \ `in` \.
+
+For string and bytes types, \ `in` \ is `True` _**if and only if**_ \ is a substring of \.
+
+[boolean operations]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not
+[comparisons]: https://docs.python.org/3/library/stdtypes.html?highlight=comparisons#comparisons
+[complex numbers]: https://docs.python.org/3/library/functions.html#complex
+[decimal numbers]: https://docs.python.org/3/library/decimal.html
+[hex]: https://docs.python.org/3/library/functions.html?highlight=hex#hex
+[id function]: https://docs.python.org/3/library/functions.html#id
+[object identity]: https://docs.python.org/3/reference/datamodel.html
+[octal]: https://docs.python.org/3/library/functions.html?#oct
+[operand]: https://www.computerhope.com/jargon/o/operand.htm
+[rational numbers]: https://docs.python.org/3/library/fractions.html
From b165869790fb0b94bb66bf5910da416ddd5ff606 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 17:07:12 -0800
Subject: [PATCH 0092/1546] Cleaned up docs and added new tasks.
---
exercises/concept/black-jack/.docs/hints.md | 32 +-
.../concept/black-jack/.docs/instructions.md | 113 +++++--
.../concept/black-jack/.docs/introduction.md | 306 +++++++++++-------
3 files changed, 288 insertions(+), 163 deletions(-)
diff --git a/exercises/concept/black-jack/.docs/hints.md b/exercises/concept/black-jack/.docs/hints.md
index f91a51a182c..6c117f1c0a5 100644
--- a/exercises/concept/black-jack/.docs/hints.md
+++ b/exercises/concept/black-jack/.docs/hints.md
@@ -4,27 +4,37 @@
## 1. Calculate the value of a card
-- You can use the equality comparison operator `==` to determine specific cards, e.g. `card == 'J'`.
-- You can use the [`int` constructor][int constructor] to get an integer number from an integer literal, e.g. `int(card)`.
+- You can use the equality comparison operator `==` to determine if a card is an ace card: `card == 'A'`.
+- You can use the containment operator `in` to determine if a substring is contained inside a string: `'Q' in 'KJQ'`.
+- You can use the [`int` constructor][int constructor] to convert a `str` of an `int` to an `int`: `int('13')`.
-## 2. Calculate the value of an ace
+## 2. Determine which card has a higher value
+- Once you have defined the `value_of_card` function, you can call it from other functions.
+- You can use the value comparison operators `>` and `<` to determine if specific cards are _greater than_ or _less than_ a given value: `3 < 12`.
+- You can use the equality comparison operator `==` to determine if two values are equal to one another.
-- You can use the order comparison operator `>` to decide the appropriate course of action, e.g. `hand_value + 11 > 21`.
+## 3. Calculate the value of an ace
+- Once you have defined the `value_of_card` function, you can call it from other functions.
+- You can use the order comparison operator `>` to decide the appropriate course of action here.
-## 3. Determine Blackjack
+## 4. Determine Blackjack
-- You can use the [`if`/`elif`/`else` syntax][if syntax] to handle different combinations of cards.
+- Remember, you can use the [`if`/`elif`/`else` syntax][if syntax] to handle different combinations of cards.
+- You can chain BOTH comparison operators and boolean operators _arbitrarily_: `y < z < x` or `(y or z) and (x or z)`
- You can reuse the already implemented `value_of_card` function.
-## 4. Splitting pairs
+## 5. Splitting pairs
+- You can reuse the already implemented `value_of_card` function.
- You can handle the `A` case (when at least one of the cards in an ace) separately.
-## 5. Doubling down
+## 6. Doubling down
-- You can chain comparison operators, e.g. `9 <= hand_value <= 11`.
-- You can use the [conditional expression][conditional expression] (sometimes called a "ternary operator")
-to shorten simple `if`/`else` statements, e.g. `1 if card == 'A' else value_of_card(card)`.
+- An `A` scored at 11 will never allow doubling down if there are two cards in the hand.
+- Given the first point, you _should_ be able to reuse the already implemented `value_of_card` function.
+- You can chain comparison operators _arbitrarily_: `y < z < x`.
+- You can use the [conditional expression][conditional expression] (_sometimes called a "ternary operator"_)
+to shorten simple `if`/`else` statements: `13 if letter == 'M' else 3`.
[python comparisons tutorial]: https://docs.python.org/3/reference/expressions.html#comparisons
[python comparisons examples]: https://www.tutorialspoint.com/python/comparison_operators_example.htm
diff --git a/exercises/concept/black-jack/.docs/instructions.md b/exercises/concept/black-jack/.docs/instructions.md
index 774b35fdb4e..04e1d382980 100644
--- a/exercises/concept/black-jack/.docs/instructions.md
+++ b/exercises/concept/black-jack/.docs/instructions.md
@@ -3,89 +3,140 @@
In this exercise you are going to implement some rules of [Blackjack][blackjack],
such as the way the game is played and scored.
-**Note** : In this exercise, _A_ means ace, _J_ means jack, _Q_ means queen, and _K_ means king cards.
-A [standard 52-card deck][standard_deck] is assumed.
+**Note** : In this exercise, _`A`_ means ace, _`J`_ means jack, _`Q`_ means queen, and _`K`_ means king.
+Jokers are discarded.
+A [standard French-suited 52-card deck][standard_deck] is assumed, but in most versions, several decks are shuffled together for play.
-## 1. Calculate the value of a card
-In Blackjack, it is up to each individual player if an ace is worth 1 or 11 points.
-Face cards (_J_, _Q_, _K_) are worth 10 points and any other card is worth its pip (numerical) value.
+## 1. Calculate the value of a card
+
+In Blackjack, it is up to each individual player if an ace is worth 1 or 11 points (_more on that later_).
+Face cards (`J`, `Q`, `K`) are scored at 10 points and any other card is worth its "pip" (_numerical_) value.
+
+
+Define the `value_of_card()` function with parameter `card`.
+The function should return the _numerical value_ of the passed-in card string.
+Since an ace can take on multiple values (1 **or** 11), this function should fix the value of an ace card at 1 for the time being.
+Later on, you will implement a function to determine the value of an ace card, give an existing hand.
-Define the `value_of_card` function with a parameter `card`.
-The value of _J_, _Q_ or _K_ is 10.
-Otherwise, return the numerical value of a card.
-An ace can take on multiple values so let's ignore _A_ for the time being.
```python
>>> value_of_card('K')
10
+
>>> value_of_card('4')
4
+
+>>> value_of_card('A')
+1
+```
+
+
+## 2. Determine which card has a higher value
+
+
+Define the `higher_card(, )` function having parameters `card_one` and `card_two`.
+For scoring purposes, the value of `J`, `Q` or `K` is 10.
+The function should return which card has the higher value for scoring.
+If both cards have an equal value, return both.
+Returning both cards can be done by using a comma in the `return` statement:
+
+
+```python
+# Using a comma in a return creates a Tuple. Tuples will be covered in a later exercise.
+>>> def returning_two_values(value_one, value_two):
+ return value_one, value_two
+
+>>> returning_two_values('K', '3')
+('K', '3')
+```
+
+An ace can take on multiple values, so we will fix `A` cards to a value of 1 for this task.
+
+```python
+>>> higher_card('K', '10')
+('K', '10')
+
+>>> higher_card('4', '6')
+'6'
+
+>>> higher_card('K', 'A')
+'K'
```
-## 2. Calculate the value of an ace
-As mentioned before, an ace can be worth _either_ 1 or 11 points.
-At the same time, players are trying to get as close to 21 as possible, without going _over_ 21.
+## 3. Calculate the value of an ace
-Define the `value_of_ace()` function with a parameter `hand_value`,
-which is the total hand value before getting an ace card.
-You now have to decide if the upcoming ace card will be scored as a 1 or 11.
-The value of the hand with the ace needs to be as high as possible _without_ going over 21.
+As mentioned before, an ace can be worth _either_ 1 **or** 11 points.
+Players try to get as close as possible to a score of 21, without going _over_ 21 (_going "bust"_).
+
+Define the `value_of_ace(, )` function with parameters `card_one` and `card_two`, which are a pair of cards already in the hand _before_ getting an ace card.
+Your function will have to decide if the upcoming ace will get a value of 1 or a value of 11, and return that value.
+Remember: the value of the hand with the ace needs to be as high as possible _without_ going over 21.
```python
->>> value_of_ace(19)
+>>> value_of_ace('6', `K`)
1
->>> value_of_ace(7)
+
+>>> value_of_ace('7', '3')
11
```
-## 3. Determine Blackjack
-If the first two cards are an ace and a ten-card, giving a count of 21 in two cards, it is known as blackjack.
+## 4. Determine a "Natural" or "Blackjack" Hand
+
+If the first two cards a player is dealt are an ace (`A`) and a ten-card (10, `K`, `Q` or `J`), giving a score of 21 in two cards, the hand is considered a `natural` or `blackjack`.
Define the `is_blackjack(, )` function with parameters `card_one` and `card_two`, which are a pair of cards.
-Determine if the two-card hand is a blackjack.
+Determine if the two-card hand is a `blackjack`, and return the boolean `True` if it is, `False` otherwise.
+
+**Note** : The score _calculation_ can be done in many ways.
+ But if possible, we'd like you to check if there is an ace and a ten-card **_in_** the hand (or at a certain position), as opposed to _summing_ the hand values.
-**Note** : This calculation can be done in many ways.
- If possible, check if there is an ace and a ten-card in the hand.
```python
>>> is_blackjack('A', 'K')
True
+
>>> is_blackjack('10', '9')
False
```
-## 4. Splitting pairs
-If the first two cards are of the same value,
-such as two sixes, or a _Q_ and _K_ a player may choose to treat them as two separate hands.
+## 5. Splitting pairs
+
+If the players first two cards are of the same value, such as two sixes, or a `Q` and `K` a player may choose to treat them as two separate hands.
This is known as "splitting pairs".
Define the `can_split_pairs(, )` function with parameters `card_one` and `card_two`, which are a pair of cards.
Determine if this two-card hand can be split into two pairs.
+If the hand can be split, return the boolean `True` otherwise, return `False`
+
+
```python
>>> can_split_pairs('Q', 'K')
True
+
>>> can_split_pairs('10', 'A')
False
```
-## 5. Doubling down
+## 6. Doubling down
-When the original two cards dealt total 9, 10, or 11 points
-a player can place an additional bet equal to the original bet.
+When the original two cards dealt total 9, 10, or 11 points, a player can place an additional bet equal to their original bet.
This is known as "doubling down".
Define the `can_double_down(, )` function with parameters `card_one` and `card_two`, which are a pair of cards.
-Determine if the two-card hand can be "doubled down".
+Determine if the two-card hand can be "doubled down", and return the boolean `True` if it can, `False` otherwise.
+
+
```python
>>> can_double_down('A', '9')
True
+
>>> can_double_down('10', '2')
False
```
-[blackjack]: https://en.wikipedia.org/wiki/Blackjack
+[blackjack]: https://bicyclecards.com/how-to-play/blackjack/
[standard_deck]: https://en.wikipedia.org/wiki/Standard_52-card_deck
diff --git a/exercises/concept/black-jack/.docs/introduction.md b/exercises/concept/black-jack/.docs/introduction.md
index eed9111f845..703f27e2b83 100644
--- a/exercises/concept/black-jack/.docs/introduction.md
+++ b/exercises/concept/black-jack/.docs/introduction.md
@@ -1,185 +1,249 @@
## Comparisons
-There are some different kinds of comparison operators in Python
-| Operator | Operation | Description |
-| -------- | ------------------------ | -------------------------------------------------------- |
-| `>` | Greater than | `a > b` is `True` if `a` is greater than `b` |
-| `<` | Less than | `a < b` is `True` if `a` is less than `b` |
-| `==` | Equal to | `a == b` is `True` if `a` is equals to `b` |
-| `>=` | Greater than or equal to | `a >= b` is `True` if `a > b` or `a == b` is `True` |
-| `<=` | Less than or equal to | `a <= b` is `True` if `a < b` or `a == b` is `True` |
-| `!=` | Not equal to | `a != b` is `True` if `a = b` is `False` |
-| `is` | Identity | `a is b` is `True` if `a` and `b` is same object |
-| `is not` | Identity | `a is not b` is `True` if `a` and `b` is not same object |
-| `in` | Containment test | `a in b` is `True` if `a` is member of `b` |
-| `not in` | Containment test | `a not in b` is `True` if `a` is not a member of `b` |
+Python supports the following basic comparison operators:
-## Greater than
-Operator `>` tests if the first operand's value is greater than the second one's.
+| Operator | Operation | Description |
+| -------- | ------------------------ | -------------------------------------------------------------- |
+| `>` | "greater than" | `a > b` is `True` if `a` is **strictly** greater in value than `b` |
+| `<` | "less than" | `a < b` is `True` if `a` is **strictly** less in value than `b` |
+| `==` | "equal to" | `a == b` is `True` if `a` is **strictly** equal to `b` in value |
+| `>=` | "greater than or equal to" | `a >= b` is `True` if `a > b` OR `a == b` in value |
+| `<=` | "less than or equal to" | `a <= b` is `True` if `a < b` or `a == b` in value |
+| `!=` | "not equal to" | `a != b` is `True` if `a == b` is `False` |
+| `is` | "identity" | `a is b` is `True` if **_and only if_** `a` and `b` are the same _object_ |
+| `is not` | "negated identity" | `a is not b` is `True` if `a` and `b` are **not** the same _object_ |
+| `in` | "containment test" | `a in b` is `True` if `a` is member, subset, or element of `b` |
+| `not in` | "negated containment test" | `a not in b` is `True` if `a` is not a member, subset, or element of `b` |
-```python
->>> 3 > 1
-True
->>> 2.99 > 3
-False
->>> 1 > 1
-False
->>> 0 > 1
-False
-```
-## Less than
+They all have the same priority (_which is higher than that of [Boolean operations][boolean operations], but lower than that of arithmetic or bitwise operations_).
+
+
+## Comparison between different data types
+
+Objects that are different types (_except numeric types_) never compare equal by default.
+Non-identical instances of a `class` will also _**not**_ compare as equal unless the `class` defines special [rich comparison][rich comparisons] methods that customize the default `object` comparison behavior.
+Customizing via `rich comparisons` will be covered in a follow-on exercise.
+For (much) more detail on this topic, see [Value comparisons][value comparisons] in the Python documentation.
+
+Numeric types are (mostly) an exception to this type matching rule.
+An `integer` **can** be considered equal to a `float` (_or an [`octal`][octal] equal to a [`hexadecimal`][hex]_), as long as the types can be implicitly converted for comparison.
+
+For the other numeric types in the Python standard library ([complex][complex numbers], [decimal][decimal numbers], [fractions][rational numbers]), comparison operators are defined where they "make sense" (_where implicit conversion does not change the outcome_), but throw a `TypeError` if the underlying objects cannot be accurately converted for comparison.
+For more information on the rules that python uses for _numeric conversion_, see [arithmetic conversions][arithmetic conversions] in the Python documentation.
-Operator `<` tests if the first operand's value is less than the second one's.
```python
->>> 3 < 1
+import fractions
+
+# A string cannot be converted to an int.
+>>> 17 == '17'
False
->>> 2.99 < 3
+
+# An int can be converted to float for comparison.
+>>> 17 == 17.0
True
->>> 1 < 1
-False
->>> 0 < 1
+
+# The fraction 6/3 can be converted to the int 2
+# The int 2 can be converted to 0b10 in binary.
+>>> 6/3 == 0b10
True
-```
-## Equal to
+# An int can be converted to a complex number with a 0 imaginary part.
+>>> 17 == complex(17)
+True
-Operator `==` tests if the first operand's value is equal to the second one's
+# The fraction 2/5 can be converted to the float 0.4
+>>> 0.4 == 2/5
+True
-```python
->>> 3 == 1
-False
->>> 2.99 == 3
-False
->>> 1 == 1
+>>> complex(2/5, 1/2) == complex(0.4, 0.5)
True
->>> 0 == 1
-False
```
-## Greater than or equal to
+Any ordered comparison of a number to a `NaN` (_not a number_) type is `False`.
+A confusing side-effect of Python's `NaN` definition is that `NaN` never compares equal to `NaN`.
-Operator `>=` tests if the first operand's value is equal to or greater than the second one's.
```python
->>> 3 >= 1
-True
->>> 2.99 >= 3
+>>> x = float('NaN')
+
+>>> 3 < x
False
->>> 1 >= 1
-True
->>> 0 >= 1
+
+>>> x < 3
+False
+
+# NaN never compares equal to NaN
+>>> x == x
False
```
-## Less than or equal to
-Operator `<=` tests if the first operand's value is equal to or less than the second one's.
+## Comparing Strings
+
+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.
+
```python
->>> 3 <= 1
+>>> 'Python' > 'Rust'
False
->>> 2.99 <= 3
-True
->>> 1 <= 1
+
+>>> 'Python' > 'JavaScript'
True
->>> 0 <= 1
+
+# Examples with Mandarin.
+# hello < goodbye
+>>> 'δ½ ε₯½' < 'εθ§'
True
-```
-## Not equal to
+# ord() of first characters
+>>> ord('δ½ '), ord('ε')
+(20320, 20877)
-Operator `!=` tests if the first operand's value is not equal to the second one's
+# ord() of second characters
+>>> ord('ε₯½'), ord('θ§')
+(22909, 35265)
-```python
->>> 3 != 1
-True
->>> 2.99 != 3
-True
->>> 1 != 1
+# And with Korean words.
+# Pretty < beautiful.
+>>> 'μμ' < 'μλ¦λ€μ΄'
False
->>> 0 != 1
-True
+
+>>> ord('μ'), ord('μ')
+(50696, 50500)
```
-## Identity test
+## Comparison Chaining
+
+Comparison operators can be chained _arbitrarily_ -- meaning that they can be used in any combination of any length.
+Note that the evaluation of an expression takes place from `left` to `right`.
+
+
+As an example, `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated **only once**.
+In both cases, `z` is _not_ evaluated **at all** when `x < y` is found to be `False`.
+This is often called `short-circuit evaluation` - the evaluation stops if the truth value of the expression has already been determined.
+
+`Short circuiting` is supported by various boolean operators, functions, and also by comparison chaining in Python.
+Unlike many other programming languages, including `C`, `C++`, `C#`, and `Java`, chained expressions like `a < b < c` in Python have a conventional [mathematical interpretation][three way boolean comparison] and precedence.
-Operator `is` tests if the first and second operand is the same object.
```python
-# comparing non-object type `is` will raise warning
->>> 1 is 1
-:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
+>>> x = 2
+>>> y = 5
+>>> z = 10
+
+>>> x < y < z
True
->>> 1 is 2
-:1: SyntaxWarning: "is" with a literal. Did you mean "=="?
+
+>>> x < y > z
False
->>> x = int(4)
->>> y = x
->>> x is y
-True
->>> y = int(5)
->>> x is y
+
+>>> x > y < z
False
```
-Operator `is not` tests if the first and second operand is not the same object.
+
+## Comparing object identity
+
+The operators `is` and `is not` test for object [_identity_][object identity], as opposed to object _value_.
+An object's identity never changes after creation and can be found by using the [`id()`][id function] function.
+
+\ `is` \ evaluates to `True` if _**and only if**_ `id()` == `id()`.
+apple `is not` orange yields the inverse.
+
+Due to their singleton status, `None` and `NotImplemented` should always be compared to items using `is` and `is not`.
+
```python
->>> 1 is not 1
-:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
-False
->>> 1 is not 2
-:1: SyntaxWarning: "is not" with a literal. Did you mean "!="?
+>>> my_fav_numbers = [1, 2, 3]
+
+>>> your_fav_numbers = my_fav_numbers
+
+>>> my_fav_numbers is your_fav_numbers
True
->>> x = int(4)
->>> y = x
->>> x is not y
+
+# The returned id will differ by system and python version.
+>>> id(my_fav_numbers)
+4517478208
+
+# your_fav_numbers is only an alias pointing to the original my_fav_numbers object.
+# Assigning a new name does not create a new object.
+>>> id(your_fav_numbers)
+4517478208
+
+
+>>> my_fav_numbers is not your_fav_numbers
False
->>> y = int(5)
->>> x is not y
+
+>>> my_fav_numbers is not None
True
+
+>>> my_fav_numbers is NotImplemented
+False
```
-## Containment test
-Operator `in` tests if the first operand is a member of the second operand.
+## Membership comparisons
+
+The operators `in` and `not in` test for _membership_.
+\ `in` \ evaluates to `True` if \ is a member of \ (_if \ is a subset of or is contained within \_), and evaluates `False` otherwise.
+\ `not in` \ returns the negation, or _opposite of_ \ `in` \.
+
+For string and bytes types, \ `in` \ is `True` _**if and only if**_ \ is a substring of \.
```python
->>> x = [1, 2, 3, 4, 5]
->>> 1 in x
-True
->>> 2 in x
-True
->>> 3 in x
+# A set of lucky numbers.
+>>> lucky_numbers = {11, 22, 33}
+>>> 22 in lucky_numbers
True
->>> 4 in x
-True
->>> 5 in x
-True
->>> 6 in x
+
+>>> 44 in lucky_numbers
False
-```
-Operator `not in` tests if the first operand is not a member of the second operand.
+# A dictionary of employees.
+>>> employee = {
+ 'name': 'John Doe',
+ 'id': 67826,
+ 'age': 33,
+ 'title': 'ceo'
+ }
+
+# Checking for the membership of certain keys.
+>>> 'age' in employee
+True
-```python
->>> x = [1, 2, 3, 4, 5]
->>> 1 not in x
-False
->>> 2 not in x
-False
->>> 3 not in x
-False
->>> 4 not in x
-False
->>> 5 not in x
+>>> 33 in employee
False
->>> 6 not in x
+
+>>> 'lastname' not in employee
+True
+
+# Checking for substring membership
+>>> name = 'Super Batman'
+>>> 'Bat' in name
True
+
+>>> 'Batwoman' in name
+False
```
-[python3-docs]: https://docs.python.org/3/library/operator.html
\ No newline at end of file
+[Value Comparisons]: https://docs.python.org/3/reference/expressions.html?highlight=nan#value-comparisons
+[arithmetic conversions]: https://docs.python.org/3/reference/expressions.html?highlight=number%20conversion#arithmetic-conversions
+[boolean operations]: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not
+[complex numbers]: https://docs.python.org/3/library/functions.html#complex
+[decimal numbers]: https://docs.python.org/3/library/decimal.html
+[hex]: https://docs.python.org/3/library/functions.html?highlight=hex#hex
+[id function]: https://docs.python.org/3/library/functions.html#id
+[lexographic order]: https://en.wikipedia.org/wiki/Lexicographic_order
+[object identity]: https://docs.python.org/3/reference/datamodel.html
+[octal]: https://docs.python.org/3/library/functions.html?#oct
+[ord]: https://docs.python.org/3/library/functions.html#ord
+[rational numbers]: https://docs.python.org/3/library/fractions.html
+[rich comparisons]: https://docs.python.org/3/reference/datamodel.html#object.__lt__
+[three way boolean comparison]: https://en.wikipedia.org/wiki/Three-way_comparison
From eb887c6848fcb1d7b7419c43ffbb478b88f0544d Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 17:07:47 -0800
Subject: [PATCH 0093/1546] Edited exercise config and exemplar for new tasks
and requirements.
---
.../concept/black-jack/.meta/config.json | 4 +-
.../concept/black-jack/.meta/exemplar.py | 93 ++++++++++++-------
2 files changed, 61 insertions(+), 36 deletions(-)
diff --git a/exercises/concept/black-jack/.meta/config.json b/exercises/concept/black-jack/.meta/config.json
index c120dafa288..76e4fc7baa9 100644
--- a/exercises/concept/black-jack/.meta/config.json
+++ b/exercises/concept/black-jack/.meta/config.json
@@ -1,8 +1,8 @@
{
"blurb": "Learn about comparisons by implementing some Black Jack judging rules.",
- "authors": ["Ticktakto", "Yabby1997", "limm-jk", "OMEGA-Y", "wnstj2007", "pranasziaukas"],
+ "authors": ["Ticktakto", "Yabby1997", "limm-jk", "OMEGA-Y", "wnstj2007", "pranasziaukas", "bethanyG"],
"icon": "poker",
- "contributors": ["bethanyg"],
+ "contributors": [],
"files": {
"solution": ["black_jack.py"],
"test": ["black_jack_test.py"],
diff --git a/exercises/concept/black-jack/.meta/exemplar.py b/exercises/concept/black-jack/.meta/exemplar.py
index 89d26bc1275..8f177ad423f 100644
--- a/exercises/concept/black-jack/.meta/exemplar.py
+++ b/exercises/concept/black-jack/.meta/exemplar.py
@@ -1,68 +1,93 @@
+"""Functions to help play and score a game of blackjack.
+
+How to play blackjack: https://bicyclecards.com/how-to-play/blackjack/
+"Standard" playing cards: https://en.wikipedia.org/wiki/Standard_52-card_deck
+
+"""
+
+
def value_of_card(card):
- """
+ """Determine the scoring value of a card.
:param card: str - given card.
- :return: int - value of a given card (J, Q, K = 10, numerical value otherwise).
+ :return: int - value of a given card (J, Q, K = 10, 'A' = 1) numerical value otherwise.
"""
- if card in ('J', 'Q', 'K'):
+ if card in('JQK'):
value = 10
+
+ elif card == 'A':
+ value = 1
+
else:
value = int(card)
+
return value
-def value_of_ace(hand_value):
+
+def higher_card(card_one, card_two):
+ """Determine which card has a higher value in the hand.
+
+ :param card_one, card_two: str - cards dealt. J, Q, K = 10, 'A' = 1, all others are numerical value.
+ :return: higher value card - str. Tuple of both cards if they are of equal value.
"""
- :param hand_value: int - current hand value.
+ card_one_value = value_of_card(card_one)
+ card_two_value = value_of_card(card_two)
+
+ if card_one_value == card_two_value:
+ result = card_one, card_two
+
+ elif card_one_value > card_two_value:
+ result = card_one
+
+ else:
+ result = card_two
+
+ return result
+
+
+def value_of_ace(card_one, card_two):
+ """Calculate the most advantageous value for the ace card.
+
+ :param card_one, card_two: str - card (J, Q, K == 10, numerical value otherwise)
:return: int - value of the upcoming ace card (either 1 or 11).
"""
- if hand_value + 11 > 21:
- value = 1
+ if 11 + (value_of_card(card_one) + value_of_card(card_two)) > 21:
+ ace_value = 1
+
else:
- value = 11
- return value
+ ace_value = 11
+
+ return ace_value
+
def is_blackjack(card_one, card_two):
- """
+ """Determine if the hand is a 'natural' or 'blackjack'.
- :param card_one: str - first card in hand.
- :param card_two: str - second card in hand.
+ :param card_one, card_two: str - cards dealt. J, Q, K = 10, 'A' = 11, all others are numerical value.
:return: bool - if the hand is a blackjack (two cards worth 21).
"""
- if card_one == 'A' and card_two != 'A':
- blackjack = value_of_card(card_two) == 10
- elif card_one != 'A' and card_two == 'A':
- blackjack = value_of_card(card_one) == 10
- else:
- blackjack = False
- return blackjack
+ return (card_one == 'A' or card_two == 'A') and (value_of_card(card_one) == 10 or value_of_card(card_two) == 10)
+
def can_split_pairs(card_one, card_two):
- """
+ """Determine if a player can split their hand into two hands.
- :param card_one: str - first card in hand.
- :param card_two: str - second card in hand.
+ :param card_one, card_two: str - cards in hand.
:return: bool - if the hand can be split into two pairs (i.e. cards are of the same value).
"""
- if card_one == 'A' or card_two == 'A':
- split_pairs = card_one == card_two
- else:
- split_pairs = value_of_card(card_one) == value_of_card(card_two)
- return split_pairs
+ return value_of_card(card_one) == value_of_card(card_two)
+
def can_double_down(card_one, card_two):
- """
+ """Determine if a blackjack player can place a double down bet.
- :param card_one: str - first card in hand.
- :param card_two: str - second card in hand.
+ :param card_one, card_two: str - first and second cards in hand.
:return: bool - if the hand can be doubled down (i.e. totals 9, 10 or 11 points).
"""
- card_one_value = 1 if card_one == 'A' else value_of_card(card_one)
- card_two_value = 1 if card_two == 'A' else value_of_card(card_two)
- hand_value = card_one_value + card_two_value
- return 9 <= hand_value <= 11
+ return 8 < value_of_card(card_one) + value_of_card(card_two) < 12
From 6a2530e83ae6143af5d6650d88c49d69c04ce643 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 17:08:14 -0800
Subject: [PATCH 0094/1546] Added new tests and re-formatted test file.
---
.../concept/black-jack/black_jack_test.py | 138 ++++++++----------
1 file changed, 64 insertions(+), 74 deletions(-)
diff --git a/exercises/concept/black-jack/black_jack_test.py b/exercises/concept/black-jack/black_jack_test.py
index bfef90bff59..bb6cc90892a 100644
--- a/exercises/concept/black-jack/black_jack_test.py
+++ b/exercises/concept/black-jack/black_jack_test.py
@@ -1,12 +1,14 @@
import unittest
import pytest
+
from black_jack import (
- value_of_card,
- value_of_ace,
- is_blackjack,
- can_split_pairs,
- can_double_down
-)
+ value_of_card,
+ higher_card,
+ value_of_ace,
+ is_blackjack,
+ can_split_pairs,
+ can_double_down
+ )
class BlackJackTest(unittest.TestCase):
@@ -14,96 +16,84 @@ class BlackJackTest(unittest.TestCase):
@pytest.mark.task(taskno=1)
def test_value_of_card(self):
data = [
- ('2', 2),
- ('5', 5),
- ('8', 8),
- ('10', 10),
- ('J', 10),
- ('Q', 10),
- ('K', 10),
- ]
+ ('2', 2), ('5', 5), ('8', 8),
+ ('A', 1), ('10', 10), ('J', 10),
+ ('Q', 10), ('K', 10)]
for variant, (card, value) in enumerate(data, 1):
with self.subTest(f'variation #{variant}', input=card, output=value):
- self.assertEqual(
- value,
- value_of_card(card),
- msg=f'Expected {value} as the value of {card}.'
- )
+ error_msg = f'Expected {value} as the value of {card}.'
+
+ self.assertEqual(value_of_card(card), value, msg=error_msg)
@pytest.mark.task(taskno=2)
- def test_value_of_ace(self):
+ def test_higher_card(self):
data = [
- (2, 11),
- (5, 11),
- (7, 11),
- (9, 11),
- (10, 11),
- (11, 1),
- (12, 1),
- (15, 1),
- (19, 1),
- (20, 1),
- ]
-
- for variant, (hand_value, ace_value) in enumerate(data, 1):
- with self.subTest(f'variation #{variant}', input=hand_value, output=ace_value):
- self.assertEqual(
- ace_value,
- value_of_ace(hand_value),
- msg=f'Expected {ace_value} as the value of ace when the hand is worth {hand_value}.'
- )
+ ('A', 'A', ('A', 'A')),
+ ('10', 'J', ('10', 'J')),
+ ('3', 'A', '3'),
+ ('3', '6', '6'),
+ ('Q', '10', ('Q', '10')),
+ ('4', '4', ('4', '4')),
+ ('9', '10', '10'),
+ ('6', '9', '9'),
+ ('4', '8', '8')]
+
+ for variant, (card_one, card_two, result) in enumerate(data, 1):
+ with self.subTest(f'variation #{variant}', card_one=card_one, card_two=card_two, output=result):
+ error_msg = f'Expected {result} as the higher value of the cards {card_one, card_two}.'
+
+ self.assertEqual(higher_card(card_one, card_two), result, msg=error_msg)
@pytest.mark.task(taskno=3)
+ def test_value_of_ace(self):
+ data = [
+ ('2', '3', 11), ('3', '6', 11), ('5', '2', 11),
+ ('8', '2', 11), ('5', '5', 11), ('Q', 'A', 1),
+ ('10', '2', 1), ('7', '8', 1), ('J', '9', 1),
+ ('K', "K", 1)]
+
+ for variant, (card_one, card_two, ace_value) in enumerate(data, 1):
+ with self.subTest(f'variation #{variant}', card_one=card_one, card_two=card_two, ace_value=ace_value):
+ error_msg = f'Expected {ace_value} as the value of an ace card when the hand has {card_one, card_two}.'
+
+ self.assertEqual(value_of_ace(card_one, card_two), ace_value, msg=error_msg)
+
+
+ @pytest.mark.task(taskno=4)
def test_is_blackjack(self):
data = [
- (('A', 'K'), True),
- (('10', 'A'), True),
- (('10', '9'), False),
- (('A', 'A'), False),
- ]
+ (('A', 'K'), True), (('10', 'A'), True),
+ (('10', '9'), False), (('A', 'A'), False)]
for variant, (hand, blackjack) in enumerate(data, 1):
with self.subTest(f'variation #{variant}', input=hand, output=blackjack):
- self.assertEqual(
- blackjack,
- is_blackjack(*hand),
- msg=f'Hand {hand} {"is" if blackjack else "is not"} a blackjack.'
- )
+ error_msg=f'Hand {hand} {"is" if blackjack else "is not"} a blackjack.'
- @pytest.mark.task(taskno=4)
+ self.assertEqual( is_blackjack(*hand), blackjack, msg=error_msg)
+
+
+ @pytest.mark.task(taskno=5)
def test_can_split_pairs(self):
data = [
- (('Q', 'K'), True),
- (('6', '6'), True),
- (('A', 'A'), True),
- (('10', 'A'), False),
- (('10', '9'), False),
- ]
+ (('Q', 'K'), True), (('6', '6'), True), (('A', 'A'), True),
+ (('10', 'A'), False), (('10', '9'), False)]
for variant, (hand, split_pairs) in enumerate(data, 1):
with self.subTest(f'variation #{variant}', input=hand, output=split_pairs):
- self.assertEqual(
- split_pairs,
- can_split_pairs(*hand),
- msg=f'Hand {hand} {"can" if split_pairs else "cannot"} be split into pairs.'
- )
+ error_msg=f'Hand {hand} {"can" if split_pairs else "cannot"} be split into pairs.'
- @pytest.mark.task(taskno=5)
+ self.assertEqual(can_split_pairs(*hand), split_pairs, msg=error_msg)
+
+
+ @pytest.mark.task(taskno=6)
def test_can_double_down(self):
data = [
- (('A', '9'), True),
- (('K', 'A'), True),
- (('4', '5'), True),
- (('A', 'A'), False),
- (('10', '2'), False),
- (('10', '9'), False),
- ]
+ (('A', '9'), True), (('K', 'A'), True), (('4', '5'), True),
+ (('A', 'A'), False), (('10', '2'), False), (('10', '9'), False)]
for variant, (hand, double_down) in enumerate(data, 1):
with self.subTest(f'variation #{variant}', input=hand, output=double_down):
- self.assertEqual(
- double_down,
- can_double_down(*hand),
- msg=f'Hand {hand} {"can" if double_down else "cannot"} be doubled down.'
- )
+ error_msg = f'Hand {hand} {"can" if double_down else "cannot"} be doubled down.'
+
+ self.assertEqual(can_double_down(*hand), double_down, msg=error_msg)
From 2f3e25496488a9414c79926ec74bf517bbef6ca3 Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 17:08:39 -0800
Subject: [PATCH 0095/1546] Added new task to stub and edited docstrings.
---
exercises/concept/black-jack/black_jack.py | 40 +++++++++++++++-------
1 file changed, 27 insertions(+), 13 deletions(-)
diff --git a/exercises/concept/black-jack/black_jack.py b/exercises/concept/black-jack/black_jack.py
index 7343184f975..65076a6d2b2 100644
--- a/exercises/concept/black-jack/black_jack.py
+++ b/exercises/concept/black-jack/black_jack.py
@@ -1,17 +1,34 @@
+"""Functions to help play and score a game of blackjack.
+
+How to play blackjack: https://bicyclecards.com/how-to-play/blackjack/
+"Standard" playing cards: https://en.wikipedia.org/wiki/Standard_52-card_deck
+
+"""
+
+
def value_of_card(card):
- """
+ """Determine the scoring value of a card.
:param card: str - given card.
- :return: int - value of a given card (J, Q, K = 10, numerical value otherwise).
+ :return: int - value of a given card (J, Q, K = 10, 'A' = 1) numerical value otherwise.
"""
pass
+def higher_card(card_one, card_two):
+ """Determine which card has a higher value in the hand.
-def value_of_ace(hand_value):
+ :param card_one, card_two: str - cards dealt. J, Q, K = 10, 'A' = 1, all others are numerical value.
+ :return: higher value card - str. Tuple of both cards if they are of equal value.
"""
- :param hand_value: int - current hand value.
+ pass
+
+
+def value_of_ace(card_one, card_two):
+ """Calculate the most advantageous value for the ace card.
+
+ :param card_one, card_two: str - card (J, Q, K == 10, numerical value otherwise)
:return: int - value of the upcoming ace card (either 1 or 11).
"""
@@ -19,10 +36,9 @@ def value_of_ace(hand_value):
def is_blackjack(card_one, card_two):
- """
+ """Determine if the hand is a 'natural' or 'blackjack'.
- :param card_one: str - first card in hand.
- :param card_two: str - second card in hand.
+ :param card_one, card_two: str - cards dealt. J, Q, K = 10, 'A' = 11, all others are numerical value.
:return: bool - if the hand is a blackjack (two cards worth 21).
"""
@@ -30,10 +46,9 @@ def is_blackjack(card_one, card_two):
def can_split_pairs(card_one, card_two):
- """
+ """Determine if a player can split their hand into two hands.
- :param card_one: str - first card in hand.
- :param card_two: str - second card in hand.
+ :param card_one, card_two: str - cards in hand.
:return: bool - if the hand can be split into two pairs (i.e. cards are of the same value).
"""
@@ -41,10 +56,9 @@ def can_split_pairs(card_one, card_two):
def can_double_down(card_one, card_two):
- """
+ """Determine if a blackjack player can place a double down bet.
- :param card_one: str - first card in hand.
- :param card_two: str - second card in hand.
+ :param card_one, card_two: str - first and second cards in hand.
:return: bool - if the hand can be doubled down (i.e. totals 9, 10 or 11 points).
"""
From c1ea061401599c4d74d9364b662341e71c504e6b Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 17:09:01 -0800
Subject: [PATCH 0096/1546] Set new exercise to beta and added new
prerequisites.
---
config.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/config.json b/config.json
index 134bd35f4d1..ea1e3819b7c 100644
--- a/config.json
+++ b/config.json
@@ -71,8 +71,8 @@
"name": "Black Jack",
"uuid": "e1a6075e-0c5e-48cd-8c50-69140961a06a",
"concepts": ["comparisons"],
- "prerequisites": ["basics"],
- "status": "wip"
+ "prerequisites": ["basics", "bools", "conditionals"],
+ "status": "beta"
},
{
"slug": "pretty-leaflet",
From 66c846491e823d204e40a1c8fcc9bb97e5d53c5a Mon Sep 17 00:00:00 2001
From: BethanyG
Date: Wed, 5 Jan 2022 21:17:09 -0800
Subject: [PATCH 0097/1546] Applied suggestions from code review and ran
documents through prittier for formatting.
---
concepts/comparisons/about.md | 571 +++++++++---------
concepts/comparisons/introduction.md | 122 ++--
exercises/concept/black-jack/.docs/hints.md | 16 +-
.../concept/black-jack/.docs/instructions.md | 18 +-
.../concept/black-jack/.docs/introduction.md | 60 +-
.../concept/black-jack/.meta/exemplar.py | 1 -
exercises/concept/black-jack/black_jack.py | 1 -
7 files changed, 374 insertions(+), 415 deletions(-)
diff --git a/concepts/comparisons/about.md b/concepts/comparisons/about.md
index 5d0c00488d2..f60bccbfaf3 100644
--- a/concepts/comparisons/about.md
+++ b/concepts/comparisons/about.md
@@ -1,291 +1,280 @@
-# About
-
-A [comparison operator][comparisons] in Python (_also called a Python relational operator_), looks at the _values_ of two [operands][operand] and returns a boolean `True` or `False` if the `comparison` condition is or is not met.
-
-The table below shows the most common Python comparison operators:
-
-
-| Operator | Operation | Description |
-| -------- | ------------------------ | -------------------------------------------------------------- |
-| `>` | "greater than" | `a > b` is `True` if `a` is **strictly** greater in value than `b` |
-| `<` | "less than" | `a < b` is `True` if `a` is **strictly** less in value than `b` |
-| `==` | "equal to" | `a == b` is `True` if `a` is **strictly** equal to `b` in value |
-| `>=` | "greater than or equal to" | `a >= b` is `True` if `a > b` OR `a == b` in value |
-| `<=` | "less than or equal to" | `a <= b` is `True` if `a < b` or `a == b` in value |
-| `!=` | "not equal to" | `a != b` is `True` if `a == b` is `False` |
-| `is` | "identity" | `a is b` is `True` if **_and only if_** `a` and `b` are the same _object_ |
-| `is not` | "negated identity" | `a is not b` is `True` if `a` and `b` are **not** the same _object_ |
-| `in` | "containment test" | `a in b` is `True` if `a` is member, subset, or element of `b` |
-| `not in` | "negated containment test" | `a not in b` is `True` if `a` is not a member, subset, or element of `b` |
-
-
-They all have the same priority (_which is higher than that of [Boolean operations][boolean operations], but lower than that of arithmetic or bitwise operations_).
-
-
-## Comparison between different data types
-
-Objects that are different types (_except numeric types_) never compare equal by default.
-Non-identical instances of a `class` will also _**not**_ compare as equal unless the `class` defines special [rich comparison][rich comparisons] methods that customize the default `object` comparison behavior.
-For (much) more detail, see [Value comparisons][value comparisons] in the Python documentation.
-
-Numeric types are (mostly) an exception to this type matching rule.
-An `integer` **can** be considered equal to a `float` (_or an [`octal`][octal] equal to a [`hexadecimal`][hex]_), as long as the types can be implicitly converted for comparison.
-
-For the other numeric types ([complex][complex numbers], [decimal][decimal numbers], [fractions][rational numbers]), comparison operators are defined where they "make sense" (_where implicit conversion does not change the outcome_), but throw a `TypeError` if the underlying objects cannot be accurately converted for comparison.
-For more information on the rules that python uses for numeric conversion, see [arithmetic conversions][arithmetic conversions] in the Python documentation.
-
-
-```python
-import fractions
-
-# A string cannot be converted to an int.
->>> 17 == '17'
-False
-
-# An int can be converted to float for comparison.
->>> 17 == 17.0
-True
-
-# The fraction 6/3 can be converted to the int 2
-# The int 2 can be converted to 0b10 in binary.
->>> 6/3 == 0b10
-True
-
-# An int can be converted to a complex number with a 0 imaginary part.
->>> 17 == complex(17)
-True
-
-# The fraction 2/5 can be converted to the float 0.4
->>> 0.4 == 2/5
-True
-
->>> complex(2/5, 1/2) == complex(0.4, 0.5)
-True
-```
-
-Any ordered comparison of a number to a `NaN` (_not a number_) type is `False`.
-A confusing side-effect of Python's `NaN` definition is that `NaN` never compares equal to `NaN`.
-If you are curious as to why `Nan` was defined this way in Python, this [Stack Overflow Post on NaN][SO NaN Post] around the setting of the international standard is an interesting read.
-
-
-```python
->>> x = float('NaN')
-
->>> 3 < x
-False
-
->>> x < 3
-False
-
-# NaN never compares equal to NaN
->>> x == x
-False
-```
-
-
-## Comparing Strings
-
-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.
-
-
-```python
->>> 'Python' > 'Rust'
-False
-
->>> 'Python' > 'JavaScript'
-True
-
-# Examples with Mandarin.
-# hello < goodbye
->>> 'δ½ ε₯½' < 'εθ§'
-True
-
-# ord() of first characters
->>> ord('δ½ '), ord('ε')
-(20320, 20877)
-
-# ord() of second characters
->>> ord('ε₯½'), ord('θ§')
-(22909, 35265)
-
-# And with Korean words.
-# Pretty < beautiful.
->>> 'μμ' < 'μλ¦λ€μ΄'
-False
-
->>> ord('μ'), ord('μ')
-(50696, 50500)
-```
-
-
-## Comparing Container Data Types
-
-Container data types (_`lists`, `tuples`, `sets`, `dicts`, etc._) also compare [_lexicographically_][lexographic order] - they are equal if both containers have the same data **and** the same data types (_in the case of `lists` and `tuples`, they must also have the same **ordering**_), unequal otherwise.
-
-
-```python
-# Comparing lists
->>> [1, 2] == [1, 2]
-True
-
-# But if the data is not in the same order, they are not equal.
->>> [2, 1] == [1, 2]
-False
-
-# The same holds true for tuples
->>> (3,4,5) == (5,4,3)
-False
-
-# Length is also compared
->>> [1, 2] < [1, 2, 3]
-True
-
-# Comparing dicts
->>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 18}
-False
-
->>> {'name': 'John', 'age': 19} == {'name': 'John', 'age': 19}
-True
-```
-
-
-## Comparison Chaining
-
-Comparison operators can be chained _arbitrarily_.
-Note that the evaluation of an expression takes place from `left` to `right`.
-For example, `x < y <= z` is equivalent to `x < y` `and` `y <= z`, except that `y` is evaluated **only once**.
-In both cases, `z` is _not_ evaluated **at all** when `x < y` is found to be `False`.
-This is often called `short-circuit evaluation` - the evaluation stops if the truth value of the expression has already been determined.
-
-`Short circuiting` is supported by various boolean operators, functions, and also by comparison chaining in Python.
-Unlike many other programming languages, including `C`, `C++`, `C#`, and `Java`, chained expressions like `a < b < c` in Python have a conventional [mathematical interpretation][three way boolean comparison] and precedence.
-
-
-```python
->>> x = 2
->>> y = 5
->>> z = 10
-
->>> x < y < z
-True
-
->>> x < y > z
-False
-
->>> x > y < z
-False
-```
-
-
-## Identity comparisons
-
-The operators `is` and `is not` test for object [_identity_][object identity], as opposed to object _value_.
-An object's identity never changes after creation and can be found by using the [`id()`][id function] function.
-
-\ `is` \ evaluates to `True` if _**and only if**_ `id()` == `id()`.
-apple `is not` orange yields the inverse.
-
-Due to their singleton status, `None` and `NotImplemented` should always be compared to items using `is` and `is not`.
-
-
-```python
->>> my_fav_numbers = [1, 2, 3]
-
->>> your_fav_numbers = my_fav_numbers
-
->>> my_fav_numbers is your_fav_numbers
-True
-
-# The returned id will differ by system and python version.
->>> id(my_fav_numbers)
-4517478208
-
-# your_fav_numbers is only an alias pointing to the original my_fav_numbers object.
-# Assigning a new name does not create a new object.
->>> id(your_fav_numbers)
-4517478208
-
-
->>> my_fav_numbers is not your_fav_numbers
-False
-
->>> my_fav_numbers is not None
-True
-
->>> my_fav_numbers is NotImplemented
-False
-```
-
-
-## Membership comparisons
-
-The operators `in` and `not in` test for _membership_.
-\ `in` \ evaluates to `True` if \ is a member of \ (_if \ is a subset of or is contained within \_), and evaluates `False` otherwise.
-\ `not in` \ returns the negation, or _opposite of_ \ `in` \.
-
-For string and bytes types, \ `in` \ is `True` _**if and only if**_ \