From 2b85a659a7f26334f5226c4a15f35b1d57615c0f Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Thu, 12 Nov 2015 00:54:25 +0100 Subject: [PATCH 01/81] circular-buffer: Implemented new exercise --- circular-buffer/circular_buffer_test.py | 109 ++++++++++++++++++++++++ circular-buffer/example.py | 37 ++++++++ config.json | 1 + 3 files changed, 147 insertions(+) create mode 100644 circular-buffer/circular_buffer_test.py create mode 100644 circular-buffer/example.py diff --git a/circular-buffer/circular_buffer_test.py b/circular-buffer/circular_buffer_test.py new file mode 100644 index 00000000000..ac742b811bd --- /dev/null +++ b/circular-buffer/circular_buffer_test.py @@ -0,0 +1,109 @@ +import unittest + +from circular_buffer import CircularBuffer +from circular_buffer import BufferFullException, BufferEmptyException + + +class CircularBufferTest(unittest.TestCase): + + def test_read_empty_buffer(self): + buf = CircularBuffer(1) + with self.assertRaises(BufferEmptyException): + buf.read() + + def test_write_and_read_back_one_item(self): + buf = CircularBuffer(1) + buf.write('1') + self.assertEqual('1', buf.read()) + with self.assertRaises(BufferEmptyException): + buf.read() + + def test_write_and_read_back_multiple_items(self): + buf = CircularBuffer(2) + buf.write('1') + buf.write('2') + self.assertEqual('1', buf.read()) + self.assertEqual('2', buf.read()) + with self.assertRaises(BufferEmptyException): + buf.read() + + def test_clearing_buffer(self): + buf = CircularBuffer(3) + for c in '123': + buf.write(c) + buf.clear() + with self.assertRaises(BufferEmptyException): + buf.read() + buf.write('1') + buf.write('2') + self.assertEqual('1', buf.read()) + buf.write('3') + self.assertEqual('2', buf.read()) + + def test_alternate_write_and_read(self): + buf = CircularBuffer(2) + buf.write('1') + self.assertEqual('1', buf.read()) + buf.write('2') + self.assertEqual('2', buf.read()) + + def test_read_back_oldest_item(self): + buf = CircularBuffer(3) + buf.write('1') + buf.write('2') + buf.read() + buf.write('3') + buf.read() + self.assertEqual('3', buf.read()) + + def test_write_full_buffer(self): + buf = CircularBuffer(2) + buf.write('1') + buf.write('2') + with self.assertRaises(BufferFullException): + buf.write('A') + + def test_overwrite_full_buffer(self): + buf = CircularBuffer(2) + buf.write('1') + buf.write('2') + buf.overwrite('A') + self.assertEqual('2', buf.read()) + self.assertEqual('A', buf.read()) + with self.assertRaises(BufferEmptyException): + buf.read() + + def test_overwrite_non_full_buffer(self): + print + print + buf = CircularBuffer(2) + buf.overwrite('1') + buf.overwrite('2') + self.assertEqual('1', buf.read()) + self.assertEqual('2', buf.read()) + with self.assertRaises(BufferEmptyException): + buf.read() + + def test_alternate_read_and_overwrite(self): + buf = CircularBuffer(5) + for c in '123': + buf.write(c) + buf.read() + buf.read() + buf.write('4') + buf.read() + for c in '5678': + buf.write(c) + buf.overwrite('A') + buf.overwrite('B') + self.assertEqual('6', buf.read()) + self.assertEqual('7', buf.read()) + self.assertEqual('8', buf.read()) + self.assertEqual('A', buf.read()) + self.assertEqual('B', buf.read()) + with self.assertRaises(BufferEmptyException): + buf.read() + + +if __name__ == '__main__': + unittest.main() diff --git a/circular-buffer/example.py b/circular-buffer/example.py new file mode 100644 index 00000000000..af448179351 --- /dev/null +++ b/circular-buffer/example.py @@ -0,0 +1,37 @@ +class BufferFullException(Exception): + pass + + +class BufferEmptyException(Exception): + pass + + +class CircularBuffer(object): + + def __init__(self, capacity): + self.buffer = bytearray(capacity) + self.read_point = 0 + self.write_point = 0 + + def clear(self): + self.buffer = bytearray(len(self.buffer)) + + def write(self, data): + if all(self.buffer): + raise BufferFullException + self.buffer[self.write_point] = data + self.write_point = (self.write_point + 1) % len(self.buffer) + + def overwrite(self, data): + self.buffer[self.write_point] = data + if all(self.buffer) and self.write_point == self.read_point: + self.read_point = (self.read_point + 1) % len(self.buffer) + self.write_point = (self.write_point + 1) % len(self.buffer) + + def read(self): + if not any(self.buffer): + raise BufferEmptyException + data = chr(self.buffer[self.read_point]) + self.buffer[self.read_point] = 0 + self.read_point = (self.read_point + 1) % len(self.buffer) + return data diff --git a/config.json b/config.json index 300e4674768..175fd5db629 100644 --- a/config.json +++ b/config.json @@ -33,6 +33,7 @@ "crypto-square", "sublist", "pythagorean-triplet", + "circular-buffer", "robot-name", "matrix", "nth-prime", From e973b94c6c966d6eca2cd9d8d9b6ea2faf438a90 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Thu, 12 Nov 2015 02:02:07 +0100 Subject: [PATCH 02/81] circular-buffer: Fixed python3 compatibility --- circular-buffer/circular_buffer_test.py | 2 -- circular-buffer/example.py | 11 +++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/circular-buffer/circular_buffer_test.py b/circular-buffer/circular_buffer_test.py index ac742b811bd..75cad02c3db 100644 --- a/circular-buffer/circular_buffer_test.py +++ b/circular-buffer/circular_buffer_test.py @@ -74,8 +74,6 @@ def test_overwrite_full_buffer(self): buf.read() def test_overwrite_non_full_buffer(self): - print - print buf = CircularBuffer(2) buf.overwrite('1') buf.overwrite('2') diff --git a/circular-buffer/example.py b/circular-buffer/example.py index af448179351..857daf8538a 100644 --- a/circular-buffer/example.py +++ b/circular-buffer/example.py @@ -13,17 +13,24 @@ def __init__(self, capacity): self.read_point = 0 self.write_point = 0 + # (protected) helper method to support python 2/3 + def _update_buffer(self, data): + try: + self.buffer[self.write_point] = data + except TypeError: + self.buffer[self.write_point] = ord(data) + def clear(self): self.buffer = bytearray(len(self.buffer)) def write(self, data): if all(self.buffer): raise BufferFullException - self.buffer[self.write_point] = data + self._update_buffer(data) self.write_point = (self.write_point + 1) % len(self.buffer) def overwrite(self, data): - self.buffer[self.write_point] = data + self._update_buffer(data) if all(self.buffer) and self.write_point == self.read_point: self.read_point = (self.read_point + 1) % len(self.buffer) self.write_point = (self.write_point + 1) % len(self.buffer) From 1bf28808fb1933950db2ce0caf671c4847564dee Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Thu, 26 Nov 2015 15:05:58 +0100 Subject: [PATCH 03/81] perfect-numbers: Implement new exercise --- config.json | 1 + perfect-numbers/example.py | 12 +++++++ perfect-numbers/perfect_numbers_test.py | 42 +++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 perfect-numbers/example.py create mode 100644 perfect-numbers/perfect_numbers_test.py diff --git a/config.json b/config.json index 41ff709f69e..aa96600041f 100644 --- a/config.json +++ b/config.json @@ -43,6 +43,7 @@ "nth-prime", "saddle-points", "beer-song", + "perfect-numbers", "secret-handshake", "twelve-days", "binary", diff --git a/perfect-numbers/example.py b/perfect-numbers/example.py new file mode 100644 index 00000000000..e80fefdcad5 --- /dev/null +++ b/perfect-numbers/example.py @@ -0,0 +1,12 @@ +def divisor_generator(n): + ''' Returns an unordered list of divisors for n (1 < n). ''' + for i in range(2, int(n ** 0.5) + 1): + if n % i == 0: + yield i + if i * i != n: + yield n // i + + +def is_perfect(n): + ''' A perfect number equals the sum of its positive divisors. ''' + return sum(divisor_generator(n)) + 1 == n diff --git a/perfect-numbers/perfect_numbers_test.py b/perfect-numbers/perfect_numbers_test.py new file mode 100644 index 00000000000..4066f031eaf --- /dev/null +++ b/perfect-numbers/perfect_numbers_test.py @@ -0,0 +1,42 @@ +import unittest + +from natural_numbers import is_perfect + + +class PerfectNumbersTest(unittest.TestCase): + + def test_first_perfect_number(self): + self.assertTrue(is_perfect(6)) + + def test_no_perfect_number(self): + self.assertFalse(is_perfect(8)) + + def test_second_perfect_number(self): + self.assertTrue(is_perfect(28)) + + def test_abundant(self): + self.assertFalse(is_perfect(20)) + + def test_answer_to_the_ultimate_question_of_life(self): + self.assertFalse(is_perfect(42)) + + def test_third_perfect_number(self): + self.assertTrue(is_perfect(496)) + + def test_odd_abundant(self): + self.assertFalse(is_perfect(945)) + + def test_fourth_perfect_number(self): + self.assertTrue(is_perfect(8128)) + + def test_fifth_perfect_number(self): + self.assertTrue(is_perfect(33550336)) + + def test_sixth_perfect_number(self): + self.assertTrue(is_perfect(8589869056)) + + def test_seventh_perfect_number(self): + self.assertTrue(is_perfect(137438691328)) + +if __name__ == '__main__': + unittest.main() From 735f3555b7070c93f52e653028ca12e6dae4e66b Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 25 Nov 2015 12:41:05 -0700 Subject: [PATCH 04/81] Clean up docs for x-api v3 --- docs/HELLO.md | 0 docs/INSTALLATION.md | 11 +++++- docs/LEARNING.md | 4 +++ docs/RESOURCES.md | 75 +++++++++++++++++++++++++++++++++++--- docs/TESTS.md | 47 ++++++++++++++++++++++++ docs/TOOLS.md | 42 ---------------------- docs/WORKFLOW.md | 86 -------------------------------------------- 7 files changed, 131 insertions(+), 134 deletions(-) delete mode 100644 docs/HELLO.md create mode 100644 docs/LEARNING.md create mode 100644 docs/TESTS.md delete mode 100644 docs/TOOLS.md delete mode 100644 docs/WORKFLOW.md diff --git a/docs/HELLO.md b/docs/HELLO.md deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 625e1aa1cfc..1c736e86daf 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -2,9 +2,18 @@ If Python isn't already available on your system follow the instructions at [the Exercism currently supports Python3.4, Python3.3 and Python2.7. - ## Packages The [Python Package Index](https://pypi.python.org/pypi) contains thousands of packages. Pretty much each of them is installable with `pip install packagename`. If you don't have __pip__ already, [get it now](https://pip.pypa.io/en/latest/installing.html)! + +## Tests + +We recommend you install [pytest](http://pytest.org/latest/) and [pytest-cache](http://pythonhosted.org/pytest-cache/). Pytest is a testing tool that will give you more flexibility over running your unit tests. + +### Installation + +```bash +$ pip install pytest pytest-cache +``` diff --git a/docs/LEARNING.md b/docs/LEARNING.md new file mode 100644 index 00000000000..550906a2905 --- /dev/null +++ b/docs/LEARNING.md @@ -0,0 +1,4 @@ +* [The Python Tutorial](https://docs.python.org/3/tutorial/) +* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) +* [Think Python](http://www.greenteapress.com/thinkpython/html/index.html) +* [The Python Library Reference](https://docs.python.org/3/library/index.html) diff --git a/docs/RESOURCES.md b/docs/RESOURCES.md index 2c4a4a6eea2..d5429b51ddb 100644 --- a/docs/RESOURCES.md +++ b/docs/RESOURCES.md @@ -1,6 +1,71 @@ -## Recommended learning resources +####PDB -* [The Python Tutorial](https://docs.python.org/3/tutorial/) -* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) -* [Think Python](http://www.greenteapress.com/thinkpython/html/index.html) -* [The Python Library Reference](https://docs.python.org/3/library/index.html) +Will drop you into the python debugger when a test fails. +To learn how to use pdb, check out the [documentation](https://docs.python.org/2/library/pdb.html#debugger-commands). + +You may also be interested in watching [Clayton Parker's "So you think you can pdb?" PyCon 2015 talk](https://www.youtube.com/watch?v=P0pIW5tJrRM) + +```bash +$ cd exercism/python/bob +$ py.test --pdb bob_test.py +``` + +####PEP8 + +PEP8 is the [python style guide](https://www.python.org/dev/peps/pep-0008/). If you would like to test for compliance to the style guide, install [pytest-pep8](https://pypi.python.org/pypi/pytest-pep8) + +```bash +$ pip install pytest-pep8 +``` + +and add the pep8 flag to your command + +```bash +$ cd exercism/python/bob +$ py.test --pep8 bob_test.py +``` + +Read the [pytest documentation](http://pytest.org/latest/contents.html#toc) and [pytest-cache](http://pythonhosted.org/pytest-cache/) documentation to learn more. + +## Visual Studio on Windows + +Follow the installation instructions for [Python Tools for Visual Studio](https://pytools.codeplex.com/wikipage?title=PTVS%20Installation) + +You can either start by creating your own project for working with the Exercism problems or you can download a Visual Studio solution that is already set up. + +### Exercism.io Visual Studio Template + +This is a Visual Studio template that comes pre-configured to work on the problems in as many languages as Visual Studio supports. + +![Solution Explorer](http://x.exercism.io/v3/tracks/python/docs/img/SolutionExplorer.png) + +1. Download the [Exercism.io Visual Studio Template](https://github.com/rprouse/Exercism.VisualStudio) from GitHub by clicking the Download Zip button on the page. +2. Unzip the template into your exercises directory, for example `C:\src\exercises` +2. Install the [Exercism CLI](http://help.exercism.io/installing-the-cli.html) +3. Open a command prompt to your exercise directory +4. Add your API key to exercism `exercism configure --key=YOUR_API_KEY` +5. Configure your source directory in exercism `exercism configure --dir=C:\src\exercises` +6. [Fetch your first exercise](http://help.exercism.io/fetching-exercises.html) `exercism fetch python` +7. Open the Exercism solution in Visual Studio +8. Expand the Exercism.python project +9. Click on **Show All Files** in Solution Explorer (See below) +10. The exercise you just fetched will appear greyed out. Right click on the folder and **Include In Project** +11. Get coding... + +![Add files](http://x.exercism.io/v3/tracks/python/docs/img/AddFiles.png) + +To run the tests, you can do so at the command line, or within Visual Studio. + +![Test Explorer](http://x.exercism.io/v3/tracks/python/docs/img/TestExplorer.png) + +## Code Style and Linting + +There's a style guide called [PEP8](http://legacy.python.org/dev/peps/pep-0008/) that many Python projects adhere to. +Read it when you get a chance! + +If you just want a quick overview of some problems in your code, use [pylint](http://www.pylint.org/)! +It can be pretty picky though, so take its results with a grain of salt. +If you don't agree with one of its points, that's a good topic for a discussion in the comments for your program! + +If you'd rather have a tool take care of your style issues, take a look at [autopep8](https://github.com/hhatto/autopep8)! +Run `autopep8 -d mycode.py` to get a diff of the changes it proposes and `autopep8 -i mycode.py` to format the code inplace! diff --git a/docs/TESTS.md b/docs/TESTS.md new file mode 100644 index 00000000000..efcb06db99d --- /dev/null +++ b/docs/TESTS.md @@ -0,0 +1,47 @@ +If you choose not to install pytest, you can still run tests individually: + +```bash +$ cd exercism/python/bob +$ python bob_test.py +``` + +## Pytest Examples + +####Run All Tests + +```bash +$ cd exercism/python/bob +$ py.test bob_test.py +``` + +####Stop After First Failure + +```bash +$ cd exercism/python/bob +$ py.test -x bob_test.py +``` + +####Failed Tests First + +Pytest-cache remembers which tests failed, and can run those tests first. + +```bash +$ cd exercism/python/bob +$ py.test --ff bob_test.py +``` + +### Recommended + +We recommend you run this command while working on exercises. + +```bash +$ cd exercism/python/bob +$ py.test -x --ff bob_test.py +``` + +####Running All Tests for All Exercises + +```bash +$ cd exercism/python/ +$ py.test +``` diff --git a/docs/TOOLS.md b/docs/TOOLS.md deleted file mode 100644 index a97c131683f..00000000000 --- a/docs/TOOLS.md +++ /dev/null @@ -1,42 +0,0 @@ -## Visual Studio on Windows - -Follow the installation instructions for [Python Tools for Visual Studio](https://pytools.codeplex.com/wikipage?title=PTVS%20Installation) - -You can either start by creating your own project for working with the Exercism problems or you can download a Visual Studio solution that is already set up. - -### Exercism.io Visual Studio Template - -This is a Visual Studio template that comes pre-configured to work on the problems in as many languages as Visual Studio supports. - -![Solution Explorer](/img/SolutionExplorer.png) - -1. Download the [Exercism.io Visual Studio Template](https://github.com/rprouse/Exercism.VisualStudio) from GitHub by clicking the Download Zip button on the page. -2. Unzip the template into your exercises directory, for example `C:\src\exercises` -2. Install the [Exercism CLI](http://help.exercism.io/installing-the-cli.html) -3. Open a command prompt to your exercise directory -4. Add your API key to exercism `exercism configure --key=YOUR_API_KEY` -5. Configure your source directory in exercism `exercism configure --dir=C:\src\exercises` -6. [Fetch your first exercise](http://help.exercism.io/fetching-exercises.html) `exercism fetch python` -7. Open the Exercism solution in Visual Studio -8. Expand the Exercism.python project -9. Click on **Show All Files** in Solution Explorer (See below) -10. The exercise you just fetched will appear greyed out. Right click on the folder and **Include In Project** -11. Get coding... - -![Add files](/img/AddFiles.png) - -To run the tests, you can do so at the command line, or within Visual Studio. - -![Test Explorer](/img/TestExplorer.png) - -## Code Style and Linting - -There's a style guide called [PEP8](http://legacy.python.org/dev/peps/pep-0008/) that many Python projects adhere to. -Read it when you get a chance! - -If you just want a quick overview of some problems in your code, use [pylint](http://www.pylint.org/)! -It can be pretty picky though, so take its results with a grain of salt. -If you don't agree with one of its points, that's a good topic for a discussion in the comments for your program! - -If you'd rather have a tool take care of your style issues, take a look at [autopep8](https://github.com/hhatto/autopep8)! -Run `autopep8 -d mycode.py` to get a diff of the changes it proposes and `autopep8 -i mycode.py` to format the code inplace! diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md deleted file mode 100644 index cad2298e32b..00000000000 --- a/docs/WORKFLOW.md +++ /dev/null @@ -1,86 +0,0 @@ -## Tests - -We recommend you install [pytest](http://pytest.org/latest/) and [pytest-cache](http://pythonhosted.org/pytest-cache/). Pytest is a testing tool that will give you more flexibility over running your unit tests. - -If you choose not to install pytest, you can still run tests individually: - -```bash -$ cd exercism/python/bob -$ python bob_test.py -``` - -### Installation - -```bash -$ pip install pytest pytest-cache -``` - -## Pytest Examples - -####Run All Tests - -```bash -$ cd exercism/python/bob -$ py.test bob_test.py -``` - -####Stop After First Failure - -```bash -$ cd exercism/python/bob -$ py.test -x bob_test.py -``` - -####Failed Tests First - -Pytest-cache remembers which tests failed, and can run those tests first. - -```bash -$ cd exercism/python/bob -$ py.test --ff bob_test.py -``` - -### Recommended - -We recommend you run this command while working on exercises. - -```bash -$ cd exercism/python/bob -$ py.test -x --ff bob_test.py -``` - -####Running All Tests for All Exercises - -```bash -$ cd exercism/python/ -$ py.test -``` - -####PDB - -Will drop you into the python debugger when a test fails. -To learn how to use pdb, check out the [documentation](https://docs.python.org/2/library/pdb.html#debugger-commands). - -You may also be interested in watching [Clayton Parker's "So you think you can pdb?" PyCon 2015 talk](https://www.youtube.com/watch?v=P0pIW5tJrRM) - -```bash -$ cd exercism/python/bob -$ py.test --pdb bob_test.py -``` - -####PEP8 - -PEP8 is the [python style guide](https://www.python.org/dev/peps/pep-0008/). If you would like to test for compliance to the style guide, install [pytest-pep8](https://pypi.python.org/pypi/pytest-pep8) - -```bash -$ pip install pytest-pep8 -``` - -and add the pep8 flag to your command - -```bash -$ cd exercism/python/bob -$ py.test --pep8 bob_test.py -``` - -Read the [pytest documentation](http://pytest.org/latest/contents.html#toc) and [pytest-cache](http://pythonhosted.org/pytest-cache/) documentation to learn more. From d19993026bfee1c2885c60eba93ce34097b34b8a Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Tue, 1 Dec 2015 20:31:43 +0100 Subject: [PATCH 05/81] rail-fence-cipher: Implement new exercise --- config.json | 1 + rail-fence-cipher/example.py | 17 +++++++++++ rail-fence-cipher/rail_fence_cipher_test.py | 34 +++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 rail-fence-cipher/example.py create mode 100644 rail-fence-cipher/rail_fence_cipher_test.py diff --git a/config.json b/config.json index 41ff709f69e..f254a3282c7 100644 --- a/config.json +++ b/config.json @@ -40,6 +40,7 @@ "pythagorean-triplet", "robot-name", "matrix", + "rail-fence-cipher", "nth-prime", "saddle-points", "beer-song", diff --git a/rail-fence-cipher/example.py b/rail-fence-cipher/example.py new file mode 100644 index 00000000000..29942b74fe5 --- /dev/null +++ b/rail-fence-cipher/example.py @@ -0,0 +1,17 @@ +from itertools import cycle, chain + + +def fence_pattern(rails, size): + zig_zag = cycle(chain(range(rails), range(rails - 2, 0, -1))) + return zip(zig_zag, range(size)) + + +def encode(msg, rails): + fence = fence_pattern(rails, len(msg)) + return ''.join(msg[i] for _, i 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])) diff --git a/rail-fence-cipher/rail_fence_cipher_test.py b/rail-fence-cipher/rail_fence_cipher_test.py new file mode 100644 index 00000000000..d46a7ec0628 --- /dev/null +++ b/rail-fence-cipher/rail_fence_cipher_test.py @@ -0,0 +1,34 @@ +import unittest + +from rail_fence_cipher import encode, decode + + +class RailFenceTests(unittest.TestCase): + + def test_encode_with_two_rails(self): + self.assertMultiLineEqual('XXXXXXXXXOOOOOOOOO', + encode('XOXOXOXOXOXOXOXOXO', 2)) + + def test_encode_with_three_rails(self): + self.assertMultiLineEqual('WECRLTEERDSOEEFEAOCAIVDEN', + encode('WEAREDISCOVEREDFLEEATONCE', 3)) + + def test_encode_with_middle_stop(self): + self.assertMultiLineEqual('ESXIEECSR', encode('EXERCISES', 4)) + + def test_decode_with_three_rails(self): + self.assertMultiLineEqual('THEDEVILISINTHEDETAILS', + decode('TEITELHDVLSNHDTISEIIEA', 3)) + + def test_decode_with_five_rails(self): + self.assertMultiLineEqual('EXERCISMISAWESOME', + decode('EIEXMSMESAORIWSCE', 5)) + + def test_decode_with_six_rails(self): + self.assertMultiLineEqual( + '112358132134558914423337761098715972584418167651094617711286', + decode('133714114238148966225439541018335470986172518171757571896261', 6) + ) + +if __name__ == '__main__': + unittest.main() From 9945d8f821b77fbf9394e4b1f0ca00ea7c8a8a9e Mon Sep 17 00:00:00 2001 From: Ramiro Batista da Luz Date: Mon, 7 Dec 2015 16:11:26 -0200 Subject: [PATCH 06/81] Add ABOUT page. --- docs/ABOUT.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 docs/ABOUT.md diff --git a/docs/ABOUT.md b/docs/ABOUT.md new file mode 100644 index 00000000000..42bd229dec7 --- /dev/null +++ b/docs/ABOUT.md @@ -0,0 +1,43 @@ +## About Python + +Python is a powerful programming language, it is well known as a "glue" that means: it is used with many other technologies. It is multi platform, runs everywhere. Is friendly and easy to learn. It is licensed as open source, most versions are compatible with the GPL with a few exceptions on old versions. But, one of the most cool things about Python is the community that is very helpful and collaborative. Take a look at: [About python](https://www.python.org/about/). + + + +### What python is good for? + +Python can be applied to many different classes of problems [what python is good for](https://docs.python.org/3/faq/general.html#what-is-python-good-for). It have a powerful standard library with string processing, Internet protocols, software engineering, operating system interfaces. Python also have a lot of third-party modules, easily found in The Python Package Index (PyPi). Python software covers areas such as: + +- [Web and Internet Development](https://www.python.org/about/apps/#web-and-internet-development) +- [Database Access](https://www.python.org/about/apps/#database-access) +- [Desktop GUIs](https://www.python.org/about/apps/#desktop-guis) +- [Scientific & Numeric](https://www.python.org/about/apps/#scientific-and-numeric) +- [Education](https://www.python.org/about/apps/#education) +- [Network Programming](https://www.python.org/about/apps/#network-programming) +- [Software & Game Development](https://www.python.org/about/apps/#software-development) + +### Who uses python? + +Let the names of just some companies talk by themselves[Success](https://www.python.org/about/success/). + +- [Industrial Light & Magic Runs on Python](https://www.python.org/about/success/ilm/) +- [D-Link Australia Uses Python to Control Firmware Updates](https://www.python.org/about/success/dlink). +- [ForecastWatch.com Uses Python To Help Meteorologists](https://www.python.org/about/success/forecastwatch/). +- [Frequentis TAPtools® - Python in Air Traffic Control](https://www.python.org/about/success/frequentis/). +- [Maritime Industry Increases Efficiency with Python](https://www.python.org/about/success/tribon/). +- [Python Streamlines Space Shuttle Mission Design](https://www.python.org/about/success/usa/). +- [Python is Rackspace's CORE Technology](https://www.python.org/about/success/rackspace/). +- [ERP5: Mission-critical ERP/CRM with Python and Zope](https://www.python.org/about/success/nexedi/). +- Many others: Google, NASA, Intel, AMD, Walt Disney Animation Studios, Canonical, Red Hat, Amazon, Netflix, and thousands upon thousands more. + +### Reasons to learn + +Some reasons to learn Python [Reasons to learn](http://www.skilledup.com/articles/reasons-to-learn-python): + +- It is easy to learn. Python was designed to help the developer not the machine. +- It helps the novice programmer. Concepts used in python can be applied to other programming languages. +- It is fun. Some projects like [Raspberry Pi](http://www.raspberrypi.org/faqs#introWhatIs) uses Python as the main language and can be used to create robots, remote controlled cars and video game consoles. +- There are many job opportunities for Python developers in companies like Google, Yahoo!, Disney, Nokia, and IBM. Not to mention a huge amount of startups. +- It have a wide range of open source web application frameworks. + +Python official web site [python website](https://www.python.org) and [python documentation](https://docs.python.org/) documentation to learn more. From e79f994e516900133575899ee863ca5cecbcfb9b Mon Sep 17 00:00:00 2001 From: Ramiro Batista da Luz Date: Tue, 8 Dec 2015 09:41:00 -0200 Subject: [PATCH 07/81] Remove unecessary header. --- docs/ABOUT.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/ABOUT.md b/docs/ABOUT.md index 42bd229dec7..7c595efc9d6 100644 --- a/docs/ABOUT.md +++ b/docs/ABOUT.md @@ -1,5 +1,3 @@ -## About Python - Python is a powerful programming language, it is well known as a "glue" that means: it is used with many other technologies. It is multi platform, runs everywhere. Is friendly and easy to learn. It is licensed as open source, most versions are compatible with the GPL with a few exceptions on old versions. But, one of the most cool things about Python is the community that is very helpful and collaborative. Take a look at: [About python](https://www.python.org/about/). From fe09a72ff4bc9035a39fb41234bc504a6232e240 Mon Sep 17 00:00:00 2001 From: Mark Mandel Date: Sat, 2 Jan 2016 00:59:11 -0600 Subject: [PATCH 08/81] Wording changes in ABOUT.md Corrected typo for 'interactive' and reworded introductory sentences to include input from @kytrinyx about resources available for Python, from https://github.com/exercism/xpython/pull/275. --- docs/ABOUT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ABOUT.md b/docs/ABOUT.md index e7553422e5a..21f99d73446 100644 --- a/docs/ABOUT.md +++ b/docs/ABOUT.md @@ -1,4 +1,4 @@ -Python is an exceptionally strong language for beginners because the code is highly readable and in many cases is as natural as reading a sentence in English. Code can be written and executed from the command line, in an interaction iPython session, or in a [Jupyter](http://jupyter.org) (iPython) notebook. +Python is a strong language for beginners. There are many resources available for programmers of all levels, the code is highly readable, and in many cases phrases are comparable to those in the English language. Code can be written and executed from the command line, in an interactive iPython session, or in a [Jupyter](http://jupyter.org) (iPython) notebook. The most common form of Python is compiled in C. This is often invisible to the beginning programmer, but if there are uses for which exceptionally fast implementation is needed then C extensions can be written to optimize Python execution. From 74c20eb832e6031093003c1066ec0e71846e3f2a Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Mon, 25 Jan 2016 20:47:01 +0100 Subject: [PATCH 09/81] accumulate: fix lambda usage (see #287) --- accumulate/accumulate_test.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/accumulate/accumulate_test.py b/accumulate/accumulate_test.py index e3f592f3287..427e4d16e10 100644 --- a/accumulate/accumulate_test.py +++ b/accumulate/accumulate_test.py @@ -18,9 +18,8 @@ def test_divmod(self): def test_composition(self): inp = [10, 17, 23] - fn1 = lambda x: divmod(x, 7) - fn2 = lambda x: 7 * x[0] + x[1] - self.assertEqual(inp, accumulate(accumulate(inp, fn1), fn2)) + self.assertEqual(inp, accumulate(accumulate(inp, lambda x: divmod(x, 7)), + lambda x: 7 * x[0] + x[1])) def test_capitalize(self): inp = ['hello', 'world'] @@ -30,8 +29,8 @@ def test_capitalize(self): def test_recursive(self): inp = list('abc') out = [['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3']] - fn = lambda x: accumulate(list('123'), lambda y: x + y) - self.assertEqual(out, accumulate(inp, fn)) + self.assertEqual(out, accumulate(inp, lambda x: accumulate(list('123'), + lambda y: x + y))) if __name__ == '__main__': From 12b48b11c2e9abe143a3a1de7ec2c437337e15ff Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Mon, 25 Jan 2016 20:52:17 +0100 Subject: [PATCH 10/81] word-count: fix lambda usage (see #287) --- word-count/example.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/word-count/example.py b/word-count/example.py index 1207bc6822d..2a4be582767 100644 --- a/word-count/example.py +++ b/word-count/example.py @@ -10,6 +10,7 @@ def decode_if_needed(string): def word_count(text): - replace_nonalpha = lambda c: c.lower() if c.isalnum() else ' ' + def replace_nonalpha(char): + return char.lower() if char.isalnum() else ' ' text = ''.join(replace_nonalpha(c) for c in decode_if_needed(text)) return Counter(text.split()) From e61777d6b428cc936cd41ff76f889b2e803323ea Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Mon, 25 Jan 2016 20:54:58 +0100 Subject: [PATCH 11/81] strain: fix lambda usage (see #287) --- strain/strain_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/strain/strain_test.py b/strain/strain_test.py index 81f8548f8b0..313db54ae11 100644 --- a/strain/strain_test.py +++ b/strain/strain_test.py @@ -24,8 +24,7 @@ def test_keep_everything(self): def test_discard_endswith(self): inp = ['dough', 'cash', 'plough', 'though', 'through', 'enough'] out = ['cash'] - fn = lambda x: str.endswith(x, 'ough') - self.assertEqual(out, discard(inp, fn)) + self.assertEqual(out, discard(inp, lambda x: str.endswith(x, 'ough'))) def test_keep_z(self): inp = ['zebra', 'arizona', 'apple', 'google', 'mozilla'] From c31cf1f0fe035c17691ec9291c137d33caa848fd Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Mon, 25 Jan 2016 21:12:24 +0100 Subject: [PATCH 12/81] luhn: fix lambda usage (see #287) --- luhn/example.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/luhn/example.py b/luhn/example.py index 5d061b568d9..06601b359dd 100644 --- a/luhn/example.py +++ b/luhn/example.py @@ -3,8 +3,9 @@ def __init__(self, number): self.number = number def addends(self): + def luhn_transform(n): + return (2 * n - 9) if (n > 4) else (2 * n) old_digits = [int(d) for d in str(self.number)] - luhn_transform = lambda n: (2 * n - 9) if (n > 4) else (2 * n) return [(luhn_transform(n) if (i % 2 == 0) else n) for i, n in enumerate(old_digits, start=len(old_digits) % 2)] From dcc5fe8734d25419b9a9a55a1b7fb690449ee94e Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Mon, 25 Jan 2016 23:26:30 +0100 Subject: [PATCH 13/81] series: fix pep8 compliance (see #287) --- series/example.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/series/example.py b/series/example.py index 5781e1d3621..bd7aedaa9a7 100644 --- a/series/example.py +++ b/series/example.py @@ -1,7 +1,6 @@ def slices(series, length): numbers = [int(digit) for digit in series] if not 1 <= length <= len(numbers): - raise ValueError("Invalid slice length for this series: " - + str(length)) + raise ValueError("Invalid slice length for this series: " + str(length)) return [numbers[i:i + length] for i in range(len(numbers) - length + 1)] From 05b29a6e2491e73e1703d2e5ff39611821f75eb4 Mon Sep 17 00:00:00 2001 From: Peter Tseng Date: Sat, 23 Jan 2016 13:00:58 -0800 Subject: [PATCH 14/81] largest-series-product: Test all combinations of corner cases The original tests had tests for "" and 0. This is when both inputs are the boundary condition. Now we should also test when only one input is at the boundary. So we should test a non-empty string with 0, and "" with a nonzero span. These are consistent with the values defined in https://github.com/exercism/x-common/blob/master/largest-series-product.json --- largest-series-product/largest_series_product_test.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/largest-series-product/largest_series_product_test.py b/largest-series-product/largest_series_product_test.py index bc5b72dc1ac..4545288c149 100644 --- a/largest-series-product/largest_series_product_test.py +++ b/largest-series-product/largest_series_product_test.py @@ -34,13 +34,20 @@ def test_big_number(self): series = "52677741234314237566414902593461595376319419139427" self.assertEqual(28350, largest_product(series, 6)) - def test_identity(self): + def test_identity_with_empty_string(self): self.assertEqual(1, largest_product("", 0)) + def test_identity_with_nonempty_string(self): + self.assertEqual(1, largest_product("123", 0)) + def test_slices_bigger_than_number(self): with self.assertRaises(ValueError): largest_product("012", 4) + def test_nonzero_slice_size_and_empty_string(self): + with self.assertRaises(ValueError): + largest_product("", 1) + if __name__ == '__main__': unittest.main() From 46f1a4d8df5d66a3dd907116c20ba66aa2a4edad Mon Sep 17 00:00:00 2001 From: Peter Tseng Date: Sat, 23 Jan 2016 13:01:58 -0800 Subject: [PATCH 15/81] largest-series-product: Add cases where all spans contain a 0 In these cases, the result should be 0 as well. This guards against solutions that assume the minimum is 1. --- largest-series-product/largest_series_product_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/largest-series-product/largest_series_product_test.py b/largest-series-product/largest_series_product_test.py index 4545288c149..da891a5bff8 100644 --- a/largest-series-product/largest_series_product_test.py +++ b/largest-series-product/largest_series_product_test.py @@ -34,6 +34,12 @@ def test_big_number(self): series = "52677741234314237566414902593461595376319419139427" self.assertEqual(28350, largest_product(series, 6)) + def test_string_with_all_zeroes(self): + self.assertEqual(0, largest_product("0000", 2)) + + def test_string_where_all_spans_contain_zero(self): + self.assertEqual(0, largest_product("99099", 3)) + def test_identity_with_empty_string(self): self.assertEqual(1, largest_product("", 0)) From b9dfe291845a31301029d947b3cf3a2ffc85b0b6 Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 26 Jan 2016 17:24:22 +0100 Subject: [PATCH 16/81] Moved the exercises to the folder exercises/. --- {accumulate => exercises/accumulate}/accumulate_test.py | 0 {accumulate => exercises/accumulate}/example.py | 0 {allergies => exercises/allergies}/allergies_test.py | 0 {allergies => exercises/allergies}/example.py | 0 {anagram => exercises/anagram}/anagram_test.py | 0 {anagram => exercises/anagram}/example.py | 0 {atbash-cipher => exercises/atbash-cipher}/atbash_cipher_test.py | 0 {atbash-cipher => exercises/atbash-cipher}/example.py | 0 {beer-song => exercises/beer-song}/beer_song_test.py | 0 {beer-song => exercises/beer-song}/example.py | 0 {binary => exercises/binary}/binary_test.py | 0 {binary => exercises/binary}/example.py | 0 {bob => exercises/bob}/bob.py | 0 {bob => exercises/bob}/bob_test.py | 0 {bob => exercises/bob}/example.py | 0 {bracket-push => exercises/bracket-push}/bracket_push_test.py | 0 {bracket-push => exercises/bracket-push}/example.py | 0 {crypto-square => exercises/crypto-square}/crypto_square_test.py | 0 {crypto-square => exercises/crypto-square}/example.py | 0 .../difference-of-squares}/difference_of_squares_test.py | 0 .../difference-of-squares}/example.py | 0 {etl => exercises/etl}/etl_test.py | 0 {etl => exercises/etl}/example.py | 0 {gigasecond => exercises/gigasecond}/example.py | 0 {gigasecond => exercises/gigasecond}/gigasecond_test.py | 0 {grade-school => exercises/grade-school}/example.py | 0 {grade-school => exercises/grade-school}/grade_school_test.py | 0 {grains => exercises/grains}/example.py | 0 {grains => exercises/grains}/grains_test.py | 0 {hamming => exercises/hamming}/example.py | 0 {hamming => exercises/hamming}/hamming_test.py | 0 {hello-world => exercises/hello-world}/example.py | 0 {hello-world => exercises/hello-world}/hello_world.py | 0 {hello-world => exercises/hello-world}/hello_world_test.py | 0 {hexadecimal => exercises/hexadecimal}/example.py | 0 {hexadecimal => exercises/hexadecimal}/hexadecimal_test.py | 0 {house => exercises/house}/example.py | 0 {house => exercises/house}/house_test.py | 0 {kindergarten-garden => exercises/kindergarten-garden}/example.py | 0 .../kindergarten-garden}/kindergarten_garden_test.py | 0 .../largest-series-product}/example.py | 0 .../largest-series-product}/largest_series_product_test.py | 0 {leap => exercises/leap}/example.py | 0 {leap => exercises/leap}/leap_test.py | 0 {luhn => exercises/luhn}/example.py | 0 {luhn => exercises/luhn}/luhn_test.py | 0 {matrix => exercises/matrix}/example.py | 0 {matrix => exercises/matrix}/matrix_test.py | 0 {meetup => exercises/meetup}/example.py | 0 {meetup => exercises/meetup}/meetup_test.py | 0 {minesweeper => exercises/minesweeper}/example.py | 0 {minesweeper => exercises/minesweeper}/minesweeper_test.py | 0 {nth-prime => exercises/nth-prime}/example.py | 0 {nth-prime => exercises/nth-prime}/nth_prime_test.py | 0 {nucleotide-count => exercises/nucleotide-count}/example.py | 0 .../nucleotide-count}/nucleotide_count_test.py | 0 {ocr-numbers => exercises/ocr-numbers}/example.py | 0 {ocr-numbers => exercises/ocr-numbers}/ocr_test.py | 0 {octal => exercises/octal}/example.py | 0 {octal => exercises/octal}/octal_test.py | 0 {palindrome-products => exercises/palindrome-products}/example.py | 0 .../palindrome-products}/palindrome_products_test.py | 0 {pangram => exercises/pangram}/example.py | 0 {pangram => exercises/pangram}/pangram_test.py | 0 {pascals-triangle => exercises/pascals-triangle}/example.py | 0 .../pascals-triangle}/pascals_triangle_test.py | 0 {phone-number => exercises/phone-number}/example.py | 0 {phone-number => exercises/phone-number}/phone_number_test.py | 0 {pig-latin => exercises/pig-latin}/example.py | 0 {pig-latin => exercises/pig-latin}/pig_latin_test.py | 0 {point-mutations => exercises/point-mutations}/example.py | 0 .../point-mutations}/point_mutations_test.py | 0 {poker => exercises/poker}/example.py | 0 {poker => exercises/poker}/poker_test.py | 0 {prime-factors => exercises/prime-factors}/example.py | 0 {prime-factors => exercises/prime-factors}/prime_factors_test.py | 0 {proverb => exercises/proverb}/example.py | 0 {proverb => exercises/proverb}/proverb_test.py | 0 {pythagorean-triplet => exercises/pythagorean-triplet}/example.py | 0 .../pythagorean-triplet}/pythagorean_triplet_test.py | 0 {queen-attack => exercises/queen-attack}/example.py | 0 {queen-attack => exercises/queen-attack}/queen_attack_test.py | 0 {raindrops => exercises/raindrops}/example.py | 0 {raindrops => exercises/raindrops}/raindrops_test.py | 0 {rectangles => exercises/rectangles}/example.py | 0 {rectangles => exercises/rectangles}/rectangles_count_test.py | 0 {rna-transcription => exercises/rna-transcription}/example.py | 0 .../rna-transcription}/rna_transcription_test.py | 0 {robot-name => exercises/robot-name}/example.py | 0 {robot-name => exercises/robot-name}/robot_name_test.py | 0 {robot-simulator => exercises/robot-simulator}/example.py | 0 .../robot-simulator}/robot_simulator_test.py | 0 {roman-numerals => exercises/roman-numerals}/example.py | 0 .../roman-numerals}/roman_numerals_test.py | 0 {run-length-encoding => exercises/run-length-encoding}/example.py | 0 .../run-length-encoding}/run_length_test.py | 0 {saddle-points => exercises/saddle-points}/example.py | 0 {saddle-points => exercises/saddle-points}/saddle_points_test.py | 0 {say => exercises/say}/example.py | 0 {say => exercises/say}/say_test.py | 0 {scrabble-score => exercises/scrabble-score}/example.py | 0 .../scrabble-score}/scrabble_score_test.py | 0 {secret-handshake => exercises/secret-handshake}/example.py | 0 .../secret-handshake}/handshake_test.py | 0 {series => exercises/series}/example.py | 0 {series => exercises/series}/series_test.py | 0 {sieve => exercises/sieve}/example.py | 0 {sieve => exercises/sieve}/sieve_test.py | 0 {simple-cipher => exercises/simple-cipher}/example.py | 0 {simple-cipher => exercises/simple-cipher}/simple_cipher_test.py | 0 {space-age => exercises/space-age}/example.py | 0 {space-age => exercises/space-age}/space_age_test.py | 0 {strain => exercises/strain}/example.py | 0 {strain => exercises/strain}/strain_test.py | 0 {sublist => exercises/sublist}/example.py | 0 {sublist => exercises/sublist}/sublist_test.py | 0 {sum-of-multiples => exercises/sum-of-multiples}/example.py | 0 .../sum-of-multiples}/sum_of_multiples_test.py | 0 {triangle => exercises/triangle}/example.py | 0 {triangle => exercises/triangle}/triangle_test.py | 0 {trinary => exercises/trinary}/example.py | 0 {trinary => exercises/trinary}/trinary_test.py | 0 {twelve-days => exercises/twelve-days}/example.py | 0 {twelve-days => exercises/twelve-days}/twelve_days_test.py | 0 {word-count => exercises/word-count}/example.py | 0 {word-count => exercises/word-count}/word_count_test.py | 0 {wordy => exercises/wordy}/example.py | 0 {wordy => exercises/wordy}/wordy_test.py | 0 {zebra-puzzle => exercises/zebra-puzzle}/example.py | 0 {zebra-puzzle => exercises/zebra-puzzle}/zebra_puzzle_test.py | 0 130 files changed, 0 insertions(+), 0 deletions(-) rename {accumulate => exercises/accumulate}/accumulate_test.py (100%) rename {accumulate => exercises/accumulate}/example.py (100%) rename {allergies => exercises/allergies}/allergies_test.py (100%) rename {allergies => exercises/allergies}/example.py (100%) rename {anagram => exercises/anagram}/anagram_test.py (100%) rename {anagram => exercises/anagram}/example.py (100%) rename {atbash-cipher => exercises/atbash-cipher}/atbash_cipher_test.py (100%) rename {atbash-cipher => exercises/atbash-cipher}/example.py (100%) rename {beer-song => exercises/beer-song}/beer_song_test.py (100%) rename {beer-song => exercises/beer-song}/example.py (100%) rename {binary => exercises/binary}/binary_test.py (100%) rename {binary => exercises/binary}/example.py (100%) rename {bob => exercises/bob}/bob.py (100%) rename {bob => exercises/bob}/bob_test.py (100%) rename {bob => exercises/bob}/example.py (100%) rename {bracket-push => exercises/bracket-push}/bracket_push_test.py (100%) rename {bracket-push => exercises/bracket-push}/example.py (100%) rename {crypto-square => exercises/crypto-square}/crypto_square_test.py (100%) rename {crypto-square => exercises/crypto-square}/example.py (100%) rename {difference-of-squares => exercises/difference-of-squares}/difference_of_squares_test.py (100%) rename {difference-of-squares => exercises/difference-of-squares}/example.py (100%) rename {etl => exercises/etl}/etl_test.py (100%) rename {etl => exercises/etl}/example.py (100%) rename {gigasecond => exercises/gigasecond}/example.py (100%) rename {gigasecond => exercises/gigasecond}/gigasecond_test.py (100%) rename {grade-school => exercises/grade-school}/example.py (100%) rename {grade-school => exercises/grade-school}/grade_school_test.py (100%) rename {grains => exercises/grains}/example.py (100%) rename {grains => exercises/grains}/grains_test.py (100%) rename {hamming => exercises/hamming}/example.py (100%) rename {hamming => exercises/hamming}/hamming_test.py (100%) rename {hello-world => exercises/hello-world}/example.py (100%) rename {hello-world => exercises/hello-world}/hello_world.py (100%) rename {hello-world => exercises/hello-world}/hello_world_test.py (100%) rename {hexadecimal => exercises/hexadecimal}/example.py (100%) rename {hexadecimal => exercises/hexadecimal}/hexadecimal_test.py (100%) rename {house => exercises/house}/example.py (100%) rename {house => exercises/house}/house_test.py (100%) rename {kindergarten-garden => exercises/kindergarten-garden}/example.py (100%) rename {kindergarten-garden => exercises/kindergarten-garden}/kindergarten_garden_test.py (100%) rename {largest-series-product => exercises/largest-series-product}/example.py (100%) rename {largest-series-product => exercises/largest-series-product}/largest_series_product_test.py (100%) rename {leap => exercises/leap}/example.py (100%) rename {leap => exercises/leap}/leap_test.py (100%) rename {luhn => exercises/luhn}/example.py (100%) rename {luhn => exercises/luhn}/luhn_test.py (100%) rename {matrix => exercises/matrix}/example.py (100%) rename {matrix => exercises/matrix}/matrix_test.py (100%) rename {meetup => exercises/meetup}/example.py (100%) rename {meetup => exercises/meetup}/meetup_test.py (100%) rename {minesweeper => exercises/minesweeper}/example.py (100%) rename {minesweeper => exercises/minesweeper}/minesweeper_test.py (100%) rename {nth-prime => exercises/nth-prime}/example.py (100%) rename {nth-prime => exercises/nth-prime}/nth_prime_test.py (100%) rename {nucleotide-count => exercises/nucleotide-count}/example.py (100%) rename {nucleotide-count => exercises/nucleotide-count}/nucleotide_count_test.py (100%) rename {ocr-numbers => exercises/ocr-numbers}/example.py (100%) rename {ocr-numbers => exercises/ocr-numbers}/ocr_test.py (100%) rename {octal => exercises/octal}/example.py (100%) rename {octal => exercises/octal}/octal_test.py (100%) rename {palindrome-products => exercises/palindrome-products}/example.py (100%) rename {palindrome-products => exercises/palindrome-products}/palindrome_products_test.py (100%) rename {pangram => exercises/pangram}/example.py (100%) rename {pangram => exercises/pangram}/pangram_test.py (100%) rename {pascals-triangle => exercises/pascals-triangle}/example.py (100%) rename {pascals-triangle => exercises/pascals-triangle}/pascals_triangle_test.py (100%) rename {phone-number => exercises/phone-number}/example.py (100%) rename {phone-number => exercises/phone-number}/phone_number_test.py (100%) rename {pig-latin => exercises/pig-latin}/example.py (100%) rename {pig-latin => exercises/pig-latin}/pig_latin_test.py (100%) rename {point-mutations => exercises/point-mutations}/example.py (100%) rename {point-mutations => exercises/point-mutations}/point_mutations_test.py (100%) rename {poker => exercises/poker}/example.py (100%) rename {poker => exercises/poker}/poker_test.py (100%) rename {prime-factors => exercises/prime-factors}/example.py (100%) rename {prime-factors => exercises/prime-factors}/prime_factors_test.py (100%) rename {proverb => exercises/proverb}/example.py (100%) rename {proverb => exercises/proverb}/proverb_test.py (100%) rename {pythagorean-triplet => exercises/pythagorean-triplet}/example.py (100%) rename {pythagorean-triplet => exercises/pythagorean-triplet}/pythagorean_triplet_test.py (100%) rename {queen-attack => exercises/queen-attack}/example.py (100%) rename {queen-attack => exercises/queen-attack}/queen_attack_test.py (100%) rename {raindrops => exercises/raindrops}/example.py (100%) rename {raindrops => exercises/raindrops}/raindrops_test.py (100%) rename {rectangles => exercises/rectangles}/example.py (100%) rename {rectangles => exercises/rectangles}/rectangles_count_test.py (100%) rename {rna-transcription => exercises/rna-transcription}/example.py (100%) rename {rna-transcription => exercises/rna-transcription}/rna_transcription_test.py (100%) rename {robot-name => exercises/robot-name}/example.py (100%) rename {robot-name => exercises/robot-name}/robot_name_test.py (100%) rename {robot-simulator => exercises/robot-simulator}/example.py (100%) rename {robot-simulator => exercises/robot-simulator}/robot_simulator_test.py (100%) rename {roman-numerals => exercises/roman-numerals}/example.py (100%) rename {roman-numerals => exercises/roman-numerals}/roman_numerals_test.py (100%) rename {run-length-encoding => exercises/run-length-encoding}/example.py (100%) rename {run-length-encoding => exercises/run-length-encoding}/run_length_test.py (100%) rename {saddle-points => exercises/saddle-points}/example.py (100%) rename {saddle-points => exercises/saddle-points}/saddle_points_test.py (100%) rename {say => exercises/say}/example.py (100%) rename {say => exercises/say}/say_test.py (100%) rename {scrabble-score => exercises/scrabble-score}/example.py (100%) rename {scrabble-score => exercises/scrabble-score}/scrabble_score_test.py (100%) rename {secret-handshake => exercises/secret-handshake}/example.py (100%) rename {secret-handshake => exercises/secret-handshake}/handshake_test.py (100%) rename {series => exercises/series}/example.py (100%) rename {series => exercises/series}/series_test.py (100%) rename {sieve => exercises/sieve}/example.py (100%) rename {sieve => exercises/sieve}/sieve_test.py (100%) rename {simple-cipher => exercises/simple-cipher}/example.py (100%) rename {simple-cipher => exercises/simple-cipher}/simple_cipher_test.py (100%) rename {space-age => exercises/space-age}/example.py (100%) rename {space-age => exercises/space-age}/space_age_test.py (100%) rename {strain => exercises/strain}/example.py (100%) rename {strain => exercises/strain}/strain_test.py (100%) rename {sublist => exercises/sublist}/example.py (100%) rename {sublist => exercises/sublist}/sublist_test.py (100%) rename {sum-of-multiples => exercises/sum-of-multiples}/example.py (100%) rename {sum-of-multiples => exercises/sum-of-multiples}/sum_of_multiples_test.py (100%) rename {triangle => exercises/triangle}/example.py (100%) rename {triangle => exercises/triangle}/triangle_test.py (100%) rename {trinary => exercises/trinary}/example.py (100%) rename {trinary => exercises/trinary}/trinary_test.py (100%) rename {twelve-days => exercises/twelve-days}/example.py (100%) rename {twelve-days => exercises/twelve-days}/twelve_days_test.py (100%) rename {word-count => exercises/word-count}/example.py (100%) rename {word-count => exercises/word-count}/word_count_test.py (100%) rename {wordy => exercises/wordy}/example.py (100%) rename {wordy => exercises/wordy}/wordy_test.py (100%) rename {zebra-puzzle => exercises/zebra-puzzle}/example.py (100%) rename {zebra-puzzle => exercises/zebra-puzzle}/zebra_puzzle_test.py (100%) diff --git a/accumulate/accumulate_test.py b/exercises/accumulate/accumulate_test.py similarity index 100% rename from accumulate/accumulate_test.py rename to exercises/accumulate/accumulate_test.py diff --git a/accumulate/example.py b/exercises/accumulate/example.py similarity index 100% rename from accumulate/example.py rename to exercises/accumulate/example.py diff --git a/allergies/allergies_test.py b/exercises/allergies/allergies_test.py similarity index 100% rename from allergies/allergies_test.py rename to exercises/allergies/allergies_test.py diff --git a/allergies/example.py b/exercises/allergies/example.py similarity index 100% rename from allergies/example.py rename to exercises/allergies/example.py diff --git a/anagram/anagram_test.py b/exercises/anagram/anagram_test.py similarity index 100% rename from anagram/anagram_test.py rename to exercises/anagram/anagram_test.py diff --git a/anagram/example.py b/exercises/anagram/example.py similarity index 100% rename from anagram/example.py rename to exercises/anagram/example.py diff --git a/atbash-cipher/atbash_cipher_test.py b/exercises/atbash-cipher/atbash_cipher_test.py similarity index 100% rename from atbash-cipher/atbash_cipher_test.py rename to exercises/atbash-cipher/atbash_cipher_test.py diff --git a/atbash-cipher/example.py b/exercises/atbash-cipher/example.py similarity index 100% rename from atbash-cipher/example.py rename to exercises/atbash-cipher/example.py diff --git a/beer-song/beer_song_test.py b/exercises/beer-song/beer_song_test.py similarity index 100% rename from beer-song/beer_song_test.py rename to exercises/beer-song/beer_song_test.py diff --git a/beer-song/example.py b/exercises/beer-song/example.py similarity index 100% rename from beer-song/example.py rename to exercises/beer-song/example.py diff --git a/binary/binary_test.py b/exercises/binary/binary_test.py similarity index 100% rename from binary/binary_test.py rename to exercises/binary/binary_test.py diff --git a/binary/example.py b/exercises/binary/example.py similarity index 100% rename from binary/example.py rename to exercises/binary/example.py diff --git a/bob/bob.py b/exercises/bob/bob.py similarity index 100% rename from bob/bob.py rename to exercises/bob/bob.py diff --git a/bob/bob_test.py b/exercises/bob/bob_test.py similarity index 100% rename from bob/bob_test.py rename to exercises/bob/bob_test.py diff --git a/bob/example.py b/exercises/bob/example.py similarity index 100% rename from bob/example.py rename to exercises/bob/example.py diff --git a/bracket-push/bracket_push_test.py b/exercises/bracket-push/bracket_push_test.py similarity index 100% rename from bracket-push/bracket_push_test.py rename to exercises/bracket-push/bracket_push_test.py diff --git a/bracket-push/example.py b/exercises/bracket-push/example.py similarity index 100% rename from bracket-push/example.py rename to exercises/bracket-push/example.py diff --git a/crypto-square/crypto_square_test.py b/exercises/crypto-square/crypto_square_test.py similarity index 100% rename from crypto-square/crypto_square_test.py rename to exercises/crypto-square/crypto_square_test.py diff --git a/crypto-square/example.py b/exercises/crypto-square/example.py similarity index 100% rename from crypto-square/example.py rename to exercises/crypto-square/example.py diff --git a/difference-of-squares/difference_of_squares_test.py b/exercises/difference-of-squares/difference_of_squares_test.py similarity index 100% rename from difference-of-squares/difference_of_squares_test.py rename to exercises/difference-of-squares/difference_of_squares_test.py diff --git a/difference-of-squares/example.py b/exercises/difference-of-squares/example.py similarity index 100% rename from difference-of-squares/example.py rename to exercises/difference-of-squares/example.py diff --git a/etl/etl_test.py b/exercises/etl/etl_test.py similarity index 100% rename from etl/etl_test.py rename to exercises/etl/etl_test.py diff --git a/etl/example.py b/exercises/etl/example.py similarity index 100% rename from etl/example.py rename to exercises/etl/example.py diff --git a/gigasecond/example.py b/exercises/gigasecond/example.py similarity index 100% rename from gigasecond/example.py rename to exercises/gigasecond/example.py diff --git a/gigasecond/gigasecond_test.py b/exercises/gigasecond/gigasecond_test.py similarity index 100% rename from gigasecond/gigasecond_test.py rename to exercises/gigasecond/gigasecond_test.py diff --git a/grade-school/example.py b/exercises/grade-school/example.py similarity index 100% rename from grade-school/example.py rename to exercises/grade-school/example.py diff --git a/grade-school/grade_school_test.py b/exercises/grade-school/grade_school_test.py similarity index 100% rename from grade-school/grade_school_test.py rename to exercises/grade-school/grade_school_test.py diff --git a/grains/example.py b/exercises/grains/example.py similarity index 100% rename from grains/example.py rename to exercises/grains/example.py diff --git a/grains/grains_test.py b/exercises/grains/grains_test.py similarity index 100% rename from grains/grains_test.py rename to exercises/grains/grains_test.py diff --git a/hamming/example.py b/exercises/hamming/example.py similarity index 100% rename from hamming/example.py rename to exercises/hamming/example.py diff --git a/hamming/hamming_test.py b/exercises/hamming/hamming_test.py similarity index 100% rename from hamming/hamming_test.py rename to exercises/hamming/hamming_test.py diff --git a/hello-world/example.py b/exercises/hello-world/example.py similarity index 100% rename from hello-world/example.py rename to exercises/hello-world/example.py diff --git a/hello-world/hello_world.py b/exercises/hello-world/hello_world.py similarity index 100% rename from hello-world/hello_world.py rename to exercises/hello-world/hello_world.py diff --git a/hello-world/hello_world_test.py b/exercises/hello-world/hello_world_test.py similarity index 100% rename from hello-world/hello_world_test.py rename to exercises/hello-world/hello_world_test.py diff --git a/hexadecimal/example.py b/exercises/hexadecimal/example.py similarity index 100% rename from hexadecimal/example.py rename to exercises/hexadecimal/example.py diff --git a/hexadecimal/hexadecimal_test.py b/exercises/hexadecimal/hexadecimal_test.py similarity index 100% rename from hexadecimal/hexadecimal_test.py rename to exercises/hexadecimal/hexadecimal_test.py diff --git a/house/example.py b/exercises/house/example.py similarity index 100% rename from house/example.py rename to exercises/house/example.py diff --git a/house/house_test.py b/exercises/house/house_test.py similarity index 100% rename from house/house_test.py rename to exercises/house/house_test.py diff --git a/kindergarten-garden/example.py b/exercises/kindergarten-garden/example.py similarity index 100% rename from kindergarten-garden/example.py rename to exercises/kindergarten-garden/example.py diff --git a/kindergarten-garden/kindergarten_garden_test.py b/exercises/kindergarten-garden/kindergarten_garden_test.py similarity index 100% rename from kindergarten-garden/kindergarten_garden_test.py rename to exercises/kindergarten-garden/kindergarten_garden_test.py diff --git a/largest-series-product/example.py b/exercises/largest-series-product/example.py similarity index 100% rename from largest-series-product/example.py rename to exercises/largest-series-product/example.py diff --git a/largest-series-product/largest_series_product_test.py b/exercises/largest-series-product/largest_series_product_test.py similarity index 100% rename from largest-series-product/largest_series_product_test.py rename to exercises/largest-series-product/largest_series_product_test.py diff --git a/leap/example.py b/exercises/leap/example.py similarity index 100% rename from leap/example.py rename to exercises/leap/example.py diff --git a/leap/leap_test.py b/exercises/leap/leap_test.py similarity index 100% rename from leap/leap_test.py rename to exercises/leap/leap_test.py diff --git a/luhn/example.py b/exercises/luhn/example.py similarity index 100% rename from luhn/example.py rename to exercises/luhn/example.py diff --git a/luhn/luhn_test.py b/exercises/luhn/luhn_test.py similarity index 100% rename from luhn/luhn_test.py rename to exercises/luhn/luhn_test.py diff --git a/matrix/example.py b/exercises/matrix/example.py similarity index 100% rename from matrix/example.py rename to exercises/matrix/example.py diff --git a/matrix/matrix_test.py b/exercises/matrix/matrix_test.py similarity index 100% rename from matrix/matrix_test.py rename to exercises/matrix/matrix_test.py diff --git a/meetup/example.py b/exercises/meetup/example.py similarity index 100% rename from meetup/example.py rename to exercises/meetup/example.py diff --git a/meetup/meetup_test.py b/exercises/meetup/meetup_test.py similarity index 100% rename from meetup/meetup_test.py rename to exercises/meetup/meetup_test.py diff --git a/minesweeper/example.py b/exercises/minesweeper/example.py similarity index 100% rename from minesweeper/example.py rename to exercises/minesweeper/example.py diff --git a/minesweeper/minesweeper_test.py b/exercises/minesweeper/minesweeper_test.py similarity index 100% rename from minesweeper/minesweeper_test.py rename to exercises/minesweeper/minesweeper_test.py diff --git a/nth-prime/example.py b/exercises/nth-prime/example.py similarity index 100% rename from nth-prime/example.py rename to exercises/nth-prime/example.py diff --git a/nth-prime/nth_prime_test.py b/exercises/nth-prime/nth_prime_test.py similarity index 100% rename from nth-prime/nth_prime_test.py rename to exercises/nth-prime/nth_prime_test.py diff --git a/nucleotide-count/example.py b/exercises/nucleotide-count/example.py similarity index 100% rename from nucleotide-count/example.py rename to exercises/nucleotide-count/example.py diff --git a/nucleotide-count/nucleotide_count_test.py b/exercises/nucleotide-count/nucleotide_count_test.py similarity index 100% rename from nucleotide-count/nucleotide_count_test.py rename to exercises/nucleotide-count/nucleotide_count_test.py diff --git a/ocr-numbers/example.py b/exercises/ocr-numbers/example.py similarity index 100% rename from ocr-numbers/example.py rename to exercises/ocr-numbers/example.py diff --git a/ocr-numbers/ocr_test.py b/exercises/ocr-numbers/ocr_test.py similarity index 100% rename from ocr-numbers/ocr_test.py rename to exercises/ocr-numbers/ocr_test.py diff --git a/octal/example.py b/exercises/octal/example.py similarity index 100% rename from octal/example.py rename to exercises/octal/example.py diff --git a/octal/octal_test.py b/exercises/octal/octal_test.py similarity index 100% rename from octal/octal_test.py rename to exercises/octal/octal_test.py diff --git a/palindrome-products/example.py b/exercises/palindrome-products/example.py similarity index 100% rename from palindrome-products/example.py rename to exercises/palindrome-products/example.py diff --git a/palindrome-products/palindrome_products_test.py b/exercises/palindrome-products/palindrome_products_test.py similarity index 100% rename from palindrome-products/palindrome_products_test.py rename to exercises/palindrome-products/palindrome_products_test.py diff --git a/pangram/example.py b/exercises/pangram/example.py similarity index 100% rename from pangram/example.py rename to exercises/pangram/example.py diff --git a/pangram/pangram_test.py b/exercises/pangram/pangram_test.py similarity index 100% rename from pangram/pangram_test.py rename to exercises/pangram/pangram_test.py diff --git a/pascals-triangle/example.py b/exercises/pascals-triangle/example.py similarity index 100% rename from pascals-triangle/example.py rename to exercises/pascals-triangle/example.py diff --git a/pascals-triangle/pascals_triangle_test.py b/exercises/pascals-triangle/pascals_triangle_test.py similarity index 100% rename from pascals-triangle/pascals_triangle_test.py rename to exercises/pascals-triangle/pascals_triangle_test.py diff --git a/phone-number/example.py b/exercises/phone-number/example.py similarity index 100% rename from phone-number/example.py rename to exercises/phone-number/example.py diff --git a/phone-number/phone_number_test.py b/exercises/phone-number/phone_number_test.py similarity index 100% rename from phone-number/phone_number_test.py rename to exercises/phone-number/phone_number_test.py diff --git a/pig-latin/example.py b/exercises/pig-latin/example.py similarity index 100% rename from pig-latin/example.py rename to exercises/pig-latin/example.py diff --git a/pig-latin/pig_latin_test.py b/exercises/pig-latin/pig_latin_test.py similarity index 100% rename from pig-latin/pig_latin_test.py rename to exercises/pig-latin/pig_latin_test.py diff --git a/point-mutations/example.py b/exercises/point-mutations/example.py similarity index 100% rename from point-mutations/example.py rename to exercises/point-mutations/example.py diff --git a/point-mutations/point_mutations_test.py b/exercises/point-mutations/point_mutations_test.py similarity index 100% rename from point-mutations/point_mutations_test.py rename to exercises/point-mutations/point_mutations_test.py diff --git a/poker/example.py b/exercises/poker/example.py similarity index 100% rename from poker/example.py rename to exercises/poker/example.py diff --git a/poker/poker_test.py b/exercises/poker/poker_test.py similarity index 100% rename from poker/poker_test.py rename to exercises/poker/poker_test.py diff --git a/prime-factors/example.py b/exercises/prime-factors/example.py similarity index 100% rename from prime-factors/example.py rename to exercises/prime-factors/example.py diff --git a/prime-factors/prime_factors_test.py b/exercises/prime-factors/prime_factors_test.py similarity index 100% rename from prime-factors/prime_factors_test.py rename to exercises/prime-factors/prime_factors_test.py diff --git a/proverb/example.py b/exercises/proverb/example.py similarity index 100% rename from proverb/example.py rename to exercises/proverb/example.py diff --git a/proverb/proverb_test.py b/exercises/proverb/proverb_test.py similarity index 100% rename from proverb/proverb_test.py rename to exercises/proverb/proverb_test.py diff --git a/pythagorean-triplet/example.py b/exercises/pythagorean-triplet/example.py similarity index 100% rename from pythagorean-triplet/example.py rename to exercises/pythagorean-triplet/example.py diff --git a/pythagorean-triplet/pythagorean_triplet_test.py b/exercises/pythagorean-triplet/pythagorean_triplet_test.py similarity index 100% rename from pythagorean-triplet/pythagorean_triplet_test.py rename to exercises/pythagorean-triplet/pythagorean_triplet_test.py diff --git a/queen-attack/example.py b/exercises/queen-attack/example.py similarity index 100% rename from queen-attack/example.py rename to exercises/queen-attack/example.py diff --git a/queen-attack/queen_attack_test.py b/exercises/queen-attack/queen_attack_test.py similarity index 100% rename from queen-attack/queen_attack_test.py rename to exercises/queen-attack/queen_attack_test.py diff --git a/raindrops/example.py b/exercises/raindrops/example.py similarity index 100% rename from raindrops/example.py rename to exercises/raindrops/example.py diff --git a/raindrops/raindrops_test.py b/exercises/raindrops/raindrops_test.py similarity index 100% rename from raindrops/raindrops_test.py rename to exercises/raindrops/raindrops_test.py diff --git a/rectangles/example.py b/exercises/rectangles/example.py similarity index 100% rename from rectangles/example.py rename to exercises/rectangles/example.py diff --git a/rectangles/rectangles_count_test.py b/exercises/rectangles/rectangles_count_test.py similarity index 100% rename from rectangles/rectangles_count_test.py rename to exercises/rectangles/rectangles_count_test.py diff --git a/rna-transcription/example.py b/exercises/rna-transcription/example.py similarity index 100% rename from rna-transcription/example.py rename to exercises/rna-transcription/example.py diff --git a/rna-transcription/rna_transcription_test.py b/exercises/rna-transcription/rna_transcription_test.py similarity index 100% rename from rna-transcription/rna_transcription_test.py rename to exercises/rna-transcription/rna_transcription_test.py diff --git a/robot-name/example.py b/exercises/robot-name/example.py similarity index 100% rename from robot-name/example.py rename to exercises/robot-name/example.py diff --git a/robot-name/robot_name_test.py b/exercises/robot-name/robot_name_test.py similarity index 100% rename from robot-name/robot_name_test.py rename to exercises/robot-name/robot_name_test.py diff --git a/robot-simulator/example.py b/exercises/robot-simulator/example.py similarity index 100% rename from robot-simulator/example.py rename to exercises/robot-simulator/example.py diff --git a/robot-simulator/robot_simulator_test.py b/exercises/robot-simulator/robot_simulator_test.py similarity index 100% rename from robot-simulator/robot_simulator_test.py rename to exercises/robot-simulator/robot_simulator_test.py diff --git a/roman-numerals/example.py b/exercises/roman-numerals/example.py similarity index 100% rename from roman-numerals/example.py rename to exercises/roman-numerals/example.py diff --git a/roman-numerals/roman_numerals_test.py b/exercises/roman-numerals/roman_numerals_test.py similarity index 100% rename from roman-numerals/roman_numerals_test.py rename to exercises/roman-numerals/roman_numerals_test.py diff --git a/run-length-encoding/example.py b/exercises/run-length-encoding/example.py similarity index 100% rename from run-length-encoding/example.py rename to exercises/run-length-encoding/example.py diff --git a/run-length-encoding/run_length_test.py b/exercises/run-length-encoding/run_length_test.py similarity index 100% rename from run-length-encoding/run_length_test.py rename to exercises/run-length-encoding/run_length_test.py diff --git a/saddle-points/example.py b/exercises/saddle-points/example.py similarity index 100% rename from saddle-points/example.py rename to exercises/saddle-points/example.py diff --git a/saddle-points/saddle_points_test.py b/exercises/saddle-points/saddle_points_test.py similarity index 100% rename from saddle-points/saddle_points_test.py rename to exercises/saddle-points/saddle_points_test.py diff --git a/say/example.py b/exercises/say/example.py similarity index 100% rename from say/example.py rename to exercises/say/example.py diff --git a/say/say_test.py b/exercises/say/say_test.py similarity index 100% rename from say/say_test.py rename to exercises/say/say_test.py diff --git a/scrabble-score/example.py b/exercises/scrabble-score/example.py similarity index 100% rename from scrabble-score/example.py rename to exercises/scrabble-score/example.py diff --git a/scrabble-score/scrabble_score_test.py b/exercises/scrabble-score/scrabble_score_test.py similarity index 100% rename from scrabble-score/scrabble_score_test.py rename to exercises/scrabble-score/scrabble_score_test.py diff --git a/secret-handshake/example.py b/exercises/secret-handshake/example.py similarity index 100% rename from secret-handshake/example.py rename to exercises/secret-handshake/example.py diff --git a/secret-handshake/handshake_test.py b/exercises/secret-handshake/handshake_test.py similarity index 100% rename from secret-handshake/handshake_test.py rename to exercises/secret-handshake/handshake_test.py diff --git a/series/example.py b/exercises/series/example.py similarity index 100% rename from series/example.py rename to exercises/series/example.py diff --git a/series/series_test.py b/exercises/series/series_test.py similarity index 100% rename from series/series_test.py rename to exercises/series/series_test.py diff --git a/sieve/example.py b/exercises/sieve/example.py similarity index 100% rename from sieve/example.py rename to exercises/sieve/example.py diff --git a/sieve/sieve_test.py b/exercises/sieve/sieve_test.py similarity index 100% rename from sieve/sieve_test.py rename to exercises/sieve/sieve_test.py diff --git a/simple-cipher/example.py b/exercises/simple-cipher/example.py similarity index 100% rename from simple-cipher/example.py rename to exercises/simple-cipher/example.py diff --git a/simple-cipher/simple_cipher_test.py b/exercises/simple-cipher/simple_cipher_test.py similarity index 100% rename from simple-cipher/simple_cipher_test.py rename to exercises/simple-cipher/simple_cipher_test.py diff --git a/space-age/example.py b/exercises/space-age/example.py similarity index 100% rename from space-age/example.py rename to exercises/space-age/example.py diff --git a/space-age/space_age_test.py b/exercises/space-age/space_age_test.py similarity index 100% rename from space-age/space_age_test.py rename to exercises/space-age/space_age_test.py diff --git a/strain/example.py b/exercises/strain/example.py similarity index 100% rename from strain/example.py rename to exercises/strain/example.py diff --git a/strain/strain_test.py b/exercises/strain/strain_test.py similarity index 100% rename from strain/strain_test.py rename to exercises/strain/strain_test.py diff --git a/sublist/example.py b/exercises/sublist/example.py similarity index 100% rename from sublist/example.py rename to exercises/sublist/example.py diff --git a/sublist/sublist_test.py b/exercises/sublist/sublist_test.py similarity index 100% rename from sublist/sublist_test.py rename to exercises/sublist/sublist_test.py diff --git a/sum-of-multiples/example.py b/exercises/sum-of-multiples/example.py similarity index 100% rename from sum-of-multiples/example.py rename to exercises/sum-of-multiples/example.py diff --git a/sum-of-multiples/sum_of_multiples_test.py b/exercises/sum-of-multiples/sum_of_multiples_test.py similarity index 100% rename from sum-of-multiples/sum_of_multiples_test.py rename to exercises/sum-of-multiples/sum_of_multiples_test.py diff --git a/triangle/example.py b/exercises/triangle/example.py similarity index 100% rename from triangle/example.py rename to exercises/triangle/example.py diff --git a/triangle/triangle_test.py b/exercises/triangle/triangle_test.py similarity index 100% rename from triangle/triangle_test.py rename to exercises/triangle/triangle_test.py diff --git a/trinary/example.py b/exercises/trinary/example.py similarity index 100% rename from trinary/example.py rename to exercises/trinary/example.py diff --git a/trinary/trinary_test.py b/exercises/trinary/trinary_test.py similarity index 100% rename from trinary/trinary_test.py rename to exercises/trinary/trinary_test.py diff --git a/twelve-days/example.py b/exercises/twelve-days/example.py similarity index 100% rename from twelve-days/example.py rename to exercises/twelve-days/example.py diff --git a/twelve-days/twelve_days_test.py b/exercises/twelve-days/twelve_days_test.py similarity index 100% rename from twelve-days/twelve_days_test.py rename to exercises/twelve-days/twelve_days_test.py diff --git a/word-count/example.py b/exercises/word-count/example.py similarity index 100% rename from word-count/example.py rename to exercises/word-count/example.py diff --git a/word-count/word_count_test.py b/exercises/word-count/word_count_test.py similarity index 100% rename from word-count/word_count_test.py rename to exercises/word-count/word_count_test.py diff --git a/wordy/example.py b/exercises/wordy/example.py similarity index 100% rename from wordy/example.py rename to exercises/wordy/example.py diff --git a/wordy/wordy_test.py b/exercises/wordy/wordy_test.py similarity index 100% rename from wordy/wordy_test.py rename to exercises/wordy/wordy_test.py diff --git a/zebra-puzzle/example.py b/exercises/zebra-puzzle/example.py similarity index 100% rename from zebra-puzzle/example.py rename to exercises/zebra-puzzle/example.py diff --git a/zebra-puzzle/zebra_puzzle_test.py b/exercises/zebra-puzzle/zebra_puzzle_test.py similarity index 100% rename from zebra-puzzle/zebra_puzzle_test.py rename to exercises/zebra-puzzle/zebra_puzzle_test.py From 99c29c3d1103677855104e39467ad2d39119090a Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 26 Jan 2016 17:25:10 +0100 Subject: [PATCH 17/81] Fixed the exercises discovery path in test/check-exercises.py. --- test/check-exercises.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/check-exercises.py b/test/check-exercises.py index 42dcd652a52..489a7eb029a 100755 --- a/test/check-exercises.py +++ b/test/check-exercises.py @@ -61,7 +61,7 @@ def main(): modname_heuristic(test_file)) else: failures = [] - for test_file in glob.glob('./*/*_test.py'): + for test_file in glob.glob('../exercises/*/*_test.py'): name = assignment_name(test_file) print('# ' + name) if check_assignment(name, test_file, modname_heuristic(test_file)): From 81376c42ca3a9f8fb4ee27c8aaee5d6f7171af7c Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 26 Jan 2016 18:44:37 +0100 Subject: [PATCH 18/81] Fixed the single-exercise test. --- test/check-exercises.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/check-exercises.py b/test/check-exercises.py index 489a7eb029a..f668bfc1dd7 100755 --- a/test/check-exercises.py +++ b/test/check-exercises.py @@ -56,7 +56,7 @@ def assignment_name(test_file): def main(): if len(sys.argv) == 2: # test a specific exercise exercise_path = sys.argv[1].strip('/') - test_file = glob.glob('./{}/*_test.py'.format(exercise_path))[0] + test_file = glob.glob('../exercises/{}/*_test.py'.format(exercise_path))[0] check_assignment(assignment_name(test_file), test_file, modname_heuristic(test_file)) else: From fbd41e5cb2a95c5eb9b1f8330d327936fcfd1cfc Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 27 Jan 2016 12:40:11 +0100 Subject: [PATCH 19/81] Fixed the relative path problem. Now the exercises discovery paths have a single dot. --- test/check-exercises.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/check-exercises.py b/test/check-exercises.py index f668bfc1dd7..49beb13b9f8 100755 --- a/test/check-exercises.py +++ b/test/check-exercises.py @@ -56,12 +56,12 @@ def assignment_name(test_file): def main(): if len(sys.argv) == 2: # test a specific exercise exercise_path = sys.argv[1].strip('/') - test_file = glob.glob('../exercises/{}/*_test.py'.format(exercise_path))[0] + test_file = glob.glob('./exercises/{}/*_test.py'.format(exercise_path))[0] check_assignment(assignment_name(test_file), test_file, modname_heuristic(test_file)) else: failures = [] - for test_file in glob.glob('../exercises/*/*_test.py'): + for test_file in glob.glob('./exercises/*/*_test.py'): name = assignment_name(test_file) print('# ' + name) if check_assignment(name, test_file, modname_heuristic(test_file)): From 0bd10c570e3d0960977a5ed811c32ab934a35027 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Wed, 2 Dec 2015 18:03:08 +0100 Subject: [PATCH 20/81] binary: Expand invalid input tests --- exercises/binary/binary_test.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/exercises/binary/binary_test.py b/exercises/binary/binary_test.py index f572dda0653..4498a58b8b2 100644 --- a/exercises/binary/binary_test.py +++ b/exercises/binary/binary_test.py @@ -10,6 +10,7 @@ class BinaryTests(unittest.TestCase): + def test_binary_1_is_decimal_1(self): self.assertEqual(1, parse_binary("1")) @@ -31,11 +32,17 @@ def test_binary_11010_is_decimal_26(self): def test_binary_10001101000_is_decimal_1128(self): self.assertEqual(1128, parse_binary("10001101000")) - def test_invalid_binary_raises_error(self): + def test_invalid_binary_text_only(self): self.assertRaises(ValueError, parse_binary, "carrot") - def test_invalid_binary_raises_error_2(self): + def test_invalid_binary_number_not_base2(self): self.assertRaises(ValueError, parse_binary, "102011") + def test_invalid_binary_numbers_with_text(self): + self.assertRaises(ValueError, parse_binary, "10nope") + + def test_invalid_binary_text_with_numbers(self): + self.assertRaises(ValueError, parse_binary, "nope10") + if __name__ == '__main__': unittest.main() From f5a152942cd552948719dc64e730a9d2427bc7dc Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 26 Jan 2016 16:56:50 +0100 Subject: [PATCH 21/81] Create LEARNING.md and TESTS.md --- docs/LEARNING.md | 18 ++++++++++++++++++ docs/TESTS.md | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 docs/LEARNING.md create mode 100644 docs/TESTS.md diff --git a/docs/LEARNING.md b/docs/LEARNING.md new file mode 100644 index 00000000000..292d3f9dcbb --- /dev/null +++ b/docs/LEARNING.md @@ -0,0 +1,18 @@ +# Learning Python From Scratch +Python is, as Wikipedia goes, a powerful *general-purpose high-level programming language*. It basically means that it can be used to write a wide variety of different kinds of software, from videogames to HTTP servers to command-line tools. + +One of the main characteristics that differentiates Python from other programming languages is its strong emphasis on readability and code cleaness. In fact, differently from other languages like JavaScript or C++, in Python code indentation has a syntactical meaning and you are forced to chose and adhere to a writing style (e.g. don't mix *tabs* and *spaces* for identation; don't use two spaces where you should use four etc.). Yes, forced: the Python interpreter will raise SyntaxErrors if it recognize wrong indentation. + +This might look like a limit at the beginning but, as you will advance in your learning path, you'll realize that enforcing this behaviour will make your code slim and more readable by default. + +For its own nature, exercism assumes that you already have a grasp of the language syntax before starting doing exercises. At least at a point where you can write simple functions in Python. From there on, you can continue your learning as you will advance in the exercism track and gradually explore new constructs and concepts. + +With this premise, a good, beginner friendly, starting point for those who don't have any experience in other languages might be the Python course on [Codecademy.com](https://www.codecademy.com/). It will help you get an understanding of the Python syntax with which you will be able to start solving exercises here on exercism. + +## Other Resources + +- [Python3 Beginner Tutorial](https://www.youtube.com/playlist?list=PL1A2CSdiySGJd0LJRRSwQZbPZaDP0q67j) +- [Learn Python The Hard Way (Book)](http://learnpythonthehardway.org/book/) +- [Offical Python3 **Documentation** and **Reference**](https://docs.python.org/3/) +- [Learn X in Y minutes (where X = Python3)](https://learnxinyminutes.com/docs/python3/) +- [The Hitchhiker’s Guide to Python](http://docs.python-guide.org/en/latest/) diff --git a/docs/TESTS.md b/docs/TESTS.md new file mode 100644 index 00000000000..c1b248a1e31 --- /dev/null +++ b/docs/TESTS.md @@ -0,0 +1,33 @@ +# Installing `pytest` + +First of all, install `pytest` through `pip`. +``` +pip3 install pytest +``` +In case your system wouldn't be able to find `pip` and return a _command not found_, response, [here](https://pip.pypa.io/en/stable/installing/) you can find a tutorial on how to install it. + +# Running the Tests + +To run the tests for a specific exercise (we will take the `bob.py` exercise as an example here), place yourself in the directory where that exercise has been fetched and run: + +``` +pytest bob_test.py +``` + +This will run all the tests, wethere they fail or not. If you'd rather stop the process and exit on the first failure, run: + +``` +pytest -x bob_test.py +``` + +**Note:** To run the tests you have to pass the name of the testsuite file to `pytest` (generally, the file ending with `_test.py`), **NOT** the file you created to solve the problem (which is, your _implementation_). This because in the latter case, since there are no defined test cases in your implementation, `pytest` will just return a positive result, specifying that it ran zero tests. Like this: + +``` +============================= bob.py ============================== + +---------------------------------------------------------------------- + +Ran 0 tests in 0.000s + +OK +``` From 187d62e5aa5965f7f2c05c733b048912d5c87a12 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Wed, 3 Feb 2016 18:26:45 -0500 Subject: [PATCH 22/81] Change underscore to hyphen for check-exercises.py The script uses a hyphen instead of an underscore --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dc3826dc448..4d08c570f5c 100644 --- a/README.md +++ b/README.md @@ -18,16 +18,16 @@ Therefore please test your changes at least with Python2.7 and Python3.5. To test a single exercise, say crypto-square, run: ``` -python2.7 test/check_exercises.py crypto-square +python2.7 test/check-exercises.py crypto-square ``` and ``` -python3.5 test/check_exercises.py crypto-square +python3.5 test/check-exercises.py crypto-square ``` To run the tests for all exercises type: ``` -python test/check_exercises.py +python test/check-exercises.py ``` ## Code Style From 970433ac79824a3f8429ac48bb9e3adfae9abc54 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Sat, 6 Feb 2016 12:49:46 +0100 Subject: [PATCH 23/81] Set flake8 max-line-length to 99 characters As discussed in #299 --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 12ebc6a0937..a858887bd83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,7 @@ install: - pip install flake8 before_script: - # ignore: - # * E501 - line length limit - - flake8 . --ignore=E501 + - flake8 ./exercises/ --max-line-length=99 --select=E,W script: - ./test/check-exercises.py From 8cdd7b913ecb43ff073659c37eaa964327c5865d Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Sun, 7 Feb 2016 17:31:40 +0100 Subject: [PATCH 24/81] Fix broken help url The help site was cannibalized and included into the main site under /languages. --- SETUP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SETUP.md b/SETUP.md index 85ab1f01d79..7093c222f4b 100644 --- a/SETUP.md +++ b/SETUP.md @@ -6,4 +6,4 @@ For example, if you're submitting `bob.py` for the Bob exercise, the submit comm For more detailed information about running tests, code style and linting, -please see the [help page](http://help.exercism.io/getting-started-with-python.html). +please see the [help page](http://exercism.io/languages/python). From 744c95fa87cb0f464919a84c095ba686b235001a Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Mon, 8 Feb 2016 12:24:10 +0100 Subject: [PATCH 25/81] Pin versions of used pip packages To avoid breaking our builds because of changes in pip packages we use for testing it makes sense to introduce version pinning to the travis build. (see #287, #295) --- .travis.yml | 4 +++- requirements-travis.txt | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 requirements-travis.txt diff --git a/.travis.yml b/.travis.yml index a858887bd83..2d505e019d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,9 @@ python: - 3.5 install: - - pip install flake8 + - pip install pep8==1.7.0 + - pip install pyflakes==1.0.0 + - pip install flake8==2.5.2 before_script: - flake8 ./exercises/ --max-line-length=99 --select=E,W diff --git a/requirements-travis.txt b/requirements-travis.txt new file mode 100644 index 00000000000..581fcdaecf7 --- /dev/null +++ b/requirements-travis.txt @@ -0,0 +1,3 @@ +flake8==2.5.2 +pep8==1.7.0 +pyflakes==1.0.0 From d036ded9e8ae4a7b5110adf90e1796ec85024fe8 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Tue, 9 Feb 2016 00:17:41 +0100 Subject: [PATCH 26/81] Add badge indicating the requirements status The badge shows if the dependencies listed in `requirements-travis.txt` which are used in the travis-ci build are up-to-date (see #306). --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d08c570f5c..228c2b89b92 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # xPython -[![Build Status](https://travis-ci.org/exercism/xpython.png?branch=master)](https://travis-ci.org/exercism/xpython) +[![Build Status](https://travis-ci.org/exercism/xpython.png?branch=master)](https://travis-ci.org/exercism/xpython) [![Requirements Status](https://requires.io/github/exercism/xpython/requirements.svg?branch=master)](https://requires.io/github/exercism/xpython/requirements/?branch=master) Exercism exercises in Python From 835da7efab0db104875d2b46ac96e7b5bcf13d43 Mon Sep 17 00:00:00 2001 From: Mark Mandel Date: Thu, 11 Feb 2016 22:29:30 -0600 Subject: [PATCH 27/81] Correct iPython to IPython --- docs/ABOUT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ABOUT.md b/docs/ABOUT.md index 21f99d73446..e0ab937866e 100644 --- a/docs/ABOUT.md +++ b/docs/ABOUT.md @@ -1,4 +1,4 @@ -Python is a strong language for beginners. There are many resources available for programmers of all levels, the code is highly readable, and in many cases phrases are comparable to those in the English language. Code can be written and executed from the command line, in an interactive iPython session, or in a [Jupyter](http://jupyter.org) (iPython) notebook. +Python is a strong language for beginners. There are many resources available for programmers of all levels, the code is highly readable, and in many cases phrases are comparable to those in the English language. Code can be written and executed from the command line, in an interactive IPython session, or in a [Jupyter](http://jupyter.org) (IPython) notebook. The most common form of Python is compiled in C. This is often invisible to the beginning programmer, but if there are uses for which exceptionally fast implementation is needed then C extensions can be written to optimize Python execution. From 0b397a8b33e9cb4a4651b88a737109dcdabd66e3 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Fri, 12 Feb 2016 11:16:10 +0100 Subject: [PATCH 28/81] Change version pinning to only use minor versions Instead of pinning to an exact release (X.Y.Z) this way we pin to a minor version which will include the bug-fix releases automatically. --- .travis.yml | 6 +++--- requirements-travis.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2d505e019d5..4f35f5e992c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,9 @@ python: - 3.5 install: - - pip install pep8==1.7.0 - - pip install pyflakes==1.0.0 - - pip install flake8==2.5.2 + - pip install "flake8>=2.5,<2.5.99" + - pip install "pep8>=1.7,<1.7.99" + - pip install "pyflakes>=1.0,<1.0.99" before_script: - flake8 ./exercises/ --max-line-length=99 --select=E,W diff --git a/requirements-travis.txt b/requirements-travis.txt index 581fcdaecf7..7664ea22d08 100644 --- a/requirements-travis.txt +++ b/requirements-travis.txt @@ -1,3 +1,3 @@ -flake8==2.5.2 -pep8==1.7.0 -pyflakes==1.0.0 +flake8>=2.5,<2.5.99 +pep8>=1.7,<1.7.99 +pyflakes>=1.0,<1.0.99 From 66cc751a7412eee9de74a2d9ad93c3afe1ea32a1 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Wed, 3 Feb 2016 17:19:49 -0500 Subject: [PATCH 29/81] acronym: implement exercise acronym: initial implementation acronym: style fixes - remove the line break in line 24/25 (acronym_test.py) - remove the unnecessary brackets in line 6 (re.findall..) (example.py) - remove the line break in line 5/6 (example.py) acronym: add acronym to config.json after sum-of-multiples --- config.json | 1 + exercises/acronym/acronym_test.py | 28 ++++++++++++++++++++++++++++ exercises/acronym/example.py | 6 ++++++ 3 files changed, 35 insertions(+) create mode 100644 exercises/acronym/acronym_test.py create mode 100644 exercises/acronym/example.py diff --git a/config.json b/config.json index 41ff709f69e..520d3376036 100644 --- a/config.json +++ b/config.json @@ -22,6 +22,7 @@ "sieve", "atbash-cipher", "sum-of-multiples", + "acronym", "say", "largest-series-product", "kindergarten-garden", diff --git a/exercises/acronym/acronym_test.py b/exercises/acronym/acronym_test.py new file mode 100644 index 00000000000..c86b91a0856 --- /dev/null +++ b/exercises/acronym/acronym_test.py @@ -0,0 +1,28 @@ +import unittest + +from acronym import abbreviate + + +class AcronymTest(unittest.TestCase): + + def test_basic(self): + self.assertEqual('PNG', abbreviate('Portable Network Graphics')) + + def test_lowercase_words(self): + self.assertEqual('ROR', abbreviate('Ruby on Rails')) + + def test_camelcase(self): + self.assertEqual('HTML', abbreviate('HyperText Markup Language')) + + def test_punctuation(self): + self.assertEqual('FIFO', abbreviate('First In, First Out')) + + def test_all_caps_words(self): + self.assertEqual('PHP', abbreviate('PHP: Hypertext Preprocessor')) + + def test_hyphenated(self): + self.assertEqual('CMOS', abbreviate('Complementary metal-oxide semiconductor')) + + +if __name__ == '__main__': + unittest.main() diff --git a/exercises/acronym/example.py b/exercises/acronym/example.py new file mode 100644 index 00000000000..6263c996439 --- /dev/null +++ b/exercises/acronym/example.py @@ -0,0 +1,6 @@ +import re + + +def abbreviate(words): + regex = '[A-Z]+[a-z]*|[a-z]+' + return ''.join(word[0].upper() for word in re.findall(regex, words)) From 850c5de1be4e6a4df1fae0270a9de03da0e73957 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Tue, 16 Feb 2016 22:36:02 +0100 Subject: [PATCH 30/81] Install packages from requirements file --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4f35f5e992c..78f6521ae39 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,7 @@ python: - 3.5 install: - - pip install "flake8>=2.5,<2.5.99" - - pip install "pep8>=1.7,<1.7.99" - - pip install "pyflakes>=1.0,<1.0.99" + - pip install -r requirements-travis.txt before_script: - flake8 ./exercises/ --max-line-length=99 --select=E,W From adeaa8d64af0efdf8e50ab4d02d3e6c7da2451ff Mon Sep 17 00:00:00 2001 From: Alberto Date: Tue, 16 Feb 2016 20:14:24 +0100 Subject: [PATCH 31/81] Fix luhn's checksum tests and implementation --- exercises/luhn/example.py | 4 ++-- exercises/luhn/luhn_test.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/luhn/example.py b/exercises/luhn/example.py index 06601b359dd..f6981cee5a6 100644 --- a/exercises/luhn/example.py +++ b/exercises/luhn/example.py @@ -10,10 +10,10 @@ def luhn_transform(n): for i, n in enumerate(old_digits, start=len(old_digits) % 2)] def checksum(self): - return sum(self.addends()) % 10 + return sum(self.addends()) def is_valid(self): - return self.checksum() == 0 + return self.checksum() % 10 == 0 @staticmethod def create(n): diff --git a/exercises/luhn/luhn_test.py b/exercises/luhn/luhn_test.py index 25f4656e58f..630b1c8ca1c 100644 --- a/exercises/luhn/luhn_test.py +++ b/exercises/luhn/luhn_test.py @@ -16,10 +16,10 @@ def test_addends_large(self): Counter(Luhn(8631).addends())) def test_checksum1(self): - self.assertEqual(2, Luhn(4913).checksum()) + self.assertEqual(22, Luhn(4913).checksum()) def test_ckecksum2(self): - self.assertEqual(1, Luhn(201773).checksum()) + self.assertEqual(21, Luhn(201773).checksum()) def test_invalid_number(self): self.assertFalse(Luhn(738).is_valid()) From e9fd3ef5f7a37597e4934c0b4a136eecb65ed9c8 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Wed, 17 Feb 2016 17:45:05 -0500 Subject: [PATCH 32/81] Robot-name: fix typo --- exercises/robot-name/robot_name_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/robot-name/robot_name_test.py b/exercises/robot-name/robot_name_test.py index aa636a29493..2d07bbe6d23 100644 --- a/exercises/robot-name/robot_name_test.py +++ b/exercises/robot-name/robot_name_test.py @@ -21,7 +21,7 @@ def test_different_robots_have_different_names(self): Robot().name ) - def test_rest_name(self): + def test_reset_name(self): # Set a seed seed = "Totally random." From f73a5131c821a4618d2cab03476a48b2243e516f Mon Sep 17 00:00:00 2001 From: Christopher Huang Date: Fri, 26 Feb 2016 18:16:48 -0800 Subject: [PATCH 33/81] Update TESTS.md Command line for pytest is `py.test`. Corrected some typos and grammar. --- docs/TESTS.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/TESTS.md b/docs/TESTS.md index c1b248a1e31..aed46b67693 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -2,25 +2,25 @@ First of all, install `pytest` through `pip`. ``` -pip3 install pytest +pip install pytest ``` -In case your system wouldn't be able to find `pip` and return a _command not found_, response, [here](https://pip.pypa.io/en/stable/installing/) you can find a tutorial on how to install it. +If you get a `command not found` response from your system, you can find a tutorial on how to install `pip` [here](https://pip.pypa.io/en/stable/installing/). # Running the Tests To run the tests for a specific exercise (we will take the `bob.py` exercise as an example here), place yourself in the directory where that exercise has been fetched and run: ``` -pytest bob_test.py +py.test bob_test.py ``` -This will run all the tests, wethere they fail or not. If you'd rather stop the process and exit on the first failure, run: +This will run all the tests, whether they fail or not. If you'd rather stop the process and exit on the first failure, run: ``` -pytest -x bob_test.py +py.test -x bob_test.py ``` -**Note:** To run the tests you have to pass the name of the testsuite file to `pytest` (generally, the file ending with `_test.py`), **NOT** the file you created to solve the problem (which is, your _implementation_). This because in the latter case, since there are no defined test cases in your implementation, `pytest` will just return a positive result, specifying that it ran zero tests. Like this: +**Note:** To run the tests you need to pass the name of the testsuite file to `pytest` (generally, the file ending with `_test.py`), **NOT** the file you created to solve the problem (which is your _implementation_). This is because in the latter case, since there are no defined test cases in your implementation, `pytest` will just return a positive result, specifying that it ran zero tests. Like this: ``` ============================= bob.py ============================== From cfc27add994a1dbee7d4f699b472fb7d296336ab Mon Sep 17 00:00:00 2001 From: Steve Coffman Date: Sat, 27 Feb 2016 11:56:18 -0500 Subject: [PATCH 34/81] Fix typo in documentation where pip is pip3 --- docs/TESTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/TESTS.md b/docs/TESTS.md index c1b248a1e31..6aa7987785e 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -2,7 +2,7 @@ First of all, install `pytest` through `pip`. ``` -pip3 install pytest +pip install pytest ``` In case your system wouldn't be able to find `pip` and return a _command not found_, response, [here](https://pip.pypa.io/en/stable/installing/) you can find a tutorial on how to install it. From da69eaec09e08dba097960dafc521599c8cc9e59 Mon Sep 17 00:00:00 2001 From: Peter Tseng Date: Sat, 12 Mar 2016 17:56:50 -0800 Subject: [PATCH 35/81] largest-series-product: Do not test slices The slices functions is an internal implementation details and thus the test case for the largest-series-product problem should not be concerned with testing it. Its presence may cause students to falsely think that their solution has to use this function, instead of the alternative implementation of only iterating through the digits once. The slices tests are already well-covered by the series exercise already existing in this track. If it is desired to give hints on how to approach this problem (which was one advantage of having the slices test), then consider including a hints file and/or directory in the largest-series-product directory. This PR arises from discussion in https://github.com/exercism/x-common/issues/192 --- .../largest_series_product_test.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/exercises/largest-series-product/largest_series_product_test.py b/exercises/largest-series-product/largest_series_product_test.py index da891a5bff8..fa9578481de 100644 --- a/exercises/largest-series-product/largest_series_product_test.py +++ b/exercises/largest-series-product/largest_series_product_test.py @@ -1,26 +1,17 @@ """Tests for the largest-series-product exercise Implementation note: -In case of invalid inputs to the 'slices' or 'largest_product' functions +In case of invalid inputs to the 'largest_product' function your program should raise a ValueError with a meaningful error message. Feel free to reuse your code for the series exercise! """ import unittest -from series import largest_product, slices +from series import largest_product class SeriesTest(unittest.TestCase): - def test_slices_of_two(self): - self.assertEqual([[9, 7], [7, 8], [8, 6], [6, 7], - [7, 5], [5, 6], [6, 4]], - slices("97867564", 2)) - - def test_overly_long_slice(self): - with self.assertRaises(ValueError): - slices("012", 4) - def test_largest_product_of_2(self): self.assertEqual(72, largest_product("0123456789", 2)) From b5cdae64b20560682cf81744b6ff4d43bbc8ba05 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Mon, 14 Mar 2016 12:11:52 +0100 Subject: [PATCH 36/81] largest-series-product: Add additional test cases In response to #317 this adds the missing test cases from the standard test data (x-common/json). --- .../largest_series_product_test.py | 56 ++++++++++++++++--- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/exercises/largest-series-product/largest_series_product_test.py b/exercises/largest-series-product/largest_series_product_test.py index fa9578481de..2904576bde2 100644 --- a/exercises/largest-series-product/largest_series_product_test.py +++ b/exercises/largest-series-product/largest_series_product_test.py @@ -4,7 +4,7 @@ In case of invalid inputs to the 'largest_product' function your program should raise a ValueError with a meaningful error message. -Feel free to reuse your code for the series exercise! +Feel free to reuse your code from the 'series' exercise! """ import unittest @@ -15,20 +15,52 @@ class SeriesTest(unittest.TestCase): def test_largest_product_of_2(self): self.assertEqual(72, largest_product("0123456789", 2)) - def test_tiny_number(self): - self.assertEqual(9, largest_product("19", 2)) + def test_largest_product_of_2_unordered(self): + self.assertEqual(48, largest_product("576802143", 2)) + + def test__largest_product_span_equals_length(self): + self.assertEqual(18, largest_product("29", 2)) def test_largest_product_of_3(self): + self.assertEqual(504, largest_product("0123456789", 3)) + + def test_largest_product_of_3_unordered(self): self.assertEqual(270, largest_product("1027839564", 3)) + def test_largest_product_of_5(self): + self.assertEqual(15120, largest_product("0123456789", 5)) + def test_big_number(self): + series = "73167176531330624919225119674426574742355349194934" + self.assertEqual(23520, largest_product(series, 6)) + + def test_another_big_number(self): series = "52677741234314237566414902593461595376319419139427" self.assertEqual(28350, largest_product(series, 6)) - def test_string_with_all_zeroes(self): + def test_project_euler_big_number(self): + series = ( + "731671765313306249192251196744265747423553491949349698352031277450632623957" + "831801698480186947885184385861560789112949495459501737958331952853208805511" + "125406987471585238630507156932909632952274430435576689664895044524452316173" + "185640309871112172238311362229893423380308135336276614282806444486645238749" + "303589072962904915604407723907138105158593079608667017242712188399879790879" + "227492190169972088809377665727333001053367881220235421809751254540594752243" + "525849077116705560136048395864467063244157221553975369781797784617406495514" + "929086256932197846862248283972241375657056057490261407972968652414535100474" + "821663704844031998900088952434506585412275886668811642717147992444292823086" + "346567481391912316282458617866458359124566529476545682848912883142607690042" + "242190226710556263211111093705442175069416589604080719840385096245544436298" + "123098787992724428490918884580156166097919133875499200524063689912560717606" + "058861164671094050775410022569831552000559357297257163626956188267042825248" + "3600823257530420752963450" + ) + self.assertEqual(23514624000, largest_product(series, 13)) + + def test_all_digits_zero(self): self.assertEqual(0, largest_product("0000", 2)) - def test_string_where_all_spans_contain_zero(self): + def test_all_spans_contain_zero(self): self.assertEqual(0, largest_product("99099", 3)) def test_identity_with_empty_string(self): @@ -37,14 +69,22 @@ def test_identity_with_empty_string(self): def test_identity_with_nonempty_string(self): self.assertEqual(1, largest_product("123", 0)) - def test_slices_bigger_than_number(self): + def test_span_long_than_number(self): with self.assertRaises(ValueError): - largest_product("012", 4) + largest_product("123", 4) - def test_nonzero_slice_size_and_empty_string(self): + def test_nonzero_span_and_empty_string(self): with self.assertRaises(ValueError): largest_product("", 1) + def test_digits_with_invalid_character(self): + with self.assertRaises(ValueError): + largest_product("1234a5", 2) + + def test_negative_span(self): + with self.assertRaises(ValueError): + largest_product("12345", -1) + if __name__ == '__main__': unittest.main() From ffa11c6f2c4ef46cf5cf5501968968128b458a15 Mon Sep 17 00:00:00 2001 From: Kartik Singhal Date: Fri, 25 Mar 2016 18:31:00 -0400 Subject: [PATCH 37/81] Merge workflow document into testing Fixes #315 --- docs/TESTS.md | 106 ++++++++++++++++++++++++++++++++++++++++++----- docs/WORKFLOW.md | 86 -------------------------------------- 2 files changed, 95 insertions(+), 97 deletions(-) delete mode 100644 docs/WORKFLOW.md diff --git a/docs/TESTS.md b/docs/TESTS.md index aed46b67693..a1842e98ecd 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -1,33 +1,117 @@ # Installing `pytest` -First of all, install `pytest` through `pip`. +We recommend you install [pytest](http://pytest.org/latest/) and +[pytest-cache](http://pythonhosted.org/pytest-cache/). `pytest` is a testing +tool that will give you more flexibility over running your unit tests. + +```bash +pip install +pytest pytest-cache ``` -pip install pytest + +If you get a `command not found` response from your system, you can find a +tutorial on how to install `pip` +[here](https://pip.pypa.io/en/stable/installing/). + +If you choose not to install `pytest`, you can still run tests individually and +skip the rest of this tutorial: + +```bash +cd exercism/python/bob +python bob_test.py ``` -If you get a `command not found` response from your system, you can find a tutorial on how to install `pip` [here](https://pip.pypa.io/en/stable/installing/). # Running the Tests -To run the tests for a specific exercise (we will take the `bob.py` exercise as an example here), place yourself in the directory where that exercise has been fetched and run: +## Run All Tests -``` +To run all tests for a specific exercise (we will take the `bob.py` exercise as +an example here), place yourself in the directory where that exercise has been +fetched and run: + +```bash py.test bob_test.py ``` -This will run all the tests, whether they fail or not. If you'd rather stop the process and exit on the first failure, run: +**Note:** To run the tests you need to pass the name of the testsuite file to +`pytest` (generally, the file ending with `_test.py`), **NOT** the file you +created to solve the problem (which is your _implementation_). This is because +in the latter case, since there are no defined test cases in your +implementation, `pytest` will just return a positive result, specifying that +it ran zero tests. Like this: + +``` +============================= bob.py ============================== + +--------------------------------------------------------------------- + +Ran 0 tests in 0.000s +OK ``` + +## More `pytest` Examples + +### Stop After First Failure +The above will run all the tests, whether they fail or not. If you'd rather stop +the process and exit on the first failure, run: + +```bash py.test -x bob_test.py ``` -**Note:** To run the tests you need to pass the name of the testsuite file to `pytest` (generally, the file ending with `_test.py`), **NOT** the file you created to solve the problem (which is your _implementation_). This is because in the latter case, since there are no defined test cases in your implementation, `pytest` will just return a positive result, specifying that it ran zero tests. Like this: +### Failed Tests First +`pytest-cache` remembers which tests failed, and can run those tests first. + +```bash +py.test --ff bob_test.py ``` -============================= bob.py ============================== ----------------------------------------------------------------------- +### Running All Tests for All Exercises -Ran 0 tests in 0.000s +```bash +cd exercism/python/ py.test +``` -OK +## Recommended Workflow + +We recommend you run this command while working on exercises. + +```bash +cd exercism/python/bob py.test -x --ff bob_test.py +``` + +## PDB + +Will drop you into the python debugger when a test fails. To learn how to use +pdb, check out the +[documentation](https://docs.python.org/3/library/pdb.html#debugger-commands). + +You may also be interested in watching [Clayton Parker's "So you think you can +pdb?" PyCon 2015 talk](https://www.youtube.com/watch?v=P0pIW5tJrRM) + +```bash +py.test --pdb bob_test.py +``` + +## PEP8 + +PEP8 is the [Style Guide for Python +Code](https://www.python.org/dev/peps/pep-0008/). If you would like to test for +compliance to the style guide, install +[pytest-pep8](https://pypi.python.org/pypi/pytest-pep8) + +```bash +pip install pytest-pep8 ``` + +and add the pep8 flag to your command + +```bash +py.test --pep8 bob_test.py +``` + +Read the [pytest documentation](http://pytest.org/latest/contents.html#toc) and +[pytest-cache](http://pythonhosted.org/pytest-cache/) documentation to learn +more. diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md deleted file mode 100644 index cad2298e32b..00000000000 --- a/docs/WORKFLOW.md +++ /dev/null @@ -1,86 +0,0 @@ -## Tests - -We recommend you install [pytest](http://pytest.org/latest/) and [pytest-cache](http://pythonhosted.org/pytest-cache/). Pytest is a testing tool that will give you more flexibility over running your unit tests. - -If you choose not to install pytest, you can still run tests individually: - -```bash -$ cd exercism/python/bob -$ python bob_test.py -``` - -### Installation - -```bash -$ pip install pytest pytest-cache -``` - -## Pytest Examples - -####Run All Tests - -```bash -$ cd exercism/python/bob -$ py.test bob_test.py -``` - -####Stop After First Failure - -```bash -$ cd exercism/python/bob -$ py.test -x bob_test.py -``` - -####Failed Tests First - -Pytest-cache remembers which tests failed, and can run those tests first. - -```bash -$ cd exercism/python/bob -$ py.test --ff bob_test.py -``` - -### Recommended - -We recommend you run this command while working on exercises. - -```bash -$ cd exercism/python/bob -$ py.test -x --ff bob_test.py -``` - -####Running All Tests for All Exercises - -```bash -$ cd exercism/python/ -$ py.test -``` - -####PDB - -Will drop you into the python debugger when a test fails. -To learn how to use pdb, check out the [documentation](https://docs.python.org/2/library/pdb.html#debugger-commands). - -You may also be interested in watching [Clayton Parker's "So you think you can pdb?" PyCon 2015 talk](https://www.youtube.com/watch?v=P0pIW5tJrRM) - -```bash -$ cd exercism/python/bob -$ py.test --pdb bob_test.py -``` - -####PEP8 - -PEP8 is the [python style guide](https://www.python.org/dev/peps/pep-0008/). If you would like to test for compliance to the style guide, install [pytest-pep8](https://pypi.python.org/pypi/pytest-pep8) - -```bash -$ pip install pytest-pep8 -``` - -and add the pep8 flag to your command - -```bash -$ cd exercism/python/bob -$ py.test --pep8 bob_test.py -``` - -Read the [pytest documentation](http://pytest.org/latest/contents.html#toc) and [pytest-cache](http://pythonhosted.org/pytest-cache/) documentation to learn more. From 54871b6e5b8af58a284316b4212015f033bb3302 Mon Sep 17 00:00:00 2001 From: de2Zotjes Date: Sun, 3 Apr 2016 17:12:40 +0200 Subject: [PATCH 38/81] grade-school: update tests * Update grade_school_test.py Changed the tests to minimize the restrictions on implementation. * Update grade_school_test.py Improve the tests not to impose restrictions on the implementation. - assertItemsEqual in py2.7 was renamed/changed to assertCountEqual in py3, had to create some filth to fix that * Update grade_school_test.py Improve the tests not to impose restrictions on the implementation. - assertItemsEqual in py2.7 was renamed/changed to assertCountEqual in py3, had to create some filth to fix that grade-school: update tests The tests were looking at implementation details. Tests now use the intended interface: grade(?) To get it compliant with both 2.7 and 3.5 a little trick to get assertCountEqual known in 2.7 was needed. * grade-school: update tests The tests were looking at implementation details. Tests now use the intended interface: grade(?) where possible To get it compliant with both 2.7 and 3.5 a little trick to get assertCountEqual known in 2.7 was needed. --- exercises/grade-school/grade_school_test.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/exercises/grade-school/grade_school_test.py b/exercises/grade-school/grade_school_test.py index 8e74b1f73ff..ebbfced7073 100644 --- a/exercises/grade-school/grade_school_test.py +++ b/exercises/grade-school/grade_school_test.py @@ -7,42 +7,47 @@ class SchoolTest(unittest.TestCase): def setUp(self): + # assertCountEqual is py3, py2 only knowns assetItemsEqual + if not hasattr(self, 'assertCountEqual'): + self.assertCountEqual = self.assertItemsEqual self.school = School("Haleakala Hippy School") def test_an_empty_school(self): - self.assertEqual({}, self.school.db) + for n in range(1, 9): + self.assertCountEqual(set(), self.school.grade(n)) def test_add_student(self): self.school.add("Aimee", 2) - self.assertEqual({2: {"Aimee"}}, self.school.db) + self.assertCountEqual(("Aimee",), self.school.grade(2)) def test_add_more_students_in_same_class(self): self.school.add("James", 2) self.school.add("Blair", 2) self.school.add("Paul", 2) - self.assertEqual({2: {"James", "Blair", "Paul"}}, self.school.db) + self.assertCountEqual(("James", "Blair", "Paul"), self.school.grade(2)) def test_add_students_to_different_grades(self): self.school.add("Chelsea", 3) self.school.add("Logan", 7) - self.assertEqual({3: {"Chelsea"}, 7: {"Logan"}}, self.school.db) + self.assertCountEqual(("Chelsea",), self.school.grade(3)) + self.assertCountEqual(("Logan",), self.school.grade(7)) def test_get_students_in_a_grade(self): self.school.add("Franklin", 5) self.school.add("Bradley", 5) self.school.add("Jeff", 1) - self.assertEqual({"Franklin", "Bradley"}, self.school.grade(5)) + self.assertCountEqual(("Franklin", "Bradley"), self.school.grade(5)) def test_get_students_in_a_non_existant_grade(self): - self.assertEqual(set(), self.school.grade(1)) + self.assertCountEqual(set(), self.school.grade(1)) def test_sort_school(self): + students = [ (3, ("Kyle",)), (4, ("Christopher", "Jennifer",)), (6, ("Kareem",)) ] - for grade, students_in_grade in students: for student in students_in_grade: self.school.add(student, grade) From e048a3e1882d8e7714a0a8b73069701c4e388caf Mon Sep 17 00:00:00 2001 From: Victor Goff Date: Sun, 3 Apr 2016 03:33:33 -0400 Subject: [PATCH 39/81] sum-of-multiples: Remove default values references #319 --- exercises/sum-of-multiples/example.py | 4 +--- exercises/sum-of-multiples/sum_of_multiples_test.py | 13 ++++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/exercises/sum-of-multiples/example.py b/exercises/sum-of-multiples/example.py index b5ab33145bc..b5a091db647 100644 --- a/exercises/sum-of-multiples/example.py +++ b/exercises/sum-of-multiples/example.py @@ -1,7 +1,5 @@ def sum_of_multiples(limit, multiples=None): - if multiples is None: - multiples = [3, 5] - elif multiples[0] == 0: + if multiples[0] == 0: # multiples of 0 don't change the sum multiples = multiples[1:] return sum(value for value in range(limit) diff --git a/exercises/sum-of-multiples/sum_of_multiples_test.py b/exercises/sum-of-multiples/sum_of_multiples_test.py index 539226cb91e..2e90939a1dd 100644 --- a/exercises/sum-of-multiples/sum_of_multiples_test.py +++ b/exercises/sum-of-multiples/sum_of_multiples_test.py @@ -3,9 +3,8 @@ 'sum_of_multiples' function: * All input numbers are non-negative 'int's, i.e. natural numbers including zero. - * If a list of factors is given, its elements are uniqe and sorted in + * A list of factors must be given, and its elements are uniqe and sorted in ascending order. - * If the 'factors' argument is missing, use the list [3, 5] instead. """ import unittest @@ -15,19 +14,19 @@ class SumOfMultiplesTest(unittest.TestCase): def test_sum_to_1(self): - self.assertEqual(0, sum_of_multiples(1)) + self.assertEqual(0, sum_of_multiples(1, [3, 5])) def test_sum_to_3(self): - self.assertEqual(3, sum_of_multiples(4)) + self.assertEqual(3, sum_of_multiples(4, [3, 5])) def test_sum_to_10(self): - self.assertEqual(23, sum_of_multiples(10)) + self.assertEqual(23, sum_of_multiples(10, [3, 5])) def test_sum_to_100(self): - self.assertEqual(2318, sum_of_multiples(100)) + self.assertEqual(2318, sum_of_multiples(100, [3, 5])) def test_sum_to_1000(self): - self.assertEqual(233168, sum_of_multiples(1000)) + self.assertEqual(233168, sum_of_multiples(1000, [3, 5])) def test_configurable_7_13_17_to_20(self): self.assertEqual(51, sum_of_multiples(20, [7, 13, 17])) From 776e725630b0172dd2ad02698fb80f9dd202e429 Mon Sep 17 00:00:00 2001 From: Victor Goff Date: Sun, 3 Apr 2016 14:41:48 -0400 Subject: [PATCH 40/81] Remove old help site links Closes #323 References exercism/todo#181 --- README.md | 2 +- docs/TOOLS.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 228c2b89b92..8175a54c330 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ If there are more details to add, put those into the body of the commit message. If you're interested, Tim Pope even has an [entire blog post](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) on good commit messages. -If you're new to Git take a look at [this short guide](http://help.exercism.io/git-workflow.html). +If you're new to Git take a look at [this short guide](https://github.com/exercism/x-common/blob/master/CONTRIBUTING.md#git-basics). ## License diff --git a/docs/TOOLS.md b/docs/TOOLS.md index a97c131683f..2832df2d355 100644 --- a/docs/TOOLS.md +++ b/docs/TOOLS.md @@ -12,11 +12,11 @@ This is a Visual Studio template that comes pre-configured to work on the proble 1. Download the [Exercism.io Visual Studio Template](https://github.com/rprouse/Exercism.VisualStudio) from GitHub by clicking the Download Zip button on the page. 2. Unzip the template into your exercises directory, for example `C:\src\exercises` -2. Install the [Exercism CLI](http://help.exercism.io/installing-the-cli.html) +2. Install the [Exercism CLI](http://exercism.io/cli) 3. Open a command prompt to your exercise directory 4. Add your API key to exercism `exercism configure --key=YOUR_API_KEY` 5. Configure your source directory in exercism `exercism configure --dir=C:\src\exercises` -6. [Fetch your first exercise](http://help.exercism.io/fetching-exercises.html) `exercism fetch python` +6. [Fetch your first exercise](http://exercism.io/languages/python) `exercism fetch python hello-world` 7. Open the Exercism solution in Visual Studio 8. Expand the Exercism.python project 9. Click on **Show All Files** in Solution Explorer (See below) From cea4ae6bf0ce9de6e6e4bba89adc2a352b415a40 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Thu, 7 Apr 2016 12:34:27 +0200 Subject: [PATCH 41/81] Update pyflakes to version 1.1.0 --- requirements-travis.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-travis.txt b/requirements-travis.txt index 7664ea22d08..1572c76e1b7 100644 --- a/requirements-travis.txt +++ b/requirements-travis.txt @@ -1,3 +1,3 @@ flake8>=2.5,<2.5.99 pep8>=1.7,<1.7.99 -pyflakes>=1.0,<1.0.99 +pyflakes>=1.1,<1.1.99 From 351906066c094b56901e71009cd276fd3db576a6 Mon Sep 17 00:00:00 2001 From: Helen Sherwood-Taylor Date: Sat, 9 Apr 2016 16:57:47 +0100 Subject: [PATCH 42/81] pangram: Add extra invalid pangram test case (#331) --- exercises/pangram/pangram_test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/exercises/pangram/pangram_test.py b/exercises/pangram/pangram_test.py index aee6b4e906c..3825f958e53 100644 --- a/exercises/pangram/pangram_test.py +++ b/exercises/pangram/pangram_test.py @@ -14,6 +14,10 @@ def test_valid_pangram(self): self.assertTrue( is_pangram('the quick brown fox jumps over the lazy dog')) + def test_invalid_pangram(self): + self.assertFalse( + is_pangram('the quick brown fish jumps over the lazy dog')) + def test_missing_x(self): self.assertFalse(is_pangram('a quick movement of the enemy will ' 'jeopardize five gunboats')) From 4e4f1e5b65617f6ad419d2df5a730a43ebd59eeb Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Thu, 14 Apr 2016 13:17:43 +0200 Subject: [PATCH 43/81] Corrects pip install command see #332 --- docs/TESTS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/TESTS.md b/docs/TESTS.md index a1842e98ecd..8025494ddbb 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -5,8 +5,7 @@ We recommend you install [pytest](http://pytest.org/latest/) and tool that will give you more flexibility over running your unit tests. ```bash -pip install -pytest pytest-cache +pip install pytest pytest-cache ``` If you get a `command not found` response from your system, you can find a From ef5beff640846af8de95e0a1ed15765664455357 Mon Sep 17 00:00:00 2001 From: Ilya Zonov Date: Sun, 8 May 2016 20:48:29 +0400 Subject: [PATCH 44/81] Fix py.test run in documentation (#334) Just add '\n' between `cd` and `py.test` commands --- docs/TESTS.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/TESTS.md b/docs/TESTS.md index 8025494ddbb..53ea9ddf3fc 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -70,7 +70,8 @@ py.test --ff bob_test.py ### Running All Tests for All Exercises ```bash -cd exercism/python/ py.test +cd exercism/python/ +py.test ``` ## Recommended Workflow @@ -78,7 +79,8 @@ cd exercism/python/ py.test We recommend you run this command while working on exercises. ```bash -cd exercism/python/bob py.test -x --ff bob_test.py +cd exercism/python/bob +py.test -x --ff bob_test.py ``` ## PDB From 1e00eb865bc7f5519d881924ba52b08e303df99e Mon Sep 17 00:00:00 2001 From: joeltaylor Date: Thu, 16 Jun 2016 10:01:22 -0400 Subject: [PATCH 45/81] Add track icon --- config.json | 3 ++- img/icon.png | Bin 0 -> 11853 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 img/icon.png diff --git a/config.json b/config.json index 520d3376036..b968c274a33 100644 --- a/config.json +++ b/config.json @@ -74,7 +74,8 @@ ], "ignored": [ "docs", - "test" + "test", + "img" ], "foregone": [ diff --git a/img/icon.png b/img/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f712112060409eef68f71b82c52da2330642d99d GIT binary patch literal 11853 zcmeHtYgAL$x9{9ZNCE^BL@g+iU{R?e1W>_>BnslAiq=;_sl*rB7Lh`=h)Oo1fN$yx zC=~FCwYEjA3iZKOte_xZwSx6QP!trDARrKu>@!#3-}^sfoN>p!AMQB!!^sC&kGbZW zYt6_0&AIpXIYCpcECyKsfYtPA0doO(*yMqbkN?y|MkNBc^`9OvX?|>0^OK4D22cMp zcj?*P)vFT*9rT+v%GdRvU#ZJ|7ww=mH!HX3s{$6(jbMisPtb>cb7Dlr2duH683a&ya?o8(%&HJ56Iac3sBje&r^NLkBhVs!O7BODSTw# z{A!jnsK)u#fUqQLHlIVm!!8X+CG__@XDfu1n*v+-+`heT*ixWB-2_yWFww91LlIPE ziU+|$kH+E+0Tk@1_cx<6MLJ2E9GHQAzR-1x5pOW(fNNbbCs$VNS3bKxXvRuKU}o1v zO#+bez}8dCtrT*gBlfu8y>vW+;Nb} z{S}hkc95Fp9YrgVX!tTvx;_1k;(N7oy(CchGweXJ-+L9k-%gjX;|9<^ zmz}uZglh#|Q$%1_mMK>XlH%!}tw4KR?&dh$s1oOA+d-7$+5(thuczMIazNJ>Xqo@r zHEFKc19HV{e}PeUI;!GB9ypX`j$}A|HT^X%Umoja7RzYFlAU&t|AY4&da%d{XUr*R z+VGrLuuLl`og#$biowH~35g2j`pLk=JatL<6N%a+6gajGH$SjKD@ae1Kvbsp)ZG3^ zGz5u0dD=h0Q^dkpbMAR|akbwIVg5@iN&3DzDLr*7N&2LK;P@0%Tt>9wa}}1pqYPFM9tY=IZ@V+LZAA$A4R+1=$NZO z%{f@9l%ZYwY;*U6`3>hJcC!F}Z`&q-_|^>JE)?77=v=Figz4kcz>N1=!wl`8L` z->=V}0Q4E6b#PJQP^tO*_-udrDzflJ6F@~$9AG#>zfe#b1Za}WEP$~i>YjOHGte9H zJR`D#xgh6KXuR7;0yN-J0CM3U5gqeSSt|o0dBVrYP`H z5vbtH2L4~HGF^_{_1Zi>_@n`7X{P}|hY;(BIW+kTX4uK9I6k0P;%xb8PU_vh2aM8{ z91!};$lu-zaO3*yY3K(k(LXW_jE=sN(;xwr!#_g{qqbc6p}`tduK#N&df&g@e6Px) zj$FxVumBk!uPhQ{7krJP47QKND-HmtnZzrojNyW0C+d9vq|VWm=AiUNB~YTvMH}4E zVf&%2EYo&400ayNh!SGNQAQv^!YS)(3)GQ7&qS>xo?lwB=f3;Lek;Nq4y@8=0EBlgZRf&Cji+3#Grll1mYhw#CPi-@3^3yM$I8zx zopI{5`28yfpYWQv5a4Z$IWV%j?v@x%p?nI44%bCOQ+qmq@L8PJZvr2mGVpQ)hKFwg zMRMeSAFY7*?N@WcY|TVEfH53UPELvgc<^o&v6+7}od4+%`}=RbkS;lD@66_2bAa}? zK34>d!?^!;*)XpCpWKe=2p9%+x`qbnQK|pRoU7^$3Y`b>FMw}aJCoVn@xtSq^NSOti;l+MPyzOVYfCr); z-0Xu39DEjAAch23^?QU_Xt<3N#+zK=DgY!268RyJf8aBG`38k}z zeTWzV9)4cyI!D+z6{g+Rhylt^Y=bnj_7A~%S)%|Qyx}Yz&!c&Wt3Wx{&C(|uBq=7xRrIv#C{fD>TPi+%KqP)-!*C)^A+7dmUkQ@LJ6G{K*dh0cf2$Y@bsdC*R{Kt1gT*7b|j2pN0==rkUk*mWGar%dH_&4QX+KPpi8h@p%- zhp~=NKn~Foibv1N(xK?}^CohHFlvEuB}!2GOEgac3s34k!PWBpr)-oEeDaw)-UD-b zWFSx)^XeX4Q~u*3By&93PV8aMr^kgdc>L*$53rN_`$$|RaAu?U+);?V5~juF2`O|`5@}H0MsvW5nUa=3yyP{2zLzBQ1XS1YWPYn zji?CdRpH+c`GikrEK%Z&F5}f)I+{`)`T(&29aG+qnqfxUFCpwIy#0AD_>jWu|EbyA z%+(gorVYa0%`)G`hlG$3Cd1CN(oG*R?Uby^5)Y)D8S)`>pOQVd#B(b**|!MfYe25Y znW}jg3S(|V>KlyIAj^qJw$ig^@>x)-U4e_` zc_JIt4v-k8^O5N8p8~+=4uDNSEoT}Y2pR4uwUMoZ6x}hh@0c(84w`Z#k~$^=o1AG# zQ?S}b_Wc1=4#1I}>tla#gMf_)V?lFhbsFcG1$>uHZnxBV0imF04qZbXGlx&J$wid9 zOzAyE>VgBK>Ha1jo;$UxsA2&vJV+4C`#}?HldR!r4n7&d=XT?0y2?Zq?)ffvLIgzV zh#DgTpGxE_dO0y?CgWKE(*HU+nvSBFSL8qr?xAFiez?1aBOCx(MslUnrJP>1&8T?F z5t?PLtnj)%@w&Z>lG*}81jv%Ffg1igA2X8--;N& zmDs4tvoD52t3y9H&7y{w4HrWBDr^AsTeQ*6oivoxB`)1zlBCikiSuvo{lLWD`F!{& z^=ExMj3?Tlw{Plw%2oNeZjCuzC{hv@^o>J&Z_~*wY8>EnI}Rxwdlhx&cqb(xG_t~B zi*=bC(@rTPZigX4J8N1(5GF8n5Ag+^)cWHLu{1`42w#SQvZMh5WP+Zt&Wucv3rIWA?8O{u0le^q9KPJlM4KTFV z>J;_SUeJ|n+8|Hf?PX z`!ieYYqW%g8*xc+MzXqBYT7%?SiH$ZhT%@K8|gt%=BJ-vNFKl0&VW7Dz=s00Dw3Fm z2F{7tAa~fzjZimSa1>ugyAB_H^ zi6$OubG~E%G!vL8C6L4!{+Wf>1yNZwfv)4x`Xx=UEX>wp-&HfaZRcj zOQ>Gi>D6EB#GxeMrzc%wy^9sv@3F0nf8}nY!D!R-8jBOKq^J9D{2Iq)yQ)uQgV~x zAuj)&co%LQ>Y?RUWzJKpaATLsDlub^IPEAVw9}EOqW-=#MTwfjv@mL1o>A${0r|v4 z1+4Pw;@V(lc|c@w(M3Iw7c-*rt&AH_Owwk^<3n9?^d)d+&o zZ-Y<)svnys6&30~kLN0wI4pjk#X_fDI|1$VJUb)xW!%J?uu#69HCFOB({FjG>SA?# z=T(M#*|EM>-@@NW%W-g2v3gVIgUB%bw>SgG@B~lnjL&1o)DM13!IxNVbQ7`53$_mg zKucr}i;NAwi}d`>hzm%8&(7H6g^5M}K?FG0wd%`F>rfnkjd;tEN$m5-gD}t2VCfob zcIu+0^YJ6}=n|;eOnc)+l37Hd1=rlr7G)on0*%p!uJ~KC7IO;K7%Xz#dBw&A^-z!! zh@~bEz2fC>NOTfwo*u>Q8ZuFeS{~@3FIqPd6Aa}y9MB%9V~62AfISM}pTyRN)`~$H zuHF?7aQFN*_Ib%(MHbSgW>|sdm)CjhLIZ`>Q;Z1nH*|U9g#2hunASaPJ@x(T;v!5= zX!}9|FcYe~aY~T};68tX;o@85IRH1y+0jcgGL!=cmOnx29q5yJBlFlGWP9>9)_}Ly z)t<*hWj*h#FmRmR`kdm<}ji>7Htk{&_}O(5uxHaFw?E)RT0T1_Ba77MSBK~ z501LF^^JCfL8-3`#CQ<;)(BvZoei8w_Gw3YjAHn-li&jo9~o1DHeVUa5*d|YXwO-M zD;lWE(|$HfQoX7i0MTDT>{JCJsgtPAq%#CgH*By0&tI&$MJsjQ5#%Us`nHxZ5=9{w zasBW*f=purNGKz-9waV7dgvp&frxrS9AU{*KvX}$T0}VPgLFAHTOzbf}VrA1!&B-sc zha)*7Ij!C2)Ht`(3Z{*WI~hZkpFvNlBM6@q*zh;=bzDp^R@Yus5H7_XR)9+Aw}q@yTE=N9n z@~4|P$b5{3@WiyU>qYB!GnnT5Y~h|vVhwq>70|h8LftwKoZkh*JM*TuI49@%+GhQV;3VSui-2r28|GLbpr2oD?$A-ZxjAZt@^td>nix$7t+?ix{VV67R>Ri zh|B3IdUGWv9?Q!PUnUf=JtBmh6MrtM&mc+)C$HrIMlYWW70*mE%C`TEAeIn-S+g~` zAxyvoygB3A8ZxBhY<$3?3E(W@j>^jG7wp zR5}o_c#gl4M;qIUEKM>KP2w+M$oa3;m<8ICjzh!A4)&&rvcHTBD3w$7Z`iMr|8<_e zgfRE0xW6<4uhh%Q5qlv%$mpkw+n;dhGBTt&vqY_H`QD1O?V5KLx6R}9E-QGm>t3IvqHi7? z?*4*e1`?vn-#qviJO22#{NA*gs_-?e4YKMJBdj9(JJU@vw<`Q_Tnrb;%9E$9*bl>( z_udVY3Mxw+q;~}VVC=ITdTHMt2X`U6zGL|J9b=^3W?e18ia_rfDq`kSf_({MB$B(J8ULg|S|tVoai+HKK*e)Q%lM2?I)SSr`yD^n~0`#ei+1N_Et2Gl=|qszu+iu zjzE*A3s(#=W{#n9Z|R&-Ys~5&O+K`1Uw3=abgbMcNEE6+u(@mPpJw#%p8Z%nQaXC! zcDHdHi-_qfafVNaEFryR-+y81g`fCuQggZZ7JWeKH%q1LV(1 zA&Kcmh@SZoN9omMi9W=PM`WIfvU#;x;$3Zm0acXG`s#cb&{t5^^#Zpmz4IgM z`2wdtKrv(^irHum!?uxINS!)ZU$nU={Ds<#((DMs?dYy7-P#Y~^0PG5o^1HH-L(zH zjRMKt7iq7Wa&i#ExFSQJ4#gHLTA+_cDR#YB#6B0o?5<(R&#w4K_6(0U(_hD#tdbwq zQVugYz7?0~qW2eFeawq8^A_NB`z#r(8=R;P<1qX;X>&;ot0~c_-O?bU{)7G~{-v^0 zMGs$NkXRoz9VeNOSu119)!p$fFKWPtUWUiercdbEyNaukUBI1S$?sQh)^2BGIn1@k zGBnJS6?Y8yD(T~V;_&lVX!p*7#!?bc+l{cj2>rE#8&6RAJkGd||g z`^}M^a(EIUN-V%<4Hl#itAjXn2b>({TPliitG^88pjmL8_#Wp)U9P)@LAN;Z-b$mqm(W#Dyog! zJ5F;h8B$Y!M#@tEh+!6#>`e7q=PlSJnAi5}jK0?XvqP}OjHPmgldzFHj>+=$PlYwZyLctn4-rnnU zzuLlOO_?#6icbIjj`Kgg@cf?+(Qe=4`2XcqZ8FtTQW|p9?4k}e+ahM0+NXif4zl~> zl{GB+`k_qS`Rd8VJ8a8lLtES4_c=!pm!VxMJ*xA1)-=|7HP=QD>F4H=Yr}(^B-7tf zud_v(Z=6+=KMd-rF7S180u8~l%!9)Xn$j{j z?cJtT|7_TmHd+Ah$&+K>kDmH49qOjh$(ev&c^RruWKpf70klb!t1X;hKZQ)k9^C8s=fQ0 z48FVH94B<@97tW z`C0eW^h%P!jIaPn=9-C`fuun3fhB&UL%BY0m#W5-{y#bRj`zp^8ajEW{nRXu<;HGiC#XR#AD8l;8g_t#x{6|>EEK@s~`Ft|r z$yHnW#)ULUsImls8-6s>G zgkcp>@$L9GKa9PxWN30_+6#Pdu{SmmKdeG{w!Azx43=)VVy_m{%L{qnv#ZIPx|#lF zAHHN$N-dnCTu}7qD~g<%+pOOMHeuD}>5v@#C0D-Wf<&dQt<)*s zWc6o=n`Ob)<+xfs(kaRZSD(>KH-5Wk$Y0h|s4=Z$>?G#w_3QGJoIY-015OOC!= z@5tUbz#oU_{0}ar}Je(O;tDMK7d2uh+CATAy%^_{Edxk>Q9y`Rx)47>`IcVUP$INgyegbPK-p04TOY?z#BLlpnyz zS>h)jfpiQt8FHR6@6czB@K^y<+h^gd-7c%`oxR_>RbVSvU3O(Kfr}my7NIc24k4lJYzyOE+$`Fg&)&%ub4Z? z4u;jn>y5_uG3^R2xZ$2Qc(S>zgMe;6fOS%=dF??ir?Ksf?S0se!1fqy6Yj1D)H03} z@7QO4qF`gwa~cAW?We+_szLEiKu?SO^*$0m z_|3U`>aFb#u(IcZ?o&NhW%s}kI}ZFkM~9!n9)KZ8^Lmb++GCpziFRDrgM2D%vmg=2 zv*+ok*ODXn`2!dH9?wu8?&98enn`W(V62^#%NInK*O5PrCw z+dd+S+J`g`T@0|?Jd8Gfe3QN|gMcIL+#60Q)bRRsAm8z8C-=s%1Jv+UB3KktCQeOE z;3F5wH(AvJHBmC0zlkW<0y#->J*X?WFpU+wJ`)6-0&7|~dhne8o@O0W7 zJBymQ`OTIu9O+#SOF+vUJ*>H@N-aA#In1R4$}1)b;Nay!q6@nOC09mj7vJ`UO)sK& pbnYIJMaD->=w0}Pzm`jnu6UnZ-z{0C>|tA79h literal 0 HcmV?d00001 From 44993548a366fe88d32ee0844af948fab1e17a70 Mon Sep 17 00:00:00 2001 From: Chris Reister Date: Tue, 21 Jun 2016 20:06:14 -0700 Subject: [PATCH 46/81] Add clock exercise --- config.json | 1 + exercises/clock/clock_test.py | 173 ++++++++++++++++++++++++++++++++++ exercises/clock/example.py | 24 +++++ 3 files changed, 198 insertions(+) create mode 100644 exercises/clock/clock_test.py create mode 100644 exercises/clock/example.py diff --git a/config.json b/config.json index 520d3376036..8f380ec76b0 100644 --- a/config.json +++ b/config.json @@ -6,6 +6,7 @@ "problems": [ "hello-world", "leap", + "clock", "pangram", "rna-transcription", "hamming", diff --git a/exercises/clock/clock_test.py b/exercises/clock/clock_test.py new file mode 100644 index 00000000000..bef54b50fd1 --- /dev/null +++ b/exercises/clock/clock_test.py @@ -0,0 +1,173 @@ +import unittest + +from clock import Clock + + +class ClockTest(unittest.TestCase): + # Test creating a new clock with an initial time. + def test_on_the_hour(self): + self.assertEqual('08:00', str(Clock(8, 0))) + + def test_past_the_hour(self): + self.assertEqual('11:09', str(Clock(11, 9))) + + def test_midnight_is_zero_hours(self): + self.assertEqual('00:00', str(Clock(24, 0))) + + def test_hour_rolls_over(self): + self.assertEqual('01:00', str(Clock(25, 0))) + + def test_hour_rolls_over_continuously(self): + self.assertEqual('04:00', str(Clock(100, 0))) + + def test_sixty_minutes_is_next_hour(self): + self.assertEqual('02:00', str(Clock(1, 60))) + + def test_minutes_roll_over(self): + self.assertEqual('02:40', str(Clock(0, 160))) + + def test_minutes_roll_over_continuously(self): + self.assertEqual('04:43', str(Clock(0, 1723))) + + def test_hour_and_minutes_roll_over(self): + self.assertEqual('03:40', str(Clock(25, 160))) + + def test_hour_and_minutes_roll_over_continuously(self): + self.assertEqual('11:01', str(Clock(201, 3001))) + + def test_hour_and_minutes_roll_over_to_exactly_midnight(self): + self.assertEqual('00:00', str(Clock(72, 8640))) + + def test_negative_hour(self): + self.assertEqual('23:15', str(Clock(-1, 15))) + + def test_negative_hour_rolls_over(self): + self.assertEqual('23:00', str(Clock(-25, 0))) + + def test_negative_hour_rolls_over_continuously(self): + self.assertEqual('05:00', str(Clock(-91, 0))) + + def test_negative_minutes(self): + self.assertEqual('00:20', str(Clock(1, -40))) + + def test_negative_minutes_roll_over(self): + self.assertEqual('22:20', str(Clock(1, -160))) + + def test_negative_minutes_roll_over_continuously(self): + self.assertEqual('16:40', str(Clock(1, -4820))) + + def test_negative_hour_and_minutes_both_roll_over(self): + self.assertEqual('20:20', str(Clock(-25, -160))) + + def test_negative_hour_and_minutes_both_roll_over_continuously(self): + self.assertEqual('22:10', str(Clock(-121, -5810))) + + # Test adding and subtracting minutes. + def test_add_minutes(self): + self.assertEqual('10:03', str(Clock(10, 0).add(3))) + + def test_add_no_minutes(self): + self.assertEqual('06:41', str(Clock(6, 41).add(0))) + + def test_add_to_next_hour(self): + self.assertEqual('01:25', str(Clock(0, 45).add(40))) + + def test_add_more_than_one_hour(self): + self.assertEqual('11:01', str(Clock(10, 0).add(61))) + + def test_add_more_than_two_hours_with_carry(self): + self.assertEqual('03:25', str(Clock(0, 45).add(160))) + + def test_add_across_midnight(self): + self.assertEqual('00:01', str(Clock(23, 59).add(2))) + + def test_add_more_than_one_day(self): + self.assertEqual('06:32', str(Clock(5, 32).add(1500))) + + def test_add_more_than_two_days(self): + self.assertEqual('11:21', str(Clock(1, 1).add(3500))) + + def test_subtract_minutes(self): + self.assertEqual('10:00', str(Clock(10, 3).add(-3))) + + def test_subtract_to_previous_hour(self): + self.assertEqual('10:00', str(Clock(10, 3).add(-3))) + + def test_subtract_more_than_an_hour(self): + self.assertEqual('09:33', str(Clock(10, 3).add(-30))) + + def test_subtract_across_midnight(self): + self.assertEqual('08:53', str(Clock(10, 3).add(-70))) + + def test_subtract_more_than_two_hours(self): + self.assertEqual('21:20', str(Clock(0, 0).add(-160))) + + def test_subtract_more_than_two_hours_with_borrow(self): + self.assertEqual('03:35', str(Clock(6, 15).add(-160))) + + def test_subtract_more_than_one_day(self): + self.assertEqual('04:32', str(Clock(5, 32).add(-1500))) + + def test_subtract_more_than_two_days(self): + self.assertEqual('00:20', str(Clock(2, 20).add(-3000))) + + # Construct two separate clocks, set times, test if they are equal. + def test_clocks_with_same_time(self): + self.assertEqual(Clock(15, 37), Clock(15, 37)) + + def test_clocks_a_minute_apart(self): + self.assertNotEqual(Clock(15, 36), Clock(15, 37)) + + def test_clocks_an_hour_apart(self): + self.assertNotEqual(Clock(14, 37), Clock(15, 37)) + + def test_clocks_with_hour_overflow(self): + self.assertNotEqual(Clock(10, 37), Clock(34, 37)) + + def test_clocks_with_hour_overflow_by_several_days(self): + self.assertEqual(Clock(3, 11), Clock(99, 11)) + + def test_clocks_a_minute_apart(self): + self.assertNotEqual(Clock(15, 36), Clock(15, 37)) + + def test_clocks_an_hour_apart(self): + self.assertNotEqual(Clock(14, 37), Clock(15, 37)) + + def test_clocks_with_hour_overflow(self): + self.assertEqual(Clock(10, 37), Clock(34, 37)) + + def test_clocks_with_hour_overflow_by_several_days(self): + self.assertEqual(Clock(3, 11), Clock(99, 11)) + + def test_clocks_with_negative_hour(self): + self.assertEqual(Clock(22, 40), Clock(-2, 40)) + + def test_clocks_with_negative_hour_that_wraps(self): + self.assertEqual(Clock(17, 3), Clock(-31, 3)) + + def test_clocks_with_negative_hour_that_wraps_multiple_times(self): + self.assertEqual(Clock(13, 49), Clock(-83, 49)) + + def test_clocks_with_minute_overflow(self): + self.assertEqual(Clock(0, 1), Clock(0, 1441)) + + def test_clocks_with_minute_overflow_by_several_days(self): + self.assertEqual(Clock(2, 2), Clock(2, 4322)) + + def test_clocks_with_negative_minute(self): + self.assertEqual(Clock(2, 40), Clock(3, -20)) + + def test_clocks_with_negative_minute_that_wraps(self): + self.assertEqual(Clock(4, 10), Clock(5, -1490)) + + def test_clocks_with_negative_minute_that_wraps_multiple_times(self): + self.assertEqual(Clock(6, 15), Clock(6, -4305)) + + def test_clocks_with_negative_hours_and_minutes(self): + self.assertEqual(Clock(7, 32), Clock(-12, -268)) + + def test_clocks_with_negative_hours_and_minutes_that_wrap(self): + self.assertEqual(Clock(18, 7), Clock(-54, -11513)) + +if __name__ == '__main__': + unittest.main() diff --git a/exercises/clock/example.py b/exercises/clock/example.py new file mode 100644 index 00000000000..8ff1e686ccb --- /dev/null +++ b/exercises/clock/example.py @@ -0,0 +1,24 @@ + +class Clock: + 'Clock that displays 24 hour clock that rollsover properly' + + def __init__(self, hour, minute): + self.hour = hour + self.minute = minute + self.cleanup() + + def __repr__(self): + return "%02d:%02d" % (self.hour, self.minute) + + def __eq__(self, other): + return repr(self) == repr(other) + + def add(self, minutes): + self.minute += minutes + return self.cleanup() + + def cleanup(self): + self.hour += self.minute // 60 + self.hour %= 24 + self.minute %= 60 + return self From fd98f9a082f743f52484ed182429e6323fb18f7a Mon Sep 17 00:00:00 2001 From: Chris Reister Date: Tue, 21 Jun 2016 20:29:06 -0700 Subject: [PATCH 47/81] clock: fixed formatting --- exercises/clock/clock_test.py | 2 +- exercises/clock/example.py | 36 +++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/exercises/clock/clock_test.py b/exercises/clock/clock_test.py index bef54b50fd1..8c7845cf2d5 100644 --- a/exercises/clock/clock_test.py +++ b/exercises/clock/clock_test.py @@ -28,7 +28,7 @@ def test_minutes_roll_over(self): def test_minutes_roll_over_continuously(self): self.assertEqual('04:43', str(Clock(0, 1723))) - + def test_hour_and_minutes_roll_over(self): self.assertEqual('03:40', str(Clock(25, 160))) diff --git a/exercises/clock/example.py b/exercises/clock/example.py index 8ff1e686ccb..bbf39fd5072 100644 --- a/exercises/clock/example.py +++ b/exercises/clock/example.py @@ -1,24 +1,24 @@ 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 - self.minute = minute - self.cleanup() + def __init__(self, hour, minute): + self.hour = hour + self.minute = minute + self.cleanup() - def __repr__(self): - return "%02d:%02d" % (self.hour, self.minute) + def __repr__(self): + return "%02d:%02d" % (self.hour, self.minute) - def __eq__(self, other): - return repr(self) == repr(other) + def __eq__(self, other): + return repr(self) == repr(other) - def add(self, minutes): - self.minute += minutes - return self.cleanup() - - def cleanup(self): - self.hour += self.minute // 60 - self.hour %= 24 - self.minute %= 60 - return self + def add(self, minutes): + self.minute += minutes + return self.cleanup() + + def cleanup(self): + self.hour += self.minute // 60 + self.hour %= 24 + self.minute %= 60 + return self From ecb9ac47e783d637f8233adc6c9fc3a14e7336a4 Mon Sep 17 00:00:00 2001 From: Patrick Jackson Date: Sun, 26 Jun 2016 16:44:37 -0700 Subject: [PATCH 48/81] sublist: Adding test for unique return values --- exercises/sublist/sublist_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exercises/sublist/sublist_test.py b/exercises/sublist/sublist_test.py index 0ac0aa29804..791101f22ce 100644 --- a/exercises/sublist/sublist_test.py +++ b/exercises/sublist/sublist_test.py @@ -4,6 +4,9 @@ class SublistTest(unittest.TestCase): + def test_unique_return_vals(self): + self.assertEqual(4, len(set([SUBLIST, SUPERLIST, EQUAL, UNEQUAL]))) + def test_empty_lists(self): self.assertEqual(EQUAL, check_lists([], [])) From a1323ad50bd54a1f5b5b9fbd59b74ab5c431b936 Mon Sep 17 00:00:00 2001 From: Patrick Jackson Date: Wed, 20 Jul 2016 13:03:07 -0700 Subject: [PATCH 49/81] pangram: Update pangram test suite Updates the pangram test suite to match the new json file in x-common. Resolves #337 --- exercises/pangram/pangram_test.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/exercises/pangram/pangram_test.py b/exercises/pangram/pangram_test.py index 3825f958e53..03b01b50f20 100644 --- a/exercises/pangram/pangram_test.py +++ b/exercises/pangram/pangram_test.py @@ -14,14 +14,26 @@ def test_valid_pangram(self): self.assertTrue( is_pangram('the quick brown fox jumps over the lazy dog')) - def test_invalid_pangram(self): - self.assertFalse( - is_pangram('the quick brown fish jumps over the lazy dog')) - def test_missing_x(self): self.assertFalse(is_pangram('a quick movement of the enemy will ' 'jeopardize five gunboats')) + def test_another_missing_character(self): + self.assertFalse( + is_pangram('the quick brown fish jumps over the lazy dog')) + + def test_pangram_with_underscores(self): + self.assertTrue( + is_pangram("the_quick_brown_fox_jumps_over_the_lazy_dog")) + + def test_pangram_with_numbers(self): + self.assertTrue( + is_pangram("the 1 quick brown fox jumps over the 2 lazy dogs")) + + def test_missing_letters_replaced_by_numbers(self): + self.assertFalse( + is_pangram("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog")) + def test_mixedcase_and_punctuation(self): self.assertTrue(is_pangram('"Five quacking Zephyrs jolt my wax bed."')) From 7cacb3166c1dc58f36e229f0c6dd0934bf93834a Mon Sep 17 00:00:00 2001 From: "I can not only fetch JSON, but parse it too" Date: Wed, 20 Jul 2016 15:41:22 -0700 Subject: [PATCH 50/81] Updated ReadMe.md Added Gitter badge to ReadMe --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8175a54c330..3708529b7ff 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # xPython [![Build Status](https://travis-ci.org/exercism/xpython.png?branch=master)](https://travis-ci.org/exercism/xpython) [![Requirements Status](https://requires.io/github/exercism/xpython/requirements.svg?branch=master)](https://requires.io/github/exercism/xpython/requirements/?branch=master) +[![Join the chat at https://gitter.im/exercism/xpython](https://badges.gitter.im/exercism/xpython.svg)](https://gitter.im/exercism/xpython?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Exercism exercises in Python From 1861f957d06e8d9c6c8c51f8d49ccc8bd5a11b88 Mon Sep 17 00:00:00 2001 From: Patrick Jackson Date: Thu, 21 Jul 2016 10:49:43 -0700 Subject: [PATCH 51/81] bob: Adding non-question trailing whitespace test As suggested by @matts-code Resolves #312 --- exercises/bob/bob_test.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/exercises/bob/bob_test.py b/exercises/bob/bob_test.py index 689d053c015..85f79c9c6b6 100644 --- a/exercises/bob/bob_test.py +++ b/exercises/bob/bob_test.py @@ -114,5 +114,10 @@ def test_ends_with_whitespace(self): 'Sure.', bob.hey('What if we end with whitespace? ') ) + def test_non_question_ends_with_whitespace(self): + self.assertEqual( + 'Whatever.', bob.hey('This is a statement with trailing whitespace ') + ) + if __name__ == '__main__': unittest.main() From 11a2040767da1271a1d63bb9639af773b8e7e91f Mon Sep 17 00:00:00 2001 From: Dog Date: Thu, 21 Jul 2016 12:07:33 -0700 Subject: [PATCH 52/81] xPython: Moving old exercise PRs to new organization --- .../circular-buffer}/circular_buffer_test.py | 0 {circular-buffer => exercises/circular-buffer}/example.py | 0 {perfect-numbers => exercises/perfect-numbers}/example.py | 0 .../perfect-numbers}/perfect_numbers_test.py | 0 {rail-fence-cipher => exercises/rail-fence-cipher}/example.py | 0 .../rail-fence-cipher}/rail_fence_cipher_test.py | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename {circular-buffer => exercises/circular-buffer}/circular_buffer_test.py (100%) rename {circular-buffer => exercises/circular-buffer}/example.py (100%) rename {perfect-numbers => exercises/perfect-numbers}/example.py (100%) rename {perfect-numbers => exercises/perfect-numbers}/perfect_numbers_test.py (100%) rename {rail-fence-cipher => exercises/rail-fence-cipher}/example.py (100%) rename {rail-fence-cipher => exercises/rail-fence-cipher}/rail_fence_cipher_test.py (100%) diff --git a/circular-buffer/circular_buffer_test.py b/exercises/circular-buffer/circular_buffer_test.py similarity index 100% rename from circular-buffer/circular_buffer_test.py rename to exercises/circular-buffer/circular_buffer_test.py diff --git a/circular-buffer/example.py b/exercises/circular-buffer/example.py similarity index 100% rename from circular-buffer/example.py rename to exercises/circular-buffer/example.py diff --git a/perfect-numbers/example.py b/exercises/perfect-numbers/example.py similarity index 100% rename from perfect-numbers/example.py rename to exercises/perfect-numbers/example.py diff --git a/perfect-numbers/perfect_numbers_test.py b/exercises/perfect-numbers/perfect_numbers_test.py similarity index 100% rename from perfect-numbers/perfect_numbers_test.py rename to exercises/perfect-numbers/perfect_numbers_test.py diff --git a/rail-fence-cipher/example.py b/exercises/rail-fence-cipher/example.py similarity index 100% rename from rail-fence-cipher/example.py rename to exercises/rail-fence-cipher/example.py diff --git a/rail-fence-cipher/rail_fence_cipher_test.py b/exercises/rail-fence-cipher/rail_fence_cipher_test.py similarity index 100% rename from rail-fence-cipher/rail_fence_cipher_test.py rename to exercises/rail-fence-cipher/rail_fence_cipher_test.py From a457845a3d649feffe41d1b6f459c88b4eb0af4a Mon Sep 17 00:00:00 2001 From: Sean Marzug-McCarthy Date: Wed, 3 Aug 2016 12:42:12 -0400 Subject: [PATCH 53/81] Word-count test name fix This test says "preserves_punction" when it's really testing that punctuation is being ignored (i.e. not included in the list of words being counted). --- exercises/word-count/word_count_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/word-count/word_count_test.py b/exercises/word-count/word_count_test.py index 1c3373c42e3..902bafc627c 100644 --- a/exercises/word-count/word_count_test.py +++ b/exercises/word-count/word_count_test.py @@ -32,7 +32,7 @@ def test_count_multiple_occurences(self): word_count('one fish two fish red fish blue fish') ) - def test_preserves_punctuation(self): + def test_ignores_punctuation(self): self.assertEqual( {'car': 1, 'carpet': 1, 'as': 1, 'java': 1, 'javascript': 1}, word_count('car : carpet as java : javascript!!&@$%^&') From 404c25ceed3a6190e018506dedba5c7dc8c927c6 Mon Sep 17 00:00:00 2001 From: Rootul Patel Date: Thu, 11 Aug 2016 19:11:43 -0400 Subject: [PATCH 54/81] Clock: remove duplicated tests (#350) * Clock: remove duplicated tests * Clock: change equality test_clocks_with_hour_overflow is supposed to test for equality --- exercises/clock/clock_test.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/exercises/clock/clock_test.py b/exercises/clock/clock_test.py index 8c7845cf2d5..01d6ec134cc 100644 --- a/exercises/clock/clock_test.py +++ b/exercises/clock/clock_test.py @@ -121,18 +121,6 @@ def test_clocks_a_minute_apart(self): def test_clocks_an_hour_apart(self): self.assertNotEqual(Clock(14, 37), Clock(15, 37)) - def test_clocks_with_hour_overflow(self): - self.assertNotEqual(Clock(10, 37), Clock(34, 37)) - - def test_clocks_with_hour_overflow_by_several_days(self): - self.assertEqual(Clock(3, 11), Clock(99, 11)) - - def test_clocks_a_minute_apart(self): - self.assertNotEqual(Clock(15, 36), Clock(15, 37)) - - def test_clocks_an_hour_apart(self): - self.assertNotEqual(Clock(14, 37), Clock(15, 37)) - def test_clocks_with_hour_overflow(self): self.assertEqual(Clock(10, 37), Clock(34, 37)) From 9ae3ba6c257ab3511da66923cbbc7b4a647f7396 Mon Sep 17 00:00:00 2001 From: Kevin Engle Date: Wed, 17 Aug 2016 11:57:29 -0700 Subject: [PATCH 55/81] xpython: first pass standardizing exercise names #344 --- exercises/beer-song/beer_song_test.py | 2 +- exercises/circular-buffer/circular_buffer_test.py | 7 +++++-- exercises/grade-school/grade_school_test.py | 2 +- exercises/kindergarten-garden/kindergarten_garden_test.py | 2 +- .../largest-series-product/largest_series_product_test.py | 2 +- exercises/leap/leap_test.py | 2 +- exercises/nth-prime/nth_prime_test.py | 2 +- exercises/nucleotide-count/nucleotide_count_test.py | 2 +- exercises/ocr-numbers/ocr_test.py | 2 +- exercises/palindrome-products/palindrome_products_test.py | 2 +- exercises/perfect-numbers/perfect_numbers_test.py | 2 +- exercises/phone-number/phone_number_test.py | 2 +- exercises/point-mutations/point_mutations_test.py | 2 +- exercises/rna-transcription/rna_transcription_test.py | 2 +- exercises/robot-name/robot_name_test.py | 2 +- exercises/roman-numerals/roman_numerals_test.py | 2 +- exercises/scrabble-score/scrabble_score_test.py | 2 +- exercises/secret-handshake/handshake_test.py | 2 +- exercises/simple-cipher/simple_cipher_test.py | 2 +- exercises/word-count/word_count_test.py | 2 +- 20 files changed, 24 insertions(+), 21 deletions(-) diff --git a/exercises/beer-song/beer_song_test.py b/exercises/beer-song/beer_song_test.py index 719372d3553..f05b8d02814 100644 --- a/exercises/beer-song/beer_song_test.py +++ b/exercises/beer-song/beer_song_test.py @@ -1,6 +1,6 @@ import unittest -from beer import song, verse +from beer_song import song, verse class BeerTest(unittest.TestCase): diff --git a/exercises/circular-buffer/circular_buffer_test.py b/exercises/circular-buffer/circular_buffer_test.py index 75cad02c3db..a51a2d7a942 100644 --- a/exercises/circular-buffer/circular_buffer_test.py +++ b/exercises/circular-buffer/circular_buffer_test.py @@ -1,7 +1,10 @@ import unittest -from circular_buffer import CircularBuffer -from circular_buffer import BufferFullException, BufferEmptyException +from circular_buffer import ( + CircularBuffer, + BufferFullException, + BufferEmptyException +) class CircularBufferTest(unittest.TestCase): diff --git a/exercises/grade-school/grade_school_test.py b/exercises/grade-school/grade_school_test.py index ebbfced7073..be22eaa0646 100644 --- a/exercises/grade-school/grade_school_test.py +++ b/exercises/grade-school/grade_school_test.py @@ -2,7 +2,7 @@ from types import GeneratorType import unittest -from school import School +from grade_school import School class SchoolTest(unittest.TestCase): diff --git a/exercises/kindergarten-garden/kindergarten_garden_test.py b/exercises/kindergarten-garden/kindergarten_garden_test.py index a9ce5690d79..258d47726be 100644 --- a/exercises/kindergarten-garden/kindergarten_garden_test.py +++ b/exercises/kindergarten-garden/kindergarten_garden_test.py @@ -1,6 +1,6 @@ import unittest -from garden import Garden +from kindergarten_garden import Garden class KindergartenGardenTests(unittest.TestCase): diff --git a/exercises/largest-series-product/largest_series_product_test.py b/exercises/largest-series-product/largest_series_product_test.py index 2904576bde2..6f396a92335 100644 --- a/exercises/largest-series-product/largest_series_product_test.py +++ b/exercises/largest-series-product/largest_series_product_test.py @@ -8,7 +8,7 @@ """ import unittest -from series import largest_product +from largest_series_product import largest_product class SeriesTest(unittest.TestCase): diff --git a/exercises/leap/leap_test.py b/exercises/leap/leap_test.py index f38516b642f..7f6aff89b93 100644 --- a/exercises/leap/leap_test.py +++ b/exercises/leap/leap_test.py @@ -1,6 +1,6 @@ import unittest -from year import is_leap_year +from leap import is_leap_year class YearTest(unittest.TestCase): diff --git a/exercises/nth-prime/nth_prime_test.py b/exercises/nth-prime/nth_prime_test.py index 0fa054b1f3d..14530b315d3 100644 --- a/exercises/nth-prime/nth_prime_test.py +++ b/exercises/nth-prime/nth_prime_test.py @@ -1,6 +1,6 @@ import unittest -from prime import nth_prime +from nth_prime import nth_prime class NthPrimeTests(unittest.TestCase): diff --git a/exercises/nucleotide-count/nucleotide_count_test.py b/exercises/nucleotide-count/nucleotide_count_test.py index b6583bca220..13153649508 100644 --- a/exercises/nucleotide-count/nucleotide_count_test.py +++ b/exercises/nucleotide-count/nucleotide_count_test.py @@ -6,7 +6,7 @@ """ import unittest -from dna import count, nucleotide_counts +from nucleotide_count import count, nucleotide_counts class DNATest(unittest.TestCase): diff --git a/exercises/ocr-numbers/ocr_test.py b/exercises/ocr-numbers/ocr_test.py index c0891009fc4..0a85c79d1ed 100644 --- a/exercises/ocr-numbers/ocr_test.py +++ b/exercises/ocr-numbers/ocr_test.py @@ -8,7 +8,7 @@ import unittest -from ocr import grid, number +from ocr_numbers import grid, number class OcrTest(unittest.TestCase): diff --git a/exercises/palindrome-products/palindrome_products_test.py b/exercises/palindrome-products/palindrome_products_test.py index 36f94055195..8b35442a88c 100644 --- a/exercises/palindrome-products/palindrome_products_test.py +++ b/exercises/palindrome-products/palindrome_products_test.py @@ -13,7 +13,7 @@ import unittest -from palindrome import smallest_palindrome, largest_palindrome +from palindrome_products import smallest_palindrome, largest_palindrome class PalindromesTests(unittest.TestCase): diff --git a/exercises/perfect-numbers/perfect_numbers_test.py b/exercises/perfect-numbers/perfect_numbers_test.py index 4066f031eaf..0dafa350501 100644 --- a/exercises/perfect-numbers/perfect_numbers_test.py +++ b/exercises/perfect-numbers/perfect_numbers_test.py @@ -1,6 +1,6 @@ import unittest -from natural_numbers import is_perfect +from perfect_numbers import is_perfect class PerfectNumbersTest(unittest.TestCase): diff --git a/exercises/phone-number/phone_number_test.py b/exercises/phone-number/phone_number_test.py index 865f6ecf905..2875f136adf 100644 --- a/exercises/phone-number/phone_number_test.py +++ b/exercises/phone-number/phone_number_test.py @@ -1,6 +1,6 @@ import unittest -from phone import Phone +from phone_number import Phone class PhoneTest(unittest.TestCase): diff --git a/exercises/point-mutations/point_mutations_test.py b/exercises/point-mutations/point_mutations_test.py index da8935e46c0..51ad035147e 100644 --- a/exercises/point-mutations/point_mutations_test.py +++ b/exercises/point-mutations/point_mutations_test.py @@ -1,6 +1,6 @@ import unittest -from dna import hamming_distance +from point_mutations import hamming_distance class DNATest(unittest.TestCase): diff --git a/exercises/rna-transcription/rna_transcription_test.py b/exercises/rna-transcription/rna_transcription_test.py index aa5f40f57a8..d0597db10f8 100644 --- a/exercises/rna-transcription/rna_transcription_test.py +++ b/exercises/rna-transcription/rna_transcription_test.py @@ -1,6 +1,6 @@ import unittest -from dna import to_rna +from rna_transcription import to_rna class DNATests(unittest.TestCase): diff --git a/exercises/robot-name/robot_name_test.py b/exercises/robot-name/robot_name_test.py index 2d07bbe6d23..a83b412e905 100644 --- a/exercises/robot-name/robot_name_test.py +++ b/exercises/robot-name/robot_name_test.py @@ -1,6 +1,6 @@ import unittest -from robot import Robot +from robot_name import Robot import random diff --git a/exercises/roman-numerals/roman_numerals_test.py b/exercises/roman-numerals/roman_numerals_test.py index 4743326e74d..f6aea47da03 100644 --- a/exercises/roman-numerals/roman_numerals_test.py +++ b/exercises/roman-numerals/roman_numerals_test.py @@ -1,6 +1,6 @@ import unittest -import roman +import roman_numerals class RomanTest(unittest.TestCase): diff --git a/exercises/scrabble-score/scrabble_score_test.py b/exercises/scrabble-score/scrabble_score_test.py index 09ad00ad938..069c6fc98c8 100644 --- a/exercises/scrabble-score/scrabble_score_test.py +++ b/exercises/scrabble-score/scrabble_score_test.py @@ -1,6 +1,6 @@ import unittest -from scrabble import score +from scrabble_score import score class WordTest(unittest.TestCase): diff --git a/exercises/secret-handshake/handshake_test.py b/exercises/secret-handshake/handshake_test.py index b25fb524634..f55dd6b94e1 100644 --- a/exercises/secret-handshake/handshake_test.py +++ b/exercises/secret-handshake/handshake_test.py @@ -1,6 +1,6 @@ import unittest -from handshake import handshake, code +from secret_handshake import handshake, code class HandshakeTest(unittest.TestCase): diff --git a/exercises/simple-cipher/simple_cipher_test.py b/exercises/simple-cipher/simple_cipher_test.py index dd78d336e8b..4bbed1078ac 100644 --- a/exercises/simple-cipher/simple_cipher_test.py +++ b/exercises/simple-cipher/simple_cipher_test.py @@ -1,6 +1,6 @@ import unittest -from cipher import Caesar, Cipher +from simple_cipher import Caesar, Cipher class CipherTest(unittest.TestCase): diff --git a/exercises/word-count/word_count_test.py b/exercises/word-count/word_count_test.py index 902bafc627c..e7d2743486f 100644 --- a/exercises/word-count/word_count_test.py +++ b/exercises/word-count/word_count_test.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import unittest -from wordcount import word_count +from word_count import word_count # to be backwards compatible with the old Python 2.X From f5b8daeb0fd6397b0f7693215fb9e04571a47b41 Mon Sep 17 00:00:00 2001 From: Dog Date: Wed, 17 Aug 2016 23:06:29 -0700 Subject: [PATCH 56/81] roman_numerals: fixed class name in test --- exercises/roman-numerals/roman_numerals_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/roman-numerals/roman_numerals_test.py b/exercises/roman-numerals/roman_numerals_test.py index f6aea47da03..8807a8a8ada 100644 --- a/exercises/roman-numerals/roman_numerals_test.py +++ b/exercises/roman-numerals/roman_numerals_test.py @@ -27,7 +27,7 @@ class RomanTest(unittest.TestCase): def test_numerals(self): for arabic, numeral in self.numerals.items(): - self.assertEqual(numeral, roman.numeral(arabic)) + self.assertEqual(numeral, roman_numerals.numeral(arabic)) if __name__ == '__main__': unittest.main() From 869cfa2488b767e508337ab9514f6d211d107145 Mon Sep 17 00:00:00 2001 From: Roshan Jossey Date: Sat, 20 Aug 2016 22:39:52 +0530 Subject: [PATCH 57/81] Update config.json to match new specification > This addresses issue #353 --- config.json | 362 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+) diff --git a/config.json b/config.json index 05810d4e8e9..972c791c0e2 100644 --- a/config.json +++ b/config.json @@ -65,6 +65,368 @@ "zebra-puzzle", "rectangles" ], + "exercises": [ + { + "slug": "hello-world", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "leap", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "clock", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "pangram", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "rna-transcription", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "hamming", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "word-count", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "gigasecond", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "bob", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "run-length-encoding", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "meetup", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "difference-of-squares", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "anagram", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "allergies", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "series", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "robot-simulator", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "sieve", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "atbash-cipher", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "sum-of-multiples", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "acronym", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "say", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "largest-series-product", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "kindergarten-garden", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "grade-school", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "roman-numerals", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "space-age", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "grains", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "luhn", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "etl", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "prime-factors", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "pig-latin", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "simple-cipher", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "scrabble-score", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "crypto-square", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "sublist", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "pythagorean-triplet", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "circular-buffer", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "robot-name", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "matrix", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "rail-fence-cipher", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "nth-prime", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "saddle-points", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "beer-song", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "perfect-numbers", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "secret-handshake", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "twelve-days", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "binary", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "palindrome-products", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "bracket-push", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "hexadecimal", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "minesweeper", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "queen-attack", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "wordy", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "phone-number", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "ocr-numbers", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "house", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "triangle", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "poker", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "zebra-puzzle", + "difficulty": 1, + "topics": [ + ] + }, + { + "slug": "rectangles", + "difficulty": 1, + "topics": [ + ] + } + ], "deprecated": [ "accumulate", "nucleotide-count", From a2242eb8c91c0e68daf111ea0c787b22b59d6ac0 Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Fri, 26 Aug 2016 11:43:53 +0100 Subject: [PATCH 58/81] minor spelling correction --- exercises/sum-of-multiples/sum_of_multiples_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/sum-of-multiples/sum_of_multiples_test.py b/exercises/sum-of-multiples/sum_of_multiples_test.py index 2e90939a1dd..f6203fd232b 100644 --- a/exercises/sum-of-multiples/sum_of_multiples_test.py +++ b/exercises/sum-of-multiples/sum_of_multiples_test.py @@ -3,7 +3,7 @@ 'sum_of_multiples' function: * All input numbers are non-negative 'int's, i.e. natural numbers including zero. - * A list of factors must be given, and its elements are uniqe and sorted in + * A list of factors must be given, and its elements are unique and sorted in ascending order. """ From 2d11a2aeac05174771bd28752b5e66b5475e247e Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Fri, 26 Aug 2016 12:27:23 +0100 Subject: [PATCH 59/81] add topics to hello-world exercise in config.json --- config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.json b/config.json index 972c791c0e2..a6a4ccd3c66 100644 --- a/config.json +++ b/config.json @@ -70,6 +70,9 @@ "slug": "hello-world", "difficulty": 1, "topics": [ + "control-flow (if-statements)", + "optional values", + "text formatting" ] }, { From 58ea64750a57e5bac9acfa343ce7a1124bda025a Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Fri, 26 Aug 2016 12:38:11 +0100 Subject: [PATCH 60/81] add topics to leap problem in config.json --- config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.json b/config.json index 972c791c0e2..da9b1693ddf 100644 --- a/config.json +++ b/config.json @@ -76,6 +76,9 @@ "slug": "leap", "difficulty": 1, "topics": [ + "control-flow (if-else statements)", + "booleans", + "logic" ] }, { From e60844a6af538701c551f64c7827f4f4fe822741 Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Fri, 26 Aug 2016 12:49:23 +0100 Subject: [PATCH 61/81] add topics to clock exercise in config.json --- config.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index 972c791c0e2..49e7022e5ba 100644 --- a/config.json +++ b/config.json @@ -80,8 +80,13 @@ }, { "slug": "clock", - "difficulty": 1, + "difficulty": 2, "topics": [ + "classes", + "time", + "mathematics", + "logic", + "text formatting" ] }, { From d82341cb92e5536708a8f165a30db6aebcc617fc Mon Sep 17 00:00:00 2001 From: Patrick Jackson Date: Fri, 2 Sep 2016 11:38:31 -0700 Subject: [PATCH 62/81] style: Update README for style requirements --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3708529b7ff..c1d98e79838 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Exercism exercises in Python ## Contributing Guide -Please see the [contributing guide](https://github.com/exercism/x-api/blob/master/CONTRIBUTING.md#the-exercise-data) +Please see the [contributing guide](https://github.com/exercism/x-common/blob/master/CONTRIBUTING.md) ## Working on the Exercises @@ -33,8 +33,13 @@ python test/check-exercises.py ## Code Style -The Python code in this repo is meant to largely obey the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/) (not all code does though). -Try the [flake8](http://flake8.readthedocs.org/en/latest/) tool if you feel unsure about questions of style. +The Python code in this repo is meant to largely obey the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/). + +This repo uses [flake8](http://flake8.readthedocs.org/en/latest/) to enforce the coding standard. When you submit a PR, it needs to pass the flake8 tool with no warnings, or it won't be accepted. Here are the settings used by the build system: + +``` +flake8 [your-code-here.py] --max-line-length=99 --select=E,W +``` ## Pull Requests From 001b0b8a7cad22c3414ff936f6b35b8bd3f798d3 Mon Sep 17 00:00:00 2001 From: michaelkunc Date: Wed, 22 Jun 2016 15:23:42 -0700 Subject: [PATCH 63/81] Add binary-search exercise --- config.json | 3 ++- .../binary-search/.cache/v/cache/lastfailed | 1 + exercises/binary-search/.cache/v/pep8/mtimes | 10 +++++++ exercises/binary-search/binary_search_test.py | 27 +++++++++++++++++++ exercises/binary-search/example.py | 24 +++++++++++++++++ 5 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 exercises/binary-search/.cache/v/cache/lastfailed create mode 100644 exercises/binary-search/.cache/v/pep8/mtimes create mode 100644 exercises/binary-search/binary_search_test.py create mode 100644 exercises/binary-search/example.py diff --git a/config.json b/config.json index d9da06b46bb..6b2a16fc923 100644 --- a/config.json +++ b/config.json @@ -63,7 +63,8 @@ "triangle", "poker", "zebra-puzzle", - "rectangles" + "rectangles", + "binary-search" ], "exercises": [ { diff --git a/exercises/binary-search/.cache/v/cache/lastfailed b/exercises/binary-search/.cache/v/cache/lastfailed new file mode 100644 index 00000000000..9e26dfeeb6e --- /dev/null +++ b/exercises/binary-search/.cache/v/cache/lastfailed @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/exercises/binary-search/.cache/v/pep8/mtimes b/exercises/binary-search/.cache/v/pep8/mtimes new file mode 100644 index 00000000000..5667234fceb --- /dev/null +++ b/exercises/binary-search/.cache/v/pep8/mtimes @@ -0,0 +1,10 @@ +{ + "/Users/michaelkunc/Desktop/xpython/exercises/binary-search/binary_search_test.py": [ + 1472913663.0, + [] + ], + "/Users/michaelkunc/Desktop/xpython/exercises/binary-search/example.py": [ + 1472914065.0, + [] + ] +} \ No newline at end of file diff --git a/exercises/binary-search/binary_search_test.py b/exercises/binary-search/binary_search_test.py new file mode 100644 index 00000000000..df0b9fd063a --- /dev/null +++ b/exercises/binary-search/binary_search_test.py @@ -0,0 +1,27 @@ +import unittest + +from example import binary_search + + +class BinarySearchTests(unittest.TestCase): + + def test_raises_error_if_list_is_not_sorted(self): + self.assertRaises(ValueError, binary_search, [44, 5, 2, 1, 4], 6) + + def test_raises_error_if_list_is_empty(self): + self.assertRaises(ValueError, binary_search, [], 1) + + def test_list_item_not_found(self): + self.assertEqual("Item not found.", + binary_search([1, 2, 3, 4, 5, 6], 23)) + + def test_list_item_found(self): + self.assertEqual(3, binary_search([1, 2, 3, 4, 5, 6, 7, 8], 4)) + + def test_list_item_found_larger_list(self): + self.assertEqual(7, binary_search( + [1, 5, 6, 7, 8, 9, 12, 14, 16, 22, 47, 100, 123], 14)) + + +if __name__ == '__main__': + unittest.main() diff --git a/exercises/binary-search/example.py b/exercises/binary-search/example.py new file mode 100644 index 00000000000..5d7c505f427 --- /dev/null +++ b/exercises/binary-search/example.py @@ -0,0 +1,24 @@ +def binary_search(search_list, value): + list_empty(search_list) + list_sorted(search_list) + low = 0 + high = len(search_list) - 1 + while low <= high: + middle = (low + high) // 2 + if search_list[middle] > value: + high = middle - 1 + elif search_list[middle] < value: + low = middle + 1 + else: + return middle + return "Item not found." + + +def list_sorted(search_list): + if not sorted(search_list) == search_list: + raise ValueError("This list must be sorted.") + + +def list_empty(search_list): + if not search_list: + raise ValueError('This list has no items.') From d09f47e6db7097f069c4a68d93660033e6f4af6a Mon Sep 17 00:00:00 2001 From: Patrick Jackson Date: Wed, 7 Sep 2016 21:33:20 -0700 Subject: [PATCH 64/81] binary-search: clean up --- .../binary-search/.cache/v/cache/lastfailed | 1 - exercises/binary-search/.cache/v/pep8/mtimes | 10 ----- exercises/binary-search/binary_search_test.py | 40 +++++++++++++------ exercises/binary-search/example.py | 14 +------ 4 files changed, 28 insertions(+), 37 deletions(-) delete mode 100644 exercises/binary-search/.cache/v/cache/lastfailed delete mode 100644 exercises/binary-search/.cache/v/pep8/mtimes diff --git a/exercises/binary-search/.cache/v/cache/lastfailed b/exercises/binary-search/.cache/v/cache/lastfailed deleted file mode 100644 index 9e26dfeeb6e..00000000000 --- a/exercises/binary-search/.cache/v/cache/lastfailed +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/exercises/binary-search/.cache/v/pep8/mtimes b/exercises/binary-search/.cache/v/pep8/mtimes deleted file mode 100644 index 5667234fceb..00000000000 --- a/exercises/binary-search/.cache/v/pep8/mtimes +++ /dev/null @@ -1,10 +0,0 @@ -{ - "/Users/michaelkunc/Desktop/xpython/exercises/binary-search/binary_search_test.py": [ - 1472913663.0, - [] - ], - "/Users/michaelkunc/Desktop/xpython/exercises/binary-search/example.py": [ - 1472914065.0, - [] - ] -} \ No newline at end of file diff --git a/exercises/binary-search/binary_search_test.py b/exercises/binary-search/binary_search_test.py index df0b9fd063a..66782a69231 100644 --- a/exercises/binary-search/binary_search_test.py +++ b/exercises/binary-search/binary_search_test.py @@ -1,27 +1,41 @@ import unittest -from example import binary_search +from binary_search import binary_search class BinarySearchTests(unittest.TestCase): - def test_raises_error_if_list_is_not_sorted(self): - self.assertRaises(ValueError, binary_search, [44, 5, 2, 1, 4], 6) + def test_finds_value_in_array_with_one_element(self): + self.assertEqual(0, binary_search([6], 6)) - def test_raises_error_if_list_is_empty(self): - self.assertRaises(ValueError, binary_search, [], 1) + def test_finds_value_in_middle_of_array(self): + self.assertEqual(3, binary_search([1, 3, 4, 6, 8, 9, 11], 6)) + + def test_finds_value_at_beginning_of_array(self): + self.assertEqual(0, binary_search([1, 3, 4, 6, 8, 9, 11], 1)) + + def test_finds_value_at_end_of_array(self): + self.assertEqual(6, binary_search([1, 3, 4, 6, 8, 9, 11], 11)) - def test_list_item_not_found(self): - self.assertEqual("Item not found.", - binary_search([1, 2, 3, 4, 5, 6], 23)) + def test_finds_value_in_array_of_odd_length(self): + self.assertEqual(9, binary_search( + [1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634], 144)) - def test_list_item_found(self): - self.assertEqual(3, binary_search([1, 2, 3, 4, 5, 6, 7, 8], 4)) + def test_finds_value_in_array_of_even_length(self): + self.assertEqual(5, binary_search( + [1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377], 21)) - def test_list_item_found_larger_list(self): - self.assertEqual(7, binary_search( - [1, 5, 6, 7, 8, 9, 12, 14, 16, 22, 47, 100, 123], 14)) + def test_identifies_value_missing(self): + self.assertRaises(ValueError, binary_search, [1, 3, 4, 6, 8, 9, 11], 7) + def test_value_smaller_than_arrays_minimum(self): + self.assertRaises(ValueError, binary_search, [1, 3, 4, 6, 8, 9, 11], 0) + + def test_value_larger_than_arrays_maximum(self): + self.assertRaises(ValueError, binary_search, [1, 3, 4, 6, 8, 9, 11], 13) + + def test_empty_array(self): + self.assertRaises(ValueError, binary_search, [], 1) if __name__ == '__main__': unittest.main() diff --git a/exercises/binary-search/example.py b/exercises/binary-search/example.py index 5d7c505f427..0b8f73a3c74 100644 --- a/exercises/binary-search/example.py +++ b/exercises/binary-search/example.py @@ -1,6 +1,4 @@ def binary_search(search_list, value): - list_empty(search_list) - list_sorted(search_list) low = 0 high = len(search_list) - 1 while low <= high: @@ -11,14 +9,4 @@ def binary_search(search_list, value): low = middle + 1 else: return middle - return "Item not found." - - -def list_sorted(search_list): - if not sorted(search_list) == search_list: - raise ValueError("This list must be sorted.") - - -def list_empty(search_list): - if not search_list: - raise ValueError('This list has no items.') + raise ValueError("Value not found.") From 1444868b953c4d3df6551cbfd1e72199c639eb47 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Mon, 12 Sep 2016 13:46:21 +0200 Subject: [PATCH 65/81] binary-search: Add to "exercises" key in config Adds the exercise to the "exercises" key in the config.json (see #360). --- config.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config.json b/config.json index 6b2a16fc923..5e2206964a4 100644 --- a/config.json +++ b/config.json @@ -437,6 +437,12 @@ "difficulty": 1, "topics": [ ] + }, + { + "slug": "binary-search", + "difficulty": 1, + "topics": [ + ] } ], "deprecated": [ From 8768a72b02b09fc674ae46383581d21a2518d712 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Mon, 19 Sep 2016 15:26:27 -0700 Subject: [PATCH 66/81] Add binary search to 'exercises' in config --- config.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config.json b/config.json index 6b2a16fc923..5e2206964a4 100644 --- a/config.json +++ b/config.json @@ -437,6 +437,12 @@ "difficulty": 1, "topics": [ ] + }, + { + "slug": "binary-search", + "difficulty": 1, + "topics": [ + ] } ], "deprecated": [ From 5472721d3eb2dcad69b2931d4f1e5aeb7b931f94 Mon Sep 17 00:00:00 2001 From: Hebert Date: Wed, 28 Sep 2016 08:07:42 -0300 Subject: [PATCH 67/81] hello-world: Add two new test functions to test blank and none names (#362) * hello-world: Add two new test functions to test blank and none names * binary-search: Add to exercises key in config --- exercises/hello-world/hello_world_test.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/exercises/hello-world/hello_world_test.py b/exercises/hello-world/hello_world_test.py index a2d2b8c89d8..7fc4a4cf79c 100644 --- a/exercises/hello-world/hello_world_test.py +++ b/exercises/hello-world/hello_world_test.py @@ -32,5 +32,18 @@ def test_hello_with_umlaut_name(self): hello_world.hello('Jürgen') ) + def test_hello_with_blank_name(self): + self.assertEqual( + 'Hello, World!', + hello_world.hello('') + ) + + def test_hello_with_none_name(self): + self.assertEqual( + 'Hello, World!', + hello_world.hello(None) + ) + + if __name__ == '__main__': unittest.main() From f47ea3be80497395069254258330c350d81bb1c8 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Wed, 28 Sep 2016 13:23:22 +0200 Subject: [PATCH 68/81] Update flake8 and pyflakes to the latest version --- requirements-travis.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-travis.txt b/requirements-travis.txt index 1572c76e1b7..94524e36b90 100644 --- a/requirements-travis.txt +++ b/requirements-travis.txt @@ -1,3 +1,3 @@ -flake8>=2.5,<2.5.99 +flake8>=3.0,<3.0.99 pep8>=1.7,<1.7.99 -pyflakes>=1.1,<1.1.99 +pyflakes>=1.3,<1.3.99 From 98d0505f89a9be78d81883ec8ede8899c552c161 Mon Sep 17 00:00:00 2001 From: cat Date: Sun, 2 Oct 2016 11:16:36 -0400 Subject: [PATCH 69/81] Add attribution for the track icon ...from exercism.io/ATTRIBUTION.md, noting the permission they gave us a step in fixing https://github.com/exercism/exercism.io/issues/3112. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c1d98e79838..0f84684379b 100644 --- a/README.md +++ b/README.md @@ -61,3 +61,6 @@ If you're new to Git take a look at [this short guide](https://github.com/exerci The MIT License (MIT) Copyright (c) 2014 Katrina Owen, _@kytrinyx.com + +## Python icon +The Python logo is an unregistered trademark. We are using a derived logo with the permission of the Python Software Foundation. From 66b5506bac07aa6d2234feefb5184421256f666a Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Fri, 7 Oct 2016 11:41:12 +0100 Subject: [PATCH 70/81] change if-statements to if-else statements this keeps it in line with the TOPICS list --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 5e2206964a4..780e98976b6 100644 --- a/config.json +++ b/config.json @@ -71,7 +71,7 @@ "slug": "hello-world", "difficulty": 1, "topics": [ - "control-flow (if-statements)", + "control-flow (if-else statements)", "optional values", "text formatting" ] From 8b08a8f67fb85206c7abf87c19fa6b25236eb92a Mon Sep 17 00:00:00 2001 From: Suraj Narwade Date: Wed, 19 Oct 2016 19:45:48 +0530 Subject: [PATCH 71/81] Add Python 3.6 in travis (#366) --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 78f6521ae39..51827ba552c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,10 @@ python: - 3.4 - 3.5 +matrix: + allow_failures: + - python: 'nightly' + install: - pip install -r requirements-travis.txt From 1399276dd87106678ecaf5d000cc0ee462dbfc17 Mon Sep 17 00:00:00 2001 From: Trey Hunner Date: Wed, 19 Oct 2016 07:17:43 -0700 Subject: [PATCH 72/81] Add flatten array exercise --- config.json | 7 ++++ exercises/flatten-array/example.py | 18 +++++++++ exercises/flatten-array/flatten_array_test.py | 40 +++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 exercises/flatten-array/example.py create mode 100644 exercises/flatten-array/flatten_array_test.py diff --git a/config.json b/config.json index 780e98976b6..2e73f80a74e 100644 --- a/config.json +++ b/config.json @@ -28,6 +28,7 @@ "largest-series-product", "kindergarten-garden", "grade-school", + "flatten-array", "roman-numerals", "space-age", "grains", @@ -222,6 +223,12 @@ "topics": [ ] }, + { + "slug": "flatten-array", + "difficulty": 1, + "topics": [ + ] + }, { "slug": "roman-numerals", "difficulty": 1, diff --git a/exercises/flatten-array/example.py b/exercises/flatten-array/example.py new file mode 100644 index 00000000000..424f01e0c81 --- /dev/null +++ b/exercises/flatten-array/example.py @@ -0,0 +1,18 @@ +def is_iterable(thing): + try: + iter(thing) + except TypeError: + return False + else: + return True + + +def flatten(iterable): + """Flatten a list of lists.""" + flattened = [] + for item in iterable: + if is_iterable(item) and not isinstance(item, (str, bytes)): + flattened += flatten(item) + elif item is not None: + flattened.append(item) + return flattened diff --git a/exercises/flatten-array/flatten_array_test.py b/exercises/flatten-array/flatten_array_test.py new file mode 100644 index 00000000000..98797e83d4d --- /dev/null +++ b/exercises/flatten-array/flatten_array_test.py @@ -0,0 +1,40 @@ +import unittest + +from flatten_array import flatten + + +class FlattenArrayTests(unittest.TestCase): + + def test_no_nesting(self): + self.assertEqual(flatten([0, 1, 2]), [0, 1, 2]) + + def test_one_level_nesting(self): + self.assertEqual(flatten([0, [1], 2]), [0, 1, 2]) + + def test_two_level_nesting(self): + self.assertEqual(flatten([0, [1, [2, 3]], [4]]), [0, 1, 2, 3, 4]) + + def test_empty_nested_lists(self): + self.assertEqual(flatten([[()]]), []) + + def test_with_none_values(self): + inputs = [0, 2, [[2, 3], 8, [[100]], None, [[None]]], -2] + expected = [0, 2, 2, 3, 8, 100, -2] + self.assertEqual(flatten(inputs), expected) + + def test_six_level_nesting(self): + inputs = [1, [2, [[3]], [4, [[5]]], 6, 7], 8] + expected = [1, 2, 3, 4, 5, 6, 7, 8] + self.assertEqual(flatten(inputs), expected) + + def test_all_values_are_none(self): + inputs = [None, [[[None]]], None, None, [[None, None], None], None] + expected = [] + self.assertEqual(flatten(inputs), expected) + + def test_strings(self): + self.assertEqual(flatten(['0', ['1', '2']]), ['0', '1', '2']) + + +if __name__ == '__main__': + unittest.main() From 5a36197f1b9f812c7eaf8c58180cb338d600549c Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Wed, 19 Oct 2016 15:19:16 +0100 Subject: [PATCH 73/81] Add topics to word-count exercise in config.json addresses #353 --- config.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/config.json b/config.json index 2e73f80a74e..d8d88911155 100644 --- a/config.json +++ b/config.json @@ -117,8 +117,13 @@ }, { "slug": "word-count", - "difficulty": 1, + "difficulty": 3, "topics": [ + "strings", + "algorithms", + "logic", + "pattern recognition", + "text formatting" ] }, { From 99b9dfd3c260dad5c2f033aefaa232a2a65c288c Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Wed, 19 Oct 2016 15:20:00 +0100 Subject: [PATCH 74/81] Add topics to hamming exercise in config.json addresses #353 --- config.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config.json b/config.json index d8d88911155..dcb6197578a 100644 --- a/config.json +++ b/config.json @@ -113,6 +113,14 @@ "slug": "hamming", "difficulty": 1, "topics": [ + "control-flow (if-else statements)", + "control-flow (loops)", + "sequences", + "sets", + "strings", + "algorithms", + "filtering", + "logic" ] }, { From 977d0e96354fa02114d5ed2261f155e54e34b467 Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Wed, 19 Oct 2016 15:20:27 +0100 Subject: [PATCH 75/81] Add topics to rna-transcription exercise in config.json addresses #353 --- config.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config.json b/config.json index dcb6197578a..5a275149860 100644 --- a/config.json +++ b/config.json @@ -107,6 +107,12 @@ "slug": "rna-transcription", "difficulty": 1, "topics": [ + "control-flow (if-else statements)", + "control-flow (loops)", + "maps", + "strings", + "logic", + "transforming" ] }, { From a0586b64211ec0f626f35ddbb81a0ec8c0832b4a Mon Sep 17 00:00:00 2001 From: Rob Phoenix Date: Wed, 19 Oct 2016 15:21:08 +0100 Subject: [PATCH 76/81] Add topics to pangram exercise in config.json addresses #353 --- config.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config.json b/config.json index 5a275149860..bed4aeee9a5 100644 --- a/config.json +++ b/config.json @@ -101,6 +101,12 @@ "slug": "pangram", "difficulty": 1, "topics": [ + "control-flow (loops)", + "control-flow (if-else statements)", + "strings", + "algorithms", + "filtering", + "logic" ] }, { From 6680c452d317acf3f6666d053602113df988d61a Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Wed, 19 Oct 2016 16:28:20 +0200 Subject: [PATCH 77/81] Activate Python 3.6 (nightly) test build see #366 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 51827ba552c..026ba228e60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,11 @@ python: - 3.3 - 3.4 - 3.5 + - nightly matrix: allow_failures: - - python: 'nightly' + - python: nightly install: - pip install -r requirements-travis.txt From 01d8dc3b77a363ddf34e682f4cef1cfd36802633 Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Wed, 19 Oct 2016 17:04:07 +0200 Subject: [PATCH 78/81] Fix assertRegexpMatches() deprecation warning --- exercises/robot-name/robot_name_test.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/exercises/robot-name/robot_name_test.py b/exercises/robot-name/robot_name_test.py index a83b412e905..bc234d50440 100644 --- a/exercises/robot-name/robot_name_test.py +++ b/exercises/robot-name/robot_name_test.py @@ -5,10 +5,15 @@ class RobotTest(unittest.TestCase): + # assertRegex() alias to adress DeprecationWarning + # assertRegexpMatches got renamed in version 3.2 + if not hasattr(unittest.TestCase, "assertRegex"): + assertRegex = unittest.TestCase.assertRegexpMatches + name_re = r'^[A-Z]{2}\d{3}$' def test_has_name(self): - self.assertRegexpMatches(Robot().name, self.name_re) + self.assertRegex(Robot().name, self.name_re) def test_name_sticks(self): robot = Robot() @@ -39,7 +44,8 @@ def test_reset_name(self): robot.reset() name2 = robot.name self.assertNotEqual(name, name2) - self.assertRegexpMatches(name2, self.name_re) + self.assertRegex(name2, self.name_re) + if __name__ == '__main__': unittest.main() From b414a74104d6976186c902012512a04b480ca35e Mon Sep 17 00:00:00 2001 From: Tammo Behrends Date: Sat, 22 Oct 2016 16:17:55 +0200 Subject: [PATCH 79/81] Remove deprecated problems key The **problems** key is deprecated in favour of **exercises** so it can be removed. We have confirmation from https://github.com/exercism/x-api/pull/137 that it is safe to *delete* the problems key. --- config.json | 64 ----------------------------------------------------- 1 file changed, 64 deletions(-) diff --git a/config.json b/config.json index bed4aeee9a5..188b16e5b92 100644 --- a/config.json +++ b/config.json @@ -3,70 +3,6 @@ "language": "Python", "repository": "https://github.com/exercism/xpython", "active": true, - "problems": [ - "hello-world", - "leap", - "clock", - "pangram", - "rna-transcription", - "hamming", - "word-count", - "gigasecond", - "bob", - "run-length-encoding", - "meetup", - "difference-of-squares", - "anagram", - "allergies", - "series", - "robot-simulator", - "sieve", - "atbash-cipher", - "sum-of-multiples", - "acronym", - "say", - "largest-series-product", - "kindergarten-garden", - "grade-school", - "flatten-array", - "roman-numerals", - "space-age", - "grains", - "luhn", - "etl", - "prime-factors", - "pig-latin", - "simple-cipher", - "scrabble-score", - "crypto-square", - "sublist", - "pythagorean-triplet", - "circular-buffer", - "robot-name", - "matrix", - "rail-fence-cipher", - "nth-prime", - "saddle-points", - "beer-song", - "perfect-numbers", - "secret-handshake", - "twelve-days", - "binary", - "palindrome-products", - "bracket-push", - "hexadecimal", - "minesweeper", - "queen-attack", - "wordy", - "phone-number", - "ocr-numbers", - "house", - "triangle", - "poker", - "zebra-puzzle", - "rectangles", - "binary-search" - ], "exercises": [ { "slug": "hello-world", From 346025577bba0f70fa8efe07f1c3fa7b61ecf812 Mon Sep 17 00:00:00 2001 From: Katrina Owen Date: Wed, 25 Nov 2015 12:41:05 -0700 Subject: [PATCH 80/81] Clean up docs for x-api v3 --- docs/HELLO.md | 0 docs/INSTALLATION.md | 11 ++++++- docs/LEARNING.md | 2 ++ docs/RESOURCES.md | 75 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 82 insertions(+), 6 deletions(-) delete mode 100644 docs/HELLO.md diff --git a/docs/HELLO.md b/docs/HELLO.md deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 625e1aa1cfc..1c736e86daf 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -2,9 +2,18 @@ If Python isn't already available on your system follow the instructions at [the Exercism currently supports Python3.4, Python3.3 and Python2.7. - ## Packages The [Python Package Index](https://pypi.python.org/pypi) contains thousands of packages. Pretty much each of them is installable with `pip install packagename`. If you don't have __pip__ already, [get it now](https://pip.pypa.io/en/latest/installing.html)! + +## Tests + +We recommend you install [pytest](http://pytest.org/latest/) and [pytest-cache](http://pythonhosted.org/pytest-cache/). Pytest is a testing tool that will give you more flexibility over running your unit tests. + +### Installation + +```bash +$ pip install pytest pytest-cache +``` diff --git a/docs/LEARNING.md b/docs/LEARNING.md index 292d3f9dcbb..af061eda0bf 100644 --- a/docs/LEARNING.md +++ b/docs/LEARNING.md @@ -14,5 +14,7 @@ With this premise, a good, beginner friendly, starting point for those who don't - [Python3 Beginner Tutorial](https://www.youtube.com/playlist?list=PL1A2CSdiySGJd0LJRRSwQZbPZaDP0q67j) - [Learn Python The Hard Way (Book)](http://learnpythonthehardway.org/book/) - [Offical Python3 **Documentation** and **Reference**](https://docs.python.org/3/) +- [The Python3 Tutorial](https://docs.python.org/3/tutorial/) - [Learn X in Y minutes (where X = Python3)](https://learnxinyminutes.com/docs/python3/) - [The Hitchhiker’s Guide to Python](http://docs.python-guide.org/en/latest/) +- [Think Python](http://www.greenteapress.com/thinkpython/html/index.html) diff --git a/docs/RESOURCES.md b/docs/RESOURCES.md index 2c4a4a6eea2..d5429b51ddb 100644 --- a/docs/RESOURCES.md +++ b/docs/RESOURCES.md @@ -1,6 +1,71 @@ -## Recommended learning resources +####PDB -* [The Python Tutorial](https://docs.python.org/3/tutorial/) -* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) -* [Think Python](http://www.greenteapress.com/thinkpython/html/index.html) -* [The Python Library Reference](https://docs.python.org/3/library/index.html) +Will drop you into the python debugger when a test fails. +To learn how to use pdb, check out the [documentation](https://docs.python.org/2/library/pdb.html#debugger-commands). + +You may also be interested in watching [Clayton Parker's "So you think you can pdb?" PyCon 2015 talk](https://www.youtube.com/watch?v=P0pIW5tJrRM) + +```bash +$ cd exercism/python/bob +$ py.test --pdb bob_test.py +``` + +####PEP8 + +PEP8 is the [python style guide](https://www.python.org/dev/peps/pep-0008/). If you would like to test for compliance to the style guide, install [pytest-pep8](https://pypi.python.org/pypi/pytest-pep8) + +```bash +$ pip install pytest-pep8 +``` + +and add the pep8 flag to your command + +```bash +$ cd exercism/python/bob +$ py.test --pep8 bob_test.py +``` + +Read the [pytest documentation](http://pytest.org/latest/contents.html#toc) and [pytest-cache](http://pythonhosted.org/pytest-cache/) documentation to learn more. + +## Visual Studio on Windows + +Follow the installation instructions for [Python Tools for Visual Studio](https://pytools.codeplex.com/wikipage?title=PTVS%20Installation) + +You can either start by creating your own project for working with the Exercism problems or you can download a Visual Studio solution that is already set up. + +### Exercism.io Visual Studio Template + +This is a Visual Studio template that comes pre-configured to work on the problems in as many languages as Visual Studio supports. + +![Solution Explorer](http://x.exercism.io/v3/tracks/python/docs/img/SolutionExplorer.png) + +1. Download the [Exercism.io Visual Studio Template](https://github.com/rprouse/Exercism.VisualStudio) from GitHub by clicking the Download Zip button on the page. +2. Unzip the template into your exercises directory, for example `C:\src\exercises` +2. Install the [Exercism CLI](http://help.exercism.io/installing-the-cli.html) +3. Open a command prompt to your exercise directory +4. Add your API key to exercism `exercism configure --key=YOUR_API_KEY` +5. Configure your source directory in exercism `exercism configure --dir=C:\src\exercises` +6. [Fetch your first exercise](http://help.exercism.io/fetching-exercises.html) `exercism fetch python` +7. Open the Exercism solution in Visual Studio +8. Expand the Exercism.python project +9. Click on **Show All Files** in Solution Explorer (See below) +10. The exercise you just fetched will appear greyed out. Right click on the folder and **Include In Project** +11. Get coding... + +![Add files](http://x.exercism.io/v3/tracks/python/docs/img/AddFiles.png) + +To run the tests, you can do so at the command line, or within Visual Studio. + +![Test Explorer](http://x.exercism.io/v3/tracks/python/docs/img/TestExplorer.png) + +## Code Style and Linting + +There's a style guide called [PEP8](http://legacy.python.org/dev/peps/pep-0008/) that many Python projects adhere to. +Read it when you get a chance! + +If you just want a quick overview of some problems in your code, use [pylint](http://www.pylint.org/)! +It can be pretty picky though, so take its results with a grain of salt. +If you don't agree with one of its points, that's a good topic for a discussion in the comments for your program! + +If you'd rather have a tool take care of your style issues, take a look at [autopep8](https://github.com/hhatto/autopep8)! +Run `autopep8 -d mycode.py` to get a diff of the changes it proposes and `autopep8 -i mycode.py` to format the code inplace! From 0604e1f67395fb47f2c80c591ffbf69325f19ec2 Mon Sep 17 00:00:00 2001 From: Ramiro Batista da Luz Date: Mon, 7 Dec 2015 16:11:26 -0200 Subject: [PATCH 81/81] Add ABOUT page. --- docs/ABOUT.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/ABOUT.md b/docs/ABOUT.md index e0ab937866e..adb4e309001 100644 --- a/docs/ABOUT.md +++ b/docs/ABOUT.md @@ -1,3 +1,5 @@ +Python is a powerful programming language, it is well known as a "glue" that means: it is used with many other technologies. It is multi platform, runs everywhere. Is friendly and easy to learn. It is licensed as open source, most versions are compatible with the GPL with a few exceptions on old versions. But, one of the most cool things about Python is the community that is very helpful and collaborative. Take a look at: [About python](https://www.python.org/about/). + Python is a strong language for beginners. There are many resources available for programmers of all levels, the code is highly readable, and in many cases phrases are comparable to those in the English language. Code can be written and executed from the command line, in an interactive IPython session, or in a [Jupyter](http://jupyter.org) (IPython) notebook. The most common form of Python is compiled in C. This is often invisible to the beginning programmer, but if there are uses for which exceptionally fast implementation is needed then C extensions can be written to optimize Python execution. @@ -5,3 +7,41 @@ The most common form of Python is compiled in C. This is often invisible to the [Python is used extensively](https://www.python.org/about/apps/) in scientific computing, finance, games, networking, internet development, and in assembling pipelines of other programs. Python was started by Guido van Rossum in 1989. Its name is an homage to the comedy troupe Monty Python. Python 2 is used widely but support may end by 2020. Python 3 was introduced in 2008 and is beginning to be adopted more widely. They are similar, but users will encounter [some differences](http://blog.teamtreehouse.com/python-2-vs-python-3). Python development is shepherded by [The Python Software Foundation](https://www.python.org/about/) and there are active community-based user groups worldwide. + +### What python is good for? + +Python can be applied to many different classes of problems [what python is good for](https://docs.python.org/3/faq/general.html#what-is-python-good-for). It have a powerful standard library with string processing, Internet protocols, software engineering, operating system interfaces. Python also have a lot of third-party modules, easily found in The Python Package Index (PyPi). Python software covers areas such as: + +- [Web and Internet Development](https://www.python.org/about/apps/#web-and-internet-development) +- [Database Access](https://www.python.org/about/apps/#database-access) +- [Desktop GUIs](https://www.python.org/about/apps/#desktop-guis) +- [Scientific & Numeric](https://www.python.org/about/apps/#scientific-and-numeric) +- [Education](https://www.python.org/about/apps/#education) +- [Network Programming](https://www.python.org/about/apps/#network-programming) +- [Software & Game Development](https://www.python.org/about/apps/#software-development) + +### Who uses python? + +Let the names of just some companies talk by themselves[Success](https://www.python.org/about/success/). + +- [Industrial Light & Magic Runs on Python](https://www.python.org/about/success/ilm/) +- [D-Link Australia Uses Python to Control Firmware Updates](https://www.python.org/about/success/dlink). +- [ForecastWatch.com Uses Python To Help Meteorologists](https://www.python.org/about/success/forecastwatch/). +- [Frequentis TAPtools® - Python in Air Traffic Control](https://www.python.org/about/success/frequentis/). +- [Maritime Industry Increases Efficiency with Python](https://www.python.org/about/success/tribon/). +- [Python Streamlines Space Shuttle Mission Design](https://www.python.org/about/success/usa/). +- [Python is Rackspace's CORE Technology](https://www.python.org/about/success/rackspace/). +- [ERP5: Mission-critical ERP/CRM with Python and Zope](https://www.python.org/about/success/nexedi/). +- Many others: Google, NASA, Intel, AMD, Walt Disney Animation Studios, Canonical, Red Hat, Amazon, Netflix, and thousands upon thousands more. + +### Reasons to learn + +Some reasons to learn Python [Reasons to learn](http://www.skilledup.com/articles/reasons-to-learn-python): + +- It is easy to learn. Python was designed to help the developer not the machine. +- It helps the novice programmer. Concepts used in python can be applied to other programming languages. +- It is fun. Some projects like [Raspberry Pi](http://www.raspberrypi.org/faqs#introWhatIs) uses Python as the main language and can be used to create robots, remote controlled cars and video game consoles. +- There are many job opportunities for Python developers in companies like Google, Yahoo!, Disney, Nokia, and IBM. Not to mention a huge amount of startups. +- It have a wide range of open source web application frameworks. + +Python official web site [python website](https://www.python.org) and [python documentation](https://docs.python.org/) documentation to learn more.