**`exercsim/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.
Exercises are grouped into **concept** exercises which teach the [Python syllabus][python-syllabus], and **practice** exercises, which are unlocked by progressing in the syllabus tree 🌴 . Concept exercises are constrained to a small set of language or syntax features. Practice exercises are open-ended, and can be used to practice concepts learned, try out new techniques, and _play_. These two exercise groupings can be found in the track [config.json][config-json], and under the `python/exercises` directory.
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].
Some defined roles in our community: [Contributors][exercism-contributors] **|** [Mentors][exercism-mentors] **|** [Maintainers][exercism-track-maintainers] **|** [Admins][exercism-admins]
[Writing Style Guide][exercism-writing-style] **|** [Markdown Specification][exercism-markdown-specification] (_ ✨ versions available in [contributing][website-contributing-section] on [exercism(dot)org][exercism-website]._)
It is not uncommon to discover typos, confusing directions, or incorrect implementations of certain tests or code examples. Or you might have a great suggestion for a hint to aid students ( 💙 ), see optimizations for exemplar or test code, find missing test cases to add, or want to correct factual and/or logical errors. Or maybe you have a great idea for an exercise or feature (❗ ).
2️⃣ Medium changes that have been agreed/discussed via a filed issue,
- [ ] Update & rebase your branch with any (recent) upstream changes.
- [ ] Spell and grammar check all prose changes.
- [ ] Run [Prettier](https://prettier.io/) on all markdown and JSON files.
- (_Optionally_) run [yapf](https://github.com/google/yapf) ([_yapf config_](https://github.com/exercism/python/blob/main/.style.yapf)) to help format your code.
- [ ] Run [flake8](http://flake8.pycqa.org/) with [_flake8 config_](https://github.com/exercism/python/blob/main/.flake8) to check general code style standards.
- [ ] Run [pylint](https://pylint.pycqa.org/en/v2.11.1/user_guide/index.html) with [_pylint config_](https://github.com/exercism/python/blob/main/pylintrc) to check extended code style standards.
- [ ] Use pytest or the [python-track-test-runner](https://github.com/exercism/python-test-runner) to test any changed `example.py`/`exemplar.py`files
against their associated test files.
- [ ] Similarly, use [pytest](https://docs.pytest.org/en/6.2.x/contents.html) or
the [python-track-test-runner](https://github.com/exercism/python-test-runner) to test any changed _**test**_ files.
- Check that tests **fail** properly, as well as succeed.
(_**e.g.**, make some tests fail on purpose to "test the tests" & failure messages_).
- [ ] Double-check all files for proper EOL.
- [ ] [Regenerate](https://github.com/exercism/python/blob/main/CONTRIBUTING.md#generating-practice-exercise-documents) exercise documents when you modified or created a `hints.md` file for a practice exercise.
- [ ] [Regenerate the test file](https://github.com/exercism/python/blob/main/CONTRIBUTING.md#auto-generated-test-files-and-test-templates) if you modified or created a `JinJa2` template file for a practice exercise.
- Run the generated test file result against its `example.py`.
- [ ] Run [`configlet-lint`](https://github.com/exercism/configlet#configlet-lint) if the track [config.json](https://github.com/exercism/docs/blob/main/building/tracks/config-json.md), or any other exercise `config.json` has been modified.
Non-code content (_exercise introductions & instructions, hints, concept write-ups, documentation etc._) should be written in [American English][american-english].
We strive to watch [the words we use][the-words-that-we-use].
When a word or phrase usage is contested/ambiguous, we default to what is best understood by our international community of learners, even if it "sounds a little weird" to a "native" American English speaker.
Our documents use [Markdown][markdown-language], with certain [alterations][exercism-markdown-widgets] & [additions][exercism-internal-linking]. Here is our full [Markdown Specification][exercism-markdown-specification]. 📐 We format/lint our Markdown with [Prettier][prettier]. ✨
- [Unittest.TestCase][unittest] syntax, with [PyTest][pytest] as a test runner.
- We are transitioning to using more PyTest features/syntax, but are leaving `Unittest` syntax in place where possible.
- Always check with a maintainer before introducing a PyTest feature into your tests.
- Test **Classes** should be titled `<ExerciseSlug>Test`. **e.g.**`class CardGamesTest(unittest.TestCase):`
- Test method names should begin with `test_`. Try to make test case names descriptive but not too long.
- Favor [_parameterizing_][distinguishing-test-iterations] tests that only vary input data. Use [unittest.TestCase.subTest][subtest] for parameterization.
- An [example from Guido's Gorgeous Lasagna][guidos-gorgeous-lasagna-testfile].
- A second [example from Card Games][card-games-testfile].
- Avoid excessive line breaks or indentation - particularly in parameterized tests.
- Excessive breaks & indentation within the `for` loops cause issues when formatting the test code for display on the website.
- Use [`enumerate()`][enumerate] where possible when indexes are needed. See [Card Games][card-games-testfile] for example usage.
- Favor using names like `inputs`, `data`, `input_data`, `test_data`, or `test_case_data` for test inputs.
- Favor using names like `results`, `expected`, `result_data`, `expected_data`, or `expected_results` for test outcomes.
- Favor putting the assert failure message outside of `self.assert()`. Name it `failure_msg`. See [Card Games][card-games-testfile] for example usage.
- Favor `f-strings` for dynamic failure messages. Please make your error messages as relevant and human-readable as possible.
- We relate test cases to **task number** via a custom [PyTest Marker][pytestmark].
- These take the form of `@pytest.mark.task(taskno=<task-number-here>)`. See [Guido's Gorgeous Lasagna][guidos-gorgeous-lasagna-testfile] for an example.
- Both linters are known to toss false-positives for some testing patterns.
- Where necessary, deploy the [`#noqa`][flake8-noqa] or [`#pylint disable=<check-name>`][pylint-disable-check] comments to suppress false-positive warnings. - See **line 16** of [Guido's Gorgeous Lasagna][guidos-gorgeous-lasagna-testfile] test file for an example of an override.
_**We know it, and trust us, we are working on fixing it.**_ But if you see 👀 something, 👄 say something. It will motivate us to fix it! 🌈
- All exercises should be written for compatibility with Python = `3.8` or `3.9`.
- Version backward _incompatibility_ (*e.g* an exercise using a `3.8` or `3.9`**only** feature) should be clearly noted in any exercise hits, links, introductions or other notes.
- _Most_ exercises will work with Python `3.6+`, and _many_ are compatible with Python `2.7+`.
- Please do not change existing exercises to add new language features without consulting with a maintainer first.
- We 💛 💙 modern Python, but we _also_ want to avoid student confusion when it comes to which Python versions support brand-new features.
- All test suites and example solutions must work in all Python versions that we currently support. When in doubt about a feature, please check with maintainers.
<pvertical-align="middle"><h2>A Little More on Exercises</h2></p>
<br>
- Each exercise must be self-contained. Please do not use or reference files that reside outside the given exercise directory. "Outside" files will not be included if a student fetches the exercise via the Command line Interface.
- **Practice exercise**, descriptions and instructions come from a centralized, cross-track [problem specifications][problem-specifications] repository.
- Any updates or changes need to be proposed/approved in `problem-specifications` first.
- If Python-specific changes become necessary, they need to be appended to the canonical instructions by creating a `instructions.append.md` file in this (`exercism/Python`) repository.
- Practice Exercise **Test Suits** for many practice exercises are similarly [auto-generated](#auto-generated-files) from data in [problem specifications][problem-specifications].
- Any changes to them need to be proposed/discussed in the `problem-specifications` repository and approved by **3 track maintainers**, since changes could potentially affect many (_or all_) exercism language tracks.
Our tooling (_runners, representers, and analyzers_) runs in isolated containers within the exercism website. Because of this isolation, exercises cannot rely on third-party or external libraries. Any library needed for an exercise or exercise tests must be incorporated as part of a tooling build, and noted for students who are using the CLI to solve problems locally.
If your exercise depends on a third-party library (_aka not part of standard Python_), please consult with maintainers about it. We may or may not be able to accommodate the package.
[**Practice exercises**][practice-exercise-files] inherit their definitions from the [problem-specifications][problem-specifications] repository in the form of _description files_. Exercise introductions, instructions and (_in the case of **many**, but not **all**_) test files are then machine-generated for each language track.
Changes to practice exercise _specifications_ should be raised/PR'd in [problem-specifications][problem-specifications] and approved by **3 track maintainers**. After an exercise change has gone through that process , related documents and tests for the Python track will need to be [re-generated](#generating-practice-exercise-documents) via [configlet][configlet]. Configlet is also used as part of the track CI, essential track and exercise linting, and other verification tasks.
If a practice exercise has an auto-generated `<exercise_slug>_test.py` file, there will be a `.meta/template.j2` and a `.meta/tests.toml` file in the exercise directory. If an exercise implements Python track-specific tests, there may be a `.meta/additional_tests.json` to define them. These `additional_tests.json` files will automatically be included in test generation.
If an unimplemented exercise has a `canonical-data.json` file in the [problem-specifications] repository, a generation template must be created. See the Python track [test generator documentation][python-track-test-generator] for more information.
Implementing Track-specific Practice Exercises is similar to implementing a `canonical` exercise that has no `canonical-data.json`. But in addition to the tests, the exercise documents (_instructions, etc._) will also need to be written manually. Carefully follow the structure of generated exercise documents and the [exercism practice exercise specification][practice-exercises].
<pverticle-align="middle"><imgid="generating-practice-exercise-documents"align="left"width="70"height="70"src="https://github.com/exercism/website-icons/blob/main/exercises/rest-api.svg"><h2>Generating Practice Exercise Documents</h2></p>
<p><b>For all Practice Exercises</b><p><imgid="regenerating-all-practice-exercise-documents"align="left"width="45"height="45"src="https://github.com/exercism/website-icons/blob/main/exercises/doubly-linked-list.svg"></p>