-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"authors": [ | ||
"sjakobi" | ||
], | ||
"contributors": [ | ||
"AnAccountForReportingBugs", | ||
"behrtam", | ||
"BethanyG", | ||
"cmccandless", | ||
"Dog", | ||
"Grociu", | ||
"ikhadykin", | ||
"kytrinyx", | ||
"mambocab", | ||
"N-Parsons", | ||
"Nishant23", | ||
"olufotebig", | ||
"pheanex", | ||
"rootulp", | ||
"thomasjpfan", | ||
"tqa236", | ||
"xitanggg", | ||
"yawpitch" | ||
], | ||
"files": { | ||
"solution": [ | ||
"luhn.py" | ||
], | ||
"test": [ | ||
"luhn_test.py" | ||
], | ||
"example": [ | ||
".meta/example.py" | ||
] | ||
}, | ||
"blurb": "Given a number determine whether or not it is valid per the Luhn formula.", | ||
"source": "The Luhn Algorithm on Wikipedia", | ||
"source_url": "https://en.wikipedia.org/wiki/Luhn_algorithm" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"track":"python","exercise":"luhn","id":"fda87fb1d5324fef81e9bfc025d2666e","url":"https://exercism.org/tracks/python/exercises/luhn","handle":"vpayno","is_requester":true,"auto_approve":false} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
# Help | ||
|
||
## Running the tests | ||
|
||
We use [pytest][pytest: Getting Started Guide] as our website test runner. | ||
You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. | ||
You should also install the following `pytest` plugins: | ||
|
||
- [pytest-cache][pytest-cache] | ||
- [pytest-subtests][pytest-subtests] | ||
|
||
Extended information can be found in our website [Python testing guide][Python track tests page]. | ||
|
||
|
||
### Running Tests | ||
|
||
To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). | ||
Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. | ||
|
||
Linux/MacOS | ||
```bash | ||
$ cd {path/to/exercise-folder-location} | ||
``` | ||
|
||
Windows | ||
```powershell | ||
PS C:\Users\foobar> cd {path\to\exercise-folder-location} | ||
``` | ||
|
||
<br> | ||
|
||
Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: | ||
|
||
Linux/MacOS | ||
```bash | ||
$ python3 -m pytest -o markers=task {exercise_test.py} | ||
==================== 7 passed in 0.08s ==================== | ||
``` | ||
|
||
Windows | ||
```powershell | ||
PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} | ||
==================== 7 passed in 0.08s ==================== | ||
``` | ||
|
||
|
||
### Common options | ||
- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) | ||
- `-v` : enable verbose output. | ||
- `-x` : stop running tests on first failure. | ||
- `--ff` : run failures from previous test before running other test cases. | ||
|
||
For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. | ||
|
||
|
||
### Fixing warnings | ||
|
||
If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: | ||
|
||
```bash | ||
PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html | ||
``` | ||
|
||
To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. | ||
We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. | ||
|
||
You can also create your own `pytest.ini` file with the following content: | ||
|
||
```ini | ||
[pytest] | ||
markers = | ||
task: A concept exercise task. | ||
``` | ||
|
||
Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. | ||
More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. | ||
|
||
Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. | ||
|
||
|
||
### Extending your IDE or Code Editor | ||
|
||
Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. | ||
Some community-sourced options can be found on our [Python track tools page][Python track tools page]. | ||
|
||
[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html | ||
[Python track tools page]: https://exercism.org/docs/tracks/python/tools | ||
[Python track tests page]: https://exercism.org/docs/tracks/python/tests | ||
[pytest-cache]:http://pythonhosted.org/pytest-cache/ | ||
[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests | ||
[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini | ||
[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats | ||
[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks | ||
[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers | ||
|
||
## Submitting your solution | ||
|
||
You can submit your solution using the `exercism submit luhn.py` command. | ||
This command will upload your solution to the Exercism website and print the solution page's URL. | ||
|
||
It's possible to submit an incomplete solution which allows you to: | ||
|
||
- See how others have completed the exercise | ||
- Request help from a mentor | ||
|
||
## Need to get help? | ||
|
||
If you'd like help solving the exercise, check the following pages: | ||
|
||
- The [Python track's documentation](https://exercism.org/docs/tracks/python) | ||
- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python) | ||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) | ||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) | ||
|
||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. | ||
|
||
Below are some resources for getting help if you run into trouble: | ||
|
||
- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. | ||
- [The Exercism Community on Discord](https://exercism.org/r/discord) | ||
- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. | ||
- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. | ||
- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. | ||
- [Python Community Forums](https://discuss.python.org/) | ||
- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) | ||
- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) | ||
- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. | ||
|
||
Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. | ||
If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# Luhn | ||
|
||
Welcome to Luhn on Exercism's Python Track. | ||
If you need help running the tests or submitting your code, check out `HELP.md`. | ||
|
||
## Instructions | ||
|
||
Given a number determine whether or not it is valid per the Luhn formula. | ||
|
||
The [Luhn algorithm][luhn] is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers and Canadian Social Insurance Numbers. | ||
|
||
The task is to check if a given string is valid. | ||
|
||
## Validating a Number | ||
|
||
Strings of length 1 or less are not valid. | ||
Spaces are allowed in the input, but they should be stripped before checking. | ||
All other non-digit characters are disallowed. | ||
|
||
### Example 1: valid credit card number | ||
|
||
```text | ||
4539 3195 0343 6467 | ||
``` | ||
|
||
The first step of the Luhn algorithm is to double every second digit, starting from the right. | ||
We will be doubling | ||
|
||
```text | ||
4_3_ 3_9_ 0_4_ 6_6_ | ||
``` | ||
|
||
If doubling the number results in a number greater than 9 then subtract 9 from the product. | ||
The results of our doubling: | ||
|
||
```text | ||
8569 6195 0383 3437 | ||
``` | ||
|
||
Then sum all of the digits: | ||
|
||
```text | ||
8+5+6+9+6+1+9+5+0+3+8+3+3+4+3+7 = 80 | ||
``` | ||
|
||
If the sum is evenly divisible by 10, then the number is valid. | ||
This number is valid! | ||
|
||
### Example 2: invalid credit card number | ||
|
||
```text | ||
8273 1232 7352 0569 | ||
``` | ||
|
||
Double the second digits, starting from the right | ||
|
||
```text | ||
7253 2262 5312 0539 | ||
``` | ||
|
||
Sum the digits | ||
|
||
```text | ||
7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57 | ||
``` | ||
|
||
57 is not evenly divisible by 10, so this number is not valid. | ||
|
||
[luhn]: https://en.wikipedia.org/wiki/Luhn_algorithm | ||
|
||
## Source | ||
|
||
### Created by | ||
|
||
- @sjakobi | ||
|
||
### Contributed to by | ||
|
||
- @AnAccountForReportingBugs | ||
- @behrtam | ||
- @BethanyG | ||
- @cmccandless | ||
- @Dog | ||
- @Grociu | ||
- @ikhadykin | ||
- @kytrinyx | ||
- @mambocab | ||
- @N-Parsons | ||
- @Nishant23 | ||
- @olufotebig | ||
- @pheanex | ||
- @rootulp | ||
- @thomasjpfan | ||
- @tqa236 | ||
- @xitanggg | ||
- @yawpitch | ||
|
||
### Based on | ||
|
||
The Luhn Algorithm on Wikipedia - https://en.wikipedia.org/wiki/Luhn_algorithm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
class Luhn: | ||
def __init__(self, card_num): | ||
pass | ||
|
||
def valid(self): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# These tests are auto-generated with test data from: | ||
# https://github.com/exercism/problem-specifications/tree/main/exercises/luhn/canonical-data.json | ||
# File last updated on 2023-07-19 | ||
|
||
import unittest | ||
|
||
from luhn import ( | ||
Luhn, | ||
) | ||
|
||
|
||
class LuhnTest(unittest.TestCase): | ||
def test_single_digit_strings_can_not_be_valid(self): | ||
self.assertIs(Luhn("1").valid(), False) | ||
|
||
def test_a_single_zero_is_invalid(self): | ||
self.assertIs(Luhn("0").valid(), False) | ||
|
||
def test_a_simple_valid_sin_that_remains_valid_if_reversed(self): | ||
self.assertIs(Luhn("059").valid(), True) | ||
|
||
def test_a_simple_valid_sin_that_becomes_invalid_if_reversed(self): | ||
self.assertIs(Luhn("59").valid(), True) | ||
|
||
def test_a_valid_canadian_sin(self): | ||
self.assertIs(Luhn("055 444 285").valid(), True) | ||
|
||
def test_invalid_canadian_sin(self): | ||
self.assertIs(Luhn("055 444 286").valid(), False) | ||
|
||
def test_invalid_credit_card(self): | ||
self.assertIs(Luhn("8273 1232 7352 0569").valid(), False) | ||
|
||
def test_invalid_long_number_with_an_even_remainder(self): | ||
self.assertIs(Luhn("1 2345 6789 1234 5678 9012").valid(), False) | ||
|
||
def test_invalid_long_number_with_a_remainder_divisible_by_5(self): | ||
self.assertIs(Luhn("1 2345 6789 1234 5678 9013").valid(), False) | ||
|
||
def test_valid_number_with_an_even_number_of_digits(self): | ||
self.assertIs(Luhn("095 245 88").valid(), True) | ||
|
||
def test_valid_number_with_an_odd_number_of_spaces(self): | ||
self.assertIs(Luhn("234 567 891 234").valid(), True) | ||
|
||
def test_valid_strings_with_a_non_digit_added_at_the_end_become_invalid(self): | ||
self.assertIs(Luhn("059a").valid(), False) | ||
|
||
def test_valid_strings_with_punctuation_included_become_invalid(self): | ||
self.assertIs(Luhn("055-444-285").valid(), False) | ||
|
||
def test_valid_strings_with_symbols_included_become_invalid(self): | ||
self.assertIs(Luhn("055# 444$ 285").valid(), False) | ||
|
||
def test_single_zero_with_space_is_invalid(self): | ||
self.assertIs(Luhn(" 0").valid(), False) | ||
|
||
def test_more_than_a_single_zero_is_valid(self): | ||
self.assertIs(Luhn("0000 0").valid(), True) | ||
|
||
def test_input_digit_9_is_correctly_converted_to_output_digit_9(self): | ||
self.assertIs(Luhn("091").valid(), True) | ||
|
||
def test_very_long_input_is_valid(self): | ||
self.assertIs(Luhn("9999999999 9999999999 9999999999 9999999999").valid(), True) | ||
|
||
def test_valid_luhn_with_an_odd_number_of_digits_and_non_zero_first_digit(self): | ||
self.assertIs(Luhn("109").valid(), True) | ||
|
||
def test_using_ascii_value_for_non_doubled_non_digit_isn_t_allowed(self): | ||
self.assertIs(Luhn("055b 444 285").valid(), False) | ||
|
||
def test_using_ascii_value_for_doubled_non_digit_isn_t_allowed(self): | ||
self.assertIs(Luhn(":9").valid(), False) | ||
|
||
def test_non_numeric_non_space_char_in_the_middle_with_a_sum_that_s_divisible_by_10_isn_t_allowed( | ||
self, | ||
): | ||
self.assertIs(Luhn("59%59").valid(), False) | ||
|
||
# Additional tests for this track | ||
|
||
def test_is_valid_can_be_called_repeatedly(self): | ||
# This test was added, because we saw many implementations | ||
# in which the first call to valid() worked, but the | ||
# second call failed(). | ||
number = Luhn("055 444 285") | ||
self.assertIs(number.valid(), True) | ||
self.assertIs(number.valid(), True) |