From 3663c8629a16d2791bfd6eaabbd9461d9d731ee2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 19 Apr 2015 17:49:56 -0700 Subject: [PATCH 01/91] Adding loop in run.bat this allows easy retesting while going through koans --- python2/run.bat | 10 ++++++++++ python3/run.bat | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/python2/run.bat b/python2/run.bat index e8d1b0f57..40eaa792d 100755 --- a/python2/run.bat +++ b/python2/run.bat @@ -8,6 +8,9 @@ REM Set this to your python folder: SET PYTHON_PATH=C:\Python27 set SCRIPT= + +:loop + REM Hunt around for python IF EXIST "python.exe" ( SET SCRIPT=%RUN_KOANS% @@ -32,4 +35,11 @@ IF NOT "" == "%SCRIPT%" ( echo python.exe contemplate_koans.py pause ) + +Set /p keepgoing="Test again? Y or N - " +if "%keepgoing%" == "y" ( + goto loop + ) + + :end diff --git a/python3/run.bat b/python3/run.bat index 68d7b9b8e..3f5e94c77 100755 --- a/python3/run.bat +++ b/python3/run.bat @@ -8,6 +8,9 @@ REM Set this to your python folder: SET PYTHON_PATH=C:\Python34 set SCRIPT= + +:loop + REM Hunt around for python IF EXIST "python.exe" ( SET SCRIPT=%RUN_KOANS% @@ -32,4 +35,10 @@ IF NOT "" == "%SCRIPT%" ( echo python.exe contemplate_koans.py pause ) + +Set /p keepgoing="Test again? y or n - " +if "%keepgoing%" == "y" ( + goto loop + ) + :end From 8a7f0b6704ee21efba3f13322173be3121534491 Mon Sep 17 00:00:00 2001 From: Clifton McIntosh Date: Sun, 3 May 2015 07:54:41 -0500 Subject: [PATCH 02/91] add an assertion in about_lists.test_ranges_with_steps to demonstrate a descending list with a step of -1. --- python2/koans/about_lists.py | 1 + python3/koans/about_lists.py | 1 + 2 files changed, 2 insertions(+) diff --git a/python2/koans/about_lists.py b/python2/koans/about_lists.py index 4d2588272..bb3740228 100644 --- a/python2/koans/about_lists.py +++ b/python2/koans/about_lists.py @@ -62,6 +62,7 @@ def test_ranges_with_steps(self): self.assertEqual(__, range(1, 8, 3)) self.assertEqual(__, range(5, -7, -4)) self.assertEqual(__, range(5, -8, -4)) + self.assertEqual(__, list(range(5, 3, -1))) def test_insertions(self): knight = ['you', 'shall', 'pass'] diff --git a/python3/koans/about_lists.py b/python3/koans/about_lists.py index d2ae9fd6d..df0823e20 100644 --- a/python3/koans/about_lists.py +++ b/python3/koans/about_lists.py @@ -62,6 +62,7 @@ def test_ranges_with_steps(self): self.assertEqual(__, list(range(1, 8, 3))) self.assertEqual(__, list(range(5, -7, -4))) self.assertEqual(__, list(range(5, -8, -4))) + self.assertEqual(__, list(range(5, 3, -1))) def test_insertions(self): knight = ['you', 'shall', 'pass'] From 01181950265a2360f30f1bcea37cd3c401438a26 Mon Sep 17 00:00:00 2001 From: Clifton McIntosh Date: Mon, 4 May 2015 21:03:36 -0500 Subject: [PATCH 03/91] correct spelling of 'forth' to 'fourth' in about_comprehension.test_creating_a_dictionary_with_dictionary_comprehension. --- python2/koans/about_comprehension.py | 2 +- python3/koans/about_comprehension.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_comprehension.py b/python2/koans/about_comprehension.py index 4b372732a..7f19c0891 100644 --- a/python2/koans/about_comprehension.py +++ b/python2/koans/about_comprehension.py @@ -50,7 +50,7 @@ def test_creating_a_set_with_set_comprehension(self): def test_creating_a_dictionary_with_dictionary_comprehension(self): dict_of_weapons = {'first': 'fear', 'second': 'surprise', - 'third':'ruthless efficiency', 'forth':'fanatical devotion', + 'third':'ruthless efficiency', 'fourth':'fanatical devotion', 'fifth': None} dict_comprehension = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} diff --git a/python3/koans/about_comprehension.py b/python3/koans/about_comprehension.py index 05cb58ec2..e5add6d9e 100644 --- a/python3/koans/about_comprehension.py +++ b/python3/koans/about_comprehension.py @@ -50,7 +50,7 @@ def test_creating_a_set_with_set_comprehension(self): def test_creating_a_dictionary_with_dictionary_comprehension(self): dict_of_weapons = {'first': 'fear', 'second': 'surprise', - 'third':'ruthless efficiency', 'forth':'fanatical devotion', + 'third':'ruthless efficiency', 'fourth':'fanatical devotion', 'fifth': None} dict_comprehension = { k.upper(): weapon for k, weapon in dict_of_weapons.items() if weapon} From ed67dcfde4ae287a2ec2652a304f64d2d0f9d6c6 Mon Sep 17 00:00:00 2001 From: John Gardner Date: Tue, 7 Jul 2015 09:29:07 -0500 Subject: [PATCH 04/91] Fix spelling of navel. --- python2/koans/about_asserts.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index 476458337..bafe44afc 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -62,17 +62,17 @@ def test_that_sometimes_we_need_to_know_the_class_type(self): # Sometimes we will ask you what the class type of an object is. # - # For example, contemplate the text string "naval". What is its class type? + # For example, contemplate the text string "navel". What is its class type? # The koans runner will include this feedback for this koan: # # AssertionError: '-=> FILL ME IN! <=-' != # - # So "naval".__class__ is equal to ? No not quite. This + # So "navel".__class__ is equal to ? No not quite. This # is just what it displays. The answer is simply str. # # See for yourself: - self.assertEqual(__, "naval".__class__) # It's str, not + self.assertEqual(__, "navel".__class__) # It's str, not # Need an illustration? More reading can be found here: # From c794f694ec492a4976d681bd662748e5a2c32ab7 Mon Sep 17 00:00:00 2001 From: John Gardner Date: Tue, 7 Jul 2015 09:33:11 -0500 Subject: [PATCH 05/91] Fix spelling of navel in py3. --- python3/koans/about_asserts.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/koans/about_asserts.py b/python3/koans/about_asserts.py index ea10ccab5..674f4f0e4 100644 --- a/python3/koans/about_asserts.py +++ b/python3/koans/about_asserts.py @@ -60,17 +60,17 @@ def test_that_sometimes_we_need_to_know_the_class_type(self): # Sometimes we will ask you what the class type of an object is. # - # For example, contemplate the text string "naval". What is its class type? + # For example, contemplate the text string "navel". What is its class type? # The koans runner will include this feedback for this koan: # # AssertionError: '-=> FILL ME IN! <=-' != # - # So "naval".__class__ is equal to ? No not quite. This + # So "navel".__class__ is equal to ? No not quite. This # is just what it displays. The answer is simply str. # # See for yourself: - self.assertEqual(__, "naval".__class__) # It's str, not + self.assertEqual(__, "navel".__class__) # It's str, not # Need an illustration? More reading can be found here: # From 6229c1c605589a34d603c73a7cc94e6668bb6411 Mon Sep 17 00:00:00 2001 From: Chong Kim Date: Wed, 2 Sep 2015 16:02:06 -0400 Subject: [PATCH 06/91] Add sniffer support --- README.rst | 31 +++++++++++++++++++++++++++++++ python2/scent.py | 12 ++++++++++++ python3/scent.py | 12 ++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 python2/scent.py create mode 100644 python3/scent.py diff --git a/README.rst b/README.rst index 1c7ef631d..890ebcbbc 100644 --- a/README.rst +++ b/README.rst @@ -124,6 +124,37 @@ fire up the command line, recreate the scenario and run queries: .. image:: http://i442.photobucket.com/albums/qq150/gregmalcolm/DebuggingPython.png +Sniffer Support +--------------- + +Sniffer allows you to run the tests continuously. If you modify any files files +in the koans directory, it will rerun the tests. + +To set this up, you need to install sniffer:: + + $ pip install sniffer + +You should also run one of these libraries depending on your system. This will +automatically trigger sniffer when a file changes, otherwise sniffer will have +to poll to see if the files have changed. + +On Linux:: + + $ pip install pyinotify + +On Windows:: + + $ pip install pywin32 + +On Mac OS X:: + + $ pip install MacFSEvents + +Once it is set up, you just run:: + + $ sniffer + +Just modify one of the koans files and you'll see that the tests are triggered automatically. Sniffer is controlled by `scent.py` Getting the Most From the Koans ------------------------------- diff --git a/python2/scent.py b/python2/scent.py new file mode 100644 index 000000000..bba14fbd9 --- /dev/null +++ b/python2/scent.py @@ -0,0 +1,12 @@ +from sniffer.api import * +import os + +watch_paths = ['.', 'koans/'] + +@file_validator +def py_files(filename): + return filename.endswith('.py') and not os.path.basename(filename).startswith('.') + +@runnable +def execute_koans(*args): + os.system('python -B contemplate_koans.py') diff --git a/python3/scent.py b/python3/scent.py new file mode 100644 index 000000000..818506b10 --- /dev/null +++ b/python3/scent.py @@ -0,0 +1,12 @@ +from sniffer.api import * +import os + +watch_paths = ['.', 'koans/'] + +@file_validator +def py_files(filename): + return filename.endswith('.py') and not os.path.basename(filename).startswith('.') + +@runnable +def execute_koans(*args): + os.system('python3 -B contemplate_koans.py') From 8157a5b7bc35061f8ac2fc1024890a8cde6bc5d1 Mon Sep 17 00:00:00 2001 From: Clifton McIntosh Date: Sat, 2 Jan 2016 09:48:18 -0600 Subject: [PATCH 07/91] Move simpler test to be the first in test_ranges_with_steps. --- python2/koans/about_lists.py | 2 +- python3/koans/about_lists.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_lists.py b/python2/koans/about_lists.py index bb3740228..d7e2ecce0 100644 --- a/python2/koans/about_lists.py +++ b/python2/koans/about_lists.py @@ -58,11 +58,11 @@ def test_lists_and_ranges(self): self.assertEqual(__, range(5, 9)) def test_ranges_with_steps(self): + self.assertEqual(__, list(range(5, 3, -1))) self.assertEqual(__, range(0, 8, 2)) self.assertEqual(__, range(1, 8, 3)) self.assertEqual(__, range(5, -7, -4)) self.assertEqual(__, range(5, -8, -4)) - self.assertEqual(__, list(range(5, 3, -1))) def test_insertions(self): knight = ['you', 'shall', 'pass'] diff --git a/python3/koans/about_lists.py b/python3/koans/about_lists.py index df0823e20..61cc3bb29 100644 --- a/python3/koans/about_lists.py +++ b/python3/koans/about_lists.py @@ -58,11 +58,11 @@ def test_lists_and_ranges(self): self.assertEqual(__, list(range(5, 9))) def test_ranges_with_steps(self): + self.assertEqual(__, list(range(5, 3, -1))) self.assertEqual(__, list(range(0, 8, 2))) self.assertEqual(__, list(range(1, 8, 3))) self.assertEqual(__, list(range(5, -7, -4))) self.assertEqual(__, list(range(5, -8, -4))) - self.assertEqual(__, list(range(5, 3, -1))) def test_insertions(self): knight = ['you', 'shall', 'pass'] From 83da249242647b57e3d3ed9a4ff643caedaf71aa Mon Sep 17 00:00:00 2001 From: Clifton McIntosh Date: Sun, 3 Jan 2016 21:45:37 -0600 Subject: [PATCH 08/91] remove list that wrapped a range in test_range_with_steps. --- python2/koans/about_lists.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_lists.py b/python2/koans/about_lists.py index d7e2ecce0..d89888f6d 100644 --- a/python2/koans/about_lists.py +++ b/python2/koans/about_lists.py @@ -58,7 +58,7 @@ def test_lists_and_ranges(self): self.assertEqual(__, range(5, 9)) def test_ranges_with_steps(self): - self.assertEqual(__, list(range(5, 3, -1))) + self.assertEqual(__, range(5, 3, -1)) self.assertEqual(__, range(0, 8, 2)) self.assertEqual(__, range(1, 8, 3)) self.assertEqual(__, range(5, -7, -4)) From 6d37213a5fb704eda3389e9a6036fe5cd39470dc Mon Sep 17 00:00:00 2001 From: adityagupta679 Date: Mon, 25 Jan 2016 12:26:38 +0530 Subject: [PATCH 09/91] Updating Comments. It should be True instead of true. A user can write true by modifying the argument "False" in lines 18 and 24 . However that wont work , because the right keyword is "True". Hence the proposed change. --- python3/koans/about_asserts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/koans/about_asserts.py b/python3/koans/about_asserts.py index 674f4f0e4..1bffa66ef 100644 --- a/python3/koans/about_asserts.py +++ b/python3/koans/about_asserts.py @@ -14,13 +14,13 @@ def test_assert_truth(self): # # http://bit.ly/about_asserts - self.assertTrue(False) # This should be true + self.assertTrue(False) # This should be True def test_assert_with_message(self): """ Enlightenment may be more easily achieved with appropriate messages. """ - self.assertTrue(False, "This should be true -- Please fix this") + self.assertTrue(False, "This should be True -- Please fix this") def test_fill_in_values(self): """ From 18c66532b12a83ec5326e8ac75b2068371fbf7a9 Mon Sep 17 00:00:00 2001 From: adityagupta679 Date: Mon, 25 Jan 2016 12:33:20 +0530 Subject: [PATCH 10/91] Updating comments. --- python2/koans/about_asserts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index bafe44afc..8c80671d7 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -15,13 +15,13 @@ def test_assert_truth(self): # # http://bit.ly/about_asserts - self.assertTrue(False) # This should be true + self.assertTrue(False) # This should be True def test_assert_with_message(self): """ Enlightenment may be more easily achieved with appropriate messages. """ - self.assertTrue(False, "This should be true -- Please fix this") + self.assertTrue(False, "This should be True -- Please fix this") def test_fill_in_values(self): """ From 669bcd1d1284009c26e4b539b7f7343aad60697f Mon Sep 17 00:00:00 2001 From: gotyaoi Date: Mon, 29 Feb 2016 14:58:01 -0800 Subject: [PATCH 11/91] Set literals are available in python 2.7 --- python3/koans/about_sets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python3/koans/about_sets.py b/python3/koans/about_sets.py index 50e20099d..87cf10959 100644 --- a/python3/koans/about_sets.py +++ b/python3/koans/about_sets.py @@ -16,7 +16,8 @@ def test_empty_sets_have_different_syntax_to_populated_sets(self): self.assertEqual(__, set()) def test_dictionaries_and_sets_use_same_curly_braces(self): - # Note: Sets have only started using braces since Python 3 + # Note: Literal sets using braces were introduced in python 3. + # They were also backported to python 2.7. self.assertEqual(__, {1, 2, 3}.__class__) self.assertEqual(__, {'one': 1, 'two': 2}.__class__) From ef48c713ec8686d1be3a66d8f41c498ae1361708 Mon Sep 17 00:00:00 2001 From: viprs Date: Tue, 24 May 2016 20:51:14 +0800 Subject: [PATCH 12/91] PEP8: delete unused import --- python2/runner/writeln_decorator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python2/runner/writeln_decorator.py b/python2/runner/writeln_decorator.py index ee3cd35c0..67d88774a 100644 --- a/python2/runner/writeln_decorator.py +++ b/python2/runner/writeln_decorator.py @@ -4,10 +4,11 @@ import sys import os + # Taken from legacy python unittest class WritelnDecorator: """Used to decorate file-like objects with a handy 'writeln' method""" - def __init__(self,stream): + def __init__(self, stream): self.stream = stream def __getattr__(self, attr): From 2718256bfbf57eba36c3f083dace32afbc101fd3 Mon Sep 17 00:00:00 2001 From: viprs Date: Tue, 24 May 2016 20:51:35 +0800 Subject: [PATCH 13/91] Revert "PEP8: delete unused import" This reverts commit ef48c713ec8686d1be3a66d8f41c498ae1361708. --- python2/runner/writeln_decorator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python2/runner/writeln_decorator.py b/python2/runner/writeln_decorator.py index 67d88774a..ee3cd35c0 100644 --- a/python2/runner/writeln_decorator.py +++ b/python2/runner/writeln_decorator.py @@ -4,11 +4,10 @@ import sys import os - # Taken from legacy python unittest class WritelnDecorator: """Used to decorate file-like objects with a handy 'writeln' method""" - def __init__(self, stream): + def __init__(self,stream): self.stream = stream def __getattr__(self, attr): From 0ded442c84f5de0dc8fac00c679ca78ef541de17 Mon Sep 17 00:00:00 2001 From: viprs Date: Tue, 24 May 2016 20:52:32 +0800 Subject: [PATCH 14/91] PEP 8: delete unused import --- python2/runner/writeln_decorator.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/python2/runner/writeln_decorator.py b/python2/runner/writeln_decorator.py index ee3cd35c0..ba19ecb62 100644 --- a/python2/runner/writeln_decorator.py +++ b/python2/runner/writeln_decorator.py @@ -1,19 +1,18 @@ #!/usr/bin/env python # encoding: utf-8 -import sys -import os # Taken from legacy python unittest class WritelnDecorator: """Used to decorate file-like objects with a handy 'writeln' method""" - def __init__(self,stream): + def __init__(self, stream): self.stream = stream def __getattr__(self, attr): return getattr(self.stream,attr) def writeln(self, arg=None): - if arg: self.write(arg) - self.write('\n') # text-mode streams translate to \r\n if needed + if arg: + self.write(arg) + self.write('\n') # text-mode streams translate to \r\n if needed From 9c09d4053ed1093bf238d56c6537d3054795f98d Mon Sep 17 00:00:00 2001 From: viprs Date: Tue, 24 May 2016 21:06:34 +0800 Subject: [PATCH 15/91] PEP 8: doc string should be tripple quoted strings --- python2/runner/mountain.py | 5 +++-- python2/runner/sensei.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/python2/runner/mountain.py b/python2/runner/mountain.py index b988c1291..32bf364d4 100644 --- a/python2/runner/mountain.py +++ b/python2/runner/mountain.py @@ -8,6 +8,7 @@ from sensei import Sensei from writeln_decorator import WritelnDecorator + class Mountain: def __init__(self): self.stream = WritelnDecorator(sys.stdout) @@ -15,9 +16,9 @@ def __init__(self): self.lesson = Sensei(self.stream) def walk_the_path(self, args=None): - "Run the koans tests with a custom runner output." + """Run the koans tests with a custom runner output.""" - if args and len(args) >=2: + if args and len(args) >= 2: args.pop(0) test_names = ["koans." + test_name for test_name in args] self.tests = unittest.TestLoader().loadTestsFromNames(test_names) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index ecb450600..e38d3a5e8 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -88,7 +88,7 @@ def learn(self): self.stream.writeln("") self.stream.writeln(self.report_progress()) if self.failures: - self.stream.writeln(self.report_remaining()) + self.stream.writeln(self.report_remaining()) self.stream.writeln("") self.stream.writeln(self.say_something_zenlike()) From c7380976519b3a42004fc3c5d2944a2f70fc7d8c Mon Sep 17 00:00:00 2001 From: Jimmy Robbins Date: Sat, 18 Jun 2016 13:32:12 -0500 Subject: [PATCH 16/91] Used python3 default regex asserts --- python3/koans/about_attribute_access.py | 8 ++++---- python3/koans/about_class_attributes.py | 10 +++++----- python3/koans/about_classes.py | 2 +- python3/koans/about_control_statements.py | 12 ++++++------ python3/koans/about_decorating_with_functions.py | 3 +-- python3/koans/about_deleting_objects.py | 4 ++-- python3/koans/about_generators.py | 4 +--- python3/koans/about_iteration.py | 2 +- python3/koans/about_methods.py | 7 +++---- python3/koans/about_monkey_patching.py | 3 +-- python3/koans/about_multiple_inheritance.py | 9 ++++----- python3/koans/about_none.py | 2 +- python3/koans/about_tuples.py | 10 ++++------ python3/runner/koan.py | 11 +---------- 14 files changed, 35 insertions(+), 52 deletions(-) diff --git a/python3/koans/about_attribute_access.py b/python3/koans/about_attribute_access.py index 4783195be..6ab5d82ca 100644 --- a/python3/koans/about_attribute_access.py +++ b/python3/koans/about_attribute_access.py @@ -36,19 +36,19 @@ def __getattribute__(self, attr_name): def test_all_attribute_reads_are_caught(self): catcher = self.CatchAllAttributeReads() - self.assertRegexpMatches(catcher.foobar, __) + self.assertRegex(catcher.foobar, __) def test_intercepting_return_values_can_disrupt_the_call_chain(self): catcher = self.CatchAllAttributeReads() - self.assertRegexpMatches(catcher.foobaz, __) # This is fine + self.assertRegex(catcher.foobaz, __) # This is fine try: catcher.foobaz(1) except TypeError as ex: err_msg = ex.args[0] - self.assertRegexpMatches(err_msg, __) + self.assertRegex(err_msg, __) # foobaz returns a string. What happens to the '(1)' part? # Try entering this into a python console to reproduce the issue: @@ -59,7 +59,7 @@ def test_intercepting_return_values_can_disrupt_the_call_chain(self): def test_changes_to_the_getattribute_implementation_affects_getattr_function(self): catcher = self.CatchAllAttributeReads() - self.assertRegexpMatches(getattr(catcher, 'any_attribute'), __) + self.assertRegex(getattr(catcher, 'any_attribute'), __) # ------------------------------------------------------------------ diff --git a/python3/koans/about_class_attributes.py b/python3/koans/about_class_attributes.py index f4b3d751f..7a5be1df4 100644 --- a/python3/koans/about_class_attributes.py +++ b/python3/koans/about_class_attributes.py @@ -75,19 +75,19 @@ def growl(cls): return "classmethod growl, arg: cls=" + cls.__name__ def test_since_classes_are_objects_you_can_define_singleton_methods_on_them_too(self): - self.assertRegexpMatches(self.Dog2.growl(), __) + self.assertRegex(self.Dog2.growl(), __) def test_classmethods_are_not_independent_of_instance_methods(self): fido = self.Dog2() - self.assertRegexpMatches(fido.growl(), __) - self.assertRegexpMatches(self.Dog2.growl(), __) + self.assertRegex(fido.growl(), __) + self.assertRegex(self.Dog2.growl(), __) def test_staticmethods_are_unbound_functions_housed_in_a_class(self): - self.assertRegexpMatches(self.Dog2.bark(), __) + self.assertRegex(self.Dog2.bark(), __) def test_staticmethods_also_overshadow_instance_methods(self): fido = self.Dog2() - self.assertRegexpMatches(fido.bark(), __) + self.assertRegex(fido.bark(), __) # ------------------------------------------------------------------ diff --git a/python3/koans/about_classes.py b/python3/koans/about_classes.py index f3ed7eeb1..22dc4e7f0 100644 --- a/python3/koans/about_classes.py +++ b/python3/koans/about_classes.py @@ -15,7 +15,7 @@ def test_instances_of_classes_can_be_created_adding_parentheses(self): self.assertEqual(__, fido.__class__.__name__) def test_classes_have_docstrings(self): - self.assertRegexpMatches(self.Dog.__doc__, __) + self.assertRegex(self.Dog.__doc__, __) # ------------------------------------------------------------------ diff --git a/python3/koans/about_control_statements.py b/python3/koans/about_control_statements.py index 3ead55fff..2ed357bcb 100644 --- a/python3/koans/about_control_statements.py +++ b/python3/koans/about_control_statements.py @@ -17,11 +17,11 @@ def test_if_then_statements(self): if True: result = 'true value' self.assertEqual(__, result) - + def test_if_then_elif_else_statements(self): if False: result = 'first value' - elif True: + elif True: result = 'true value' else: result = 'default value' @@ -73,8 +73,8 @@ def test_for_statement_with_tuples(self): text = __ - self.assertRegexpMatches(result[2], text) + self.assertRegex(result[2], text) - self.assertNoRegexpMatches(result[0], text) - self.assertNoRegexpMatches(result[1], text) - self.assertNoRegexpMatches(result[3], text) + self.assertNotRegex(result[0], text) + self.assertNotRegex(result[1], text) + self.assertNotRegex(result[3], text) diff --git a/python3/koans/about_decorating_with_functions.py b/python3/koans/about_decorating_with_functions.py index 260ad12ac..a51260213 100644 --- a/python3/koans/about_decorating_with_functions.py +++ b/python3/koans/about_decorating_with_functions.py @@ -14,7 +14,7 @@ def mediocre_song(self): return "o/~ We all live in a broken submarine o/~" def test_decorators_can_modify_a_function(self): - self.assertRegexpMatches(self.mediocre_song(), __) + self.assertRegex(self.mediocre_song(), __) self.assertEqual(__, self.mediocre_song.wow_factor) # ------------------------------------------------------------------ @@ -30,4 +30,3 @@ def render_tag(self, name): def test_decorators_can_change_a_function_output(self): self.assertEqual(__, self.render_tag('llama')) - diff --git a/python3/koans/about_deleting_objects.py b/python3/koans/about_deleting_objects.py index bec3e9e29..152265c98 100644 --- a/python3/koans/about_deleting_objects.py +++ b/python3/koans/about_deleting_objects.py @@ -48,8 +48,8 @@ def test_del_can_remove_attributes(self): except AttributeError as e: err_msg2 = e.args[0] - self.assertRegexpMatches(err_msg1, __) - self.assertRegexpMatches(err_msg2, __) + self.assertRegex(err_msg1, __) + self.assertRegex(err_msg2, __) # ==================================================================== diff --git a/python3/koans/about_generators.py b/python3/koans/about_generators.py index f623d0070..5ab4821ec 100644 --- a/python3/koans/about_generators.py +++ b/python3/koans/about_generators.py @@ -116,7 +116,7 @@ def test_before_sending_a_value_to_a_generator_next_must_be_called(self): except TypeError as ex: ex2 = ex - self.assertRegexpMatches(ex2.args[0], __) + self.assertRegex(ex2.args[0], __) # ------------------------------------------------------------------ @@ -142,5 +142,3 @@ def test_send_none_is_equivalent_to_next(self): next(generator) # 'next(generator)' is exactly equivalent to 'generator.send(None)' self.assertEqual(__, generator.send(None)) - - diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index c7810545b..93d64504a 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -26,7 +26,7 @@ def test_iterating_with_next(self): except StopIteration as ex: err_msg = 'Ran out of iterations' - self.assertRegexpMatches(err_msg, __) + self.assertRegex(err_msg, __) # ------------------------------------------------------------------ diff --git a/python3/koans/about_methods.py b/python3/koans/about_methods.py index c9572ad25..796a07ea5 100644 --- a/python3/koans/about_methods.py +++ b/python3/koans/about_methods.py @@ -24,7 +24,7 @@ def test_calling_functions_with_wrong_number_of_arguments(self): # Note, the text comparison works for Python 3.2 # It has changed in the past and may change in the future - self.assertRegexpMatches(msg, + self.assertRegex(msg, r'my_global_function\(\) missing 2 required positional arguments') try: @@ -33,7 +33,7 @@ def test_calling_functions_with_wrong_number_of_arguments(self): msg = e.args[0] # Note, watch out for parenthesis. They need slashes in front! - self.assertRegexpMatches(msg, __) + self.assertRegex(msg, __) # ------------------------------------------------------------------ @@ -126,7 +126,7 @@ def method_with_documentation(self): return "ok" def test_the_documentation_can_be_viewed_with_the_doc_method(self): - self.assertRegexpMatches(self.method_with_documentation.__doc__, __) + self.assertRegex(self.method_with_documentation.__doc__, __) # ------------------------------------------------------------------ @@ -160,4 +160,3 @@ def test_attributes_with_double_underscore_prefixes_are_subject_to_name_mangling # Name mangling exists to avoid name clash issues when subclassing. # It is not for providing effective access protection - diff --git a/python3/koans/about_monkey_patching.py b/python3/koans/about_monkey_patching.py index a7e738418..bdea2b8b9 100644 --- a/python3/koans/about_monkey_patching.py +++ b/python3/koans/about_monkey_patching.py @@ -35,7 +35,7 @@ def test_most_built_in_classes_cannot_be_monkey_patched(self): except Exception as ex: err_msg = ex.args[0] - self.assertRegexpMatches(err_msg, __) + self.assertRegex(err_msg, __) # ------------------------------------------------------------------ @@ -46,4 +46,3 @@ def test_subclasses_of_built_in_classes_can_be_be_monkey_patched(self): self.assertEqual(__, self.MyInt(1).is_even()) self.assertEqual(__, self.MyInt(2).is_even()) - diff --git a/python3/koans/about_multiple_inheritance.py b/python3/koans/about_multiple_inheritance.py index 9af59fc48..4227f7eb9 100644 --- a/python3/koans/about_multiple_inheritance.py +++ b/python3/koans/about_multiple_inheritance.py @@ -87,7 +87,7 @@ def here(self): def test_normal_methods_are_available_in_the_object(self): jeff = self.Spiderpig() - self.assertRegexpMatches(jeff.speak(), __) + self.assertRegex(jeff.speak(), __) def test_base_class_methods_are_also_available_in_the_object(self): jeff = self.Spiderpig() @@ -126,16 +126,15 @@ def test_we_can_inspect_the_method_resolution_order(self): def test_confirm_the_mro_controls_the_calling_order(self): jeff = self.Spiderpig() - self.assertRegexpMatches(jeff.here(), 'Spiderpig') + self.assertRegex(jeff.here(), 'Spiderpig') next = super(AboutMultipleInheritance.Spiderpig, jeff) - self.assertRegexpMatches(next.here(), 'Pig') + self.assertRegex(next.here(), 'Pig') next = super(AboutMultipleInheritance.Pig, jeff) - self.assertRegexpMatches(next.here(), __) + self.assertRegex(next.here(), __) # Hang on a minute?!? That last class name might be a super class of # the 'jeff' object, but its hardly a superclass of Pig, is it? # # To avoid confusion it may help to think of super() as next_mro(). - diff --git a/python3/koans/about_none.py b/python3/koans/about_none.py index 680cb1007..8cf04f034 100644 --- a/python3/koans/about_none.py +++ b/python3/koans/about_none.py @@ -41,7 +41,7 @@ def test_what_exception_do_you_get_when_calling_nonexistent_methods(self): # What message was attached to the exception? # (HINT: replace __ with part of the error message.) - self.assertRegexpMatches(ex2.args[0], __) + self.assertRegex(ex2.args[0], __) def test_none_is_distinct(self): """ diff --git a/python3/koans/about_tuples.py b/python3/koans/about_tuples.py index 76c193395..cc6ac5291 100644 --- a/python3/koans/about_tuples.py +++ b/python3/koans/about_tuples.py @@ -9,16 +9,17 @@ def test_creating_a_tuple(self): self.assertEqual(__, count_of_three[2]) def test_tuples_are_immutable_so_item_assignment_is_not_possible(self): - count_of_three = (1, 2, 5) + + count_of_three = (1, 2, 5) try: count_of_three[2] = "three" except TypeError as ex: msg = ex.args[0] - # Note, assertRegexpMatches() uses regular expression pattern matching, + # Note, assertRegex() uses regular expression pattern matching, # so you don't have to copy the whole message. - self.assertRegexpMatches(msg, __) + self.assertRegex(msg, __) def test_tuples_are_immutable_so_appending_is_not_possible(self): count_of_three = (1, 2, 5) @@ -63,6 +64,3 @@ def test_tuples_are_good_for_representing_records(self): self.assertEqual(__, locations[2][0]) self.assertEqual(__, locations[0][1][2]) - - - diff --git a/python3/runner/koan.py b/python3/runner/koan.py index 28a9d101b..929ccb41b 100644 --- a/python3/runner/koan.py +++ b/python3/runner/koan.py @@ -20,13 +20,4 @@ class ___(Exception): class Koan(unittest.TestCase): - def assertNoRegexpMatches(self, text, expected_regex, msg=None): - """ - Throw an exception if the regular expresson pattern is not matched - """ - if isinstance(expected_regex, (str, bytes)): - expected_regex = re.compile(expected_regex) - if expected_regex.search(text): - msg = msg or "Regexp matched" - msg = '{0}: {1!r} found in {2!r}'.format(msg, expected_regex.pattern, text) - raise self.failureException(msg) + pass From 15b1b49ca6a08ac1285f0d01745bffaec9c9ed97 Mon Sep 17 00:00:00 2001 From: Ryan Tanay Date: Thu, 14 Jul 2016 18:22:45 -0500 Subject: [PATCH 17/91] Monty Python reference in about_control_statements.py (#131) * Corrected reference to Monty Python swallow bit Not sure if the Amazonian Swallow is a reference I'm just not getting, but it's the airspeed velocity of African and European Swallows we're worried about when it comes to crossing bridges. * Trimmed trailing whitespace * Corrected reference to Monty Python swallow bit Mirrored changes from python3 to python2 to correct Amazonian -> European --- python2/koans/about_control_statements.py | 6 +++--- python3/koans/about_control_statements.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python2/koans/about_control_statements.py b/python2/koans/about_control_statements.py index 38665cb15..13f5e0dc0 100644 --- a/python2/koans/about_control_statements.py +++ b/python2/koans/about_control_statements.py @@ -18,11 +18,11 @@ def test_if_then_statements(self): if True: result = 'true value' self.assertEqual(__, result) - + def test_if_then_elif_else_statements(self): if False: result = 'first value' - elif True: + elif True: result = 'true value' else: result = 'default value' @@ -66,7 +66,7 @@ def test_for_statement_with_tuples(self): ("Lancelot", "Blue"), ("Galahad", "I don't know!"), ("Robin", "Blue! I mean Green!"), - ("Arthur", "Is that an African Swallow or Amazonian Swallow?") + ("Arthur", "Is that an African Swallow or European Swallow?") ] result = [] for knight, answer in round_table: diff --git a/python3/koans/about_control_statements.py b/python3/koans/about_control_statements.py index 2ed357bcb..842c8d91f 100644 --- a/python3/koans/about_control_statements.py +++ b/python3/koans/about_control_statements.py @@ -65,7 +65,7 @@ def test_for_statement_with_tuples(self): ("Lancelot", "Blue"), ("Galahad", "I don't know!"), ("Robin", "Blue! I mean Green!"), - ("Arthur", "Is that an African Swallow or Amazonian Swallow?") + ("Arthur", "Is that an African Swallow or European Swallow?") ] result = [] for knight, answer in round_table: From 385e952960150e60ff6187a6be11fe6598d81c86 Mon Sep 17 00:00:00 2001 From: Ryan Tanay Date: Tue, 19 Jul 2016 21:30:17 -0500 Subject: [PATCH 18/91] Typo fix in explanatory comment (#133) * Corrected reference to Monty Python swallow bit Not sure if the Amazonian Swallow is a reference I'm just not getting, but it's the airspeed velocity of African and European Swallows we're worried about when it comes to crossing bridges. * Trimmed trailing whitespace * Corrected reference to Monty Python swallow bit Mirrored changes from python3 to python2 to correct Amazonian -> European * Fixed typo in explanatory comment --- python2/koans/about_packages.py | 2 +- python3/koans/about_packages.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_packages.py b/python2/koans/about_packages.py index 5eeab5945..2c535ad47 100644 --- a/python2/koans/about_packages.py +++ b/python2/koans/about_packages.py @@ -53,7 +53,7 @@ def test_use_absolute_imports_to_import_upper_level_modules(self): self.assertEqual(__, contemplate_koans.__name__) - # contemplate_koans.py is the root module in this package because its + # contemplate_koans.py is the root module in this package because it's # the first python module called in koans. # # If contemplate_koans.py was based in a_package_folder that would be diff --git a/python3/koans/about_packages.py b/python3/koans/about_packages.py index afc6976fb..69288a1c8 100644 --- a/python3/koans/about_packages.py +++ b/python3/koans/about_packages.py @@ -45,7 +45,7 @@ def test_use_absolute_imports_to_import_upper_level_modules(self): self.assertEqual(__, contemplate_koans.__name__) - # contemplate_koans.py is the root module in this package because its + # contemplate_koans.py is the root module in this package because it's # the first python module called in koans. # # If contemplate_koans.py was based in a_package_folder that would be From 7c523514bbe66570615c59d6c7523c9119c77b55 Mon Sep 17 00:00:00 2001 From: gilmrjc Date: Wed, 20 Jul 2016 20:40:07 -0500 Subject: [PATCH 19/91] Changing variable name (Closes #117) (#134) The variable name "fib" in test_iterators_are_a_type renamed to "total" to avoid confusion about what the function is doing. --- python3/koans/about_iteration.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index 93d64504a..d232d07b8 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -8,12 +8,12 @@ class AboutIteration(Koan): def test_iterators_are_a_type(self): it = iter(range(1,6)) - fib = 0 + total = 0 for num in it: - fib += num + total += num - self.assertEqual(__ , fib) + self.assertEqual(__ , total) def test_iterating_with_next(self): stages = iter(['alpha','beta','gamma']) From 4e1bb9a4d26fdcbbfae38ad4a39715bfaa7e2eca Mon Sep 17 00:00:00 2001 From: Wellington Moraes Date: Mon, 12 Sep 2016 17:08:48 -0300 Subject: [PATCH 20/91] add python 3.4 and 3.5 (#136) add python 3.4 and 3.5 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0ef668f20..1f94c3610 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ python: - 2.7 - 3.2 - 3.3 + - 3.4 + - 3.5 script: - PYTHON_VER=`python -c 'import sys; print(sys.version_info[0])'` From d44aec58cb5faf6984c54c8ecb8936f569a6648a Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Thu, 29 Sep 2016 23:10:40 -0400 Subject: [PATCH 21/91] Fixes #137: test_everything_else_is_treated_as_true (#142) In the Python 2 and 3 versions of koans/about_true_and_false.py: self.truth_value(1,) is an integer argument followed by an optional comma. It just happened to produce the desired answer, because bool(1) is True. self.truth_value((1,)) is a tuple argument. Changed the tuple to (0,) to demonstrate that its truthiness comes from the presence of _any_ elements, and not from the truth value of the element itself. Also, added an easier example before it --- self.truth_value([0]) --- to introduce the same idea with the simpler list-literal syntax (no "magic" comma to worry about). Finally, changed the whitespace and line wrapping so the Python 2 and 3 files are identical. Reported by: egonluo https://github.com/egonluo Issue #137: https://github.com/gregmalcolm/python_koans/issues/137 --- python2/koans/about_true_and_false.py | 3 ++- python3/koans/about_true_and_false.py | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/python2/koans/about_true_and_false.py b/python2/koans/about_true_and_false.py index 51a6b537f..5f06a63db 100644 --- a/python2/koans/about_true_and_false.py +++ b/python2/koans/about_true_and_false.py @@ -34,7 +34,8 @@ def test_blank_strings_are_treated_as_false(self): def test_everything_else_is_treated_as_true(self): self.assertEqual(__, self.truth_value(1)) - self.assertEqual(__, self.truth_value(1,)) + self.assertEqual(__, self.truth_value([0])) + self.assertEqual(__, self.truth_value((0,))) self.assertEqual( __, self.truth_value("Python is named after Monty Python")) diff --git a/python3/koans/about_true_and_false.py b/python3/koans/about_true_and_false.py index 4aa021a4c..5f06a63db 100644 --- a/python3/koans/about_true_and_false.py +++ b/python3/koans/about_true_and_false.py @@ -3,6 +3,7 @@ from runner.koan import * + class AboutTrueAndFalse(Koan): def truth_value(self, condition): if condition: @@ -33,7 +34,10 @@ def test_blank_strings_are_treated_as_false(self): def test_everything_else_is_treated_as_true(self): self.assertEqual(__, self.truth_value(1)) - self.assertEqual(__, self.truth_value(1,)) - self.assertEqual(__, self.truth_value("Python is named after Monty Python")) + self.assertEqual(__, self.truth_value([0])) + self.assertEqual(__, self.truth_value((0,))) + self.assertEqual( + __, + self.truth_value("Python is named after Monty Python")) self.assertEqual(__, self.truth_value(' ')) self.assertEqual(__, self.truth_value('0')) From ade4b6e86e1636731c3e1a5e0abbabfd0250f295 Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Thu, 29 Sep 2016 23:30:21 -0400 Subject: [PATCH 22/91] Unmockify (#141) * Removed unneeded mocks from mountain and sensei tests. Some of the Mock objects "leaked out" into other tests, especially runner.path_to_enlightenment.koans, which was untestable after it had been replaced with a Mock. * Globally-visible Mocks -> "with patch():" blocks. Python 2 and 3: test_sensei.py replaced some methods of runner.mockable_test_result.MockableTestResult with new Mock objects. I did not experience these "leaking" into other tests, but they could have. Also, removed unused "import sys" from both 2 and 3 versions. --- python2/runner/runner_tests/test_mountain.py | 11 ++--- python2/runner/runner_tests/test_sensei.py | 47 +++++++------------- python3/runner/runner_tests/test_mountain.py | 11 ++--- python3/runner/runner_tests/test_sensei.py | 34 +++++--------- 4 files changed, 35 insertions(+), 68 deletions(-) diff --git a/python2/runner/runner_tests/test_mountain.py b/python2/runner/runner_tests/test_mountain.py index 0f8d08ccc..5736f49ac 100644 --- a/python2/runner/runner_tests/test_mountain.py +++ b/python2/runner/runner_tests/test_mountain.py @@ -5,17 +5,14 @@ from libs.mock import * from runner.mountain import Mountain -from runner import path_to_enlightenment class TestMountain(unittest.TestCase): def setUp(self): - path_to_enlightenment.koans = Mock() self.mountain = Mountain() - self.mountain.stream.writeln = Mock() def test_it_gets_test_results(self): - self.mountain.lesson.learn = Mock() - self.mountain.walk_the_path() - self.assertTrue(self.mountain.lesson.learn.called) - + with patch_object(self.mountain.stream, 'writeln', Mock()): + with patch_object(self.mountain.lesson, 'learn', Mock()): + self.mountain.walk_the_path() + self.assertTrue(self.mountain.lesson.learn.called) diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index 8149a7fac..999f6709a 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import sys import unittest import re @@ -10,7 +9,6 @@ from runner.sensei import Sensei from runner.writeln_decorator import WritelnDecorator from runner.mockable_test_result import MockableTestResult -from runner import path_to_enlightenment class AboutParrots: pass @@ -81,36 +79,33 @@ class AboutFreemasons: """ + class TestSensei(unittest.TestCase): def setUp(self): - self.sensei = Sensei(WritelnDecorator(sys.stdout)) - self.sensei.stream.writeln = Mock() - path_to_enlightenment.koans = Mock() - self.tests = Mock() - self.tests.countTestCases = Mock() + self.sensei = Sensei(WritelnDecorator(Mock())) def test_that_failures_are_handled_in_the_base_class(self): - MockableTestResult.addFailure = Mock() - self.sensei.addFailure(Mock(), Mock()) - self.assertTrue(MockableTestResult.addFailure.called) + with patch('runner.mockable_test_result.MockableTestResult.addFailure', Mock()): + self.sensei.addFailure(Mock(), Mock()) + self.assertTrue(MockableTestResult.addFailure.called) def test_that_it_successes_only_count_if_passes_are_currently_allowed(self): - self.sensei.passesCount = Mock() - MockableTestResult.addSuccess = Mock() - self.sensei.addSuccess(Mock()) - self.assertTrue(self.sensei.passesCount.called) + with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()): + self.sensei.passesCount = Mock() + self.sensei.addSuccess(Mock()) + self.assertTrue(self.sensei.passesCount.called) def test_that_it_passes_on_add_successes_message(self): - MockableTestResult.addSuccess = Mock() - self.sensei.addSuccess(Mock()) - self.assertTrue(MockableTestResult.addSuccess.called) + with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()): + self.sensei.addSuccess(Mock()) + self.assertTrue(MockableTestResult.addSuccess.called) def test_that_it_increases_the_passes_on_every_success(self): - pass_count = self.sensei.pass_count - MockableTestResult.addSuccess = Mock() - self.sensei.addSuccess(Mock()) - self.assertEqual(pass_count + 1, self.sensei.pass_count) + with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()): + pass_count = self.sensei.pass_count + self.sensei.addSuccess(Mock()) + self.assertEqual(pass_count + 1, self.sensei.pass_count) def test_that_nothing_is_returned_as_a_first_result_if_there_are_no_failures(self): self.sensei.failures = [] @@ -236,7 +231,6 @@ def test_that_if_there_are_0_successes_it_will_say_the_first_zen_of_python_koans self.sensei.pass_count = 0 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Beautiful is better than ugly", words) self.assertTrue(m and m.group(0)) @@ -244,7 +238,6 @@ def test_that_if_there_is_1_successes_it_will_say_the_second_zen_of_python_koans self.sensei.pass_count = 1 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Explicit is better than implicit", words) self.assertTrue(m and m.group(0)) @@ -252,15 +245,13 @@ def test_that_if_there_is_10_successes_it_will_say_the_sixth_zen_of_python_koans self.sensei.pass_count = 10 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Sparse is better than dense", words) self.assertTrue(m and m.group(0)) def test_that_if_there_is_36_successes_it_will_say_the_final_zen_of_python_koans(self): - self.sensei.pass_count = 36 self.sensei.failures = Mock() + self.sensei.pass_count = 36 words = self.sensei.say_something_zenlike() - m = re.search("Namespaces are one honking great idea", words) self.assertTrue(m and m.group(0)) @@ -268,26 +259,22 @@ def test_that_if_there_is_37_successes_it_will_say_the_first_zen_of_python_koans self.sensei.pass_count = 37 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Beautiful is better than ugly", words) self.assertTrue(m and m.group(0)) def test_that_total_lessons_return_7_if_there_are_7_lessons(self): self.sensei.filter_all_lessons = Mock() self.sensei.filter_all_lessons.return_value = [1,2,3,4,5,6,7] - self.assertEqual(7, self.sensei.total_lessons()) def test_that_total_lessons_return_0_if_all_lessons_is_none(self): self.sensei.filter_all_lessons = Mock() self.sensei.filter_all_lessons.return_value = None - self.assertEqual(0, self.sensei.total_lessons()) def test_total_koans_return_43_if_there_are_43_test_cases(self): self.sensei.tests.countTestCases = Mock() self.sensei.tests.countTestCases.return_value = 43 - self.assertEqual(43, self.sensei.total_koans()) def test_filter_all_lessons_will_discover_test_classes_if_none_have_been_discovered_yet(self): diff --git a/python3/runner/runner_tests/test_mountain.py b/python3/runner/runner_tests/test_mountain.py index 0f8d08ccc..5736f49ac 100644 --- a/python3/runner/runner_tests/test_mountain.py +++ b/python3/runner/runner_tests/test_mountain.py @@ -5,17 +5,14 @@ from libs.mock import * from runner.mountain import Mountain -from runner import path_to_enlightenment class TestMountain(unittest.TestCase): def setUp(self): - path_to_enlightenment.koans = Mock() self.mountain = Mountain() - self.mountain.stream.writeln = Mock() def test_it_gets_test_results(self): - self.mountain.lesson.learn = Mock() - self.mountain.walk_the_path() - self.assertTrue(self.mountain.lesson.learn.called) - + with patch_object(self.mountain.stream, 'writeln', Mock()): + with patch_object(self.mountain.lesson, 'learn', Mock()): + self.mountain.walk_the_path() + self.assertTrue(self.mountain.lesson.learn.called) diff --git a/python3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py index 416c7ce2f..a1ee062d4 100644 --- a/python3/runner/runner_tests/test_sensei.py +++ b/python3/runner/runner_tests/test_sensei.py @@ -1,7 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import sys import unittest import re @@ -10,7 +9,6 @@ from runner.sensei import Sensei from runner.writeln_decorator import WritelnDecorator from runner.mockable_test_result import MockableTestResult -from runner import path_to_enlightenment class AboutParrots: pass @@ -32,7 +30,7 @@ class AboutFreemasons: pass error_assertion_with_message = """Traceback (most recent call last): - File "/Users/Greg/hg/python_koans/koans/about_exploding_trousers.py ", line 43, in test_durability + File "/Users/Greg/hg/python_koans/koans/about_exploding_trousers.py", line 43, in test_durability self.assertEqual("Steel","Lard", "Another fine mess you've got me into Stanley...") AssertionError: Another fine mess you've got me into Stanley...""" @@ -85,23 +83,19 @@ class AboutFreemasons: class TestSensei(unittest.TestCase): def setUp(self): - self.sensei = Sensei(WritelnDecorator(sys.stdout)) - self.sensei.stream.writeln = Mock() - path_to_enlightenment.koans = Mock() - self.tests = Mock() - self.tests.countTestCases = Mock() + self.sensei = Sensei(WritelnDecorator(Mock())) def test_that_it_successes_only_count_if_passes_are_currently_allowed(self): - self.sensei.passesCount = Mock() - MockableTestResult.addSuccess = Mock() - self.sensei.addSuccess(Mock()) - self.assertTrue(self.sensei.passesCount.called) + with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()): + self.sensei.passesCount = Mock() + self.sensei.addSuccess(Mock()) + self.assertTrue(self.sensei.passesCount.called) def test_that_it_increases_the_passes_on_every_success(self): - pass_count = self.sensei.pass_count - MockableTestResult.addSuccess = Mock() - self.sensei.addSuccess(Mock()) - self.assertEqual(pass_count + 1, self.sensei.pass_count) + with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()): + pass_count = self.sensei.pass_count + self.sensei.addSuccess(Mock()) + self.assertEqual(pass_count + 1, self.sensei.pass_count) def test_that_nothing_is_returned_as_sorted_result_if_there_are_no_failures(self): self.sensei.failures = [] @@ -216,7 +210,6 @@ def test_that_if_there_are_0_successes_it_will_say_the_first_zen_of_python_koans self.sensei.pass_count = 0 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Beautiful is better than ugly", words) self.assertTrue(m and m.group(0)) @@ -224,7 +217,6 @@ def test_that_if_there_is_1_successes_it_will_say_the_second_zen_of_python_koans self.sensei.pass_count = 1 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Explicit is better than implicit", words) self.assertTrue(m and m.group(0)) @@ -232,7 +224,6 @@ def test_that_if_there_is_10_successes_it_will_say_the_sixth_zen_of_python_koans self.sensei.pass_count = 10 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Sparse is better than dense", words) self.assertTrue(m and m.group(0)) @@ -240,7 +231,6 @@ def test_that_if_there_is_36_successes_it_will_say_the_final_zen_of_python_koans self.sensei.pass_count = 36 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Namespaces are one honking great idea", words) self.assertTrue(m and m.group(0)) @@ -248,26 +238,22 @@ def test_that_if_there_is_37_successes_it_will_say_the_first_zen_of_python_koans self.sensei.pass_count = 37 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() - m = re.search("Beautiful is better than ugly", words) self.assertTrue(m and m.group(0)) def test_that_total_lessons_return_7_if_there_are_7_lessons(self): self.sensei.filter_all_lessons = Mock() self.sensei.filter_all_lessons.return_value = [1,2,3,4,5,6,7] - self.assertEqual(7, self.sensei.total_lessons()) def test_that_total_lessons_return_0_if_all_lessons_is_none(self): self.sensei.filter_all_lessons = Mock() self.sensei.filter_all_lessons.return_value = None - self.assertEqual(0, self.sensei.total_lessons()) def test_total_koans_return_43_if_there_are_43_test_cases(self): self.sensei.tests.countTestCases = Mock() self.sensei.tests.countTestCases.return_value = 43 - self.assertEqual(43, self.sensei.total_koans()) def test_filter_all_lessons_will_discover_test_classes_if_none_have_been_discovered_yet(self): From 95736d38ce42b42cc17a34f2f23d40e2ea26b722 Mon Sep 17 00:00:00 2001 From: Mike Pirnat Date: Thu, 29 Sep 2016 23:39:41 -0400 Subject: [PATCH 23/91] Corrected singular/plural disagreements in test function names In a wild fit of pedantry, I have changed test function names in test_sensei for both Python 2 and 3 to hvae correct verb conjugation ("is" for a single success, "are" for multiple successes). --- python2/runner/runner_tests/test_sensei.py | 8 ++++---- python3/runner/runner_tests/test_sensei.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index 999f6709a..004a48d3c 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -234,28 +234,28 @@ def test_that_if_there_are_0_successes_it_will_say_the_first_zen_of_python_koans m = re.search("Beautiful is better than ugly", words) self.assertTrue(m and m.group(0)) - def test_that_if_there_is_1_successes_it_will_say_the_second_zen_of_python_koans(self): + def test_that_if_there_is_1_success_it_will_say_the_second_zen_of_python_koans(self): self.sensei.pass_count = 1 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() m = re.search("Explicit is better than implicit", words) self.assertTrue(m and m.group(0)) - def test_that_if_there_is_10_successes_it_will_say_the_sixth_zen_of_python_koans(self): + def test_that_if_there_are_10_successes_it_will_say_the_sixth_zen_of_python_koans(self): self.sensei.pass_count = 10 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() m = re.search("Sparse is better than dense", words) self.assertTrue(m and m.group(0)) - def test_that_if_there_is_36_successes_it_will_say_the_final_zen_of_python_koans(self): + def test_that_if_there_are_36_successes_it_will_say_the_final_zen_of_python_koans(self): self.sensei.failures = Mock() self.sensei.pass_count = 36 words = self.sensei.say_something_zenlike() m = re.search("Namespaces are one honking great idea", words) self.assertTrue(m and m.group(0)) - def test_that_if_there_is_37_successes_it_will_say_the_first_zen_of_python_koans_again(self): + def test_that_if_there_are_37_successes_it_will_say_the_first_zen_of_python_koans_again(self): self.sensei.pass_count = 37 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() diff --git a/python3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py index a1ee062d4..b36c253be 100644 --- a/python3/runner/runner_tests/test_sensei.py +++ b/python3/runner/runner_tests/test_sensei.py @@ -213,28 +213,28 @@ def test_that_if_there_are_0_successes_it_will_say_the_first_zen_of_python_koans m = re.search("Beautiful is better than ugly", words) self.assertTrue(m and m.group(0)) - def test_that_if_there_is_1_successes_it_will_say_the_second_zen_of_python_koans(self): + def test_that_if_there_is_1_success_it_will_say_the_second_zen_of_python_koans(self): self.sensei.pass_count = 1 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() m = re.search("Explicit is better than implicit", words) self.assertTrue(m and m.group(0)) - def test_that_if_there_is_10_successes_it_will_say_the_sixth_zen_of_python_koans(self): + def test_that_if_there_are_10_successes_it_will_say_the_sixth_zen_of_python_koans(self): self.sensei.pass_count = 10 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() m = re.search("Sparse is better than dense", words) self.assertTrue(m and m.group(0)) - def test_that_if_there_is_36_successes_it_will_say_the_final_zen_of_python_koans(self): + def test_that_if_there_are_36_successes_it_will_say_the_final_zen_of_python_koans(self): self.sensei.pass_count = 36 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() m = re.search("Namespaces are one honking great idea", words) self.assertTrue(m and m.group(0)) - def test_that_if_there_is_37_successes_it_will_say_the_first_zen_of_python_koans_again(self): + def test_that_if_there_are_37_successes_it_will_say_the_first_zen_of_python_koans_again(self): self.sensei.pass_count = 37 self.sensei.failures = Mock() words = self.sensei.say_something_zenlike() From d6a00e745fe9a68afce407ef79179e33242540cc Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Thu, 29 Sep 2016 23:45:29 -0400 Subject: [PATCH 24/91] Test-name fixes (#139) * about_method_bindings: Fixed test name. In the Python 3 version, the function test_set_descriptor_changes_behavior_of_attribute_assignment was named: test_set_descriptor_changes_behavior_of_attribute_assignment_changes --- with an extra "_changes" at the end. Renamed it to match the more sensible Python 2 version's name. * python3/koans/about_inheritance: Fixed test name. Removed extra 'this_' left over from the Python 2 version of test: test_this_all_classes_in_python_3_ultimately_inherit_from_object_class renamed to: test_all_classes_in_python_3_ultimately_inherit_from_object_class. --- python3/koans/about_inheritance.py | 4 ++-- python3/koans/about_method_bindings.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python3/koans/about_inheritance.py b/python3/koans/about_inheritance.py index c7b02923c..5d2407dfa 100644 --- a/python3/koans/about_inheritance.py +++ b/python3/koans/about_inheritance.py @@ -25,7 +25,7 @@ def bark(self): def test_subclasses_have_the_parent_as_an_ancestor(self): self.assertEqual(__, issubclass(self.Chihuahua, self.Dog)) - def test_this_all_classes_in_python_3_ultimately_inherit_from_object_class(self): + def test_all_classes_in_python_3_ultimately_inherit_from_object_class(self): self.assertEqual(__, issubclass(self.Chihuahua, object)) # Note: This isn't the case in Python 2. In that version you have @@ -86,4 +86,4 @@ def test_base_init_does_not_get_called_automatically(self): def test_base_init_has_to_be_called_explicitly(self): boxer = self.Greyhound("Boxer") - self.assertEqual(__, boxer.name) \ No newline at end of file + self.assertEqual(__, boxer.name) diff --git a/python3/koans/about_method_bindings.py b/python3/koans/about_method_bindings.py index 5fa83204c..020851bd5 100644 --- a/python3/koans/about_method_bindings.py +++ b/python3/koans/about_method_bindings.py @@ -83,7 +83,7 @@ def __set__(self, obj, val): color = SuperColor() - def test_set_descriptor_changes_behavior_of_attribute_assignment_changes(self): + def test_set_descriptor_changes_behavior_of_attribute_assignment(self): self.assertEqual(None, self.color.choice) self.color = 'purple' self.assertEqual(__, self.color.choice) From 24c65e12914983ef51ea0da125acae0055240032 Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Tue, 27 Sep 2016 08:29:51 -0400 Subject: [PATCH 25/91] about_generators.py: Removed redundant list() calls. --- python2/koans/about_generators.py | 4 ++-- python3/koans/about_generators.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python2/koans/about_generators.py b/python2/koans/about_generators.py index 5fc239cae..74dcdc5a8 100644 --- a/python2/koans/about_generators.py +++ b/python2/koans/about_generators.py @@ -43,8 +43,8 @@ def test_generator_expressions_are_a_one_shot_deal(self): attempt1 = list(dynamite) attempt2 = list(dynamite) - self.assertEqual(__, list(attempt1)) - self.assertEqual(__, list(attempt2)) + self.assertEqual(__, attempt1) + self.assertEqual(__, attempt2) # ------------------------------------------------------------------ diff --git a/python3/koans/about_generators.py b/python3/koans/about_generators.py index 5ab4821ec..db955c495 100644 --- a/python3/koans/about_generators.py +++ b/python3/koans/about_generators.py @@ -44,8 +44,8 @@ def test_generator_expressions_are_a_one_shot_deal(self): attempt1 = list(dynamite) attempt2 = list(dynamite) - self.assertEqual(__, list(attempt1)) - self.assertEqual(__, list(attempt2)) + self.assertEqual(__, attempt1) + self.assertEqual(__, attempt2) # ------------------------------------------------------------------ From 6ebf5b6e1d4941d912792b961d191749c78a16fb Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Tue, 27 Sep 2016 08:31:45 -0400 Subject: [PATCH 26/91] about_generators: renamed test_coroutines_can_take_arguments. It's not a coroutine, and it doesn't take any arguments. New name: test_generators_can_be_manually_iterated_and_closed. --- python2/koans/about_generators.py | 2 +- python3/koans/about_generators.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_generators.py b/python2/koans/about_generators.py index 74dcdc5a8..6a7b732c7 100644 --- a/python2/koans/about_generators.py +++ b/python2/koans/about_generators.py @@ -60,7 +60,7 @@ def test_generator_method_will_yield_values_during_iteration(self): result.append(item) self.assertEqual(__, result) - def test_coroutines_can_take_arguments(self): + def test_generators_can_be_manually_iterated_and_closed(self): result = self.simple_generator_method() self.assertEqual(__, next(result)) self.assertEqual(__, next(result)) diff --git a/python3/koans/about_generators.py b/python3/koans/about_generators.py index db955c495..a85d9161d 100644 --- a/python3/koans/about_generators.py +++ b/python3/koans/about_generators.py @@ -61,7 +61,7 @@ def test_generator_method_will_yield_values_during_iteration(self): result.append(item) self.assertEqual(__, result) - def test_coroutines_can_take_arguments(self): + def test_generators_can_be_manually_iterated_and_closed(self): result = self.simple_generator_method() self.assertEqual(__, next(result)) self.assertEqual(__, next(result)) From b1c7361b4f6ab96ddcbbee1eb430ffe88c2aa941 Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Tue, 27 Sep 2016 08:42:47 -0400 Subject: [PATCH 27/91] about_generators: Renamed generator_with_coroutine and test. generator_with_coroutine is really just a simple coroutine. Renamed to just: coroutine. test_generators_can_take_coroutines renamed to slightly more descriptive: test_generators_can_act_as_coroutines. --- python2/koans/about_generators.py | 8 ++++---- python3/koans/about_generators.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python2/koans/about_generators.py b/python2/koans/about_generators.py index 6a7b732c7..21b32cc3c 100644 --- a/python2/koans/about_generators.py +++ b/python2/koans/about_generators.py @@ -91,12 +91,12 @@ def test_generator_keeps_track_of_local_variables(self): # ------------------------------------------------------------------ - def generator_with_coroutine(self): + def coroutine(self): result = yield yield result - def test_generators_can_take_coroutines(self): - generator = self.generator_with_coroutine() + def test_generators_can_act_as_coroutines(self): + generator = self.coroutine() # THINK ABOUT IT: # Why is this line necessary? @@ -108,7 +108,7 @@ def test_generators_can_take_coroutines(self): self.assertEqual(__, generator.send(1 + 2)) def test_before_sending_a_value_to_a_generator_next_must_be_called(self): - generator = self.generator_with_coroutine() + generator = self.coroutine() try: generator.send(1 + 2) diff --git a/python3/koans/about_generators.py b/python3/koans/about_generators.py index a85d9161d..3edc43a24 100644 --- a/python3/koans/about_generators.py +++ b/python3/koans/about_generators.py @@ -92,12 +92,12 @@ def test_generator_keeps_track_of_local_variables(self): # ------------------------------------------------------------------ - def generator_with_coroutine(self): + def coroutine(self): result = yield yield result - def test_generators_can_take_coroutines(self): - generator = self.generator_with_coroutine() + def test_generators_can_act_as_coroutines(self): + generator = self.coroutine() # THINK ABOUT IT: # Why is this line necessary? @@ -109,7 +109,7 @@ def test_generators_can_take_coroutines(self): self.assertEqual(__, generator.send(1 + 2)) def test_before_sending_a_value_to_a_generator_next_must_be_called(self): - generator = self.generator_with_coroutine() + generator = self.coroutine() try: generator.send(1+2) From 66fa62172075c2deb82818551abbc7bdcd0f9820 Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Tue, 27 Sep 2016 08:46:14 -0400 Subject: [PATCH 28/91] test_before_sending_a_value_to_a_generator_next_must_be_called Python 3's whitespace and general structure changed to match Python 2 version's. --- python3/koans/about_generators.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/python3/koans/about_generators.py b/python3/koans/about_generators.py index 3edc43a24..a81a43ba6 100644 --- a/python3/koans/about_generators.py +++ b/python3/koans/about_generators.py @@ -112,11 +112,9 @@ def test_before_sending_a_value_to_a_generator_next_must_be_called(self): generator = self.coroutine() try: - generator.send(1+2) + generator.send(1 + 2) except TypeError as ex: - ex2 = ex - - self.assertRegex(ex2.args[0], __) + self.assertRegex(ex.args[0], __) # ------------------------------------------------------------------ From ca7f7ac695f8c12850b88ee8b5cd1e74cfd6cecc Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Fri, 30 Sep 2016 19:02:00 -0400 Subject: [PATCH 29/91] about_modules.py: Copy old Python 2 fixes to Python 3 version. (#144) * about_modules: Py3 now mostly matches Py2 version. Ported changes made to the Python 2 version of about_modules.py (sha d65e6904, 2012-02-10) to the Python 3 version. They are now identical, except that the Python 3 version... 1. ...uses the new relative import syntax. 2. ...uses with-assertRaises(): instead of try-except. This changed one test name, but otherwise only comments and docstrings. * about_modules: Renamed test about __all__. In Python 2 and 3 versions, renamed the test method test_a_modules_XallX_statement_limits_what_wildcards_will_match to test_a_module_can_limit_wildcard_imports. Also, reformatted its docstring to put the Python code on its own line. --- python2/koans/about_modules.py | 7 +++++-- python3/koans/about_modules.py | 32 +++++++++++++++++++------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/python2/koans/about_modules.py b/python2/koans/about_modules.py index ddd1be9ff..95badd8ed 100644 --- a/python2/koans/about_modules.py +++ b/python2/koans/about_modules.py @@ -60,8 +60,11 @@ def test_private_attributes_are_still_accessible_in_modules(self): # module level attribute hiding doesn't affect class attributes # (unless the class itself is hidden). - def test_a_modules_XallX_statement_limits_what_wildcards_will_match(self): - """Examine results of from local_module_with_all_defined import *""" + def test_a_module_can_limit_wildcard_imports(self): + """ + Examine results of: + from local_module_with_all_defined import * + """ # 'Goat' is on the __all__ list goat = Goat() diff --git a/python3/koans/about_modules.py b/python3/koans/about_modules.py index 721ba2a45..7a266171d 100644 --- a/python3/koans/about_modules.py +++ b/python3/koans/about_modules.py @@ -11,9 +11,10 @@ from .another_local_module import * from .local_module_with_all_defined import * + class AboutModules(Koan): def test_importing_other_python_scripts_as_modules(self): - from . import local_module # local_module.py + from . import local_module # local_module.py duck = local_module.Duck() self.assertEqual(__, duck.name) @@ -21,7 +22,7 @@ def test_importing_other_python_scripts_as_modules(self): def test_importing_attributes_from_classes_using_from_keyword(self): from .local_module import Duck - duck = Duck() # no module qualifier needed this time + duck = Duck() # no module qualifier needed this time self.assertEqual(__, duck.name) def test_we_can_import_multiple_items_at_once(self): @@ -33,10 +34,11 @@ def test_we_can_import_multiple_items_at_once(self): self.assertEqual(__, joes_dog.identify()) def test_importing_all_module_attributes_at_once(self): - # NOTE Using this module level import declared at the top of this script: - # from .another_local_module import * - # - # Import wildcard cannot be used from within classes or functions + """ + importing all attributes at once is done like so: + from .another_local_module import * + The import wildcard cannot be used from within classes or functions. + """ goose = Goose() hamster = Hamster() @@ -45,21 +47,24 @@ def test_importing_all_module_attributes_at_once(self): self.assertEqual(__, hamster.name) def test_modules_hide_attributes_prefixed_by_underscores(self): - with self.assertRaises(___): private_squirrel = _SecretSquirrel() + with self.assertRaises(___): + private_squirrel = _SecretSquirrel() def test_private_attributes_are_still_accessible_in_modules(self): - from .local_module import Duck # local_module.py + from .local_module import Duck # local_module.py duck = Duck() self.assertEqual(__, duck._password) # module level attribute hiding doesn't affect class attributes # (unless the class itself is hidden). - def test_a_module_can_choose_which_attributes_are_available_to_wildcards(self): - # NOTE Using this module level import declared at the top of this script: - # from .local_module_with_all_defined import * + def test_a_module_can_limit_wildcard_imports(self): + """ + Examine results of: + from .local_module_with_all_defined import * + """ - # 'Goat' is on the __ALL__ list + # 'Goat' is on the __all__ list goat = Goat() self.assertEqual(__, goat.name) @@ -68,4 +73,5 @@ def test_a_module_can_choose_which_attributes_are_available_to_wildcards(self): self.assertEqual(__, lizard.name) # SecretDuck? Never heard of her! - with self.assertRaises(___): duck = SecretDuck() + with self.assertRaises(___): + duck = SecretDuck() From 3fe14a4f367afd82477b8581f6bb55616f830db6 Mon Sep 17 00:00:00 2001 From: s0urav Date: Wed, 5 Oct 2016 16:32:23 +0530 Subject: [PATCH 30/91] deleted repeated words (#145) --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 890ebcbbc..3e165ddc1 100644 --- a/README.rst +++ b/README.rst @@ -63,7 +63,7 @@ You can download Python from here: http://www.python.org/download After installing Python make sure the folder containing the python executable -is in the system path. In other words, you need to be able to be able to run +is in the system path. In other words, you need to be able to run Python from a command console. With Python 2 it will be called `python` or `python.exe` depending on the operating system. For Python 3 it will either be `python3` or for windows it will be `python.exe`. From 214d87a601a7cc04992727bb6dbadb5d7241d212 Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Sun, 4 Dec 2016 19:59:59 -0500 Subject: [PATCH 31/91] Importer (#146) * New koan loader: path_to_enlightenment.koans(). path_to_enlightenment.py now loads koans by name from a text file, instead of having them hard-coded. The names are stored in the python[23]/koans.txt file. koans calls a few helper functions to import all the actual koans. This includes a temporary test in python[23]/runner/runner_tests/test_path_to_enlightenment.py to verify the new test suite matches the original. * path_to_enlightenment: Now uses loadTestsFromName(). unittest.TestLoader already _has_ methods to load TestCases by name. * path_to_enlightenment.py: Added _useful_ tests. 2 new TestCase classes: TestFilterKoanNames and TestKoansSuite. TestKoansSuite needs more and better tests, but TestCase and TestSuite objects are hard to test without importing every constituent test by hand. That would require hard-coding the koans into the tests, which would break the instant someone adds a new koan... which is what loading the koans from a config file is supposed to fix in the first place. * Removed TestPathToEnlightenment. It was only temporary. * test_path_to_enlightenment: Safe for Python 3.1. The Unicode literal syntax requires Python 3.3+. TestCase.assertIsInstance requires Python 3.2+. --- python2/_runner_tests.py | 6 + python2/koans.txt | 41 ++++++ python2/runner/path_to_enlightenment.py | 135 +++++++----------- .../test_path_to_enlightenment.py | 103 +++++++++++++ python3/_runner_tests.py | 6 + python3/koans.txt | 40 ++++++ python3/runner/path_to_enlightenment.py | 133 +++++++---------- .../test_path_to_enlightenment.py | 103 +++++++++++++ 8 files changed, 403 insertions(+), 164 deletions(-) create mode 100644 python2/koans.txt create mode 100644 python2/runner/runner_tests/test_path_to_enlightenment.py create mode 100644 python3/koans.txt create mode 100644 python3/runner/runner_tests/test_path_to_enlightenment.py diff --git a/python2/_runner_tests.py b/python2/_runner_tests.py index ad0ad6847..26fec382d 100644 --- a/python2/_runner_tests.py +++ b/python2/_runner_tests.py @@ -7,14 +7,20 @@ from runner.runner_tests.test_mountain import TestMountain from runner.runner_tests.test_sensei import TestSensei from runner.runner_tests.test_helper import TestHelper +from runner.runner_tests.test_path_to_enlightenment import TestFilterKoanNames +from runner.runner_tests.test_path_to_enlightenment import TestKoansSuite + def suite(): suite = unittest.TestSuite() suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMountain)) suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSensei)) suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestHelper)) + suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFilterKoanNames)) + suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestKoansSuite)) return suite + if __name__ == '__main__': res = unittest.TextTestRunner(verbosity=2).run(suite()) sys.exit(not res.wasSuccessful()) diff --git a/python2/koans.txt b/python2/koans.txt new file mode 100644 index 000000000..e980c7ea2 --- /dev/null +++ b/python2/koans.txt @@ -0,0 +1,41 @@ +# Lines starting with # are ignored. +koans.about_asserts.AboutAsserts +koans.about_strings.AboutStrings +koans.about_none.AboutNone +koans.about_lists.AboutLists +koans.about_list_assignments.AboutListAssignments +koans.about_dictionaries.AboutDictionaries +koans.about_string_manipulation.AboutStringManipulation +koans.about_tuples.AboutTuples +koans.about_methods.AboutMethods +koans.about_control_statements.AboutControlStatements +koans.about_true_and_false.AboutTrueAndFalse +koans.about_sets.AboutSets +koans.about_triangle_project.AboutTriangleProject +koans.about_exceptions.AboutExceptions +koans.about_triangle_project2.AboutTriangleProject2 +koans.about_iteration.AboutIteration +koans.about_comprehension.AboutComprehension +koans.about_generators.AboutGenerators +koans.about_lambdas.AboutLambdas +koans.about_scoring_project.AboutScoringProject +koans.about_classes.AboutClasses +koans.about_new_style_classes.AboutNewStyleClasses +koans.about_with_statements.AboutWithStatements +koans.about_monkey_patching.AboutMonkeyPatching +koans.about_dice_project.AboutDiceProject +koans.about_method_bindings.AboutMethodBindings +koans.about_decorating_with_functions.AboutDecoratingWithFunctions +koans.about_decorating_with_classes.AboutDecoratingWithClasses +koans.about_inheritance.AboutInheritance +koans.about_multiple_inheritance.AboutMultipleInheritance +koans.about_scope.AboutScope +koans.about_modules.AboutModules +koans.about_packages.AboutPackages +koans.about_class_attributes.AboutClassAttributes +koans.about_attribute_access.AboutAttributeAccess +koans.about_deleting_objects.AboutDeletingObjects +koans.about_proxy_object_project.AboutProxyObjectProject +koans.about_proxy_object_project.TelevisionTest +koans.about_extra_credit.AboutExtraCredit +koans.about_regex.AboutRegex diff --git a/python2/runner/path_to_enlightenment.py b/python2/runner/path_to_enlightenment.py index 21758bcec..b6c2fa55f 100644 --- a/python2/runner/path_to_enlightenment.py +++ b/python2/runner/path_to_enlightenment.py @@ -1,93 +1,62 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# The path to enlightenment starts with the following: +''' +Functions to load the test cases ("koans") that make up the +Path to Enlightenment. +''' +import io import unittest -from koans.about_asserts import AboutAsserts -from koans.about_strings import AboutStrings -from koans.about_none import AboutNone -from koans.about_lists import AboutLists -from koans.about_list_assignments import AboutListAssignments -from koans.about_dictionaries import AboutDictionaries -from koans.about_string_manipulation import AboutStringManipulation -from koans.about_tuples import AboutTuples -from koans.about_methods import AboutMethods -from koans.about_control_statements import AboutControlStatements -from koans.about_true_and_false import AboutTrueAndFalse -from koans.about_sets import AboutSets -from koans.about_triangle_project import AboutTriangleProject -from koans.about_exceptions import AboutExceptions -from koans.about_triangle_project2 import AboutTriangleProject2 -from koans.about_iteration import AboutIteration -from koans.about_comprehension import AboutComprehension -from koans.about_generators import AboutGenerators -from koans.about_lambdas import AboutLambdas -from koans.about_scoring_project import AboutScoringProject -from koans.about_classes import AboutClasses -from koans.about_new_style_classes import AboutNewStyleClasses -from koans.about_with_statements import AboutWithStatements -from koans.about_monkey_patching import AboutMonkeyPatching -from koans.about_dice_project import AboutDiceProject -from koans.about_method_bindings import AboutMethodBindings -from koans.about_decorating_with_functions import AboutDecoratingWithFunctions -from koans.about_decorating_with_classes import AboutDecoratingWithClasses -from koans.about_inheritance import AboutInheritance -from koans.about_multiple_inheritance import AboutMultipleInheritance -from koans.about_regex import AboutRegex -from koans.about_scope import AboutScope -from koans.about_modules import AboutModules -from koans.about_packages import AboutPackages -from koans.about_class_attributes import AboutClassAttributes -from koans.about_attribute_access import AboutAttributeAccess -from koans.about_deleting_objects import AboutDeletingObjects -from koans.about_proxy_object_project import * -from koans.about_extra_credit import AboutExtraCredit -def koans(): - loader = unittest.TestLoader() +# The path to enlightenment starts with the following: +KOANS_FILENAME = 'koans.txt' + + +def filter_koan_names(lines): + ''' + Strips leading and trailing whitespace, then filters out blank + lines and comment lines. + ''' + for line in lines: + line = line.strip() + if line.startswith('#'): + continue + if line: + yield line + return + + +def names_from_file(filename): + ''' + Opens the given ``filename`` and yields the fully-qualified names + of TestCases found inside (one per line). + ''' + with io.open(filename, 'rt', encoding='utf8') as names_file: + for name in filter_koan_names(names_file): + yield name + return + + +def koans_suite(names): + ''' + Returns a ``TestSuite`` loaded with all tests found in the given + ``names``, preserving the order in which they are found. + ''' suite = unittest.TestSuite() + loader = unittest.TestLoader() loader.sortTestMethodsUsing = None - suite.addTests(loader.loadTestsFromTestCase(AboutAsserts)) - suite.addTests(loader.loadTestsFromTestCase(AboutStrings)) - suite.addTests(loader.loadTestsFromTestCase(AboutNone)) - suite.addTests(loader.loadTestsFromTestCase(AboutLists)) - suite.addTests(loader.loadTestsFromTestCase(AboutListAssignments)) - suite.addTests(loader.loadTestsFromTestCase(AboutDictionaries)) - suite.addTests(loader.loadTestsFromTestCase(AboutStringManipulation)) - suite.addTests(loader.loadTestsFromTestCase(AboutTuples)) - suite.addTests(loader.loadTestsFromTestCase(AboutMethods)) - suite.addTests(loader.loadTestsFromTestCase(AboutControlStatements)) - suite.addTests(loader.loadTestsFromTestCase(AboutTrueAndFalse)) - suite.addTests(loader.loadTestsFromTestCase(AboutSets)) - suite.addTests(loader.loadTestsFromTestCase(AboutTriangleProject)) - suite.addTests(loader.loadTestsFromTestCase(AboutExceptions)) - suite.addTests(loader.loadTestsFromTestCase(AboutTriangleProject2)) - suite.addTests(loader.loadTestsFromTestCase(AboutIteration)) - suite.addTests(loader.loadTestsFromTestCase(AboutComprehension)) - suite.addTests(loader.loadTestsFromTestCase(AboutGenerators)) - suite.addTests(loader.loadTestsFromTestCase(AboutLambdas)) - suite.addTests(loader.loadTestsFromTestCase(AboutScoringProject)) - suite.addTests(loader.loadTestsFromTestCase(AboutClasses)) - suite.addTests(loader.loadTestsFromTestCase(AboutNewStyleClasses)) - suite.addTests(loader.loadTestsFromTestCase(AboutWithStatements)) - suite.addTests(loader.loadTestsFromTestCase(AboutMonkeyPatching)) - suite.addTests(loader.loadTestsFromTestCase(AboutDiceProject)) - suite.addTests(loader.loadTestsFromTestCase(AboutMethodBindings)) - suite.addTests(loader.loadTestsFromTestCase(AboutDecoratingWithFunctions)) - suite.addTests(loader.loadTestsFromTestCase(AboutDecoratingWithClasses)) - suite.addTests(loader.loadTestsFromTestCase(AboutInheritance)) - suite.addTests(loader.loadTestsFromTestCase(AboutMultipleInheritance)) - suite.addTests(loader.loadTestsFromTestCase(AboutScope)) - suite.addTests(loader.loadTestsFromTestCase(AboutModules)) - suite.addTests(loader.loadTestsFromTestCase(AboutPackages)) - suite.addTests(loader.loadTestsFromTestCase(AboutClassAttributes)) - suite.addTests(loader.loadTestsFromTestCase(AboutAttributeAccess)) - suite.addTests(loader.loadTestsFromTestCase(AboutDeletingObjects)) - suite.addTests(loader.loadTestsFromTestCase(AboutProxyObjectProject)) - suite.addTests(loader.loadTestsFromTestCase(TelevisionTest)) - suite.addTests(loader.loadTestsFromTestCase(AboutExtraCredit)) - suite.addTests(loader.loadTestsFromTestCase(AboutRegex)) - + for name in names: + tests = loader.loadTestsFromName(name) + suite.addTests(tests) return suite + + +def koans(filename=KOANS_FILENAME): + ''' + Returns a ``TestSuite`` loaded with all the koans (``TestCase``s) + listed in ``filename``. + ''' + names = names_from_file(filename) + return koans_suite(names) diff --git a/python2/runner/runner_tests/test_path_to_enlightenment.py b/python2/runner/runner_tests/test_path_to_enlightenment.py new file mode 100644 index 000000000..25bff45e1 --- /dev/null +++ b/python2/runner/runner_tests/test_path_to_enlightenment.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import io +import unittest + +from runner import path_to_enlightenment as pte + + +class TestFilterKoanNames(unittest.TestCase): + + def test_empty_input_produces_empty_output(self): + infile = io.StringIO(u'') + expected = [] + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(expected, received) + return + + def test_names_yielded_match_names_in_file(self): + names = [ + u'this.is.a.test', + u'this.is.only.a.test', + ] + infile = io.StringIO(u'\n'.join(names)) + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(names, received) + return + + def test_whitespace_is_stripped(self): + names = [ + u'this.is.a.test', + u' white.space.should.be.stripped', + u'this.is.only.a.test', + u'white.space.should.be.stripped ', + ] + infile = io.StringIO(u'\n'.join(names)) + expected = [ + u'this.is.a.test', + u'white.space.should.be.stripped', + u'this.is.only.a.test', + u'white.space.should.be.stripped', + ] + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(expected, received) + return + + def test_commented_out_names_are_excluded(self): + names = [ + u'this.is.a.test', + u'#this.is.a.comment', + u'this.is.only.a.test', + u' # this.is.also a.comment ', + ] + infile = io.StringIO(u'\n'.join(names)) + expected = [ + u'this.is.a.test', + u'this.is.only.a.test', + ] + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(expected, received) + return + + def all_blank_or_comment_lines_produce_empty_output(self): + names = [ + u' ', + u'# This is a comment.', + u'\t', + u' # This is also a comment.', + ] + infile = io.StringIO(u'\n'.join(names)) + expected = [] + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(expected, received) + return + + +class TestKoansSuite(unittest.TestCase): + + def test_empty_input_produces_empty_testsuite(self): + names = [] + suite = pte.koans_suite(names) + self.assertIsInstance(suite, unittest.TestSuite) + expected = [] + received = list(suite) + self.assertListEqual(expected, received) + return + + def test_testcase_names_appear_in_testsuite(self): + names = [ + 'koans.about_asserts.AboutAsserts', + 'koans.about_none.AboutNone', + 'koans.about_strings.AboutStrings', + ] + suite = pte.koans_suite(names) + self.assertIsInstance(suite, unittest.TestSuite) + expected = [ + 'AboutAsserts', + 'AboutNone', + 'AboutStrings', + ] + received = sorted(set(test.__class__.__name__ for test in suite)) + self.assertListEqual(expected, received) + return diff --git a/python3/_runner_tests.py b/python3/_runner_tests.py index ad0ad6847..26fec382d 100644 --- a/python3/_runner_tests.py +++ b/python3/_runner_tests.py @@ -7,14 +7,20 @@ from runner.runner_tests.test_mountain import TestMountain from runner.runner_tests.test_sensei import TestSensei from runner.runner_tests.test_helper import TestHelper +from runner.runner_tests.test_path_to_enlightenment import TestFilterKoanNames +from runner.runner_tests.test_path_to_enlightenment import TestKoansSuite + def suite(): suite = unittest.TestSuite() suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMountain)) suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSensei)) suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestHelper)) + suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFilterKoanNames)) + suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestKoansSuite)) return suite + if __name__ == '__main__': res = unittest.TextTestRunner(verbosity=2).run(suite()) sys.exit(not res.wasSuccessful()) diff --git a/python3/koans.txt b/python3/koans.txt new file mode 100644 index 000000000..8e2788028 --- /dev/null +++ b/python3/koans.txt @@ -0,0 +1,40 @@ +# Lines starting with # are ignored. +koans.about_asserts.AboutAsserts +koans.about_strings.AboutStrings +koans.about_none.AboutNone +koans.about_lists.AboutLists +koans.about_list_assignments.AboutListAssignments +koans.about_dictionaries.AboutDictionaries +koans.about_string_manipulation.AboutStringManipulation +koans.about_tuples.AboutTuples +koans.about_methods.AboutMethods +koans.about_control_statements.AboutControlStatements +koans.about_true_and_false.AboutTrueAndFalse +koans.about_sets.AboutSets +koans.about_triangle_project.AboutTriangleProject +koans.about_exceptions.AboutExceptions +koans.about_triangle_project2.AboutTriangleProject2 +koans.about_iteration.AboutIteration +koans.about_comprehension.AboutComprehension +koans.about_generators.AboutGenerators +koans.about_lambdas.AboutLambdas +koans.about_scoring_project.AboutScoringProject +koans.about_classes.AboutClasses +koans.about_with_statements.AboutWithStatements +koans.about_monkey_patching.AboutMonkeyPatching +koans.about_dice_project.AboutDiceProject +koans.about_method_bindings.AboutMethodBindings +koans.about_decorating_with_functions.AboutDecoratingWithFunctions +koans.about_decorating_with_classes.AboutDecoratingWithClasses +koans.about_inheritance.AboutInheritance +koans.about_multiple_inheritance.AboutMultipleInheritance +koans.about_scope.AboutScope +koans.about_modules.AboutModules +koans.about_packages.AboutPackages +koans.about_class_attributes.AboutClassAttributes +koans.about_attribute_access.AboutAttributeAccess +koans.about_deleting_objects.AboutDeletingObjects +koans.about_proxy_object_project.AboutProxyObjectProject +koans.about_proxy_object_project.TelevisionTest +koans.about_extra_credit.AboutExtraCredit +koans.about_regex.AboutRegex diff --git a/python3/runner/path_to_enlightenment.py b/python3/runner/path_to_enlightenment.py index e8a23fa32..b6c2fa55f 100644 --- a/python3/runner/path_to_enlightenment.py +++ b/python3/runner/path_to_enlightenment.py @@ -1,91 +1,62 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# The path to enlightenment starts with the following: +''' +Functions to load the test cases ("koans") that make up the +Path to Enlightenment. +''' +import io import unittest -from koans.about_asserts import AboutAsserts -from koans.about_strings import AboutStrings -from koans.about_none import AboutNone -from koans.about_lists import AboutLists -from koans.about_list_assignments import AboutListAssignments -from koans.about_dictionaries import AboutDictionaries -from koans.about_string_manipulation import AboutStringManipulation -from koans.about_tuples import AboutTuples -from koans.about_methods import AboutMethods -from koans.about_control_statements import AboutControlStatements -from koans.about_true_and_false import AboutTrueAndFalse -from koans.about_sets import AboutSets -from koans.about_triangle_project import AboutTriangleProject -from koans.about_exceptions import AboutExceptions -from koans.about_triangle_project2 import AboutTriangleProject2 -from koans.about_iteration import AboutIteration -from koans.about_comprehension import AboutComprehension -from koans.about_generators import AboutGenerators -from koans.about_lambdas import AboutLambdas -from koans.about_scoring_project import AboutScoringProject -from koans.about_classes import AboutClasses -from koans.about_with_statements import AboutWithStatements -from koans.about_monkey_patching import AboutMonkeyPatching -from koans.about_dice_project import AboutDiceProject -from koans.about_method_bindings import AboutMethodBindings -from koans.about_decorating_with_functions import AboutDecoratingWithFunctions -from koans.about_decorating_with_classes import AboutDecoratingWithClasses -from koans.about_inheritance import AboutInheritance -from koans.about_multiple_inheritance import AboutMultipleInheritance -from koans.about_regex import AboutRegex -from koans.about_scope import AboutScope -from koans.about_modules import AboutModules -from koans.about_packages import AboutPackages -from koans.about_class_attributes import AboutClassAttributes -from koans.about_attribute_access import AboutAttributeAccess -from koans.about_deleting_objects import AboutDeletingObjects -from koans.about_proxy_object_project import * -from koans.about_extra_credit import AboutExtraCredit -def koans(): - loader = unittest.TestLoader() +# The path to enlightenment starts with the following: +KOANS_FILENAME = 'koans.txt' + + +def filter_koan_names(lines): + ''' + Strips leading and trailing whitespace, then filters out blank + lines and comment lines. + ''' + for line in lines: + line = line.strip() + if line.startswith('#'): + continue + if line: + yield line + return + + +def names_from_file(filename): + ''' + Opens the given ``filename`` and yields the fully-qualified names + of TestCases found inside (one per line). + ''' + with io.open(filename, 'rt', encoding='utf8') as names_file: + for name in filter_koan_names(names_file): + yield name + return + + +def koans_suite(names): + ''' + Returns a ``TestSuite`` loaded with all tests found in the given + ``names``, preserving the order in which they are found. + ''' suite = unittest.TestSuite() + loader = unittest.TestLoader() loader.sortTestMethodsUsing = None - suite.addTests(loader.loadTestsFromTestCase(AboutAsserts)) - suite.addTests(loader.loadTestsFromTestCase(AboutStrings)) - suite.addTests(loader.loadTestsFromTestCase(AboutNone)) - suite.addTests(loader.loadTestsFromTestCase(AboutLists)) - suite.addTests(loader.loadTestsFromTestCase(AboutListAssignments)) - suite.addTests(loader.loadTestsFromTestCase(AboutDictionaries)) - suite.addTests(loader.loadTestsFromTestCase(AboutStringManipulation)) - suite.addTests(loader.loadTestsFromTestCase(AboutTuples)) - suite.addTests(loader.loadTestsFromTestCase(AboutMethods)) - suite.addTests(loader.loadTestsFromTestCase(AboutControlStatements)) - suite.addTests(loader.loadTestsFromTestCase(AboutTrueAndFalse)) - suite.addTests(loader.loadTestsFromTestCase(AboutSets)) - suite.addTests(loader.loadTestsFromTestCase(AboutTriangleProject)) - suite.addTests(loader.loadTestsFromTestCase(AboutExceptions)) - suite.addTests(loader.loadTestsFromTestCase(AboutTriangleProject2)) - suite.addTests(loader.loadTestsFromTestCase(AboutIteration)) - suite.addTests(loader.loadTestsFromTestCase(AboutComprehension)) - suite.addTests(loader.loadTestsFromTestCase(AboutGenerators)) - suite.addTests(loader.loadTestsFromTestCase(AboutLambdas)) - suite.addTests(loader.loadTestsFromTestCase(AboutScoringProject)) - suite.addTests(loader.loadTestsFromTestCase(AboutClasses)) - suite.addTests(loader.loadTestsFromTestCase(AboutWithStatements)) - suite.addTests(loader.loadTestsFromTestCase(AboutMonkeyPatching)) - suite.addTests(loader.loadTestsFromTestCase(AboutDiceProject)) - suite.addTests(loader.loadTestsFromTestCase(AboutMethodBindings)) - suite.addTests(loader.loadTestsFromTestCase(AboutDecoratingWithFunctions)) - suite.addTests(loader.loadTestsFromTestCase(AboutDecoratingWithClasses)) - suite.addTests(loader.loadTestsFromTestCase(AboutInheritance)) - suite.addTests(loader.loadTestsFromTestCase(AboutMultipleInheritance)) - suite.addTests(loader.loadTestsFromTestCase(AboutScope)) - suite.addTests(loader.loadTestsFromTestCase(AboutModules)) - suite.addTests(loader.loadTestsFromTestCase(AboutPackages)) - suite.addTests(loader.loadTestsFromTestCase(AboutClassAttributes)) - suite.addTests(loader.loadTestsFromTestCase(AboutAttributeAccess)) - suite.addTests(loader.loadTestsFromTestCase(AboutDeletingObjects)) - suite.addTests(loader.loadTestsFromTestCase(AboutProxyObjectProject)) - suite.addTests(loader.loadTestsFromTestCase(TelevisionTest)) - suite.addTests(loader.loadTestsFromTestCase(AboutExtraCredit)) - suite.addTests(loader.loadTestsFromTestCase(AboutRegex)) - + for name in names: + tests = loader.loadTestsFromName(name) + suite.addTests(tests) return suite + + +def koans(filename=KOANS_FILENAME): + ''' + Returns a ``TestSuite`` loaded with all the koans (``TestCase``s) + listed in ``filename``. + ''' + names = names_from_file(filename) + return koans_suite(names) diff --git a/python3/runner/runner_tests/test_path_to_enlightenment.py b/python3/runner/runner_tests/test_path_to_enlightenment.py new file mode 100644 index 000000000..dd00a40ef --- /dev/null +++ b/python3/runner/runner_tests/test_path_to_enlightenment.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import io +import unittest + +from runner import path_to_enlightenment as pte + + +class TestFilterKoanNames(unittest.TestCase): + + def test_empty_input_produces_empty_output(self): + infile = io.StringIO('') + expected = [] + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(expected, received) + return + + def test_names_yielded_match_names_in_file(self): + names = [ + 'this.is.a.test', + 'this.is.only.a.test', + ] + infile = io.StringIO('\n'.join(names)) + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(names, received) + return + + def test_whitespace_is_stripped(self): + names = [ + 'this.is.a.test', + ' white.space.should.be.stripped', + 'this.is.only.a.test', + 'white.space.should.be.stripped ', + ] + infile = io.StringIO('\n'.join(names)) + expected = [ + 'this.is.a.test', + 'white.space.should.be.stripped', + 'this.is.only.a.test', + 'white.space.should.be.stripped', + ] + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(expected, received) + return + + def test_commented_out_names_are_excluded(self): + names = [ + 'this.is.a.test', + '#this.is.a.comment', + 'this.is.only.a.test', + ' # this.is.also a.comment ', + ] + infile = io.StringIO('\n'.join(names)) + expected = [ + 'this.is.a.test', + 'this.is.only.a.test', + ] + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(expected, received) + return + + def all_blank_or_comment_lines_produce_empty_output(self): + names = [ + ' ', + '# This is a comment.', + '\t', + ' # This is also a comment.', + ] + infile = io.StringIO('\n'.join(names)) + expected = [] + received = list(pte.filter_koan_names(infile)) + self.assertListEqual(expected, received) + return + + +class TestKoansSuite(unittest.TestCase): + + def test_empty_input_produces_empty_testsuite(self): + names = [] + suite = pte.koans_suite(names) + self.assertTrue(isinstance(suite, unittest.TestSuite)) + expected = [] + received = list(suite) + self.assertListEqual(expected, received) + return + + def test_testcase_names_appear_in_testsuite(self): + names = [ + 'koans.about_asserts.AboutAsserts', + 'koans.about_none.AboutNone', + 'koans.about_strings.AboutStrings', + ] + suite = pte.koans_suite(names) + self.assertTrue(isinstance(suite, unittest.TestSuite)) + expected = [ + 'AboutAsserts', + 'AboutNone', + 'AboutStrings', + ] + received = sorted(set(test.__class__.__name__ for test in suite)) + self.assertListEqual(expected, received) + return From 9dca2c03cfefafeca8f0fb6f85d47525bbe39126 Mon Sep 17 00:00:00 2001 From: Alejandro Villarreal Date: Sun, 4 Dec 2016 19:04:55 -0600 Subject: [PATCH 32/91] Explain errors to be handled in TriangleProject2 (#147) --- python2/koans/about_triangle_project2.py | 10 ++++++++-- python3/koans/about_triangle_project2.py | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/python2/koans/about_triangle_project2.py b/python2/koans/about_triangle_project2.py index ad637f602..0704edc1a 100644 --- a/python2/koans/about_triangle_project2.py +++ b/python2/koans/about_triangle_project2.py @@ -11,9 +11,15 @@ class AboutTriangleProject2(Koan): # The first assignment did not talk about how to handle errors. # Let's handle that part now. def test_illegal_triangles_throw_exceptions(self): - # Calls triangle(0, 0, 0) + # In the code below, each line calls the specfied method with the arguments passed to it. + # E.g. this line: + # self.assertRaises(TriangleError, triangle, 0, 0, 0) + # calls triangle(0, 0, 0) + + # All sides should be greater than 0 self.assertRaises(TriangleError, triangle, 0, 0, 0) - self.assertRaises(TriangleError, triangle, 3, 4, -5) + + # The sum of any two sides should be greater than the third one self.assertRaises(TriangleError, triangle, 1, 1, 3) self.assertRaises(TriangleError, triangle, 2, 5, 2) diff --git a/python3/koans/about_triangle_project2.py b/python3/koans/about_triangle_project2.py index 83267d082..6113f6180 100644 --- a/python3/koans/about_triangle_project2.py +++ b/python3/koans/about_triangle_project2.py @@ -10,15 +10,15 @@ class AboutTriangleProject2(Koan): # The first assignment did not talk about how to handle errors. # Let's handle that part now. def test_illegal_triangles_throw_exceptions(self): + # All sides should be greater than 0 with self.assertRaises(TriangleError): triangle(0, 0, 0) - with self.assertRaises(TriangleError): triangle(3, 4, -5) + # The sum of any two sides should be greater than the third one with self.assertRaises(TriangleError): triangle(1, 1, 3) - with self.assertRaises(TriangleError): triangle(2, 5, 2) From 23ade002f0e45e2cd2bfa5d974b89ed349bf65e2 Mon Sep 17 00:00:00 2001 From: egonluo <9925174@qq.com> Date: Mon, 5 Dec 2016 09:32:52 +0800 Subject: [PATCH 33/91] Update about_new_style_classes.py to make new-style class tests more consistent (#148) Changed __class__ to __class__.__name__ in line 49 to be consistent with other tests illustrating new-style classes. --- python2/koans/about_new_style_classes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_new_style_classes.py b/python2/koans/about_new_style_classes.py index 6a2077580..9ce7e3aef 100644 --- a/python2/koans/about_new_style_classes.py +++ b/python2/koans/about_new_style_classes.py @@ -46,7 +46,7 @@ def test_old_style_classes_have_type_but_no_class_attribute(self): def test_new_style_classes_have_same_class_as_type(self): new_style = self.NewStyleClass() - self.assertEqual(__, self.NewStyleClass.__class__) + self.assertEqual(__, self.NewStyleClass.__class__.__name__) self.assertEqual( __, type(self.NewStyleClass) == self.NewStyleClass.__class__) From b61f2fb002b7f1d135717e04c32a178751c6adb4 Mon Sep 17 00:00:00 2001 From: Mike Pirnat Date: Sun, 4 Dec 2016 20:35:44 -0500 Subject: [PATCH 34/91] Improved comments about classic and new-style classes --- python2/koans/about_new_style_classes.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/python2/koans/about_new_style_classes.py b/python2/koans/about_new_style_classes.py index 9ce7e3aef..a41f9a34b 100644 --- a/python2/koans/about_new_style_classes.py +++ b/python2/koans/about_new_style_classes.py @@ -7,14 +7,18 @@ class AboutNewStyleClasses(Koan): class OldStyleClass: "An old style class" - # Original class style have been phased out in Python 3. + # Original style classes from Python 2.1 and earlier, also known as + # "classic classes", have been phased out in Python 3. class NewStyleClass(object): "A new style class" - # Introduced in Python 2.2 + # Introduced in Python 2.2 to unify types and classes. + # + # If you want to learn more, see: + # https://www.python.org/download/releases/2.2.3/descrintro/ # # Aside from this set of tests, Python Koans sticks exclusively to this - # kind of class + # kind of class. pass def test_new_style_classes_inherit_from_object_base_class(self): From 95bfb6a6b37668dd951ce220dded7e3df04ace6e Mon Sep 17 00:00:00 2001 From: Mike Pirnat Date: Sun, 4 Dec 2016 20:51:38 -0500 Subject: [PATCH 35/91] Fix #97 - remove debug code that causes infinite loop Debug code in python2/koans/about_attribute access caused an infinite loop when run. It has been removed per the suggestions in the bug description. Also made the Python 3 version of this bit consistent with the Python 2 version by relocating a comment. --- python2/koans/about_attribute_access.py | 4 ---- python3/koans/about_attribute_access.py | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/python2/koans/about_attribute_access.py b/python2/koans/about_attribute_access.py index ac9e16f20..24d30fde6 100644 --- a/python2/koans/about_attribute_access.py +++ b/python2/koans/about_attribute_access.py @@ -105,10 +105,6 @@ def __init__(self): self.no_of_getattribute_calls = 0 def __getattribute__(self, attr_name): - #Uncomment for debugging info: - #print 'Debug __getattribute__(' + type(self).__name__ + \ - # "." + attr_name + ") dict=" + str(self.__dict__) - # We need something that is outside the scope of this class: global stack_depth stack_depth += 1 diff --git a/python3/koans/about_attribute_access.py b/python3/koans/about_attribute_access.py index 6ab5d82ca..f12f61143 100644 --- a/python3/koans/about_attribute_access.py +++ b/python3/koans/about_attribute_access.py @@ -93,7 +93,8 @@ def __init__(self): self.no_of_getattribute_calls = 0 def __getattribute__(self, attr_name): - global stack_depth # We need something that is outside the scope of this class + # We need something that is outside the scope of this class: + global stack_depth stack_depth += 1 if stack_depth<=10: # to prevent a stack overflow From 3ce0bbc3f0a688ec9b69f56444cc3a4f390b28b3 Mon Sep 17 00:00:00 2001 From: Henrique Soejima Date: Fri, 9 Dec 2016 01:06:41 -0200 Subject: [PATCH 36/91] adding the achieved percentage of success (#151) --- python2/runner/sensei.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index e38d3a5e8..28f3d65c8 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -167,10 +167,12 @@ def scrapeInterestingStackDump(self, err): return stack_text def report_progress(self): - return "You have completed {0} koans and " \ - "{1} lessons.".format( + return "You have completed {0} ({2} %) koans and " \ + "{1} (out of {3}) lessons.".format( self.pass_count, - self.lesson_pass_count) + self.lesson_pass_count, + self.pass_count*100/self.total_koans(), + self.total_lessons()) def report_remaining(self): koans_remaining = self.total_koans() - self.pass_count From 53df61e2d3d80df9f38898524fa56939744499f3 Mon Sep 17 00:00:00 2001 From: Mike Pirnat Date: Thu, 8 Dec 2016 22:17:35 -0500 Subject: [PATCH 37/91] Added progress percentage to Python 3 runner to be consistent with Py2 --- python3/runner/sensei.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index 6aeb49608..edbf4557b 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -167,10 +167,12 @@ def scrapeInterestingStackDump(self, err): return stack_text def report_progress(self): - return "You have completed {0} koans and " \ - "{1} lessons.".format( + return "You have completed {0} ({2} %) koans and " \ + "{1} (out of {3}) lessons.".format( self.pass_count, - self.lesson_pass_count) + self.lesson_pass_count, + self.pass_count*100//self.total_koans(), + self.total_lessons()) def report_remaining(self): koans_remaining = self.total_koans() - self.pass_count From 37c7ee1d941b32868d554895b7cf79d844066924 Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Fri, 21 Jul 2017 19:01:31 -0400 Subject: [PATCH 38/91] Whitespace fixes from Py2 version applied to Py3. This makes the Python 3 version of about_regex.py identical to the Python 2 version. Most of the whitespace and grammar fixes were made to only the Python 2 version on Fri 10 Feb 2012 by gregmalcolm, as part of a larger commit: Merged generators fix from engored and pep8 fixes from sietsebb via bitbucket mirror https://github.com/gregmalcolm/python_koans/commit/d65e6904712416c663abd2a67dcf2d71153015c2#diff-612bda3dc05c74b8fdd16c0df2dd28c8 (Only about a half-dozen minor changes have been made since then.) --- python3/koans/about_regex.py | 106 +++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 41 deletions(-) diff --git a/python3/koans/about_regex.py b/python3/koans/about_regex.py index ad52e2946..f562594e5 100644 --- a/python3/koans/about_regex.py +++ b/python3/koans/about_regex.py @@ -2,11 +2,15 @@ # -*- coding: utf-8 -*- from runner.koan import * + import re + + class AboutRegex(Koan): """ - These koans are based on the Ben's book: Regular Expressions in 10 minutes. - I found this books very useful so I decided to write a koans in order to practice everything I had learned from it. + These koans are based on Ben's book: Regular Expressions in 10 + minutes. I found this book very useful, so I decided to write + a koan file in order to practice everything it taught me. http://www.forta.com/books/0672325667/ """ @@ -14,47 +18,60 @@ def test_matching_literal_text(self): """ Lesson 1 Matching Literal String """ - string = "Hello, my name is Felix and this koans are based on the Ben's book: Regular Expressions in 10 minutes." + string = "Hello, my name is Felix and these koans are based " + \ + "on Ben's book: Regular Expressions in 10 minutes." m = re.search(__, string) - self.assertTrue(m and m.group(0) and m.group(0)== 'Felix', "I want my name") + self.assertTrue( + m and m.group(0) and + m.group(0) == 'Felix', + "I want my name") def test_matching_literal_text_how_many(self): """ - Lesson 1 How many matches? - - The default behaviour of most regular expression engines is to return just the first match. - In python you have the next options: - - match() --> Determine if the RE matches at the beginning of the string. - search() --> Scan through a string, looking for any location where this RE matches. - findall() --> Find all substrings where the RE matches, and returns them as a list. - finditer() --> Find all substrings where the RE matches, and returns them as an iterator. - + Lesson 1 -- How many matches? + + The default behaviour of most regular expression engines is + to return just the first match. In python you have the + following options: + + match() --> Determine if the RE matches at the + beginning of the string. + search() --> Scan through a string, looking for any + location where this RE matches. + findall() --> Find all substrings where the RE + matches, and return them as a list. + finditer() --> Find all substrings where the RE + matches, and return them as an iterator. """ - string = "Hello, my name is Felix and this koans are based on the Ben's book: Regular Expressions in 10 minutes. Repeat My name is Felix" - m = re.match('Felix', string) #TIP: Maybe match it's not the best option + string = ("Hello, my name is Felix and these koans are based " + + "on Ben's book: Regular Expressions in 10 minutes. " + + "Repeat My name is Felix") + m = re.match('Felix', string) # TIP: match may not be the best option - # I want to know how many times appears my name + # I want to know how many times my name appears self.assertEqual(m, __) def test_matching_literal_text_not_case_sensitivity(self): """ - Lesson 1 Matching Literal String non case sensitivity. - Most regex implementations also support matches that are not case sensitive. In python you can use re.IGNORECASE, in - Javascript you can specify the optional i flag. - In Ben's book you can see more languages. + Lesson 1 -- Matching Literal String non case sensitivity. + Most regex implementations also support matches that are not + case sensitive. In python you can use re.IGNORECASE, in + Javascript you can specify the optional i flag. In Ben's + book you can see more languages. """ - string = "Hello, my name is Felix or felix and this koans is based on the Ben's book: Regular Expressions in 10 minutes." + string = "Hello, my name is Felix or felix and this koan " + \ + "is based on Ben's book: Regular Expressions in 10 minutes." self.assertEqual(re.findall("felix", string), __) self.assertEqual(re.findall("felix", string, re.IGNORECASE), __) def test_matching_any_character(self): """ - Lesson 1 Matching any character + Lesson 1: Matching any character - . matches any character, alphabetic characters, digits and . + `.` matches any character: alphabetic characters, digits, + and punctuation. """ string = "pecks.xlx\n" \ + "orders1.xls\n" \ @@ -63,17 +80,19 @@ def test_matching_any_character(self): + "na2.xls\n" \ + "sa1.xls" - # TIP: remember the name of this lesson - - change_this_search_string = 'a..xlx' # <-- I want to find all uses of myArray - self.assertEquals(len(re.findall(change_this_search_string, string)),3) + # I want to find all uses of myArray + change_this_search_string = 'a..xlx' + self.assertEquals( + len(re.findall(change_this_search_string, string)), + 3) def test_matching_set_character(self): """ - Lesson 2 Matching sets of characters + Lesson 2 -- Matching sets of characters - A set of characters is defined using the metacharacters [ and ]. Everything between them is part of the set and - any one of the set members must match (but not all). + A set of characters is defined using the metacharacters + `[` and `]`. Everything between them is part of the set, and + any single one of the set members will match. """ string = "sales.xlx\n" \ + "sales1.xls\n" \ @@ -84,16 +103,21 @@ def test_matching_set_character(self): + "na2.xls\n" \ + "sa1.xls\n" \ + "ca1.xls" - # I want to find all files for North America(na) or South America(sa), but not (ca) - # TIP you can use the pattern .a. which matches in above test but in this case matches more than you want + # I want to find all files for North America(na) or South + # America(sa), but not (ca) TIP you can use the pattern .a. + # which matches in above test but in this case matches more than + # you want change_this_search_string = '[nsc]a[2-9].xls' - self.assertEquals(len(re.findall(change_this_search_string, string)),3) + self.assertEquals( + len(re.findall(change_this_search_string, string)), + 3) def test_anything_but_matching(self): """ - Lesson 2 Using character set ranges - Occasionally, you'll want a list of characters that you don't want to match. - Character sets can be negated using the ^ metacharacter. + Lesson 2 -- Using character set ranges + Occasionally, you'll have a list of characters that you don't + want to match. Character sets can be negated using the ^ + metacharacter. """ string = "sales.xlx\n" \ @@ -109,8 +133,8 @@ def test_anything_but_matching(self): + "sa1.xls\n" \ + "ca1.xls" - # I want to find the name sam + # I want to find the name 'sam' change_this_search_string = '[^nc]am' - self.assertEquals(re.findall(change_this_search_string, string), ['sam.xls']) - - + self.assertEquals( + re.findall(change_this_search_string, string), + ['sam.xls']) From d2d621d102fc1c79bb42a063f0572f64859f6937 Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Mon, 18 Sep 2017 19:29:28 -0400 Subject: [PATCH 39/91] Switching to github hosted images --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 3e165ddc1..16dc828d7 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,7 @@ Python Koans Python Koans is a port of Edgecase's "Ruby Koans" which can be found at http://rubykoans.com/. -.. image:: http://i442.photobucket.com/albums/qq150/gregmalcolm/PythonKoansScreenshot.png +.. image:: https://user-images.githubusercontent.com/2614930/28401740-ec6214b2-6cd0-11e7-8afd-30ed3102bfd6.png Python Koans is an interactive tutorial for learning the Python programming language by making tests pass. @@ -99,7 +99,7 @@ or:: In my case I'm using Python 3 with windows, so I fire up my command shell (cmd.exe) and run this: -.. image:: http://i442.photobucket.com/albums/qq150/gregmalcolm/GettingStarted.png +.. image:: https://user-images.githubusercontent.com/2614930/28401747-f723ff00-6cd0-11e7-9b9a-a6993b753cf6.png Apparently a test failed:: @@ -122,7 +122,7 @@ expected value should be. For example:: This is where the Python Command Line can come in handy. In this case I can fire up the command line, recreate the scenario and run queries: -.. image:: http://i442.photobucket.com/albums/qq150/gregmalcolm/DebuggingPython.png +.. image:: https://user-images.githubusercontent.com/2614930/28401750-f9dcb296-6cd0-11e7-98eb-c20318eada33.png Sniffer Support --------------- From 57f83735eb715efac6240af2d6cf7b67de898ad8 Mon Sep 17 00:00:00 2001 From: StaNov Date: Thu, 21 Dec 2017 20:58:03 +0100 Subject: [PATCH 40/91] IDEA folder added to .gitignore and .hgignore --- .gitignore | 1 + .hgignore | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 27b56e02d..776f6d90d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .DS_Store answers .hg +.idea \ No newline at end of file diff --git a/.hgignore b/.hgignore index cf9029f6d..f1035d222 100644 --- a/.hgignore +++ b/.hgignore @@ -4,3 +4,4 @@ syntax: glob .DS_Store answers .git +.idea \ No newline at end of file From 45263063db93a7fb82f41dc90732d3aab10dd115 Mon Sep 17 00:00:00 2001 From: Aaron Date: Mon, 25 Dec 2017 10:19:40 +0800 Subject: [PATCH 41/91] Update README.rst --- README.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.rst b/README.rst index 16dc828d7..d0be70c9d 100644 --- a/README.rst +++ b/README.rst @@ -145,6 +145,11 @@ On Linux:: On Windows:: $ pip install pywin32 + +(If that failed, try:: + + $ pip install pypiwin32 +) On Mac OS X:: From f6a3335e9ab5cf4687b67bfeb91cae7c9352bed1 Mon Sep 17 00:00:00 2001 From: Aaron Date: Wed, 3 Jan 2018 15:35:15 +0800 Subject: [PATCH 42/91] pypiwin32 220 sucks, install 221 manually boy, Windows really took my time to make it work! --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index d0be70c9d..9424f9756 100644 --- a/README.rst +++ b/README.rst @@ -149,6 +149,10 @@ On Windows:: (If that failed, try:: $ pip install pypiwin32 + + then grab a proper version of pypiwin32 installer and install it:: + + https://github.com/mhammond/pywin32/releases ) On Mac OS X:: From 76db2a789ee043c0ca437b36df6b5d8587a398b4 Mon Sep 17 00:00:00 2001 From: Manuel Lorenzo Date: Wed, 7 Feb 2018 14:11:47 +0100 Subject: [PATCH 43/91] fixed tiny typo --- Contributor Notes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Contributor Notes.txt b/Contributor Notes.txt index 23e32335a..b97fc6aea 100644 --- a/Contributor Notes.txt +++ b/Contributor Notes.txt @@ -2,7 +2,7 @@ Testing a specific koan =================================== -This will help when adding/modifing koans +This will help when adding/modifying koans Running a whole test case: From ac8c11aaf97e2eb470d2aa65b7db0fe98dad804d Mon Sep 17 00:00:00 2001 From: Manuel Lorenzo Date: Wed, 7 Feb 2018 14:56:58 +0100 Subject: [PATCH 44/91] remove redundant `expected` variable --- python2/runner/runner_tests/test_sensei.py | 6 ------ python3/runner/runner_tests/test_sensei.py | 6 ------ 2 files changed, 12 deletions(-) diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index 004a48d3c..c4cb03f8b 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -134,12 +134,6 @@ def test_that_nothing_is_returned_as_sorted_result_if_there_are_3_shuffled_resul (AboutMessiahs(),"File 'about_messiahs.py', line 844") ] - expected = [ - (AboutTennis(),"File 'about_tennis.py', line 2"), - (AboutTennis(),"File 'about_tennis.py', line 30"), - (AboutTennis(),"File 'about_tennis.py', line 299") - ] - results = self.sensei.sortFailures("AboutTennis") self.assertEqual(3, len(results)) self.assertEqual(2, results[0][0]) diff --git a/python3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py index b36c253be..109133557 100644 --- a/python3/runner/runner_tests/test_sensei.py +++ b/python3/runner/runner_tests/test_sensei.py @@ -120,12 +120,6 @@ def test_that_nothing_is_returned_as_sorted_result_if_there_are_3_shuffled_resul (AboutMessiahs(),"File 'about_messiahs.py', line 844") ] - expected = [ - (AboutTennis(),"File 'about_tennis.py', line 2"), - (AboutTennis(),"File 'about_tennis.py', line 30"), - (AboutTennis(),"File 'about_tennis.py', line 299") - ] - results = self.sensei.sortFailures("AboutTennis") self.assertEqual(3, len(results)) self.assertEqual(2, results[0][0]) From 875f16301dfd91dbff1a300b95260dd4ba71c2dd Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Sun, 11 Feb 2018 15:19:36 -0500 Subject: [PATCH 45/91] Python 3 test_finding_lines2() assert passes as-is Fixes issue #169, reported in @denis-roy's pull request #157: The Python 3 version of AboutWithStatements.test_finding_lines2 contains an assertNotEqual(__, ...) that passes without the student having to change anything. I think the idea was that the assertNotEqual would test that the student-written function returns _anything_ (by default, the pass statement returns None), while the assertEqual would test that furthermore the return value is correct. In this version, the general (not-None) assertion is tested before the specific. Also, both assertions have the passing / expected values hard-coded, meaning the student should change only the function they test, not the assertions themselves. --- python2/koans/about_with_statements.py | 7 ++++--- python3/koans/about_with_statements.py | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/python2/koans/about_with_statements.py b/python2/koans/about_with_statements.py index 08515428b..2842832a5 100644 --- a/python2/koans/about_with_statements.py +++ b/python2/koans/about_with_statements.py @@ -91,12 +91,13 @@ def test_counting_lines2(self): # ------------------------------------------------------------------ def find_line2(self, file_name): - # Rewrite find_line using the Context Manager. - pass + # Using the context manager self.FileContextManager, rewrite this + # function to return the first line containing the letter 'e'. + return None def test_finding_lines2(self): - self.assertEqual(__, self.find_line2("example_file.txt")) self.assertNotEqual(None, self.find_line2("example_file.txt")) + self.assertEqual('test\n', self.find_line2("example_file.txt")) # ------------------------------------------------------------------ diff --git a/python3/koans/about_with_statements.py b/python3/koans/about_with_statements.py index 9d126dd33..0ae9b5ff8 100644 --- a/python3/koans/about_with_statements.py +++ b/python3/koans/about_with_statements.py @@ -90,12 +90,13 @@ def test_counting_lines2(self): # ------------------------------------------------------------------ def find_line2(self, file_name): - # Rewrite find_line using the Context Manager. - pass + # Using the context manager self.FileContextManager, rewrite this + # function to return the first line containing the letter 'e'. + return None def test_finding_lines2(self): - self.assertEqual(__, self.find_line2("example_file.txt")) - self.assertNotEqual(__, self.find_line2("example_file.txt")) + self.assertNotEqual(None, self.find_line2("example_file.txt")) + self.assertEqual('test\n', self.find_line2("example_file.txt")) # ------------------------------------------------------------------ From 602498be3e34737a5a6f19499fd1e470a11f088e Mon Sep 17 00:00:00 2001 From: Danny Date: Mon, 12 Feb 2018 19:37:22 -0400 Subject: [PATCH 46/91] tweaked the tuple lesson for greater clarity (#167) * tweaked the tuple lesson for greater clarity --- python2/koans/about_tuples.py | 3 ++- python3/koans/about_tuples.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_tuples.py b/python2/koans/about_tuples.py index 84ba5d552..7ef9a886d 100644 --- a/python2/koans/about_tuples.py +++ b/python2/koans/about_tuples.py @@ -41,7 +41,8 @@ def test_tuples_can_only_be_changed_through_replacement(self): def test_tuples_of_one_look_peculiar(self): self.assertEqual(__, (1).__class__) self.assertEqual(__, (1,).__class__) - self.assertEqual(__, ("Hello comma!", )) + self.assertEqual(__, ("I'm a tuple",)) + self.assertEqual(__, ("Not a tuple")) def test_tuple_constructor_can_be_surprising(self): self.assertEqual(__, tuple("Surprise!")) diff --git a/python3/koans/about_tuples.py b/python3/koans/about_tuples.py index cc6ac5291..35a8e4a63 100644 --- a/python3/koans/about_tuples.py +++ b/python3/koans/about_tuples.py @@ -39,7 +39,8 @@ def test_tuples_can_only_be_changed_through_replacement(self): def test_tuples_of_one_look_peculiar(self): self.assertEqual(__, (1).__class__) self.assertEqual(__, (1,).__class__) - self.assertEqual(__, ("Hello comma!", )) + self.assertEqual(__, ("I'm a tuple",)) + self.assertEqual(__, ("Not a tuple")) def test_tuple_constructor_can_be_surprising(self): self.assertEqual(__, tuple("Surprise!")) From 7d810418bf1a0b2b44256a635b9d992d0f6e2ed0 Mon Sep 17 00:00:00 2001 From: Leo Dronkers Date: Tue, 13 Feb 2018 09:41:25 +0100 Subject: [PATCH 47/91] Typo in specfied fix --- python2/koans/about_triangle_project2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_triangle_project2.py b/python2/koans/about_triangle_project2.py index 0704edc1a..444e95092 100644 --- a/python2/koans/about_triangle_project2.py +++ b/python2/koans/about_triangle_project2.py @@ -11,7 +11,7 @@ class AboutTriangleProject2(Koan): # The first assignment did not talk about how to handle errors. # Let's handle that part now. def test_illegal_triangles_throw_exceptions(self): - # In the code below, each line calls the specfied method with the arguments passed to it. + # In the code below, each line calls the specified method with the arguments passed to it. # E.g. this line: # self.assertRaises(TriangleError, triangle, 0, 0, 0) # calls triangle(0, 0, 0) From 4a9ad23f50a7c54fa0d38ca27bd963b3625faf23 Mon Sep 17 00:00:00 2001 From: Colin Jones Date: Fri, 23 Feb 2018 13:10:16 -0600 Subject: [PATCH 48/91] Fix minor typo in comment (#172) --- python2/koans/about_comprehension.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_comprehension.py b/python2/koans/about_comprehension.py index 7f19c0891..6919073ba 100644 --- a/python2/koans/about_comprehension.py +++ b/python2/koans/about_comprehension.py @@ -46,7 +46,7 @@ def test_double_list_comprehension(self): def test_creating_a_set_with_set_comprehension(self): comprehension = { x for x in 'aabbbcccc'} - self.assertEqual(__, comprehension) # rememeber that set members are unique + self.assertEqual(__, comprehension) # remember that set members are unique def test_creating_a_dictionary_with_dictionary_comprehension(self): dict_of_weapons = {'first': 'fear', 'second': 'surprise', From a667a11bda934e431b605c8e4c981ae2fe3100ad Mon Sep 17 00:00:00 2001 From: beaglebao <40451758+beaglebao@users.noreply.github.com> Date: Wed, 25 Jul 2018 18:17:22 +0800 Subject: [PATCH 49/91] Update Lisence Update the year of Lisence --- MIT-LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MIT-LICENSE b/MIT-LICENSE index 128401ac9..e3b0a3575 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2010 Greg Malcolm and The Status Is Not Quo +Copyright (c) 2010-2018 Greg Malcolm and The Status Is Not Quo Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation From 2fd7067e20f2ed4fe026478a80c47e560d34d96f Mon Sep 17 00:00:00 2001 From: endenis Date: Mon, 3 Sep 2018 02:42:22 +0200 Subject: [PATCH 50/91] Remove unused variable --- python3/koans/about_proxy_object_project.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python3/koans/about_proxy_object_project.py b/python3/koans/about_proxy_object_project.py index 663a4f633..db70e0c70 100644 --- a/python3/koans/about_proxy_object_project.py +++ b/python3/koans/about_proxy_object_project.py @@ -56,7 +56,6 @@ def test_proxy_records_messages_sent_to_tv(self): def test_proxy_handles_invalid_messages(self): tv = Proxy(Television()) - ex = None with self.assertRaises(AttributeError): tv.no_such_method() From 0cdeb62d9f47c8fcd743f873dab40bf8cb117487 Mon Sep 17 00:00:00 2001 From: endenis Date: Mon, 3 Sep 2018 10:10:23 +0200 Subject: [PATCH 51/91] Fix wrong filename for extra credit koan --- python2/runner/sensei.py | 2 +- python3/runner/sensei.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index 28f3d65c8..e598626a3 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -99,7 +99,7 @@ def learn(self): self.stream.writeln("\n{0}That was the last one, well done!" \ .format(Fore.MAGENTA)) self.stream.writeln( - "\nIf you want more, take a look at about_extra_credit_task.py") + "\nIf you want more, take a look at about_extra_credit.py") def errorReport(self): problem = self.firstFailure() diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index edbf4557b..4a8d5cd96 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -98,7 +98,7 @@ def learn(self): self.stream.writeln("\n{0}That was the last one, well done!" \ .format(Fore.MAGENTA)) self.stream.writeln( - "\nIf you want more, take a look at about_extra_credit_task.py{0}{1}" \ + "\nIf you want more, take a look at about_extra_credit.py{0}{1}" \ .format(Fore.RESET, Style.NORMAL)) def errorReport(self): From f3c263aa7334b461ed5ff5a3f704386bacb3959b Mon Sep 17 00:00:00 2001 From: kolapsys Date: Mon, 1 Oct 2018 18:29:19 +0300 Subject: [PATCH 52/91] Change bit.ly/__class__ links to repo wiki links (#182) * Change bit.ly/__class__ links to repo wiki links --- python2/koans/about_asserts.py | 2 +- python3/koans/about_asserts.py | 2 +- python3/koans/about_none.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index 8c80671d7..26d53ed7e 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -76,4 +76,4 @@ def test_that_sometimes_we_need_to_know_the_class_type(self): # Need an illustration? More reading can be found here: # - # http://bit.ly/__class__ + # https://github.com/gregmalcolm/python_koans/wiki/Class-Attribute diff --git a/python3/koans/about_asserts.py b/python3/koans/about_asserts.py index 1bffa66ef..d17ed0cdf 100644 --- a/python3/koans/about_asserts.py +++ b/python3/koans/about_asserts.py @@ -74,5 +74,5 @@ def test_that_sometimes_we_need_to_know_the_class_type(self): # Need an illustration? More reading can be found here: # - # http://bit.ly/__class__ + # https://github.com/gregmalcolm/python_koans/wiki/Class-Attribute diff --git a/python3/koans/about_none.py b/python3/koans/about_none.py index 8cf04f034..1731f0108 100644 --- a/python3/koans/about_none.py +++ b/python3/koans/about_none.py @@ -35,7 +35,7 @@ def test_what_exception_do_you_get_when_calling_nonexistent_methods(self): # # Need a recap on how to evaluate __class__ attributes? # - # http://bit.ly/__class__ + # https://github.com/gregmalcolm/python_koans/wiki/Class-Attribute self.assertEqual(__, ex2.__class__) From 57f709acdf326833fa864b3740d71189fa9a7ae9 Mon Sep 17 00:00:00 2001 From: Tracy B Porter Date: Mon, 5 Nov 2018 14:27:49 -0600 Subject: [PATCH 53/91] Show filter applies the rule to all items in a list. Break apart the last test for clarity. Removed try-catch as it seems unnecessary. --- python3/koans/about_iteration.py | 43 ++++++++++++++------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index d232d07b8..77cc52e9d 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -64,21 +64,23 @@ def is_even(item): self.assertEqual(__, even_numbers) - def test_just_return_first_item_found(self): - def is_big_name(item): - return len(item) > 4 - - names = ["Jim", "Bill", "Clarence", "Doug", "Eli"] - name = None + def test_filter_returns_all_items_matching_criterion(self): + def is_big_name(item): + return len(item) > 4 + names = ["Jim", "Bill", "Clarence", "Doug", "Eli", "Elizabeth"] iterator = filter(is_big_name, names) + + self.assertEqual(__, next(iterator)) + self.assertEqual(__, next(iterator)) + try: - name = next(iterator) + next(iterator) + pass except StopIteration: msg = 'Ran out of big names' - self.assertEqual(__, name) - + self.assertEquals(__, msg) # ------------------------------------------------------------------ @@ -120,18 +122,11 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): result = map(self.add_ten, range(1,4)) self.assertEqual(__, list(result)) - try: - file = open("example_file.txt") - - try: - def make_upcase(line): - return line.strip().upper() - upcase_lines = map(make_upcase, file.readlines()) - self.assertEqual(__, list(upcase_lines)) - finally: - # Arg, this is ugly. - # We will figure out how to fix this later. - file.close() - except IOError: - # should never happen - self.fail() + def test_lines_in_a_file_are_iterable_sequences_too(self): + def make_upcase(line): + return line.strip().title() + + file = open("example_file.txt") + upcase_lines = map(make_upcase, file.readlines()) + self.assertEqual(__, list(upcase_lines)) + file.close() From 15c13ede72ea64d21cb2d1737b4238619427c216 Mon Sep 17 00:00:00 2001 From: Tracy B Porter Date: Tue, 6 Nov 2018 08:33:19 -0600 Subject: [PATCH 54/91] correctly indent function. --- python3/koans/about_iteration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index 77cc52e9d..1faca8e33 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -65,8 +65,8 @@ def is_even(item): self.assertEqual(__, even_numbers) def test_filter_returns_all_items_matching_criterion(self): - def is_big_name(item): - return len(item) > 4 + def is_big_name(item): + return len(item) > 4 names = ["Jim", "Bill", "Clarence", "Doug", "Eli", "Elizabeth"] iterator = filter(is_big_name, names) From f34228503b20ab88f493c3597fd96219c2829c35 Mon Sep 17 00:00:00 2001 From: ronbo Date: Wed, 12 Jun 2019 14:04:16 -0700 Subject: [PATCH 55/91] Fixed typo in readme --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d0be70c9d..ef018c4f6 100644 --- a/README.rst +++ b/README.rst @@ -105,7 +105,7 @@ Apparently a test failed:: AssertionError: False is not True -It also tells me exactly where the problem in, its an assert on line 12 +It also tells me exactly where the problem is, it's an assert on line 12 of .\\koans\\about_asserts.py. This one is easy, just change False to True to make the test pass. From 1ed399171c011f1854ccff1770dc87aab428aec3 Mon Sep 17 00:00:00 2001 From: "david.valderrama" Date: Tue, 18 Jun 2019 16:42:41 +0900 Subject: [PATCH 56/91] Update python3 test: test_tuples_of_one_look_peculiar --- python3/koans/about_tuples.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/koans/about_tuples.py b/python3/koans/about_tuples.py index 35a8e4a63..2d65ea8f1 100644 --- a/python3/koans/about_tuples.py +++ b/python3/koans/about_tuples.py @@ -39,8 +39,8 @@ def test_tuples_can_only_be_changed_through_replacement(self): def test_tuples_of_one_look_peculiar(self): self.assertEqual(__, (1).__class__) self.assertEqual(__, (1,).__class__) - self.assertEqual(__, ("I'm a tuple",)) - self.assertEqual(__, ("Not a tuple")) + self.assertEqual(__, ("I'm a tuple",).__class__) + self.assertEqual(__, ("Not a tuple").__class__) def test_tuple_constructor_can_be_surprising(self): self.assertEqual(__, tuple("Surprise!")) From 75b749221afea775b9c23d84a26b9790ea7bd09e Mon Sep 17 00:00:00 2001 From: "david.valderrama" Date: Tue, 18 Jun 2019 16:42:51 +0900 Subject: [PATCH 57/91] Update python2 test: test_tuples_of_one_look_peculiar --- python2/koans/about_tuples.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_tuples.py b/python2/koans/about_tuples.py index 7ef9a886d..89e0eff29 100644 --- a/python2/koans/about_tuples.py +++ b/python2/koans/about_tuples.py @@ -41,8 +41,8 @@ def test_tuples_can_only_be_changed_through_replacement(self): def test_tuples_of_one_look_peculiar(self): self.assertEqual(__, (1).__class__) self.assertEqual(__, (1,).__class__) - self.assertEqual(__, ("I'm a tuple",)) - self.assertEqual(__, ("Not a tuple")) + self.assertEqual(__, ("I'm a tuple",).__class__) + self.assertEqual(__, ("Not a tuple").__class__) def test_tuple_constructor_can_be_surprising(self): self.assertEqual(__, tuple("Surprise!")) From 06751db3d556ca505975c6ce8d629c979d76be0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gil=20Gon=C3=A7alves?= Date: Tue, 10 Mar 2020 06:43:37 +0000 Subject: [PATCH 58/91] Remove python2 support Fix #203 --- .travis.yml | 1 - README.rst | 6 +- python2/_runner_tests.py | 26 -- python2/contemplate_koans.py | 36 --- python2/example_file.txt | 4 - python2/koans.txt | 41 --- python2/koans/GREEDS_RULES.txt | 66 ----- python2/koans/__init__.py | 4 - python2/koans/a_normal_folder/a_module.py | 7 - python2/koans/a_package_folder/__init__.py | 4 - python2/koans/a_package_folder/a_module.py | 7 - python2/koans/about_asserts.py | 79 ----- python2/koans/about_attribute_access.py | 225 -------------- python2/koans/about_class_attributes.py | 165 ----------- python2/koans/about_classes.py | 160 ---------- python2/koans/about_comprehension.py | 61 ---- python2/koans/about_control_statements.py | 82 ------ .../koans/about_decorating_with_classes.py | 129 -------- .../koans/about_decorating_with_functions.py | 32 -- python2/koans/about_deleting_objects.py | 127 -------- python2/koans/about_dice_project.py | 71 ----- python2/koans/about_dictionaries.py | 59 ---- python2/koans/about_exceptions.py | 68 ----- python2/koans/about_extra_credit.py | 20 -- python2/koans/about_generators.py | 141 --------- python2/koans/about_inheritance.py | 92 ------ python2/koans/about_iteration.py | 115 -------- python2/koans/about_lambdas.py | 29 -- python2/koans/about_list_assignments.py | 31 -- python2/koans/about_lists.py | 107 ------- python2/koans/about_method_bindings.py | 98 ------- python2/koans/about_methods.py | 169 ----------- python2/koans/about_modules.py | 81 ----- python2/koans/about_monkey_patching.py | 50 ---- python2/koans/about_multiple_inheritance.py | 141 --------- python2/koans/about_new_style_classes.py | 68 ----- python2/koans/about_none.py | 51 ---- python2/koans/about_packages.py | 68 ----- python2/koans/about_proxy_object_project.py | 163 ----------- python2/koans/about_regex.py | 140 --------- python2/koans/about_scope.py | 92 ------ python2/koans/about_scoring_project.py | 74 ----- python2/koans/about_sets.py | 43 --- python2/koans/about_string_manipulation.py | 76 ----- python2/koans/about_strings.py | 95 ------ python2/koans/about_triangle_project.py | 24 -- python2/koans/about_triangle_project2.py | 25 -- python2/koans/about_true_and_false.py | 43 --- python2/koans/about_tuples.py | 71 ----- python2/koans/about_with_statements.py | 109 ------- python2/koans/another_local_module.py | 20 -- python2/koans/jims.py | 7 - python2/koans/joes.py | 7 - python2/koans/local_module.py | 11 - .../koans/local_module_with_all_defined.py | 25 -- python2/koans/triangle.py | 27 -- python2/libs/__init__.py | 4 - python2/libs/colorama/LICENSE-colorama | 33 --- python2/libs/colorama/__init__.py | 7 - python2/libs/colorama/ansi.py | 50 ---- python2/libs/colorama/ansitowin32.py | 189 ------------ python2/libs/colorama/initialise.py | 56 ---- python2/libs/colorama/win32.py | 134 --------- python2/libs/colorama/winterm.py | 120 -------- python2/libs/mock.py | 271 ----------------- python2/run.bat | 45 --- python2/run.sh | 7 - python2/runner/__init__.py | 5 - python2/runner/helper.py | 5 - python2/runner/koan.py | 40 --- python2/runner/mockable_test_result.py | 10 - python2/runner/mountain.py | 27 -- python2/runner/path_to_enlightenment.py | 62 ---- python2/runner/runner_tests/__init__.py | 4 - python2/runner/runner_tests/test_helper.py | 17 -- python2/runner/runner_tests/test_mountain.py | 18 -- .../test_path_to_enlightenment.py | 103 ------- python2/runner/runner_tests/test_sensei.py | 277 ------------------ python2/runner/sensei.py | 269 ----------------- python2/runner/writeln_decorator.py | 18 -- python2/scent.py | 12 - 81 files changed, 3 insertions(+), 5553 deletions(-) delete mode 100644 python2/_runner_tests.py delete mode 100644 python2/contemplate_koans.py delete mode 100644 python2/example_file.txt delete mode 100644 python2/koans.txt delete mode 100644 python2/koans/GREEDS_RULES.txt delete mode 100644 python2/koans/__init__.py delete mode 100644 python2/koans/a_normal_folder/a_module.py delete mode 100644 python2/koans/a_package_folder/__init__.py delete mode 100644 python2/koans/a_package_folder/a_module.py delete mode 100644 python2/koans/about_asserts.py delete mode 100644 python2/koans/about_attribute_access.py delete mode 100644 python2/koans/about_class_attributes.py delete mode 100644 python2/koans/about_classes.py delete mode 100644 python2/koans/about_comprehension.py delete mode 100644 python2/koans/about_control_statements.py delete mode 100644 python2/koans/about_decorating_with_classes.py delete mode 100644 python2/koans/about_decorating_with_functions.py delete mode 100644 python2/koans/about_deleting_objects.py delete mode 100644 python2/koans/about_dice_project.py delete mode 100644 python2/koans/about_dictionaries.py delete mode 100644 python2/koans/about_exceptions.py delete mode 100644 python2/koans/about_extra_credit.py delete mode 100644 python2/koans/about_generators.py delete mode 100644 python2/koans/about_inheritance.py delete mode 100644 python2/koans/about_iteration.py delete mode 100644 python2/koans/about_lambdas.py delete mode 100644 python2/koans/about_list_assignments.py delete mode 100644 python2/koans/about_lists.py delete mode 100644 python2/koans/about_method_bindings.py delete mode 100644 python2/koans/about_methods.py delete mode 100644 python2/koans/about_modules.py delete mode 100644 python2/koans/about_monkey_patching.py delete mode 100644 python2/koans/about_multiple_inheritance.py delete mode 100644 python2/koans/about_new_style_classes.py delete mode 100644 python2/koans/about_none.py delete mode 100644 python2/koans/about_packages.py delete mode 100644 python2/koans/about_proxy_object_project.py delete mode 100755 python2/koans/about_regex.py delete mode 100644 python2/koans/about_scope.py delete mode 100644 python2/koans/about_scoring_project.py delete mode 100644 python2/koans/about_sets.py delete mode 100644 python2/koans/about_string_manipulation.py delete mode 100644 python2/koans/about_strings.py delete mode 100644 python2/koans/about_triangle_project.py delete mode 100644 python2/koans/about_triangle_project2.py delete mode 100644 python2/koans/about_true_and_false.py delete mode 100644 python2/koans/about_tuples.py delete mode 100644 python2/koans/about_with_statements.py delete mode 100644 python2/koans/another_local_module.py delete mode 100644 python2/koans/jims.py delete mode 100644 python2/koans/joes.py delete mode 100644 python2/koans/local_module.py delete mode 100644 python2/koans/local_module_with_all_defined.py delete mode 100644 python2/koans/triangle.py delete mode 100644 python2/libs/__init__.py delete mode 100644 python2/libs/colorama/LICENSE-colorama delete mode 100644 python2/libs/colorama/__init__.py delete mode 100644 python2/libs/colorama/ansi.py delete mode 100644 python2/libs/colorama/ansitowin32.py delete mode 100644 python2/libs/colorama/initialise.py delete mode 100644 python2/libs/colorama/win32.py delete mode 100644 python2/libs/colorama/winterm.py delete mode 100644 python2/libs/mock.py delete mode 100755 python2/run.bat delete mode 100755 python2/run.sh delete mode 100644 python2/runner/__init__.py delete mode 100644 python2/runner/helper.py delete mode 100644 python2/runner/koan.py delete mode 100644 python2/runner/mockable_test_result.py delete mode 100644 python2/runner/mountain.py delete mode 100644 python2/runner/path_to_enlightenment.py delete mode 100644 python2/runner/runner_tests/__init__.py delete mode 100644 python2/runner/runner_tests/test_helper.py delete mode 100644 python2/runner/runner_tests/test_mountain.py delete mode 100644 python2/runner/runner_tests/test_path_to_enlightenment.py delete mode 100644 python2/runner/runner_tests/test_sensei.py delete mode 100644 python2/runner/sensei.py delete mode 100644 python2/runner/writeln_decorator.py delete mode 100644 python2/scent.py diff --git a/.travis.yml b/.travis.yml index 1f94c3610..e49fbf9c6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python python: - - 2.7 - 3.2 - 3.3 - 3.4 diff --git a/README.rst b/README.rst index ef018c4f6..e75f88a5e 100644 --- a/README.rst +++ b/README.rst @@ -75,7 +75,7 @@ If you have problems, this may help: Windows users may also want to update the line in the batch file `run.bat` to set the python path:: - SET PYTHON_PATH=C:\Python27 + SET PYTHON_PATH=C:\Python37 Getting Started @@ -145,9 +145,9 @@ On Linux:: On Windows:: $ pip install pywin32 - + (If that failed, try:: - + $ pip install pypiwin32 ) diff --git a/python2/_runner_tests.py b/python2/_runner_tests.py deleted file mode 100644 index 26fec382d..000000000 --- a/python2/_runner_tests.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import sys -import unittest - -from runner.runner_tests.test_mountain import TestMountain -from runner.runner_tests.test_sensei import TestSensei -from runner.runner_tests.test_helper import TestHelper -from runner.runner_tests.test_path_to_enlightenment import TestFilterKoanNames -from runner.runner_tests.test_path_to_enlightenment import TestKoansSuite - - -def suite(): - suite = unittest.TestSuite() - suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMountain)) - suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestSensei)) - suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestHelper)) - suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestFilterKoanNames)) - suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestKoansSuite)) - return suite - - -if __name__ == '__main__': - res = unittest.TextTestRunner(verbosity=2).run(suite()) - sys.exit(not res.wasSuccessful()) diff --git a/python2/contemplate_koans.py b/python2/contemplate_koans.py deleted file mode 100644 index 34e06d7bb..000000000 --- a/python2/contemplate_koans.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Acknowledgment: -# -# Python Koans is a port of Ruby Koans originally written by Jim Weirich -# and Joe O'brien of Edgecase. There are some differences and tweaks specific -# to the Python language, but a great deal of it has been copied wholesale. -# So thank guys! -# - -import sys - - -if __name__ == '__main__': - if sys.version_info >= (3, 0): - print("\nThis is the Python 2 version of Python Koans, but you are " + - "running it with Python 3 or newer!\n\n" - "Did you accidentally use the wrong python script? \nTry:\n\n" + - " python contemplate_koans.py\n") - else: - if sys.version_info < (2, 7): - print("\n" + - "********************************************************\n" + - "WARNING:\n" + - "This version of Python Koans was designed for " + - "Python 2.7 or greater.\n" + - "Your version of Python is older, so you may run into " + - "problems!\n\n" + - "But lets see how far we get...\n" + - "********************************************************\n") - - from runner.mountain import Mountain - - Mountain().walk_the_path(sys.argv) diff --git a/python2/example_file.txt b/python2/example_file.txt deleted file mode 100644 index ffe7cbd89..000000000 --- a/python2/example_file.txt +++ /dev/null @@ -1,4 +0,0 @@ -this -is -a -test diff --git a/python2/koans.txt b/python2/koans.txt deleted file mode 100644 index e980c7ea2..000000000 --- a/python2/koans.txt +++ /dev/null @@ -1,41 +0,0 @@ -# Lines starting with # are ignored. -koans.about_asserts.AboutAsserts -koans.about_strings.AboutStrings -koans.about_none.AboutNone -koans.about_lists.AboutLists -koans.about_list_assignments.AboutListAssignments -koans.about_dictionaries.AboutDictionaries -koans.about_string_manipulation.AboutStringManipulation -koans.about_tuples.AboutTuples -koans.about_methods.AboutMethods -koans.about_control_statements.AboutControlStatements -koans.about_true_and_false.AboutTrueAndFalse -koans.about_sets.AboutSets -koans.about_triangle_project.AboutTriangleProject -koans.about_exceptions.AboutExceptions -koans.about_triangle_project2.AboutTriangleProject2 -koans.about_iteration.AboutIteration -koans.about_comprehension.AboutComprehension -koans.about_generators.AboutGenerators -koans.about_lambdas.AboutLambdas -koans.about_scoring_project.AboutScoringProject -koans.about_classes.AboutClasses -koans.about_new_style_classes.AboutNewStyleClasses -koans.about_with_statements.AboutWithStatements -koans.about_monkey_patching.AboutMonkeyPatching -koans.about_dice_project.AboutDiceProject -koans.about_method_bindings.AboutMethodBindings -koans.about_decorating_with_functions.AboutDecoratingWithFunctions -koans.about_decorating_with_classes.AboutDecoratingWithClasses -koans.about_inheritance.AboutInheritance -koans.about_multiple_inheritance.AboutMultipleInheritance -koans.about_scope.AboutScope -koans.about_modules.AboutModules -koans.about_packages.AboutPackages -koans.about_class_attributes.AboutClassAttributes -koans.about_attribute_access.AboutAttributeAccess -koans.about_deleting_objects.AboutDeletingObjects -koans.about_proxy_object_project.AboutProxyObjectProject -koans.about_proxy_object_project.TelevisionTest -koans.about_extra_credit.AboutExtraCredit -koans.about_regex.AboutRegex diff --git a/python2/koans/GREEDS_RULES.txt b/python2/koans/GREEDS_RULES.txt deleted file mode 100644 index 58b5a9cb6..000000000 --- a/python2/koans/GREEDS_RULES.txt +++ /dev/null @@ -1,66 +0,0 @@ -= Playing Greed - -Greed is a dice game played among 2 or more players, using 5 -six-sided dice. - -== Playing Greed - -Each player takes a turn consisting of one or more rolls of the dice. -On the first roll of the game, a player rolls all five dice which are -scored according to the following: - - Three 1's => 1000 points - Three 6's => 600 points - Three 5's => 500 points - Three 4's => 400 points - Three 3's => 300 points - Three 2's => 200 points - One 1 => 100 points - One 5 => 50 points - -A single die can only be counted once in each roll. For example, -a "5" can only count as part of a triplet (contributing to the 500 -points) or as a single 50 points, but not both in the same roll. - -Example Scoring - - Throw Score - --------- ------------------ - 5 1 3 4 1 50 + 2 * 100 = 250 - 1 1 1 3 1 1000 + 100 = 1100 - 2 4 4 5 4 400 + 50 = 450 - -The dice not contributing to the score are called the non-scoring -dice. "3" and "4" are non-scoring dice in the first example. "3" is -a non-scoring die in the second, and "2" is a non-score die in the -final example. - -After a player rolls and the score is calculated, the scoring dice are -removed and the player has the option of rolling again using only the -non-scoring dice. If all of the thrown dice are scoring, then the -player may roll all 5 dice in the next roll. - -The player may continue to roll as long as each roll scores points. If -a roll has zero points, then the player loses not only their turn, but -also accumulated score for that turn. If a player decides to stop -rolling before rolling a zero-point roll, then the accumulated points -for the turn is added to his total score. - -== Getting "In The Game" - -Before a player is allowed to accumulate points, they must get at -least 300 points in a single turn. Once they have achieved 300 points -in a single turn, the points earned in that turn and each following -turn will be counted toward their total score. - -== End Game - -Once a player reaches 3000 (or more) points, the game enters the final -round where each of the other players gets one more turn. The winner -is the player with the highest score after the final round. - -== References - -Greed is described on Wikipedia at -http://en.wikipedia.org/wiki/Greed_(dice_game), however the rules are -a bit different from the rules given here. diff --git a/python2/koans/__init__.py b/python2/koans/__init__.py deleted file mode 100644 index a11870b25..000000000 --- a/python2/koans/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# koans diff --git a/python2/koans/a_normal_folder/a_module.py b/python2/koans/a_normal_folder/a_module.py deleted file mode 100644 index 59e06f574..000000000 --- a/python2/koans/a_normal_folder/a_module.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -class Duck(object): - @property - def name(self): - return "Howard" \ No newline at end of file diff --git a/python2/koans/a_package_folder/__init__.py b/python2/koans/a_package_folder/__init__.py deleted file mode 100644 index 20f417e99..000000000 --- a/python2/koans/a_package_folder/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -an_attribute = 1984 \ No newline at end of file diff --git a/python2/koans/a_package_folder/a_module.py b/python2/koans/a_package_folder/a_module.py deleted file mode 100644 index 899ac9702..000000000 --- a/python2/koans/a_package_folder/a_module.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -class Duck(object): - @property - def name(self): - return "Donald" \ No newline at end of file diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py deleted file mode 100644 index 26d53ed7e..000000000 --- a/python2/koans/about_asserts.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutAsserts(Koan): - - def test_assert_truth(self): - """ - We shall contemplate truth by testing reality, via asserts. - """ - - # Confused? This video should help: - # - # http://bit.ly/about_asserts - - self.assertTrue(False) # This should be True - - def test_assert_with_message(self): - """ - Enlightenment may be more easily achieved with appropriate messages. - """ - self.assertTrue(False, "This should be True -- Please fix this") - - def test_fill_in_values(self): - """ - Sometimes we will ask you to fill in the values - """ - self.assertEqual(__, 1 + 1) - - def test_assert_equality(self): - """ - To understand reality, we must compare our expectations against - reality. - """ - expected_value = __ - actual_value = 1 + 1 - self.assertTrue(expected_value == actual_value) - - def test_a_better_way_of_asserting_equality(self): - """ - Some ways of asserting equality are better than others. - """ - expected_value = __ - actual_value = 1 + 1 - - self.assertEqual(expected_value, actual_value) - - def test_that_unittest_asserts_work_the_same_way_as_python_asserts(self): - """ - Understand what lies within. - """ - - # This throws an AssertionError exception - assert False - - def test_that_sometimes_we_need_to_know_the_class_type(self): - """ - What is in a class name? - """ - - # Sometimes we will ask you what the class type of an object is. - # - # For example, contemplate the text string "navel". What is its class type? - # The koans runner will include this feedback for this koan: - # - # AssertionError: '-=> FILL ME IN! <=-' != - # - # So "navel".__class__ is equal to ? No not quite. This - # is just what it displays. The answer is simply str. - # - # See for yourself: - - self.assertEqual(__, "navel".__class__) # It's str, not - - # Need an illustration? More reading can be found here: - # - # https://github.com/gregmalcolm/python_koans/wiki/Class-Attribute diff --git a/python2/koans/about_attribute_access.py b/python2/koans/about_attribute_access.py deleted file mode 100644 index 24d30fde6..000000000 --- a/python2/koans/about_attribute_access.py +++ /dev/null @@ -1,225 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Partially based on AboutMessagePassing in the Ruby Koans -# - -from runner.koan import * - - -class AboutAttributeAccess(Koan): - - class TypicalObject(object): - pass - - def test_calling_undefined_functions_normally_results_in_errors(self): - typical = self.TypicalObject() - - try: - typical.foobar() - except Exception as exception: - self.assertEqual(__, exception.__class__.__name__) - self.assertMatch(__, exception[0]) - - def test_calling_getattribute_causes_an_attribute_error(self): - typical = self.TypicalObject() - - try: - typical.__getattribute__('foobar') - except AttributeError as exception: - self.assertMatch(__, exception[0]) - - # THINK ABOUT IT: - # - # If the method __getattribute__() causes the AttributeError, then - # what would happen if we redefine __getattribute__()? - - # ------------------------------------------------------------------ - - class CatchAllAttributeReads(object): - def __getattribute__(self, attr_name): - return "Someone called '" + attr_name + \ - "' and it could not be found" - - def test_all_attribute_reads_are_caught(self): - catcher = self.CatchAllAttributeReads() - - self.assertMatch(__, catcher.foobar) - - def test_intercepting_return_values_can_disrupt_the_call_chain(self): - catcher = self.CatchAllAttributeReads() - - self.assertMatch(__, catcher.foobaz) # This is fine - - try: - catcher.foobaz(1) - except TypeError as ex: - self.assertMatch(__, ex[0]) - - # foobaz returns a string. What happens to the '(1)' part? - # Try entering this into a python console to reproduce the issue: - # - # "foobaz"(1) - # - - def test_changing_getattribute_will_affect__the_getattr_function(self): - catcher = self.CatchAllAttributeReads() - - self.assertMatch(__, getattr(catcher, 'any_attribute')) - - # ------------------------------------------------------------------ - - class WellBehavedFooCatcher(object): - def __getattribute__(self, attr_name): - if attr_name[:3] == "foo": - return "Foo to you too" - else: - return \ - super(AboutAttributeAccess.WellBehavedFooCatcher, self). \ - __getattribute__(attr_name) - - def test_foo_attributes_are_caught(self): - catcher = self.WellBehavedFooCatcher() - - self.assertEqual(__, catcher.foo_bar) - self.assertEqual(__, catcher.foo_baz) - - def test_non_foo_messages_are_treated_normally(self): - catcher = self.WellBehavedFooCatcher() - - try: - catcher.normal_undefined_attribute - except AttributeError as ex: - self.assertMatch(__, ex[0]) - - # ------------------------------------------------------------------ - - global stack_depth - stack_depth = 0 - - class RecursiveCatcher(object): - def __init__(self): - global stack_depth - stack_depth = 0 - self.no_of_getattribute_calls = 0 - - def __getattribute__(self, attr_name): - # We need something that is outside the scope of this class: - global stack_depth - stack_depth += 1 - - if stack_depth <= 10: # to prevent a stack overflow - self.no_of_getattribute_calls += 1 - # Oops! We just accessed an attribute: no_of_getattribute_calls - # Guess what happens when self.no_of_getattribute_calls is - # accessed? - - # Using 'object' directly because using super() here will also - # trigger a __getattribute__() call. - return object.__getattribute__(self, attr_name) - - def my_method(self): - pass - - def test_getattribute_is_a_bit_overzealous_sometimes(self): - catcher = self.RecursiveCatcher() - catcher.my_method() - global stack_depth - self.assertEqual(__, stack_depth) - - # ------------------------------------------------------------------ - - class MinimalCatcher(object): - class DuffObject(object): - pass - - def __init__(self): - self.no_of_getattr_calls = 0 - - def __getattr__(self, attr_name): - self.no_of_getattr_calls += 1 - return self.DuffObject - - def my_method(self): - pass - - def test_getattr_ignores_known_attributes(self): - catcher = self.MinimalCatcher() - catcher.my_method() - - self.assertEqual(__, catcher.no_of_getattr_calls) - - def test_getattr_only_catches_unknown_attributes(self): - catcher = self.MinimalCatcher() - catcher.purple_flamingos() - catcher.free_pie() - - self.assertEqual(__, - catcher.give_me_duff_or_give_me_death().__class__.__name__) - - self.assertEqual(__, catcher.no_of_getattr_calls) - - # ------------------------------------------------------------------ - - class PossessiveSetter(object): - def __setattr__(self, attr_name, value): - new_attr_name = attr_name - - if attr_name[-5:] == 'comic': - new_attr_name = "my_" + new_attr_name - elif attr_name[-3:] == 'pie': - new_attr_name = "a_" + new_attr_name - - object.__setattr__(self, new_attr_name, value) - - def test_setattr_intercepts_attribute_assignments(self): - fanboy = self.PossessiveSetter() - - fanboy.comic = 'The Laminator, issue #1' - fanboy.pie = 'blueberry' - - self.assertEqual(__, fanboy.a_pie) - - # - # NOTE: Change the prefix to make this next assert pass - # - - prefix = '__' - self.assertEqual( - "The Laminator, issue #1", - getattr(fanboy, prefix + '_comic')) - - # ------------------------------------------------------------------ - - class ScarySetter(object): - def __init__(self): - self.num_of_coconuts = 9 - self._num_of_private_coconuts = 2 - - def __setattr__(self, attr_name, value): - new_attr_name = attr_name - - if attr_name[0] != '_': - new_attr_name = "altered_" + new_attr_name - - object.__setattr__(self, new_attr_name, value) - - def test_it_modifies_external_attribute_as_expected(self): - setter = self.ScarySetter() - setter.e = "mc hammer" - - self.assertEqual(__, setter.altered_e) - - def test_it_mangles_some_internal_attributes(self): - setter = self.ScarySetter() - - try: - coconuts = setter.num_of_coconuts - except AttributeError: - self.assertEqual(__, setter.altered_num_of_coconuts) - - def test_in_this_case_private_attributes_remain_unmangled(self): - setter = self.ScarySetter() - - self.assertEqual(__, setter._num_of_private_coconuts) diff --git a/python2/koans/about_class_attributes.py b/python2/koans/about_class_attributes.py deleted file mode 100644 index e94b1ae8c..000000000 --- a/python2/koans/about_class_attributes.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Based on AboutClassMethods in the Ruby Koans -# - -from runner.koan import * - - -class AboutClassAttributes(Koan): - class Dog(object): - pass - - def test_new_style_class_objects_are_objects(self): - # Note: Old style class instances are not objects but they are being - # phased out in Python 3. - - fido = self.Dog() - self.assertEqual(__, isinstance(fido, object)) - - def test_classes_are_types(self): - self.assertEqual(__, self.Dog.__class__ == type) - - def test_classes_are_objects_too(self): - self.assertEqual(__, issubclass(self.Dog, object)) - - def test_objects_have_methods(self): - fido = self.Dog() - self.assertEqual(__, len(dir(fido))) - - def test_classes_have_methods(self): - self.assertEqual(__, len(dir(self.Dog))) - - def test_creating_objects_without_defining_a_class(self): - singularity = object() - self.assertEqual(__, len(dir(singularity))) - - def test_defining_attributes_on_individual_objects(self): - fido = self.Dog() - fido.legs = 4 - - self.assertEqual(__, fido.legs) - - def test_defining_functions_on_individual_objects(self): - fido = self.Dog() - fido.wag = lambda: 'fidos wag' - - self.assertEqual(__, fido.wag()) - - def test_other_objects_are_not_affected_by_these_singleton_functions(self): - fido = self.Dog() - rover = self.Dog() - - def wag(): - return 'fidos wag' - fido.wag = wag - - try: - rover.wag() - except Exception as ex: - self.assertMatch(__, ex[0]) - - # ------------------------------------------------------------------ - - class Dog2(object): - def wag(self): - return 'instance wag' - - def bark(self): - return "instance bark" - - def growl(self): - return "instance growl" - - @staticmethod - def bark(): - return "staticmethod bark, arg: None" - - @classmethod - def growl(cls): - return "classmethod growl, arg: cls=" + cls.__name__ - - def test_like_all_objects_classes_can_have_singleton_methods(self): - self.assertMatch(__, self.Dog2.growl()) - - def test_classmethods_are_not_independent_of_instance_methods(self): - fido = self.Dog2() - self.assertMatch(__, fido.growl()) - self.assertMatch(__, self.Dog2.growl()) - - def test_staticmethods_are_unbound_functions_housed_in_a_class(self): - self.assertMatch(__, self.Dog2.bark()) - - def test_staticmethods_also_overshadow_instance_methods(self): - fido = self.Dog2() - self.assertMatch(__, fido.bark()) - - # ------------------------------------------------------------------ - - class Dog3(object): - def __init__(self): - self._name = None - - def get_name_from_instance(self): - return self._name - - def set_name_from_instance(self, name): - self._name = name - - @classmethod - def get_name(cls): - return cls._name - - @classmethod - def set_name(cls, name): - cls._name = name - - name = property(get_name, set_name) - name_from_instance = property( - get_name_from_instance, set_name_from_instance) - - def test_classmethods_can_not_be_used_as_properties(self): - fido = self.Dog3() - try: - fido.name = "Fido" - except Exception as ex: - self.assertMatch(__, ex[0]) - - def test_classes_and_instances_do_not_share_instance_attributes(self): - fido = self.Dog3() - fido.set_name_from_instance("Fido") - fido.set_name("Rover") - self.assertEqual(__, fido.get_name_from_instance()) - self.assertEqual(__, self.Dog3.get_name()) - - def test_classes_and_instances_do_share_class_attributes(self): - fido = self.Dog3() - fido.set_name("Fido") - self.assertEqual(__, fido.get_name()) - self.assertEqual(__, self.Dog3.get_name()) - - # ------------------------------------------------------------------ - - class Dog4(object): - def a_class_method(cls): - return 'dogs class method' - - def a_static_method(): - return 'dogs static method' - - a_class_method = classmethod(a_class_method) - a_static_method = staticmethod(a_static_method) - - def test_you_can_define_class_methods_without_using_a_decorator(self): - self.assertEqual(__, self.Dog4.a_class_method()) - - def test_you_can_define_static_methods_without_using_a_decorator(self): - self.assertEqual(__, self.Dog4.a_static_method()) - - # ------------------------------------------------------------------ - - def test_you_can_explicitly_call_class_methods_from_instance_methods(self): - fido = self.Dog4() - self.assertEqual(__, fido.__class__.a_class_method()) diff --git a/python2/koans/about_classes.py b/python2/koans/about_classes.py deleted file mode 100644 index 7b82e60d1..000000000 --- a/python2/koans/about_classes.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutClasses(Koan): - class Dog(object): - "Dogs need regular walkies. Never, ever let them drive." - - def test_instances_of_classes_can_be_created_adding_parentheses(self): - fido = self.Dog() - self.assertEqual(__, fido.__class__.__name__) - - def test_classes_have_docstrings(self): - self.assertMatch(__, self.Dog.__doc__) - - # ------------------------------------------------------------------ - - class Dog2(object): - def __init__(self): - self._name = 'Paul' - - def set_name(self, a_name): - self._name = a_name - - def test_init_method_is_the_constructor(self): - dog = self.Dog2() - self.assertEqual(__, dog._name) - - def test_private_attributes_are_not_really_private(self): - dog = self.Dog2() - dog.set_name("Fido") - self.assertEqual(__, dog._name) - # The _ prefix in _name implies private ownership, but nothing is truly - # private in Python. - - def test_you_can_also_access_the_value_out_using_getattr_and_dict(self): - fido = self.Dog2() - fido.set_name("Fido") - - self.assertEqual(__, getattr(fido, "_name")) - # getattr(), setattr() and delattr() are a way of accessing attributes - # by method rather than through assignment operators - - self.assertEqual(__, fido.__dict__["_name"]) - # Yes, this works here, but don't rely on the __dict__ object! Some - # class implementations use optimization which result in __dict__ not - # showing everything. - - # ------------------------------------------------------------------ - - class Dog3(object): - def __init__(self): - self._name = None - - def set_name(self, a_name): - self._name = a_name - - def get_name(self): - return self._name - - name = property(get_name, set_name) - - def test_that_name_can_be_read_as_a_property(self): - fido = self.Dog3() - fido.set_name("Fido") - - self.assertEqual(__, fido.get_name()) # access as method - self.assertEqual(__, fido.name) # access as property - - # ------------------------------------------------------------------ - - class Dog4(object): - def __init__(self): - self._name = None - - @property - def name(self): - return self._name - - @name.setter - def name(self, a_name): - self._name = a_name - - def test_creating_properties_with_decorators_is_slightly_easier(self): - fido = self.Dog4() - - fido.name = "Fido" - self.assertEqual(__, fido.name) - - # ------------------------------------------------------------------ - - class Dog5(object): - def __init__(self, initial_name): - self._name = initial_name - - @property - def name(self): - return self._name - - def test_init_provides_initial_values_for_instance_variables(self): - fido = self.Dog5("Fido") - self.assertEqual(__, fido.name) - - def test_args_must_match_init(self): - self.assertRaises(___, self.Dog5) # Evaluates self.Dog5() - - # THINK ABOUT IT: - # Why is this so? - - def test_different_objects_have_different_instance_variables(self): - fido = self.Dog5("Fido") - rover = self.Dog5("Rover") - - self.assertEqual(____, rover.name == fido.name) - - # ------------------------------------------------------------------ - - class Dog6(object): - def __init__(self, initial_name): - self._name = initial_name - - def get_self(self): - return self - - def __str__(self): - # - # Implement this! - # - return __ - - def __repr__(self): - return "" - - def test_inside_a_method_self_refers_to_the_containing_object(self): - fido = self.Dog6("Fido") - - self.assertEqual(__, fido.get_self()) # Not a string! - - def test_str_provides_a_string_version_of_the_object(self): - fido = self.Dog6("Fido") - self.assertEqual("Fido", str(fido)) - - def test_str_is_used_explicitly_in_string_interpolation(self): - fido = self.Dog6("Fido") - self.assertEqual(__, "My dog is " + str(fido)) - - def test_repr_provides_a_more_complete_string_version(self): - fido = self.Dog6("Fido") - self.assertEqual(__, repr(fido)) - - def test_all_objects_support_str_and_repr(self): - seq = [1, 2, 3] - - self.assertEqual(__, str(seq)) - self.assertEqual(__, repr(seq)) - - self.assertEqual(__, str("STRING")) - self.assertEqual(__, repr("STRING")) diff --git a/python2/koans/about_comprehension.py b/python2/koans/about_comprehension.py deleted file mode 100644 index 6919073ba..000000000 --- a/python2/koans/about_comprehension.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutComprehension(Koan): - - - def test_creating_lists_with_list_comprehensions(self): - feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals', - 'fruit bats'] - - comprehension = [delicacy.capitalize() for delicacy in feast] - - self.assertEqual(__, comprehension[0]) - self.assertEqual(__, comprehension[2]) - - def test_filtering_lists_with_list_comprehensions(self): - feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals', - 'fruit bats'] - - comprehension = [delicacy for delicacy in feast if len(delicacy) > 6] - - self.assertEqual(__, len(feast)) - self.assertEqual(__, len(comprehension)) - - def test_unpacking_tuples_in_list_comprehensions(self): - list_of_tuples = [(1, 'lumberjack'), (2, 'inquisition'), (4, 'spam')] - comprehension = [ skit * number for number, skit in list_of_tuples ] - - self.assertEqual(__, comprehension[0]) - self.assertEqual(__, len(comprehension[2])) - - def test_double_list_comprehension(self): - list_of_eggs = ['poached egg', 'fried egg'] - list_of_meats = ['lite spam', 'ham spam', 'fried spam'] - - - comprehension = [ '{0} and {1}'.format(egg, meat) for egg in list_of_eggs for meat in list_of_meats] - - - self.assertEqual(__, len(comprehension)) - self.assertEqual(__, comprehension[0]) - - def test_creating_a_set_with_set_comprehension(self): - comprehension = { x for x in 'aabbbcccc'} - - self.assertEqual(__, comprehension) # remember that set members are unique - - def test_creating_a_dictionary_with_dictionary_comprehension(self): - dict_of_weapons = {'first': 'fear', 'second': 'surprise', - 'third':'ruthless efficiency', 'fourth':'fanatical devotion', - 'fifth': None} - - dict_comprehension = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} - - self.assertEqual(__, 'first' in dict_comprehension) - self.assertEqual(__, 'FIRST' in dict_comprehension) - self.assertEqual(__, len(dict_of_weapons)) - self.assertEqual(__, len(dict_comprehension)) diff --git a/python2/koans/about_control_statements.py b/python2/koans/about_control_statements.py deleted file mode 100644 index 13f5e0dc0..000000000 --- a/python2/koans/about_control_statements.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutControlStatements(Koan): - - def test_if_then_else_statements(self): - if True: - result = 'true value' - else: - result = 'false value' - self.assertEqual(__, result) - - def test_if_then_statements(self): - result = 'default value' - if True: - result = 'true value' - self.assertEqual(__, result) - - def test_if_then_elif_else_statements(self): - if False: - result = 'first value' - elif True: - result = 'true value' - else: - result = 'default value' - self.assertEqual(__, result) - - def test_while_statement(self): - i = 1 - result = 1 - while i <= 10: - result = result * i - i += 1 - self.assertEqual(__, result) - - def test_break_statement(self): - i = 1 - result = 1 - while True: - if i > 10: break - result = result * i - i += 1 - self.assertEqual(__, result) - - def test_continue_statement(self): - i = 0 - result = [] - while i < 10: - i += 1 - if (i % 2) == 0: continue - result.append(i) - self.assertEqual(__, result) - - def test_for_statement(self): - phrase = ["fish", "and", "chips"] - result = [] - for item in phrase: - result.append(item.upper()) - self.assertEqual([__, __, __], result) - - def test_for_statement_with_tuples(self): - round_table = [ - ("Lancelot", "Blue"), - ("Galahad", "I don't know!"), - ("Robin", "Blue! I mean Green!"), - ("Arthur", "Is that an African Swallow or European Swallow?") - ] - result = [] - for knight, answer in round_table: - result.append("Contestant: '" + knight + \ - "' Answer: '" + answer + "'") - - text = __ - - self.assertMatch(text, result[2]) - - self.assertNoMatch(text, result[0]) - self.assertNoMatch(text, result[1]) - self.assertNoMatch(text, result[3]) diff --git a/python2/koans/about_decorating_with_classes.py b/python2/koans/about_decorating_with_classes.py deleted file mode 100644 index b8f67a573..000000000 --- a/python2/koans/about_decorating_with_classes.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - -import functools - - -class AboutDecoratingWithClasses(Koan): - def maximum(self, a, b): - if a > b: - return a - else: - return b - - def test_partial_that_wrappers_no_args(self): - """ - Before we can understand this type of decorator we need to consider - the partial. - """ - max = functools.partial(self.maximum) - - self.assertEqual(__, max(7, 23)) - self.assertEqual(__, max(10, -10)) - - def test_partial_that_wrappers_first_arg(self): - max0 = functools.partial(self.maximum, 0) - - self.assertEqual(__, max0(-4)) - self.assertEqual(__, max0(5)) - - def test_partial_that_wrappers_all_args(self): - always99 = functools.partial(self.maximum, 99, 20) - always20 = functools.partial(self.maximum, 9, 20) - - self.assertEqual(__, always99()) - self.assertEqual(__, always20()) - - # ------------------------------------------------------------------ - - class doubleit(object): - def __init__(self, fn): - self.fn = fn - - def __call__(self, *args): - return self.fn(*args) + ', ' + self.fn(*args) - - def __get__(self, obj, cls=None): - if not obj: - # Decorating an unbound function - return self - else: - # Decorating a bound method - return functools.partial(self, obj) - - @doubleit - def foo(self): - return "foo" - - @doubleit - def parrot(self, text): - return text.upper() - - def test_decorator_with_no_arguments(self): - # To clarify: the decorator above the function has no arguments, even - # if the decorated function does - - self.assertEqual(__, self.foo()) - self.assertEqual(__, self.parrot('pieces of eight')) - - # ------------------------------------------------------------------ - - def sound_check(self): - #Note: no decorator - return "Testing..." - - def test_what_a_decorator_is_doing_to_a_function(self): - #wrap the function with the decorator - self.sound_check = self.doubleit(self.sound_check) - - self.assertEqual(__, self.sound_check()) - - # ------------------------------------------------------------------ - - class documenter(object): - def __init__(self, *args): - self.fn_doc = args[0] - - def __call__(self, fn): - def decorated_function(*args): - return fn(*args) - - if fn.__doc__: - decorated_function.__doc__ = fn.__doc__ + ": " + self.fn_doc - else: - decorated_function.__doc__ = self.fn_doc - return decorated_function - - @documenter("Increments a value by one. Kind of.") - def count_badly(self, num): - num += 1 - if num == 3: - return 5 - else: - return num - - @documenter("Does nothing") - def idler(self, num): - "Idler" - pass - - def test_decorator_with_an_argument(self): - self.assertEqual(__, self.count_badly(2)) - self.assertEqual(__, self.count_badly.__doc__) - - def test_documentor_which_already_has_a_docstring(self): - self.assertEqual(__, self.idler.__doc__) - - # ------------------------------------------------------------------ - - @documenter("DOH!") - @doubleit - @doubleit - def homer(self): - return "D'oh" - - def test_we_can_chain_decorators(self): - self.assertEqual(__, self.homer()) - self.assertEqual(__, self.homer.__doc__) diff --git a/python2/koans/about_decorating_with_functions.py b/python2/koans/about_decorating_with_functions.py deleted file mode 100644 index c2bfe28f4..000000000 --- a/python2/koans/about_decorating_with_functions.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutDecoratingWithFunctions(Koan): - def addcowbell(fn): - fn.wow_factor = 'COWBELL BABY!' - return fn - - @addcowbell - def mediocre_song(self): - return "o/~ We all live in a broken submarine o/~" - - def test_decorators_can_modify_a_function(self): - self.assertMatch(__, self.mediocre_song()) - self.assertEqual(__, self.mediocre_song.wow_factor) - - # ------------------------------------------------------------------ - - def xmltag(fn): - def func(*args): - return '<' + fn(*args) + '/>' - return func - - @xmltag - def render_tag(self, name): - return name - - def test_decorators_can_change_a_function_output(self): - self.assertEqual(__, self.render_tag('llama')) diff --git a/python2/koans/about_deleting_objects.py b/python2/koans/about_deleting_objects.py deleted file mode 100644 index e8a556dc1..000000000 --- a/python2/koans/about_deleting_objects.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutDeletingObjects(Koan): - def test_del_can_remove_slices(self): - lottery_nums = [4, 8, 15, 16, 23, 42] - del lottery_nums[1] - del lottery_nums[2:4] - - self.assertEqual(__, lottery_nums) - - def test_del_can_remove_entire_lists(self): - lottery_nums = [4, 8, 15, 16, 23, 42] - del lottery_nums - try: - win = lottery_nums - except Exception as e: - pass - self.assertMatch(__, e[0]) - - # -------------------------------------------------------------------- - - class ClosingSale(object): - def __init__(self): - self.hamsters = 7 - self.zebras = 84 - - def cameras(self): - return 34 - - def toilet_brushes(self): - return 48 - - def jellies(self): - return 5 - - def test_del_can_remove_attributes(self): - crazy_discounts = self.ClosingSale() - del self.ClosingSale.toilet_brushes - del crazy_discounts.hamsters - - try: - still_available = crazy_discounts.toilet_brushes() - except AttributeError as e: - err_msg1 = e.args[0] - - try: - still_available = crazy_discounts.hamsters - except AttributeError as e: - err_msg2 = e.args[0] - - self.assertMatch(__, err_msg1) - self.assertMatch(__, err_msg2) - - # -------------------------------------------------------------------- - - class ClintEastwood(object): - def __init__(self): - self._name = None - - def get_name(self): - try: - return self._name - except: - return "The man with no name" - - def set_name(self, name): - self._name = name - - def del_name(self): - del self._name - - name = property(get_name, set_name, del_name, \ - "Mr Eastwood's current alias") - - def test_del_works_with_properties(self): - cowboy = self.ClintEastwood() - cowboy.name = 'Senor Ninguno' - self.assertEqual('Senor Ninguno', cowboy.name) - - del cowboy.name - self.assertEqual(__, cowboy.name) - - # -------------------------------------------------------------------- - - class Prisoner(object): - def __init__(self): - self._name = None - - @property - def name(self): - return self._name - - @name.setter - def name(self, name): - self._name = name - - @name.deleter - def name(self): - self._name = 'Number Six' - - def test_another_way_to_make_a_deletable_property(self): - citizen = self.Prisoner() - citizen.name = "Patrick" - self.assertEqual('Patrick', citizen.name) - - del citizen.name - self.assertEqual(__, citizen.name) - - # -------------------------------------------------------------------- - - class MoreOrganisedClosingSale(ClosingSale): - def __init__(self): - self.last_deletion = None - super(AboutDeletingObjects.ClosingSale, self).__init__() - - def __delattr__(self, attr_name): - self.last_deletion = attr_name - - def tests_del_can_be_overriden(self): - sale = self.MoreOrganisedClosingSale() - self.assertEqual(5, sale.jellies()) - del sale.jellies - self.assertEqual(__, sale.last_deletion) diff --git a/python2/koans/about_dice_project.py b/python2/koans/about_dice_project.py deleted file mode 100644 index c2710075f..000000000 --- a/python2/koans/about_dice_project.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - -import random - - -class DiceSet(object): - def __init__(self): - self._values = None - - @property - def values(self): - return self._values - - def roll(self, n): - # Needs implementing! - # Tip: random.randint(min, max) can be used to generate random numbers - pass - - -class AboutDiceProject(Koan): - def test_can_create_a_dice_set(self): - dice = DiceSet() - self.assertTrue(dice) - - def test_rolling_the_dice_returns_a_set_of_integers_between_1_and_6(self): - dice = DiceSet() - - dice.roll(5) - self.assertTrue(isinstance(dice.values, list), "should be a list") - self.assertEqual(5, len(dice.values)) - for value in dice.values: - self.assertTrue( - value >= 1 and value <= 6, - "value " + str(value) + " must be between 1 and 6") - - def test_dice_values_do_not_change_unless_explicitly_rolled(self): - dice = DiceSet() - dice.roll(5) - first_time = dice.values - second_time = dice.values - self.assertEqual(first_time, second_time) - - def test_dice_values_should_change_between_rolls(self): - dice = DiceSet() - - dice.roll(5) - first_time = dice.values - - dice.roll(5) - second_time = dice.values - - self.assertNotEqual(first_time, second_time, \ - "Two rolls should not be equal") - - # THINK ABOUT IT: - # - # If the rolls are random, then it is possible (although not - # likely) that two consecutive rolls are equal. What would be a - # better way to test this? - - def test_you_can_roll_different_numbers_of_dice(self): - dice = DiceSet() - - dice.roll(3) - self.assertEqual(3, len(dice.values)) - - dice.roll(1) - self.assertEqual(1, len(dice.values)) diff --git a/python2/koans/about_dictionaries.py b/python2/koans/about_dictionaries.py deleted file mode 100644 index 8591b5439..000000000 --- a/python2/koans/about_dictionaries.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Based on AboutHashes in the Ruby Koans -# - -from runner.koan import * - - -class AboutDictionaries(Koan): - def test_creating_dictionaries(self): - empty_dict = dict() - self.assertEqual(dict, type(empty_dict)) - self.assertEqual(dict(), empty_dict) - self.assertEqual(__, len(empty_dict)) - - def test_dictionary_literals(self): - empty_dict = {} - self.assertEqual(dict, type(empty_dict)) - babel_fish = {'one': 'uno', 'two': 'dos'} - self.assertEqual(__, len(babel_fish)) - - def test_accessing_dictionaries(self): - babel_fish = {'one': 'uno', 'two': 'dos'} - self.assertEqual(__, babel_fish['one']) - self.assertEqual(__, babel_fish['two']) - - def test_changing_dictionaries(self): - babel_fish = {'one': 'uno', 'two': 'dos'} - babel_fish['one'] = 'eins' - - expected = {'two': 'dos', 'one': __} - self.assertEqual(expected, babel_fish) - - def test_dictionary_is_unordered(self): - dict1 = {'one': 'uno', 'two': 'dos'} - dict2 = {'two': 'dos', 'one': 'uno'} - - self.assertEqual(____, dict1 == dict2) - - def test_dictionary_keys_and_values(self): - babel_fish = {'one': 'uno', 'two': 'dos'} - self.assertEqual(__, len(babel_fish.keys())) - self.assertEqual(__, len(babel_fish.values())) - self.assertEqual(__, 'one' in babel_fish.keys()) - self.assertEqual(__, 'two' in babel_fish.values()) - self.assertEqual(__, 'uno' in babel_fish.keys()) - self.assertEqual(__, 'dos' in babel_fish.values()) - - def test_making_a_dictionary_from_a_sequence_of_keys(self): - cards = {}.fromkeys( - ('red warrior', 'green elf', 'blue valkyrie', 'yellow dwarf', - 'confused looking zebra'), - 42) - - self.assertEqual(__, len(cards)) - self.assertEqual(__, cards['green elf']) - self.assertEqual(__, cards['yellow dwarf']) diff --git a/python2/koans/about_exceptions.py b/python2/koans/about_exceptions.py deleted file mode 100644 index dd2b3823f..000000000 --- a/python2/koans/about_exceptions.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutExceptions(Koan): - - class MySpecialError(RuntimeError): - pass - - def test_exceptions_inherit_from_exception(self): - mro = self.MySpecialError.__mro__ - self.assertEqual(__, mro[1].__name__) - self.assertEqual(__, mro[2].__name__) - self.assertEqual(__, mro[3].__name__) - self.assertEqual(__, mro[4].__name__) - - def test_try_clause(self): - result = None - try: - self.fail("Oops") - except StandardError as ex: - result = 'exception handled' - - self.assertEqual(__, result) - - self.assertEqual(____, isinstance(ex, StandardError)) - self.assertEqual(____, isinstance(ex, RuntimeError)) - - self.assertTrue(issubclass(RuntimeError, StandardError), \ - "RuntimeError is a subclass of StandardError") - - self.assertEqual(__, ex[0]) - - def test_raising_a_specific_error(self): - result = None - try: - raise self.MySpecialError, "My Message" - except self.MySpecialError as ex: - result = 'exception handled' - - self.assertEqual(__, result) - self.assertEqual(__, ex[0]) - - def test_else_clause(self): - result = None - try: - pass - except RuntimeError: - result = 'it broke' - pass - else: - result = 'no damage done' - - self.assertEqual(__, result) - - def test_finally_clause(self): - result = None - try: - self.fail("Oops") - except: - # no code here - pass - finally: - result = 'always run' - - self.assertEqual(__, result) diff --git a/python2/koans/about_extra_credit.py b/python2/koans/about_extra_credit.py deleted file mode 100644 index f37732154..000000000 --- a/python2/koans/about_extra_credit.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# EXTRA CREDIT: -# -# Create a program that will play the Greed Game. -# Rules for the game are in GREED_RULES.TXT. -# -# You already have a DiceSet class and score function you can use. -# Write a player class and a Game class to complete the project. This -# is a free form assignment, so approach it however you desire. - -from runner.koan import * - - -class AboutExtraCredit(Koan): - # Write tests here. If you need extra test classes add them to the - # test suite in runner/path_to_enlightenment.py - def test_extra_credit_task(self): - pass diff --git a/python2/koans/about_generators.py b/python2/koans/about_generators.py deleted file mode 100644 index 21b32cc3c..000000000 --- a/python2/koans/about_generators.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Written in place of AboutBlocks in the Ruby Koans -# -# Note: Both blocks and generators use a yield keyword, but they behave -# a lot differently -# - -from runner.koan import * - - -class AboutGenerators(Koan): - - def test_generating_values_on_the_fly(self): - result = list() - bacon_generator = (n + ' bacon' for \ - n in ['crunchy', 'veggie', 'danish']) - for bacon in bacon_generator: - result.append(bacon) - self.assertEqual(__, result) - - def test_generators_are_different_to_list_comprehensions(self): - num_list = [x * 2 for x in range(1, 3)] - num_generator = (x * 2 for x in range(1, 3)) - - self.assertEqual(2, num_list[0]) - - # A generator has to be iterated through. - self.assertEqual(__, list(num_generator)[0]) - - # Both list comprehensions and generators can be iterated - # though. However, a generator function is only called on the - # first iteration. The values are generated on the fly instead - # of stored. - # - # Generators are more memory friendly, but less versatile - - def test_generator_expressions_are_a_one_shot_deal(self): - dynamite = ('Boom!' for n in range(3)) - - attempt1 = list(dynamite) - attempt2 = list(dynamite) - - self.assertEqual(__, attempt1) - self.assertEqual(__, attempt2) - - # ------------------------------------------------------------------ - - def simple_generator_method(self): - yield 'peanut' - yield 'butter' - yield 'and' - yield 'jelly' - - def test_generator_method_will_yield_values_during_iteration(self): - result = list() - for item in self.simple_generator_method(): - result.append(item) - self.assertEqual(__, result) - - def test_generators_can_be_manually_iterated_and_closed(self): - result = self.simple_generator_method() - self.assertEqual(__, next(result)) - self.assertEqual(__, next(result)) - result.close() - - # ------------------------------------------------------------------ - - def square_me(self, seq): - for x in seq: - yield x * x - - def test_generator_method_with_parameter(self): - result = self.square_me(range(2, 5)) - self.assertEqual(__, list(result)) - - # ------------------------------------------------------------------ - - def sum_it(self, seq): - value = 0 - for num in seq: - # The local state of 'value' will be retained between iterations - value += num - yield value - - def test_generator_keeps_track_of_local_variables(self): - result = self.sum_it(range(2, 5)) - self.assertEqual(__, list(result)) - - # ------------------------------------------------------------------ - - def coroutine(self): - result = yield - yield result - - def test_generators_can_act_as_coroutines(self): - generator = self.coroutine() - - # THINK ABOUT IT: - # Why is this line necessary? - # - # Hint: Read the "Specification: Sending Values into Generators" - # section of http://www.python.org/dev/peps/pep-0342/ - next(generator) - - self.assertEqual(__, generator.send(1 + 2)) - - def test_before_sending_a_value_to_a_generator_next_must_be_called(self): - generator = self.coroutine() - - try: - generator.send(1 + 2) - except TypeError as ex: - self.assertMatch(__, ex[0]) - - # ------------------------------------------------------------------ - - def yield_tester(self): - value = yield - if value: - yield value - else: - yield 'no value' - - def test_generators_can_see_if_they_have_been_called_with_a_value(self): - generator = self.yield_tester() - next(generator) - self.assertEqual('with value', generator.send('with value')) - - generator2 = self.yield_tester() - next(generator2) - self.assertEqual(__, next(generator2)) - - def test_send_none_is_equivalent_to_next(self): - generator = self.yield_tester() - - next(generator) - # 'next(generator)' is exactly equivalent to 'generator.send(None)' - self.assertEqual(__, generator.send(None)) diff --git a/python2/koans/about_inheritance.py b/python2/koans/about_inheritance.py deleted file mode 100644 index e4310ad9a..000000000 --- a/python2/koans/about_inheritance.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutInheritance(Koan): - class Dog(object): - def __init__(self, name): - self._name = name - - @property - def name(self): - return self._name - - def bark(self): - return "WOOF" - - class Chihuahua(Dog): - def wag(self): - return "happy" - - def bark(self): - return "yip" - - def test_subclasses_have_the_parent_as_an_ancestor(self): - self.assertEqual(____, issubclass(self.Chihuahua, self.Dog)) - - def test_this_subclass_ultimately_inherits_from_object_class(self): - self.assertEqual(____, issubclass(self.Chihuahua, object)) - - def test_instances_inherit_behavior_from_parent_class(self): - chico = self.Chihuahua("Chico") - self.assertEqual(__, chico.name) - - def test_subclasses_add_new_behavior(self): - chico = self.Chihuahua("Chico") - self.assertEqual(__, chico.wag()) - - try: - fido = self.Dog("Fido") - fido.wag() - except StandardError as ex: - self.assertMatch(__, ex[0]) - - def test_subclasses_can_modify_existing_behavior(self): - chico = self.Chihuahua("Chico") - self.assertEqual(__, chico.bark()) - - fido = self.Dog("Fido") - self.assertEqual(__, fido.bark()) - - # ------------------------------------------------------------------ - - class BullDog(Dog): - def bark(self): - return super(AboutInheritance.BullDog, self).bark() + ", GRR" - - def test_subclasses_can_invoke_parent_behavior_via_super(self): - ralph = self.BullDog("Ralph") - self.assertEqual(__, ralph.bark()) - - # ------------------------------------------------------------------ - - class GreatDane(Dog): - def growl(self): - return super(AboutInheritance.GreatDane, self).bark() + ", GROWL" - - def test_super_works_across_methods(self): - george = self.GreatDane("George") - self.assertEqual(__, george.growl()) - - # --------------------------------------------------------- - - class Pug(Dog): - def __init__(self, name): - pass - - class Greyhound(Dog): - def __init__(self, name): - super(AboutInheritance.Greyhound, self).__init__(name) - - def test_base_init_does_not_get_called_automatically(self): - snoopy = self.Pug("Snoopy") - try: - name = snoopy.name - except Exception as ex: - self.assertMatch(__, ex[0]) - - def test_base_init_has_to_be_called_explicitly(self): - boxer = self.Greyhound("Boxer") - self.assertEqual(__, boxer.name) diff --git a/python2/koans/about_iteration.py b/python2/koans/about_iteration.py deleted file mode 100644 index 73adc58e9..000000000 --- a/python2/koans/about_iteration.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutIteration(Koan): - - def test_iterators_are_a_type(self): - it = iter(range(1, 6)) - - fib = 0 - - for num in it: - fib += num - - self.assertEqual(__, fib) - - def test_iterating_with_next(self): - stages = iter(['alpha', 'beta', 'gamma']) - - try: - self.assertEqual(__, next(stages)) - next(stages) - self.assertEqual(__, next(stages)) - next(stages) - except StopIteration as ex: - err_msg = 'Ran out of iterations' - - self.assertMatch(__, err_msg) - - # ------------------------------------------------------------------ - - def add_ten(self, item): - return item + 10 - - def test_map_transforms_elements_of_a_list(self): - seq = [1, 2, 3] - - mapped_seq = map(self.add_ten, seq) - self.assertEqual(__, mapped_seq) - - def test_filter_selects_certain_items_from_a_list(self): - def is_even(item): - return (item % 2) == 0 - - seq = [1, 2, 3, 4, 5, 6] - - even_numbers = filter(is_even, seq) - self.assertEqual(__, even_numbers) - - def test_just_return_first_item_found(self): - def is_big_name(item): - return len(item) > 4 - - names = ["Jim", "Bill", "Clarence", "Doug", "Eli"] - - # NOTE This still iterates through the whole names, so not particularly - # efficient - self.assertEqual([__], filter(is_big_name, names)[:1]) - - # Boring but effective - for item in names: - if is_big_name(item): - self.assertEqual(__, item) - break - - # ------------------------------------------------------------------ - - def add(self, accum, item): - return accum + item - - def multiply(self, accum, item): - return accum * item - - def test_reduce_will_blow_your_mind(self): - result = reduce(self.add, [2, 3, 4]) - self.assertEqual(__, result) - - result2 = reduce(self.multiply, [2, 3, 4], 1) - self.assertEqual(__, result2) - - # Extra Credit: - # Describe in your own words what reduce does. - - # ------------------------------------------------------------------ - - def test_use_pass_for_iterations_with_no_body(self): - for num in range(1, 5): - pass - - self.assertEqual(__, num) - - # ------------------------------------------------------------------ - - def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): - # Ranges are an iterable sequence - result = map(self.add_ten, range(1, 4)) - self.assertEqual(__, list(result)) - - try: - f = open("example_file.txt") - - try: - def make_upcase(line): - return line.strip().upper() - upcase_lines = map(make_upcase, f.readlines()) - self.assertEqual(__, list(upcase_lines)) - finally: - # Arg, this is ugly. - # We will figure out how to fix this later. - f.close() - except IOError: - # should never happen - self.fail() diff --git a/python2/koans/about_lambdas.py b/python2/koans/about_lambdas.py deleted file mode 100644 index dfc72f9e6..000000000 --- a/python2/koans/about_lambdas.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Based slightly on the lambdas section of AboutBlocks in the Ruby Koans -# - -from runner.koan import * - - -class AboutLambdas(Koan): - def test_lambdas_can_be_assigned_to_variables_and_called_explicitly(self): - add_one = lambda n: n + 1 - self.assertEqual(__, add_one(10)) - - # ------------------------------------------------------------------ - - def make_order(self, order): - return lambda qty: str(qty) + " " + order + "s" - - def test_accessing_lambda_via_assignment(self): - sausages = self.make_order('sausage') - eggs = self.make_order('egg') - - self.assertEqual(__, sausages(3)) - self.assertEqual(__, eggs(2)) - - def test_accessing_lambda_without_assignment(self): - self.assertEqual(__, self.make_order('spam')(39823)) diff --git a/python2/koans/about_list_assignments.py b/python2/koans/about_list_assignments.py deleted file mode 100644 index 2c0267805..000000000 --- a/python2/koans/about_list_assignments.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Based on AboutArrayAssignments in the Ruby Koans -# - -from runner.koan import * - - -class AboutListAssignments(Koan): - def test_non_parallel_assignment(self): - names = ["John", "Smith"] - self.assertEqual(__, names) - - def test_parallel_assignments(self): - first_name, last_name = ["John", "Smith"] - self.assertEqual(__, first_name) - self.assertEqual(__, last_name) - - def test_parallel_assignments_with_sublists(self): - first_name, last_name = [["Willie", "Rae"], "Johnson"] - self.assertEqual(__, first_name) - self.assertEqual(__, last_name) - - def test_swapping_with_parallel_assignment(self): - first_name = "Roy" - last_name = "Rob" - first_name, last_name = last_name, first_name - self.assertEqual(__, first_name) - self.assertEqual(__, last_name) diff --git a/python2/koans/about_lists.py b/python2/koans/about_lists.py deleted file mode 100644 index d89888f6d..000000000 --- a/python2/koans/about_lists.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Based on AboutArrays in the Ruby Koans -# - -from runner.koan import * - - -class AboutLists(Koan): - def test_creating_lists(self): - empty_list = list() - self.assertEqual(list, type(empty_list)) - self.assertEqual(__, len(empty_list)) - - def test_list_literals(self): - nums = list() - self.assertEqual([], nums) - - nums[0:] = [1] - self.assertEqual([1], nums) - - nums[1:] = [2] - self.assertEqual([1, __], nums) - - nums.append(333) - self.assertEqual([1, 2, __], nums) - - def test_accessing_list_elements(self): - noms = ['peanut', 'butter', 'and', 'jelly'] - - self.assertEqual(__, noms[0]) - self.assertEqual(__, noms[3]) - self.assertEqual(__, noms[-1]) - self.assertEqual(__, noms[-3]) - - def test_slicing_lists(self): - noms = ['peanut', 'butter', 'and', 'jelly'] - - self.assertEqual(__, noms[0:1]) - self.assertEqual(__, noms[0:2]) - self.assertEqual(__, noms[2:2]) - self.assertEqual(__, noms[2:20]) - self.assertEqual(__, noms[4:0]) - self.assertEqual(__, noms[4:100]) - self.assertEqual(__, noms[5:0]) - - def test_slicing_to_the_edge(self): - noms = ['peanut', 'butter', 'and', 'jelly'] - - self.assertEqual(__, noms[2:]) - self.assertEqual(__, noms[:2]) - - def test_lists_and_ranges(self): - self.assertEqual(list, type(range(5))) - self.assertEqual(__, range(5)) - self.assertEqual(__, range(5, 9)) - - def test_ranges_with_steps(self): - self.assertEqual(__, range(5, 3, -1)) - self.assertEqual(__, range(0, 8, 2)) - self.assertEqual(__, range(1, 8, 3)) - self.assertEqual(__, range(5, -7, -4)) - self.assertEqual(__, range(5, -8, -4)) - - def test_insertions(self): - knight = ['you', 'shall', 'pass'] - knight.insert(2, 'not') - self.assertEqual(__, knight) - - knight.insert(0, 'Arthur') - self.assertEqual(__, knight) - - def test_popping_lists(self): - stack = [10, 20, 30, 40] - stack.append('last') - - self.assertEqual(__, stack) - - popped_value = stack.pop() - self.assertEqual(__, popped_value) - self.assertEqual(__, stack) - - popped_value = stack.pop(1) - self.assertEqual(__, popped_value) - self.assertEqual(__, stack) - - # Notice that there is a "pop" but no "push" in python? - - # Part of the Python philosophy is that there ideally should be one and - # only one way of doing anything. A 'push' is the same as an 'append'. - - # To learn more about this try typing "import this" from the python - # console... ;) - - def test_use_deques_for_making_queues(self): - from collections import deque - - queue = deque([1, 2]) - queue.append('last') - - self.assertEqual(__, list(queue)) - - popped_value = queue.popleft() - self.assertEqual(__, popped_value) - self.assertEqual(__, list(queue)) diff --git a/python2/koans/about_method_bindings.py b/python2/koans/about_method_bindings.py deleted file mode 100644 index dfa87894f..000000000 --- a/python2/koans/about_method_bindings.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -def function(): - return "pineapple" - - -def function2(): - return "tractor" - - -class Class(object): - def method(self): - return "parrot" - - -class AboutMethodBindings(Koan): - def test_methods_are_bound_to_an_object(self): - obj = Class() - self.assertEqual(__, obj.method.im_self == obj) - - def test_methods_are_also_bound_to_a_function(self): - obj = Class() - self.assertEqual(__, obj.method()) - self.assertEqual(__, obj.method.im_func(obj)) - - def test_functions_have_attributes(self): - self.assertEqual(__, len(dir(function))) - self.assertEqual(__, dir(function) == dir(Class.method.im_func)) - - def test_bound_methods_have_different_attributes(self): - obj = Class() - self.assertEqual(__, len(dir(obj.method))) - - def test_setting_attributes_on_an_unbound_function(self): - function.cherries = 3 - self.assertEqual(__, function.cherries) - - def test_setting_attributes_on_a_bound_method_directly(self): - obj = Class() - try: - obj.method.cherries = 3 - except AttributeError as ex: - self.assertMatch(__, ex[0]) - - def test_setting_attributes_on_methods_by_accessing_the_inner_function(self): - obj = Class() - obj.method.im_func.cherries = 3 - self.assertEqual(__, obj.method.cherries) - - def test_functions_can_have_inner_functions(self): - function2.get_fruit = function - self.assertEqual(__, function2.get_fruit()) - - def test_inner_functions_are_unbound(self): - function2.get_fruit = function - try: - cls = function2.get_fruit.im_self - except AttributeError as ex: - self.assertMatch(__, ex[0]) - - # ------------------------------------------------------------------ - - class BoundClass(object): - def __get__(self, obj, cls): - return (self, obj, cls) - - binding = BoundClass() - - def test_get_descriptor_resolves_attribute_binding(self): - bound_obj, binding_owner, owner_type = self.binding - # Look at BoundClass.__get__(): - # bound_obj = self - # binding_owner = obj - # owner_type = cls - - self.assertEqual(__, bound_obj.__class__.__name__) - self.assertEqual(__, binding_owner.__class__.__name__) - self.assertEqual(AboutMethodBindings, owner_type) - - # ------------------------------------------------------------------ - - class SuperColor(object): - def __init__(self): - self.choice = None - - def __set__(self, obj, val): - self.choice = val - - color = SuperColor() - - def test_set_descriptor_changes_behavior_of_attribute_assignment(self): - self.assertEqual(None, self.color.choice) - self.color = 'purple' - self.assertEqual(__, self.color.choice) diff --git a/python2/koans/about_methods.py b/python2/koans/about_methods.py deleted file mode 100644 index fd924f9c9..000000000 --- a/python2/koans/about_methods.py +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Partially based on AboutMethods in the Ruby Koans -# - -from runner.koan import * - - -def my_global_function(a, b): - return a + b - - -class AboutMethods(Koan): - def test_calling_a_global_function(self): - self.assertEqual(__, my_global_function(2, 3)) - - # NOTE: Wrong number of arguments is not a SYNTAX error, but a - # runtime error. - def test_calling_functions_with_wrong_number_of_arguments(self): - try: - my_global_function() - except Exception as exception: - # NOTE: The .__name__ attribute will convert the class - # into a string value. - self.assertEqual(__, exception.__class__.__name__) - self.assertMatch( - r'my_global_function\(\) takes exactly 2 arguments \(0 given\)', - exception[0]) - - try: - my_global_function(1, 2, 3) - except Exception as e: - - # Note, watch out for parenthesis. They need slashes in front! - self.assertMatch(__, e[0]) - - # ------------------------------------------------------------------ - - def pointless_method(self, a, b): - sum = a + b - - def test_which_does_not_return_anything(self): - self.assertEqual(__, self.pointless_method(1, 2)) - # Notice that methods accessed from class scope do not require - # you to pass the first "self" argument? - - # ------------------------------------------------------------------ - - def method_with_defaults(self, a, b='default_value'): - return [a, b] - - def test_calling_with_default_values(self): - self.assertEqual(__, self.method_with_defaults(1)) - self.assertEqual(__, self.method_with_defaults(1, 2)) - - # ------------------------------------------------------------------ - - def method_with_var_args(self, *args): - return args - - def test_calling_with_variable_arguments(self): - self.assertEqual(__, self.method_with_var_args()) - self.assertEqual(('one', ), self.method_with_var_args('one')) - self.assertEqual(__, self.method_with_var_args('one', 'two')) - - # ------------------------------------------------------------------ - - def function_with_the_same_name(self, a, b): - return a + b - - def test_functions_without_self_arg_are_global_functions(self): - def function_with_the_same_name(a, b): - return a * b - - self.assertEqual(__, function_with_the_same_name(3, 4)) - - def test_calling_methods_in_same_class_with_explicit_receiver(self): - def function_with_the_same_name(a, b): - return a * b - - self.assertEqual(__, self.function_with_the_same_name(3, 4)) - - # ------------------------------------------------------------------ - - def another_method_with_the_same_name(self): - return 10 - - link_to_overlapped_method = another_method_with_the_same_name - - def another_method_with_the_same_name(self): - return 42 - - def test_that_old_methods_are_hidden_by_redefinitions(self): - self.assertEqual(__, self.another_method_with_the_same_name()) - - def test_that_overlapped_method_is_still_there(self): - self.assertEqual(__, self.link_to_overlapped_method()) - - # ------------------------------------------------------------------ - - def empty_method(self): - pass - - def test_methods_that_do_nothing_need_to_use_pass_as_a_filler(self): - self.assertEqual(__, self.empty_method()) - - def test_pass_does_nothing_at_all(self): - "You" - "shall" - "not" - pass - self.assertEqual(____, "Still got to this line" != None) - - # ------------------------------------------------------------------ - - def one_line_method(self): return 'Madagascar' - - def test_no_indentation_required_for_one_line_statement_bodies(self): - self.assertEqual(__, self.one_line_method()) - - # ------------------------------------------------------------------ - - def method_with_documentation(self): - "A string placed at the beginning of a function is used for documentation" - return "ok" - - def test_the_documentation_can_be_viewed_with_the_doc_method(self): - self.assertMatch(__, self.method_with_documentation.__doc__) - - # ------------------------------------------------------------------ - - class Dog(object): - def name(self): - return "Fido" - - def _tail(self): - # Prefixing a method with an underscore implies private scope - return "wagging" - - def __password(self): - return 'password' # Genius! - - def test_calling_methods_in_other_objects(self): - rover = self.Dog() - self.assertEqual(__, rover.name()) - - def test_private_access_is_implied_but_not_enforced(self): - rover = self.Dog() - - # This is a little rude, but legal - self.assertEqual(__, rover._tail()) - - def test_double_underscore_attribute_prefixes_cause_name_mangling(self): - """Attributes names that start with a double underscore get - mangled when an instance is created.""" - rover = self.Dog() - try: - #This may not be possible... - password = rover.__password() - except Exception as ex: - self.assertEqual(__, ex.__class__.__name__) - - # But this still is! - self.assertEqual(__, rover._Dog__password()) - - # Name mangling exists to avoid name clash issues when subclassing. - # It is not for providing effective access protection diff --git a/python2/koans/about_modules.py b/python2/koans/about_modules.py deleted file mode 100644 index 95badd8ed..000000000 --- a/python2/koans/about_modules.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# This is very different to AboutModules in Ruby Koans -# Our AboutMultipleInheritance class is a little more comparable -# - -from runner.koan import * - -from another_local_module import * -from local_module_with_all_defined import * - - -class AboutModules(Koan): - def test_importing_other_python_scripts_as_modules(self): - import local_module # local_module.py - - duck = local_module.Duck() - self.assertEqual(__, duck.name) - - def test_importing_attributes_from_classes_using_from_keyword(self): - from local_module import Duck - - duck = Duck() # no module qualifier needed this time - self.assertEqual(__, duck.name) - - def test_we_can_import_multiple_items_at_once(self): - import jims, joes - - jims_dog = jims.Dog() - joes_dog = joes.Dog() - self.assertEqual(__, jims_dog.identify()) - self.assertEqual(__, joes_dog.identify()) - - def test_importing_all_module_attributes_at_once(self): - """ - importing all attributes at once is done like so: - from another_local_module import * - The import wildcard cannot be used from within classes or functions. - """ - - goose = Goose() - hamster = Hamster() - - self.assertEqual(__, goose.name) - self.assertEqual(__, hamster.name) - - def test_modules_hide_attributes_prefixed_by_underscores(self): - try: - private_squirrel = _SecretSquirrel() - except NameError as ex: - self.assertMatch(__, ex[0]) - - def test_private_attributes_are_still_accessible_in_modules(self): - from local_module import Duck # local_module.py - - duck = Duck() - self.assertEqual(__, duck._password) - # module level attribute hiding doesn't affect class attributes - # (unless the class itself is hidden). - - def test_a_module_can_limit_wildcard_imports(self): - """ - Examine results of: - from local_module_with_all_defined import * - """ - - # 'Goat' is on the __all__ list - goat = Goat() - self.assertEqual(__, goat.name) - - # How about velociraptors? - lizard = _Velociraptor() - self.assertEqual(__, lizard.name) - - # SecretDuck? Never heard of her! - try: - duck = SecretDuck() - except NameError as ex: - self.assertMatch(__, ex[0]) diff --git a/python2/koans/about_monkey_patching.py b/python2/koans/about_monkey_patching.py deleted file mode 100644 index 65bd461d9..000000000 --- a/python2/koans/about_monkey_patching.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Related to AboutOpenClasses in the Ruby Koans -# - -from runner.koan import * - - -class AboutMonkeyPatching(Koan): - class Dog(object): - def bark(self): - return "WOOF" - - def test_as_defined_dogs_do_bark(self): - fido = self.Dog() - self.assertEqual(__, fido.bark()) - - # ------------------------------------------------------------------ - - # Add a new method to an existing class. - def test_after_patching_dogs_can_both_wag_and_bark(self): - def wag(self): - return "HAPPY" - - self.Dog.wag = wag - - fido = self.Dog() - self.assertEqual(__, fido.wag()) - self.assertEqual(__, fido.bark()) - - # ------------------------------------------------------------------ - - def test_most_built_in_classes_cannot_be_monkey_patched(self): - try: - int.is_even = lambda self: (self % 2) == 0 - except StandardError as ex: - self.assertMatch(__, ex[0]) - - # ------------------------------------------------------------------ - - class MyInt(int): - pass - - def test_subclasses_of_built_in_classes_can_be_be_monkey_patched(self): - self.MyInt.is_even = lambda self: (self % 2) == 0 - - self.assertEqual(____, self.MyInt(1).is_even()) - self.assertEqual(____, self.MyInt(2).is_even()) diff --git a/python2/koans/about_multiple_inheritance.py b/python2/koans/about_multiple_inheritance.py deleted file mode 100644 index b204c85c5..000000000 --- a/python2/koans/about_multiple_inheritance.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Slightly based on AboutModules in the Ruby Koans -# - -from runner.koan import * - - -class AboutMultipleInheritance(Koan): - class Nameable(object): - def __init__(self): - self._name = None - - def set_name(self, new_name): - self._name = new_name - - def here(self): - return "In Nameable class" - - class Animal(object): - def legs(self): - return 4 - - def can_climb_walls(self): - return False - - def here(self): - return "In Animal class" - - class Pig(Animal): - def __init__(self): - super(AboutMultipleInheritance.Animal, self).__init__() - self._name = "Jasper" - - @property - def name(self): - return self._name - - def speak(self): - return "OINK" - - def color(self): - return 'pink' - - def here(self): - return "In Pig class" - - class Spider(Animal): - def __init__(self): - super(AboutMultipleInheritance.Animal, self).__init__() - self._name = "Boris" - - def can_climb_walls(self): - return True - - def legs(self): - return 8 - - def color(self): - return 'black' - - def here(self): - return "In Spider class" - - class Spiderpig(Pig, Spider, Nameable): - def __init__(self): - super(AboutMultipleInheritance.Pig, self).__init__() - super(AboutMultipleInheritance.Nameable, self).__init__() - self._name = "Jeff" - - def speak(self): - return "This looks like a job for Spiderpig!" - - def here(self): - return "In Spiderpig class" - - # - # Hierarchy: - # Animal - # / \ - # Pig Spider Nameable - # \ | / - # Spiderpig - # - # ------------------------------------------------------------------ - - def test_normal_methods_are_available_in_the_object(self): - jeff = self.Spiderpig() - self.assertMatch(__, jeff.speak()) - - def test_base_class_methods_are_also_available_in_the_object(self): - jeff = self.Spiderpig() - try: - jeff.set_name("Rover") - except: - self.fail("This should not happen") - self.assertEqual(____, jeff.can_climb_walls()) - - def test_base_class_methods_can_affect_instance_variables_in_the_object(self): - jeff = self.Spiderpig() - self.assertEqual(__, jeff.name) - - jeff.set_name("Rover") - self.assertEqual(__, jeff.name) - - def test_left_hand_side_inheritance_tends_to_be_higher_priority(self): - jeff = self.Spiderpig() - self.assertEqual(__, jeff.color()) - - def test_super_class_methods_are_higher_priority_than_super_super_classes(self): - jeff = self.Spiderpig() - self.assertEqual(__, jeff.legs()) - - def test_we_can_inspect_the_method_resolution_order(self): - # - # MRO = Method Resolution Order - # - mro = type(self.Spiderpig()).__mro__ - self.assertEqual('Spiderpig', mro[0].__name__) - self.assertEqual('Pig', mro[1].__name__) - self.assertEqual(__, mro[2].__name__) - self.assertEqual(__, mro[3].__name__) - self.assertEqual(__, mro[4].__name__) - self.assertEqual(__, mro[5].__name__) - - def test_confirm_the_mro_controls_the_calling_order(self): - jeff = self.Spiderpig() - self.assertMatch('Spiderpig', jeff.here()) - - next = super(AboutMultipleInheritance.Spiderpig, jeff) - self.assertMatch('Pig', next.here()) - - next = super(AboutMultipleInheritance.Pig, jeff) - self.assertMatch(__, next.here()) - - # Hang on a minute?!? That last class name might be a super class of - # the 'jeff' object, but its hardly a superclass of Pig, is it? - # - # To avoid confusion it may help to think of super() as next_mro(). diff --git a/python2/koans/about_new_style_classes.py b/python2/koans/about_new_style_classes.py deleted file mode 100644 index a41f9a34b..000000000 --- a/python2/koans/about_new_style_classes.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutNewStyleClasses(Koan): - class OldStyleClass: - "An old style class" - # Original style classes from Python 2.1 and earlier, also known as - # "classic classes", have been phased out in Python 3. - - class NewStyleClass(object): - "A new style class" - # Introduced in Python 2.2 to unify types and classes. - # - # If you want to learn more, see: - # https://www.python.org/download/releases/2.2.3/descrintro/ - # - # Aside from this set of tests, Python Koans sticks exclusively to this - # kind of class. - pass - - def test_new_style_classes_inherit_from_object_base_class(self): - self.assertEqual(____, issubclass(self.NewStyleClass, object)) - self.assertEqual(____, issubclass(self.OldStyleClass, object)) - - def test_new_style_classes_have_more_attributes(self): - self.assertEqual(__, len(dir(self.OldStyleClass))) - self.assertEqual(__, self.OldStyleClass.__doc__) - self.assertEqual(__, self.OldStyleClass.__module__) - - self.assertEqual(__, len(dir(self.NewStyleClass))) - # To examine the available attributes, run - # 'dir()' - # from a python console - - # ------------------------------------------------------------------ - - def test_old_style_classes_have_type_but_no_class_attribute(self): - self.assertEqual(__, type(self.OldStyleClass).__name__) - - try: - cls = self.OldStyleClass.__class__.__name__ - except Exception as ex: - pass - - # What was that error message from the exception? - self.assertMatch(__, ex[0]) - - def test_new_style_classes_have_same_class_as_type(self): - new_style = self.NewStyleClass() - self.assertEqual(__, self.NewStyleClass.__class__.__name__) - self.assertEqual( - __, - type(self.NewStyleClass) == self.NewStyleClass.__class__) - - # ------------------------------------------------------------------ - - def test_in_old_style_instances_class_is_different_to_type(self): - old_style = self.OldStyleClass() - self.assertEqual(__, old_style.__class__.__name__) - self.assertEqual(__, type(old_style).__name__) - - def test_new_style_instances_have_same_class_as_type(self): - new_style = self.NewStyleClass() - self.assertEqual(__, new_style.__class__.__name__) - self.assertEqual(__, type(new_style) == new_style.__class__) diff --git a/python2/koans/about_none.py b/python2/koans/about_none.py deleted file mode 100644 index e64164dbd..000000000 --- a/python2/koans/about_none.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Based on AboutNil in the Ruby Koans -# - -from runner.koan import * - - -class AboutNone(Koan): - - def test_none_is_an_object(self): - "Unlike NULL in a lot of languages" - self.assertEqual(__, isinstance(None, object)) - - def test_none_is_universal(self): - "There is only one None" - self.assertEqual(__, None is None) - - def test_what_exception_do_you_get_when_calling_nonexistent_methods(self): - """ - What is the Exception that is thrown when you call a method that does - not exist? - - Hint: launch python command console and try the code in the - block below. - - Don't worry about what 'try' and 'except' do, we'll talk about - this later - """ - try: - None.some_method_none_does_not_know_about() - except Exception as ex: - # What exception has been caught? - # - # Need a recap on how to evaluate __class__ attributes? - # https://github.com/gregmalcolm/python_koans/wiki/Class-Attribute - - self.assertEqual(__, ex.__class__) - - # What message was attached to the exception? - # (HINT: replace __ with part of the error message.) - self.assertMatch(__, ex.args[0]) - - def test_none_is_distinct(self): - """ - None is distinct from other things which are False. - """ - self.assertEqual(____, None is not 0) - self.assertEqual(____, None is not False) diff --git a/python2/koans/about_packages.py b/python2/koans/about_packages.py deleted file mode 100644 index 2c535ad47..000000000 --- a/python2/koans/about_packages.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# This is very different to AboutModules in Ruby Koans -# Our AboutMultipleInheritance class is a little more comparable -# - -from runner.koan import * - -# -# Package hierarchy of Python Koans project: -# -# contemplate_koans.py -# koans/ -# __init__.py -# about_asserts.py -# about_attribute_access.py -# about_class_attributes.py -# about_classes.py -# ... -# a_package_folder/ -# __init__.py -# a_module.py - - -class AboutPackages(Koan): - def test_subfolders_can_form_part_of_a_module_package(self): - # Import ./a_package_folder/a_module.py - from a_package_folder.a_module import Duck - - duck = Duck() - self.assertEqual(__, duck.name) - - def test_subfolders_become_modules_if_they_have_an_init_module(self): - # Import ./a_package_folder/__init__.py - from a_package_folder import an_attribute - - self.assertEqual(__, an_attribute) - - def test_subfolders_without_an_init_module_are_not_part_of_the_package(self): - # Import ./a_normal_folder/ - try: - import a_normal_folder - except ImportError as ex: - self.assertMatch(__, ex[0]) - - # ------------------------------------------------------------------ - - def test_use_absolute_imports_to_import_upper_level_modules(self): - # Import /contemplate_koans.py - import contemplate_koans - - self.assertEqual(__, contemplate_koans.__name__) - - # contemplate_koans.py is the root module in this package because it's - # the first python module called in koans. - # - # If contemplate_koans.py was based in a_package_folder that would be - # the root folder, which would make reaching the koans folder - # almost impossible. So always leave the starting python script in - # a folder which can reach everything else. - - def test_import_a_module_in_a_subfolder_using_an_absolute_path(self): - # Import contemplate_koans.py/koans/a_package_folder/a_module.py - from koans.a_package_folder.a_module import Duck - - self.assertEqual(__, Duck.__module__) diff --git a/python2/koans/about_proxy_object_project.py b/python2/koans/about_proxy_object_project.py deleted file mode 100644 index 4e391bc40..000000000 --- a/python2/koans/about_proxy_object_project.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Project: Create a Proxy Class -# -# In this assignment, create a proxy class (one is started for you -# below). You should be able to initialize the proxy object with any -# object. Any attributes called on the proxy object should be forwarded -# to the target object. As each attribute call is sent, the proxy should -# record the name of the attribute sent. -# -# The proxy class is started for you. You will need to add a method -# missing handler and any other supporting methods. The specification -# of the Proxy class is given in the AboutProxyObjectProject koan. - -# Note: This is a bit trickier than its Ruby Koans counterpart, but you -# can do it! - -from runner.koan import * - - -class Proxy(object): - def __init__(self, target_object): - # WRITE CODE HERE - - #initialize '_obj' attribute last. Trust me on this! - self._obj = target_object - - # WRITE CODE HERE - - -# The proxy object should pass the following Koan: -# -class AboutProxyObjectProject(Koan): - def test_proxy_method_returns_wrapped_object(self): - # NOTE: The Television class is defined below - tv = Proxy(Television()) - - self.assertTrue(isinstance(tv, Proxy)) - - def test_tv_methods_still_perform_their_function(self): - tv = Proxy(Television()) - - tv.channel = 10 - tv.power() - - self.assertEqual(10, tv.channel) - self.assertTrue(tv.is_on()) - - def test_proxy_records_messages_sent_to_tv(self): - tv = Proxy(Television()) - - tv.power() - tv.channel = 10 - - self.assertEqual(['power', 'channel'], tv.messages()) - - def test_proxy_handles_invalid_messages(self): - tv = Proxy(Television()) - - ex = None - try: - tv.no_such_method() - except AttributeError as ex: - pass - - self.assertEqual(AttributeError, type(ex)) - - def test_proxy_reports_methods_have_been_called(self): - tv = Proxy(Television()) - - tv.power() - tv.power() - - self.assertTrue(tv.was_called('power')) - self.assertFalse(tv.was_called('channel')) - - def test_proxy_counts_method_calls(self): - tv = Proxy(Television()) - - tv.power() - tv.channel = 48 - tv.power() - - self.assertEqual(2, tv.number_of_times_called('power')) - self.assertEqual(1, tv.number_of_times_called('channel')) - self.assertEqual(0, tv.number_of_times_called('is_on')) - - def test_proxy_can_record_more_than_just_tv_objects(self): - proxy = Proxy("Py Ohio 2010") - - result = proxy.upper() - - self.assertEqual("PY OHIO 2010", result) - - result = proxy.split() - - self.assertEqual(["Py", "Ohio", "2010"], result) - self.assertEqual(['upper', 'split'], proxy.messages()) - - -# ==================================================================== -# The following code is to support the testing of the Proxy class. No -# changes should be necessary to anything below this comment. - -# Example class using in the proxy testing above. -class Television(object): - def __init__(self): - self._channel = None - self._power = None - - @property - def channel(self): - return self._channel - - @channel.setter - def channel(self, value): - self._channel = value - - def power(self): - if self._power == 'on': - self._power = 'off' - else: - self._power = 'on' - - def is_on(self): - return self._power == 'on' - - -# Tests for the Television class. All of theses tests should pass. -class TelevisionTest(Koan): - def test_it_turns_on(self): - tv = Television() - - tv.power() - self.assertTrue(tv.is_on()) - - def test_it_also_turns_off(self): - tv = Television() - - tv.power() - tv.power() - - self.assertFalse(tv.is_on()) - - def test_edge_case_on_off(self): - tv = Television() - - tv.power() - tv.power() - tv.power() - - self.assertTrue(tv.is_on()) - - tv.power() - - self.assertFalse(tv.is_on()) - - def test_can_set_the_channel(self): - tv = Television() - - tv.channel = 11 - self.assertEqual(11, tv.channel) diff --git a/python2/koans/about_regex.py b/python2/koans/about_regex.py deleted file mode 100755 index f562594e5..000000000 --- a/python2/koans/about_regex.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - -import re - - -class AboutRegex(Koan): - """ - These koans are based on Ben's book: Regular Expressions in 10 - minutes. I found this book very useful, so I decided to write - a koan file in order to practice everything it taught me. - http://www.forta.com/books/0672325667/ - """ - - def test_matching_literal_text(self): - """ - Lesson 1 Matching Literal String - """ - string = "Hello, my name is Felix and these koans are based " + \ - "on Ben's book: Regular Expressions in 10 minutes." - m = re.search(__, string) - self.assertTrue( - m and m.group(0) and - m.group(0) == 'Felix', - "I want my name") - - def test_matching_literal_text_how_many(self): - """ - Lesson 1 -- How many matches? - - The default behaviour of most regular expression engines is - to return just the first match. In python you have the - following options: - - match() --> Determine if the RE matches at the - beginning of the string. - search() --> Scan through a string, looking for any - location where this RE matches. - findall() --> Find all substrings where the RE - matches, and return them as a list. - finditer() --> Find all substrings where the RE - matches, and return them as an iterator. - """ - string = ("Hello, my name is Felix and these koans are based " + - "on Ben's book: Regular Expressions in 10 minutes. " + - "Repeat My name is Felix") - m = re.match('Felix', string) # TIP: match may not be the best option - - # I want to know how many times my name appears - self.assertEqual(m, __) - - def test_matching_literal_text_not_case_sensitivity(self): - """ - Lesson 1 -- Matching Literal String non case sensitivity. - Most regex implementations also support matches that are not - case sensitive. In python you can use re.IGNORECASE, in - Javascript you can specify the optional i flag. In Ben's - book you can see more languages. - - """ - string = "Hello, my name is Felix or felix and this koan " + \ - "is based on Ben's book: Regular Expressions in 10 minutes." - - self.assertEqual(re.findall("felix", string), __) - self.assertEqual(re.findall("felix", string, re.IGNORECASE), __) - - def test_matching_any_character(self): - """ - Lesson 1: Matching any character - - `.` matches any character: alphabetic characters, digits, - and punctuation. - """ - string = "pecks.xlx\n" \ - + "orders1.xls\n" \ - + "apec1.xls\n" \ - + "na1.xls\n" \ - + "na2.xls\n" \ - + "sa1.xls" - - # I want to find all uses of myArray - change_this_search_string = 'a..xlx' - self.assertEquals( - len(re.findall(change_this_search_string, string)), - 3) - - def test_matching_set_character(self): - """ - Lesson 2 -- Matching sets of characters - - A set of characters is defined using the metacharacters - `[` and `]`. Everything between them is part of the set, and - any single one of the set members will match. - """ - string = "sales.xlx\n" \ - + "sales1.xls\n" \ - + "orders3.xls\n" \ - + "apac1.xls\n" \ - + "sales2.xls\n" \ - + "na1.xls\n" \ - + "na2.xls\n" \ - + "sa1.xls\n" \ - + "ca1.xls" - # I want to find all files for North America(na) or South - # America(sa), but not (ca) TIP you can use the pattern .a. - # which matches in above test but in this case matches more than - # you want - change_this_search_string = '[nsc]a[2-9].xls' - self.assertEquals( - len(re.findall(change_this_search_string, string)), - 3) - - def test_anything_but_matching(self): - """ - Lesson 2 -- Using character set ranges - Occasionally, you'll have a list of characters that you don't - want to match. Character sets can be negated using the ^ - metacharacter. - - """ - string = "sales.xlx\n" \ - + "sales1.xls\n" \ - + "orders3.xls\n" \ - + "apac1.xls\n" \ - + "sales2.xls\n" \ - + "sales3.xls\n" \ - + "europe2.xls\n" \ - + "sam.xls\n" \ - + "na1.xls\n" \ - + "na2.xls\n" \ - + "sa1.xls\n" \ - + "ca1.xls" - - # I want to find the name 'sam' - change_this_search_string = '[^nc]am' - self.assertEquals( - re.findall(change_this_search_string, string), - ['sam.xls']) diff --git a/python2/koans/about_scope.py b/python2/koans/about_scope.py deleted file mode 100644 index aca08058f..000000000 --- a/python2/koans/about_scope.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - -import jims -import joes - -counter = 0 # Global - - -class AboutScope(Koan): - # - # NOTE: - # Look in jims.py and joes.py to see definitions of Dog used - # for this set of tests - # - - def test_dog_is_not_available_in_the_current_scope(self): - try: - fido = Dog() - except Exception as ex: - self.assertMatch(__, ex[0]) - - def test_you_can_reference_nested_classes_using_the_scope_operator(self): - fido = jims.Dog() - # name 'jims' module name is taken from jims.py filename - - rover = joes.Dog() - self.assertEqual(__, fido.identify()) - self.assertEqual(__, rover.identify()) - - self.assertEqual(____, type(fido) == type(rover)) - self.assertEqual(____, jims.Dog == joes.Dog) - - # ------------------------------------------------------------------ - - class str(object): - pass - - def test_bare_bones_class_names_do_not_assume_the_current_scope(self): - self.assertEqual(____, AboutScope.str == str) - - def test_nested_string_is_not_the_same_as_the_system_string(self): - self.assertEqual(____, self.str == type("HI")) - - def test_str_without_self_prefix_stays_in_the_global_scope(self): - self.assertEqual(____, str == type("HI")) - - # ------------------------------------------------------------------ - - PI = 3.1416 - - def test_constants_are_defined_with_an_initial_uppercase_letter(self): - self.assertAlmostEqual(_____, self.PI) - # Note, floating point numbers in python are not precise. - # assertAlmostEqual will check that it is 'close enough' - - def test_constants_are_assumed_by_convention_only(self): - self.PI = "rhubarb" - self.assertEqual(_____, self.PI) - # There aren't any real constants in python. Its up to the developer - # to keep to the convention and not modify them. - - # ------------------------------------------------------------------ - - def increment_using_local_counter(self, counter): - counter = counter + 1 - - def increment_using_global_counter(self): - global counter - counter = counter + 1 - - def test_incrementing_with_local_counter(self): - global counter - start = counter - self.increment_using_local_counter(start) - self.assertEqual(____, counter == start + 1) - - def test_incrementing_with_global_counter(self): - global counter - start = counter - self.increment_using_global_counter() - self.assertEqual(____, counter == start + 1) - - # ------------------------------------------------------------------ - - global deadly_bingo - deadly_bingo = [4, 8, 15, 16, 23, 42] - - def test_global_attributes_can_be_created_in_the_middle_of_a_class(self): - self.assertEqual(__, deadly_bingo[5]) diff --git a/python2/koans/about_scoring_project.py b/python2/koans/about_scoring_project.py deleted file mode 100644 index da51563b4..000000000 --- a/python2/koans/about_scoring_project.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -# Greed is a dice game where you roll up to five dice to accumulate -# points. The following "score" function will be used calculate the -# score of a single roll of the dice. -# -# A greed roll is scored as follows: -# -# * A set of three ones is 1000 points -# -# * A set of three numbers (other than ones) is worth 100 times the -# number. (e.g. three fives is 500 points). -# -# * A one (that is not part of a set of three) is worth 100 points. -# -# * A five (that is not part of a set of three) is worth 50 points. -# -# * Everything else is worth 0 points. -# -# -# Examples: -# -# score([1, 1, 1, 5, 1]) => 1150 points -# score([2, 3, 4, 6, 2]) => 0 points -# score([3, 4, 5, 3, 3]) => 350 points -# score([1, 5, 1, 2, 4]) => 250 points -# -# More scoring examples are given in the tests below: -# -# Your goal is to write the score method. - -def score(dice): - # You need to write this method - pass - - -class AboutScoringProject(Koan): - def test_score_of_an_empty_list_is_zero(self): - self.assertEqual(0, score([])) - - def test_score_of_a_single_roll_of_5_is_50(self): - self.assertEqual(50, score([5])) - - def test_score_of_a_single_roll_of_1_is_100(self): - self.assertEqual(100, score([1])) - - def test_score_of_multiple_1s_and_5s_is_the_sum_of_individual_scores(self): - self.assertEqual(300, score([1, 5, 5, 1])) - - def test_score_of_single_2s_3s_4s_and_6s_are_zero(self): - self.assertEqual(0, score([2, 3, 4, 6])) - - def test_score_of_a_triple_1_is_1000(self): - self.assertEqual(1000, score([1, 1, 1])) - - def test_score_of_other_triples_is_100x(self): - self.assertEqual(200, score([2, 2, 2])) - self.assertEqual(300, score([3, 3, 3])) - self.assertEqual(400, score([4, 4, 4])) - self.assertEqual(500, score([5, 5, 5])) - self.assertEqual(600, score([6, 6, 6])) - - def test_score_of_mixed_is_sum(self): - self.assertEqual(250, score([2, 5, 2, 2, 3])) - self.assertEqual(550, score([5, 5, 5, 5])) - self.assertEqual(1150, score([1, 1, 1, 5, 1])) - - def test_ones_not_left_out(self): - self.assertEqual(300, score([1, 2, 2, 2])) - self.assertEqual(350, score([1, 5, 2, 2, 2])) diff --git a/python2/koans/about_sets.py b/python2/koans/about_sets.py deleted file mode 100644 index 86403d5d5..000000000 --- a/python2/koans/about_sets.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutSets(Koan): - def test_sets_make_keep_lists_unique(self): - highlanders = ['MacLeod', 'Ramirez', 'MacLeod', 'Matunas', - 'MacLeod', 'Malcolm', 'MacLeod'] - - there_can_only_be_only_one = set(highlanders) - - self.assertEqual(__, there_can_only_be_only_one) - - def test_sets_are_unordered(self): - self.assertEqual(set([__, __, __, __, __]), set('12345')) - - def test_convert_the_set_into_a_list_to_sort_it(self): - self.assertEqual(__, sorted(set('13245'))) - - # ------------------------------------------------------------------ - - def test_set_have_arithmetic_operators(self): - scotsmen = set(['MacLeod', 'Wallace', 'Willie']) - warriors = set(['MacLeod', 'Wallace', 'Leonidas']) - - self.assertEqual(__, scotsmen - warriors) - self.assertEqual(__, scotsmen | warriors) - self.assertEqual(__, scotsmen & warriors) - self.assertEqual(__, scotsmen ^ warriors) - - # ------------------------------------------------------------------ - - def test_we_can_query_set_membership(self): - self.assertEqual(__, 127 in set([127, 0, 0, 1])) - self.assertEqual(__, 'cow' not in set('apocalypse now')) - - def test_we_can_compare_subsets(self): - self.assertEqual(__, set('cake') <= set('cherry cake')) - self.assertEqual(__, set('cake').issubset(set('cherry cake'))) - - self.assertEqual(__, set('cake') > set('pie')) diff --git a/python2/koans/about_string_manipulation.py b/python2/koans/about_string_manipulation.py deleted file mode 100644 index c395309cc..000000000 --- a/python2/koans/about_string_manipulation.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutStringManipulation(Koan): - - def test_use_format_to_interpolate_variables(self): - value1 = 'one' - value2 = 2 - string = "The values are {0} and {1}".format(value1, value2) - self.assertEqual(__, string) - - def test_formatted_values_can_be_shown_in_any_order_or_be_repeated(self): - value1 = 'doh' - value2 = 'DOH' - string = "The values are {1}, {0}, {0} and {1}!".format(value1, value2) - self.assertEqual(__, string) - - def test_any_python_expression_may_be_interpolated(self): - import math # import a standard python module with math functions - - decimal_places = 4 - string = "The square root of 5 is {0:.{1}f}".format(math.sqrt(5), \ - decimal_places) - self.assertEqual(__, string) - - def test_you_can_get_a_substring_from_a_string(self): - string = "Bacon, lettuce and tomato" - self.assertEqual(__, string[7:10]) - - def test_you_can_get_a_single_character_from_a_string(self): - string = "Bacon, lettuce and tomato" - self.assertEqual(__, string[1]) - - def test_single_characters_can_be_represented_by_integers(self): - self.assertEqual(__, ord('a')) - self.assertEqual(__, ord('b') == (ord('a') + 1)) - - def test_strings_can_be_split(self): - string = "Sausage Egg Cheese" - words = string.split() - self.assertEqual([__, __, __], words) - - def test_strings_can_be_split_with_different_patterns(self): - import re # import python regular expression library - - string = "the,rain;in,spain" - pattern = re.compile(',|;') - - words = pattern.split(string) - - self.assertEqual([__, __, __, __], words) - - # `pattern` is a Python regular expression pattern which matches - # ',' or ';' - - def test_raw_strings_do_not_interpret_escape_characters(self): - string = r'\n' - self.assertNotEqual('\n', string) - self.assertEqual(__, string) - self.assertEqual(__, len(string)) - - # Useful in regular expressions, file paths, URLs, etc. - - def test_strings_can_be_joined(self): - words = ["Now", "is", "the", "time"] - self.assertEqual(__, ' '.join(words)) - - def test_strings_can_change_case(self): - self.assertEqual(__, 'guido'.capitalize()) - self.assertEqual(__, 'guido'.upper()) - self.assertEqual(__, 'TimBot'.lower()) - self.assertEqual(__, 'guido van rossum'.title()) - self.assertEqual(__, 'ToTaLlY aWeSoMe'.swapcase()) diff --git a/python2/koans/about_strings.py b/python2/koans/about_strings.py deleted file mode 100644 index abfcf5981..000000000 --- a/python2/koans/about_strings.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutStrings(Koan): - - def test_double_quoted_strings_are_strings(self): - string = "Hello, world." - self.assertEqual(__, isinstance(string, basestring)) - - def test_single_quoted_strings_are_also_strings(self): - string = 'Goodbye, world.' - self.assertEqual(__, isinstance(string, basestring)) - - def test_triple_quote_strings_are_also_strings(self): - string = """Howdy, world!""" - self.assertEqual(__, isinstance(string, basestring)) - - def test_triple_single_quotes_work_too(self): - string = '''Bonjour tout le monde!''' - self.assertEqual(__, isinstance(string, basestring)) - - def test_raw_strings_are_also_strings(self): - string = r"Konnichi wa, world!" - self.assertEqual(__, isinstance(string, basestring)) - - def test_use_single_quotes_to_create_string_with_double_quotes(self): - string = 'He said, "Go Away."' - self.assertEqual(__, string) - - def test_use_double_quotes_to_create_strings_with_single_quotes(self): - string = "Don't" - self.assertEqual(__, string) - - def test_use_backslash_for_escaping_quotes_in_strings(self): - a = "He said, \"Don't\"" - b = 'He said, "Don\'t"' - self.assertEqual(__, (a == b)) - - def test_use_backslash_at_the_end_of_a_line_to_continue_onto_the_next_line(self): - string = "It was the best of times,\n\ -It was the worst of times." - self.assertEqual(__, len(string)) - - def test_triple_quoted_strings_can_span_lines(self): - string = """ -Howdy, -world! -""" - self.assertEqual(__, len(string)) - - def test_triple_quoted_strings_need_less_escaping(self): - a = "Hello \"world\"." - b = """Hello "world".""" - self.assertEqual(__, (a == b)) - - def test_escaping_quotes_at_the_end_of_triple_quoted_string(self): - string = """Hello "world\"""" - self.assertEqual(__, string) - - def test_plus_concatenates_strings(self): - string = "Hello, " + "world" - self.assertEqual(__, string) - - def test_adjacent_strings_are_concatenated_automatically(self): - string = "Hello" ", " "world" - self.assertEqual(__, string) - - def test_plus_will_not_modify_original_strings(self): - hi = "Hello, " - there = "world" - string = hi + there - self.assertEqual(__, hi) - self.assertEqual(__, there) - - def test_plus_equals_will_append_to_end_of_string(self): - hi = "Hello, " - there = "world" - hi += there - self.assertEqual(__, hi) - - def test_plus_equals_also_leaves_original_string_unmodified(self): - original = "Hello, " - hi = original - there = "world" - hi += there - self.assertEqual(__, original) - - def test_most_strings_interpret_escape_characters(self): - string = "\n" - self.assertEqual('\n', string) - self.assertEqual("""\n""", string) - self.assertEqual(__, len(string)) diff --git a/python2/koans/about_triangle_project.py b/python2/koans/about_triangle_project.py deleted file mode 100644 index 065e4ab37..000000000 --- a/python2/koans/about_triangle_project.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - -# You need to write the triangle method in the file 'triangle.py' -from triangle import * - - -class AboutTriangleProject(Koan): - def test_equilateral_triangles_have_equal_sides(self): - self.assertEqual('equilateral', triangle(2, 2, 2)) - self.assertEqual('equilateral', triangle(10, 10, 10)) - - def test_isosceles_triangles_have_exactly_two_sides_equal(self): - self.assertEqual('isosceles', triangle(3, 4, 4)) - self.assertEqual('isosceles', triangle(4, 3, 4)) - self.assertEqual('isosceles', triangle(4, 4, 3)) - self.assertEqual('isosceles', triangle(10, 10, 2)) - - def test_scalene_triangles_have_no_equal_sides(self): - self.assertEqual('scalene', triangle(3, 4, 5)) - self.assertEqual('scalene', triangle(10, 11, 12)) - self.assertEqual('scalene', triangle(5, 4, 2)) diff --git a/python2/koans/about_triangle_project2.py b/python2/koans/about_triangle_project2.py deleted file mode 100644 index 444e95092..000000000 --- a/python2/koans/about_triangle_project2.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - -# You need to finish implementing triangle() in the file 'triangle.py' -from triangle import * - - -class AboutTriangleProject2(Koan): - # The first assignment did not talk about how to handle errors. - # Let's handle that part now. - def test_illegal_triangles_throw_exceptions(self): - # In the code below, each line calls the specified method with the arguments passed to it. - # E.g. this line: - # self.assertRaises(TriangleError, triangle, 0, 0, 0) - # calls triangle(0, 0, 0) - - # All sides should be greater than 0 - self.assertRaises(TriangleError, triangle, 0, 0, 0) - self.assertRaises(TriangleError, triangle, 3, 4, -5) - - # The sum of any two sides should be greater than the third one - self.assertRaises(TriangleError, triangle, 1, 1, 3) - self.assertRaises(TriangleError, triangle, 2, 5, 2) diff --git a/python2/koans/about_true_and_false.py b/python2/koans/about_true_and_false.py deleted file mode 100644 index 5f06a63db..000000000 --- a/python2/koans/about_true_and_false.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutTrueAndFalse(Koan): - def truth_value(self, condition): - if condition: - return 'true stuff' - else: - return 'false stuff' - - def test_true_is_treated_as_true(self): - self.assertEqual(__, self.truth_value(True)) - - def test_false_is_treated_as_false(self): - self.assertEqual(__, self.truth_value(False)) - - def test_none_is_treated_as_false(self): - self.assertEqual(__, self.truth_value(None)) - - def test_zero_is_treated_as_false(self): - self.assertEqual(__, self.truth_value(0)) - - def test_empty_collections_are_treated_as_false(self): - self.assertEqual(__, self.truth_value([])) - self.assertEqual(__, self.truth_value(())) - self.assertEqual(__, self.truth_value({})) - self.assertEqual(__, self.truth_value(set())) - - def test_blank_strings_are_treated_as_false(self): - self.assertEqual(__, self.truth_value("")) - - def test_everything_else_is_treated_as_true(self): - self.assertEqual(__, self.truth_value(1)) - self.assertEqual(__, self.truth_value([0])) - self.assertEqual(__, self.truth_value((0,))) - self.assertEqual( - __, - self.truth_value("Python is named after Monty Python")) - self.assertEqual(__, self.truth_value(' ')) - self.assertEqual(__, self.truth_value('0')) diff --git a/python2/koans/about_tuples.py b/python2/koans/about_tuples.py deleted file mode 100644 index 89e0eff29..000000000 --- a/python2/koans/about_tuples.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from runner.koan import * - - -class AboutTuples(Koan): - def test_creating_a_tuple(self): - count_of_three = (1, 2, 5) - self.assertEqual(__, count_of_three[2]) - - def test_tuples_are_immutable_so_item_assignment_is_not_possible(self): - count_of_three = (1, 2, 5) - try: - count_of_three[2] = "three" - except TypeError as ex: - self.assertMatch(__, ex[0]) - - def test_tuples_are_immutable_so_appending_is_not_possible(self): - count_of_three = (1, 2, 5) - try: - count_of_three.append("boom") - except Exception as ex: - self.assertEqual(AttributeError, type(ex)) - - # Note, assertMatch() uses regular expression pattern matching, - # so you don't have to copy the whole message. - self.assertMatch(__, ex[0]) - - # Tuples are less flexible than lists, but faster. - - def test_tuples_can_only_be_changed_through_replacement(self): - count_of_three = (1, 2, 5) - - list_count = list(count_of_three) - list_count.append("boom") - count_of_three = tuple(list_count) - - self.assertEqual(__, count_of_three) - - def test_tuples_of_one_look_peculiar(self): - self.assertEqual(__, (1).__class__) - self.assertEqual(__, (1,).__class__) - self.assertEqual(__, ("I'm a tuple",).__class__) - self.assertEqual(__, ("Not a tuple").__class__) - - def test_tuple_constructor_can_be_surprising(self): - self.assertEqual(__, tuple("Surprise!")) - - def test_creating_empty_tuples(self): - self.assertEqual(__, ()) - self.assertEqual(__, tuple()) # Sometimes less confusing - - def test_tuples_can_be_embedded(self): - lat = (37, 14, 6, 'N') - lon = (115, 48, 40, 'W') - place = ('Area 51', lat, lon) - self.assertEqual(__, place) - - def test_tuples_are_good_for_representing_records(self): - locations = [ - ("Illuminati HQ", (38, 52, 15.56, 'N'), (77, 3, 21.46, 'W')), - ("Stargate B", (41, 10, 43.92, 'N'), (1, 49, 34.29, 'W')), - ] - - locations.append( - ("Cthulhu", (26, 40, 1, 'N'), (70, 45, 7, 'W')) - ) - - self.assertEqual(__, locations[2][0]) - self.assertEqual(__, locations[0][1][2]) diff --git a/python2/koans/about_with_statements.py b/python2/koans/about_with_statements.py deleted file mode 100644 index 2842832a5..000000000 --- a/python2/koans/about_with_statements.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# -# Based on AboutSandwichCode in the Ruby Koans -# - -from runner.koan import * - -import re # For regular expression string comparisons - - -class AboutWithStatements(Koan): - def count_lines(self, file_name): - try: - f = open(file_name) - try: - return len(f.readlines()) - finally: - f.close() - except IOError: - # should never happen - self.fail() - - def test_counting_lines(self): - self.assertEqual(__, self.count_lines("example_file.txt")) - - # ------------------------------------------------------------------ - - def find_line(self, file_name): - try: - f = open(file_name) - try: - for line in f.readlines(): - match = re.search('e', line) - if match: - return line - finally: - f.close() - except IOError: - # should never happen - self.fail() - - def test_finding_lines(self): - self.assertEqual(__, self.find_line("example_file.txt")) - - ## ------------------------------------------------------------------ - ## THINK ABOUT IT: - ## - ## The count_lines and find_line are similar, and yet different. - ## They both follow the pattern of "sandwich code". - ## - ## Sandwich code is code that comes in three parts: (1) the top slice - ## of bread, (2) the meat, and (3) the bottom slice of bread. - ## The bread part of the sandwich almost always goes together, but - ## the meat part changes all the time. - ## - ## Because the changing part of the sandwich code is in the middle, - ## abstracting the top and bottom bread slices to a library can be - ## difficult in many languages. - ## - ## (Aside for C++ programmers: The idiom of capturing allocated - ## pointers in a smart pointer constructor is an attempt to deal with - ## the problem of sandwich code for resource allocation.) - ## - ## Python solves the problem using Context Managers. Consider the - ## following code: - ## - - class FileContextManager(): - def __init__(self, file_name): - self._file_name = file_name - self._file = None - - def __enter__(self): - self._file = open(self._file_name) - return self._file - - def __exit__(self, cls, value, tb): - self._file.close() - - # Now we write: - - def count_lines2(self, file_name): - with self.FileContextManager(file_name) as f: - return len(f.readlines()) - - def test_counting_lines2(self): - self.assertEqual(__, self.count_lines2("example_file.txt")) - - # ------------------------------------------------------------------ - - def find_line2(self, file_name): - # Using the context manager self.FileContextManager, rewrite this - # function to return the first line containing the letter 'e'. - return None - - def test_finding_lines2(self): - self.assertNotEqual(None, self.find_line2("example_file.txt")) - self.assertEqual('test\n', self.find_line2("example_file.txt")) - - # ------------------------------------------------------------------ - - def count_lines3(self, file_name): - with open(file_name) as f: - return len(f.readlines()) - - def test_open_already_has_its_own_built_in_context_manager(self): - self.assertEqual(__, self.count_lines3("example_file.txt")) diff --git a/python2/koans/another_local_module.py b/python2/koans/another_local_module.py deleted file mode 100644 index e27c53dde..000000000 --- a/python2/koans/another_local_module.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - - -class Goose(object): - @property - def name(self): - return "Mr Stabby" - - -class Hamster(object): - @property - def name(self): - return "Phil" - - -class _SecretSquirrel(object): - @property - def name(self): - return "Mr Anonymous" diff --git a/python2/koans/jims.py b/python2/koans/jims.py deleted file mode 100644 index 761882f13..000000000 --- a/python2/koans/jims.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - - -class Dog(object): - def identify(self): - return "jims dog" diff --git a/python2/koans/joes.py b/python2/koans/joes.py deleted file mode 100644 index 7cab94866..000000000 --- a/python2/koans/joes.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - - -class Dog(object): - def identify(self): - return "joes dog" diff --git a/python2/koans/local_module.py b/python2/koans/local_module.py deleted file mode 100644 index 762a55a5e..000000000 --- a/python2/koans/local_module.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - - -class Duck(object): - def __init__(self): - self._password = 'password' # Genius! - - @property - def name(self): - return "Daffy" diff --git a/python2/koans/local_module_with_all_defined.py b/python2/koans/local_module_with_all_defined.py deleted file mode 100644 index 90488cd60..000000000 --- a/python2/koans/local_module_with_all_defined.py +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -__all__ = ( - 'Goat', - '_Velociraptor' -) - - -class Goat(object): - @property - def name(self): - return "George" - - -class _Velociraptor(object): - @property - def name(self): - return "Cuddles" - - -class SecretDuck(object): - @property - def name(self): - return "None of your business" diff --git a/python2/koans/triangle.py b/python2/koans/triangle.py deleted file mode 100644 index 8f3faeed3..000000000 --- a/python2/koans/triangle.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Triangle Project Code. - - -# triangle(a, b, c) analyzes the lengths of the sides of a triangle -# (represented by a, b and c) and returns the type of triangle. -# -# It returns: -# 'equilateral' if all sides are equal -# 'isosceles' if exactly 2 sides are equal -# 'scalene' if no sides are equal -# -# The tests for this method can be found in -# about_triangle_project.py -# and -# about_triangle_project_2.py -# -def triangle(a, b, c): - # DELETE 'PASS' AND WRITE THIS CODE - pass - - -# Error class used in part 2. No need to change this code. -class TriangleError(StandardError): - pass diff --git a/python2/libs/__init__.py b/python2/libs/__init__.py deleted file mode 100644 index 421eaef9f..000000000 --- a/python2/libs/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Dummy file to support python package hierarchy diff --git a/python2/libs/colorama/LICENSE-colorama b/python2/libs/colorama/LICENSE-colorama deleted file mode 100644 index b7464472e..000000000 --- a/python2/libs/colorama/LICENSE-colorama +++ /dev/null @@ -1,33 +0,0 @@ -Copyright (c) 2010 Jonathan Hartley - -Released under the New BSD license (reproduced below), or alternatively you may -use this software under any OSI approved open source license such as those at -http://opensource.org/licenses/alphabetical - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name(s) of the copyright holders, nor those of its contributors - may be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/python2/libs/colorama/__init__.py b/python2/libs/colorama/__init__.py deleted file mode 100644 index 2d127fa8e..000000000 --- a/python2/libs/colorama/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -from .initialise import init, deinit, reinit -from .ansi import Fore, Back, Style -from .ansitowin32 import AnsiToWin32 - -VERSION = '0.2.7' - diff --git a/python2/libs/colorama/ansi.py b/python2/libs/colorama/ansi.py deleted file mode 100644 index 5dfe374ce..000000000 --- a/python2/libs/colorama/ansi.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -''' -This module generates ANSI character codes to printing colors to terminals. -See: http://en.wikipedia.org/wiki/ANSI_escape_code -''' - -CSI = '\033[' - -def code_to_chars(code): - return CSI + str(code) + 'm' - -class AnsiCodes(object): - def __init__(self, codes): - for name in dir(codes): - if not name.startswith('_'): - value = getattr(codes, name) - setattr(self, name, code_to_chars(value)) - -class AnsiFore: - BLACK = 30 - RED = 31 - GREEN = 32 - YELLOW = 33 - BLUE = 34 - MAGENTA = 35 - CYAN = 36 - WHITE = 37 - RESET = 39 - -class AnsiBack: - BLACK = 40 - RED = 41 - GREEN = 42 - YELLOW = 43 - BLUE = 44 - MAGENTA = 45 - CYAN = 46 - WHITE = 47 - RESET = 49 - -class AnsiStyle: - BRIGHT = 1 - DIM = 2 - NORMAL = 22 - RESET_ALL = 0 - -Fore = AnsiCodes( AnsiFore ) -Back = AnsiCodes( AnsiBack ) -Style = AnsiCodes( AnsiStyle ) - diff --git a/python2/libs/colorama/ansitowin32.py b/python2/libs/colorama/ansitowin32.py deleted file mode 100644 index ea0a6c15f..000000000 --- a/python2/libs/colorama/ansitowin32.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -import re -import sys - -from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style -from .winterm import WinTerm, WinColor, WinStyle -from .win32 import windll - - -if windll is not None: - winterm = WinTerm() - - -def is_a_tty(stream): - return hasattr(stream, 'isatty') and stream.isatty() - - -class StreamWrapper(object): - ''' - Wraps a stream (such as stdout), acting as a transparent proxy for all - attribute access apart from method 'write()', which is delegated to our - Converter instance. - ''' - def __init__(self, wrapped, converter): - # double-underscore everything to prevent clashes with names of - # attributes on the wrapped stream object. - self.__wrapped = wrapped - self.__convertor = converter - - def __getattr__(self, name): - return getattr(self.__wrapped, name) - - def write(self, text): - self.__convertor.write(text) - - -class AnsiToWin32(object): - ''' - Implements a 'write()' method which, on Windows, will strip ANSI character - sequences from the text, and if outputting to a tty, will convert them into - win32 function calls. - ''' - ANSI_RE = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') - - def __init__(self, wrapped, convert=None, strip=None, autoreset=False): - # The wrapped stream (normally sys.stdout or sys.stderr) - self.wrapped = wrapped - - # should we reset colors to defaults after every .write() - self.autoreset = autoreset - - # create the proxy wrapping our output stream - self.stream = StreamWrapper(wrapped, self) - - on_windows = sys.platform.startswith('win') - - # should we strip ANSI sequences from our output? - if strip is None: - strip = on_windows - self.strip = strip - - # should we should convert ANSI sequences into win32 calls? - if convert is None: - convert = on_windows and is_a_tty(wrapped) - self.convert = convert - - # dict of ansi codes to win32 functions and parameters - self.win32_calls = self.get_win32_calls() - - # are we wrapping stderr? - self.on_stderr = self.wrapped is sys.stderr - - - def should_wrap(self): - ''' - True if this class is actually needed. If false, then the output - stream will not be affected, nor will win32 calls be issued, so - wrapping stdout is not actually required. This will generally be - False on non-Windows platforms, unless optional functionality like - autoreset has been requested using kwargs to init() - ''' - return self.convert or self.strip or self.autoreset - - - def get_win32_calls(self): - if self.convert and winterm: - return { - AnsiStyle.RESET_ALL: (winterm.reset_all, ), - AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), - AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), - AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), - AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), - AnsiFore.RED: (winterm.fore, WinColor.RED), - AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), - AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), - AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), - AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), - AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), - AnsiFore.WHITE: (winterm.fore, WinColor.GREY), - AnsiFore.RESET: (winterm.fore, ), - AnsiBack.BLACK: (winterm.back, WinColor.BLACK), - AnsiBack.RED: (winterm.back, WinColor.RED), - AnsiBack.GREEN: (winterm.back, WinColor.GREEN), - AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), - AnsiBack.BLUE: (winterm.back, WinColor.BLUE), - AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), - AnsiBack.CYAN: (winterm.back, WinColor.CYAN), - AnsiBack.WHITE: (winterm.back, WinColor.GREY), - AnsiBack.RESET: (winterm.back, ), - } - - - def write(self, text): - if self.strip or self.convert: - self.write_and_convert(text) - else: - self.wrapped.write(text) - self.wrapped.flush() - if self.autoreset: - self.reset_all() - - - def reset_all(self): - if self.convert: - self.call_win32('m', (0,)) - elif is_a_tty(self.wrapped): - self.wrapped.write(Style.RESET_ALL) - - - def write_and_convert(self, text): - ''' - Write the given text to our wrapped stream, stripping any ANSI - sequences from the text, and optionally converting them into win32 - calls. - ''' - cursor = 0 - for match in self.ANSI_RE.finditer(text): - start, end = match.span() - self.write_plain_text(text, cursor, start) - self.convert_ansi(*match.groups()) - cursor = end - self.write_plain_text(text, cursor, len(text)) - - - def write_plain_text(self, text, start, end): - if start < end: - self.wrapped.write(text[start:end]) - self.wrapped.flush() - - - def convert_ansi(self, paramstring, command): - if self.convert: - params = self.extract_params(paramstring) - self.call_win32(command, params) - - - def extract_params(self, paramstring): - def split(paramstring): - for p in paramstring.split(';'): - if p != '': - yield int(p) - return tuple(split(paramstring)) - - - def call_win32(self, command, params): - if params == []: - params = [0] - if command == 'm': - for param in params: - if param in self.win32_calls: - func_args = self.win32_calls[param] - func = func_args[0] - args = func_args[1:] - kwargs = dict(on_stderr=self.on_stderr) - func(*args, **kwargs) - elif command in ('H', 'f'): # set cursor position - func = winterm.set_cursor_position - func(params, on_stderr=self.on_stderr) - elif command in ('J'): - func = winterm.erase_data - func(params, on_stderr=self.on_stderr) - elif command == 'A': - if params == () or params == None: - num_rows = 1 - else: - num_rows = params[0] - func = winterm.cursor_up - func(num_rows, on_stderr=self.on_stderr) - diff --git a/python2/libs/colorama/initialise.py b/python2/libs/colorama/initialise.py deleted file mode 100644 index cba3676dd..000000000 --- a/python2/libs/colorama/initialise.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -import atexit -import sys - -from .ansitowin32 import AnsiToWin32 - - -orig_stdout = sys.stdout -orig_stderr = sys.stderr - -wrapped_stdout = sys.stdout -wrapped_stderr = sys.stderr - -atexit_done = False - - -def reset_all(): - AnsiToWin32(orig_stdout).reset_all() - - -def init(autoreset=False, convert=None, strip=None, wrap=True): - - if not wrap and any([autoreset, convert, strip]): - raise ValueError('wrap=False conflicts with any other arg=True') - - global wrapped_stdout, wrapped_stderr - sys.stdout = wrapped_stdout = \ - wrap_stream(orig_stdout, convert, strip, autoreset, wrap) - sys.stderr = wrapped_stderr = \ - wrap_stream(orig_stderr, convert, strip, autoreset, wrap) - - global atexit_done - if not atexit_done: - atexit.register(reset_all) - atexit_done = True - - -def deinit(): - sys.stdout = orig_stdout - sys.stderr = orig_stderr - - -def reinit(): - sys.stdout = wrapped_stdout - sys.stderr = wrapped_stdout - - -def wrap_stream(stream, convert, strip, autoreset, wrap): - if wrap: - wrapper = AnsiToWin32(stream, - convert=convert, strip=strip, autoreset=autoreset) - if wrapper.should_wrap(): - stream = wrapper.stream - return stream - - diff --git a/python2/libs/colorama/win32.py b/python2/libs/colorama/win32.py deleted file mode 100644 index f4024f95e..000000000 --- a/python2/libs/colorama/win32.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. - -# from winbase.h -STDOUT = -11 -STDERR = -12 - -try: - from ctypes import windll - from ctypes import wintypes -except ImportError: - windll = None - SetConsoleTextAttribute = lambda *_: None -else: - from ctypes import ( - byref, Structure, c_char, c_short, c_uint32, c_ushort, POINTER - ) - - class CONSOLE_SCREEN_BUFFER_INFO(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("dwSize", wintypes._COORD), - ("dwCursorPosition", wintypes._COORD), - ("wAttributes", wintypes.WORD), - ("srWindow", wintypes.SMALL_RECT), - ("dwMaximumWindowSize", wintypes._COORD), - ] - def __str__(self): - return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( - self.dwSize.Y, self.dwSize.X - , self.dwCursorPosition.Y, self.dwCursorPosition.X - , self.wAttributes - , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right - , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X - ) - - _GetStdHandle = windll.kernel32.GetStdHandle - _GetStdHandle.argtypes = [ - wintypes.DWORD, - ] - _GetStdHandle.restype = wintypes.HANDLE - - _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo - _GetConsoleScreenBufferInfo.argtypes = [ - wintypes.HANDLE, - POINTER(CONSOLE_SCREEN_BUFFER_INFO), - ] - _GetConsoleScreenBufferInfo.restype = wintypes.BOOL - - _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute - _SetConsoleTextAttribute.argtypes = [ - wintypes.HANDLE, - wintypes.WORD, - ] - _SetConsoleTextAttribute.restype = wintypes.BOOL - - _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition - _SetConsoleCursorPosition.argtypes = [ - wintypes.HANDLE, - wintypes._COORD, - ] - _SetConsoleCursorPosition.restype = wintypes.BOOL - - _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA - _FillConsoleOutputCharacterA.argtypes = [ - wintypes.HANDLE, - c_char, - wintypes.DWORD, - wintypes._COORD, - POINTER(wintypes.DWORD), - ] - _FillConsoleOutputCharacterA.restype = wintypes.BOOL - - _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute - _FillConsoleOutputAttribute.argtypes = [ - wintypes.HANDLE, - wintypes.WORD, - wintypes.DWORD, - wintypes._COORD, - POINTER(wintypes.DWORD), - ] - _FillConsoleOutputAttribute.restype = wintypes.BOOL - - handles = { - STDOUT: _GetStdHandle(STDOUT), - STDERR: _GetStdHandle(STDERR), - } - - def GetConsoleScreenBufferInfo(stream_id=STDOUT): - handle = handles[stream_id] - csbi = CONSOLE_SCREEN_BUFFER_INFO() - success = _GetConsoleScreenBufferInfo( - handle, byref(csbi)) - return csbi - - def SetConsoleTextAttribute(stream_id, attrs): - handle = handles[stream_id] - return _SetConsoleTextAttribute(handle, attrs) - - def SetConsoleCursorPosition(stream_id, position): - position = wintypes._COORD(*position) - # If the position is out of range, do nothing. - if position.Y <= 0 or position.X <= 0: - return - # Adjust for Windows' SetConsoleCursorPosition: - # 1. being 0-based, while ANSI is 1-based. - # 2. expecting (x,y), while ANSI uses (y,x). - adjusted_position = wintypes._COORD(position.Y - 1, position.X - 1) - # Adjust for viewport's scroll position - sr = GetConsoleScreenBufferInfo(STDOUT).srWindow - adjusted_position.Y += sr.Top - adjusted_position.X += sr.Left - # Resume normal processing - handle = handles[stream_id] - return _SetConsoleCursorPosition(handle, adjusted_position) - - def FillConsoleOutputCharacter(stream_id, char, length, start): - handle = handles[stream_id] - char = c_char(char) - length = wintypes.DWORD(length) - num_written = wintypes.DWORD(0) - # Note that this is hard-coded for ANSI (vs wide) bytes. - success = _FillConsoleOutputCharacterA( - handle, char, length, start, byref(num_written)) - return num_written.value - - def FillConsoleOutputAttribute(stream_id, attr, length, start): - ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' - handle = handles[stream_id] - attribute = wintypes.WORD(attr) - length = wintypes.DWORD(length) - num_written = wintypes.DWORD(0) - # Note that this is hard-coded for ANSI (vs wide) bytes. - return _FillConsoleOutputAttribute( - handle, attribute, length, start, byref(num_written)) diff --git a/python2/libs/colorama/winterm.py b/python2/libs/colorama/winterm.py deleted file mode 100644 index 270881154..000000000 --- a/python2/libs/colorama/winterm.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -from . import win32 - - -# from wincon.h -class WinColor(object): - BLACK = 0 - BLUE = 1 - GREEN = 2 - CYAN = 3 - RED = 4 - MAGENTA = 5 - YELLOW = 6 - GREY = 7 - -# from wincon.h -class WinStyle(object): - NORMAL = 0x00 # dim text, dim background - BRIGHT = 0x08 # bright text, dim background - - -class WinTerm(object): - - def __init__(self): - self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes - self.set_attrs(self._default) - self._default_fore = self._fore - self._default_back = self._back - self._default_style = self._style - - def get_attrs(self): - return self._fore + self._back * 16 + self._style - - def set_attrs(self, value): - self._fore = value & 7 - self._back = (value >> 4) & 7 - self._style = value & WinStyle.BRIGHT - - def reset_all(self, on_stderr=None): - self.set_attrs(self._default) - self.set_console(attrs=self._default) - - def fore(self, fore=None, on_stderr=False): - if fore is None: - fore = self._default_fore - self._fore = fore - self.set_console(on_stderr=on_stderr) - - def back(self, back=None, on_stderr=False): - if back is None: - back = self._default_back - self._back = back - self.set_console(on_stderr=on_stderr) - - def style(self, style=None, on_stderr=False): - if style is None: - style = self._default_style - self._style = style - self.set_console(on_stderr=on_stderr) - - def set_console(self, attrs=None, on_stderr=False): - if attrs is None: - attrs = self.get_attrs() - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - win32.SetConsoleTextAttribute(handle, attrs) - - def get_position(self, handle): - position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition - # Because Windows coordinates are 0-based, - # and win32.SetConsoleCursorPosition expects 1-based. - position.X += 1 - position.Y += 1 - return position - - def set_cursor_position(self, position=None, on_stderr=False): - if position is None: - #I'm not currently tracking the position, so there is no default. - #position = self.get_position() - return - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - win32.SetConsoleCursorPosition(handle, position) - - def cursor_up(self, num_rows=0, on_stderr=False): - if num_rows == 0: - return - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - position = self.get_position(handle) - adjusted_position = (position.Y - num_rows, position.X) - self.set_cursor_position(adjusted_position, on_stderr) - - def erase_data(self, mode=0, on_stderr=False): - # 0 (or None) should clear from the cursor to the end of the screen. - # 1 should clear from the cursor to the beginning of the screen. - # 2 should clear the entire screen. (And maybe move cursor to (1,1)?) - # - # At the moment, I only support mode 2. From looking at the API, it - # should be possible to calculate a different number of bytes to clear, - # and to do so relative to the cursor position. - if mode[0] not in (2,): - return - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - # here's where we'll home the cursor - coord_screen = win32.COORD(0,0) - csbi = win32.GetConsoleScreenBufferInfo(handle) - # get the number of character cells in the current buffer - dw_con_size = csbi.dwSize.X * csbi.dwSize.Y - # fill the entire screen with blanks - win32.FillConsoleOutputCharacter(handle, ' ', dw_con_size, coord_screen) - # now set the buffer's attributes accordingly - win32.FillConsoleOutputAttribute(handle, self.get_attrs(), dw_con_size, coord_screen ); - # put the cursor at (0, 0) - win32.SetConsoleCursorPosition(handle, (coord_screen.X, coord_screen.Y)) diff --git a/python2/libs/mock.py b/python2/libs/mock.py deleted file mode 100644 index 38c446db2..000000000 --- a/python2/libs/mock.py +++ /dev/null @@ -1,271 +0,0 @@ -# mock.py -# Test tools for mocking and patching. -# Copyright (C) 2007-2009 Michael Foord -# E-mail: fuzzyman AT voidspace DOT org DOT uk - -# mock 0.6.0 -# http://www.voidspace.org.uk/python/mock/ - -# Released subject to the BSD License -# Please see http://www.voidspace.org.uk/python/license.shtml - -# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml -# Comments, suggestions and bug reports welcome. - - -__all__ = ( - 'Mock', - 'patch', - 'patch_object', - 'sentinel', - 'DEFAULT' -) - -__version__ = '0.6.0 modified by Greg Malcolm' - -class SentinelObject(object): - def __init__(self, name): - self.name = name - - def __repr__(self): - return ''.format(self.name) - - -class Sentinel(object): - def __init__(self): - self._sentinels = {} - - def __getattr__(self, name): - return self._sentinels.setdefault(name, SentinelObject(name)) - - -sentinel = Sentinel() - -DEFAULT = sentinel.DEFAULT - -class OldStyleClass: - pass -ClassType = type(OldStyleClass) - -def _is_magic(name): - return '__{0!s}__'.format(name[2:-2]) == name - -def _copy(value): - if type(value) in (dict, list, tuple, set): - return type(value)(value) - return value - - -class Mock(object): - - def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, - name=None, parent=None, wraps=None): - self._parent = parent - self._name = name - if spec is not None and not isinstance(spec, list): - spec = [member for member in dir(spec) if not _is_magic(member)] - - self._methods = spec - self._children = {} - self._return_value = return_value - self.side_effect = side_effect - self._wraps = wraps - - self.reset_mock() - - - def reset_mock(self): - self.called = False - self.call_args = None - self.call_count = 0 - self.call_args_list = [] - self.method_calls = [] - for child in self._children.values(): - child.reset_mock() - if isinstance(self._return_value, Mock): - self._return_value.reset_mock() - - - def __get_return_value(self): - if self._return_value is DEFAULT: - self._return_value = Mock() - return self._return_value - - def __set_return_value(self, value): - self._return_value = value - - return_value = property(__get_return_value, __set_return_value) - - - def __call__(self, *args, **kwargs): - self.called = True - self.call_count += 1 - self.call_args = (args, kwargs) - self.call_args_list.append((args, kwargs)) - - parent = self._parent - name = self._name - while parent is not None: - parent.method_calls.append((name, args, kwargs)) - if parent._parent is None: - break - name = parent._name + '.' + name - parent = parent._parent - - ret_val = DEFAULT - if self.side_effect is not None: - if (isinstance(self.side_effect, Exception) or - isinstance(self.side_effect, (type, ClassType)) and - issubclass(self.side_effect, Exception)): - raise self.side_effect - - ret_val = self.side_effect(*args, **kwargs) - if ret_val is DEFAULT: - ret_val = self.return_value - - if self._wraps is not None and self._return_value is DEFAULT: - return self._wraps(*args, **kwargs) - if ret_val is DEFAULT: - ret_val = self.return_value - return ret_val - - - def __getattr__(self, name): - if self._methods is not None: - if name not in self._methods: - raise AttributeError("Mock object has no attribute '{0!s}'".format(name)) - elif _is_magic(name): - raise AttributeError(name) - - if name not in self._children: - wraps = None - if self._wraps is not None: - wraps = getattr(self._wraps, name) - self._children[name] = Mock(parent=self, name=name, wraps=wraps) - - return self._children[name] - - - def assert_called_with(self, *args, **kwargs): - assert self.call_args == (args, kwargs), 'Expected: {0!s}\nCalled with: {1!s}'.format((args, kwargs), self.call_args) - - -def _dot_lookup(thing, comp, import_path): - try: - return getattr(thing, comp) - except AttributeError: - __import__(import_path) - return getattr(thing, comp) - - -def _importer(target): - components = target.split('.') - import_path = components.pop(0) - thing = __import__(import_path) - - for comp in components: - import_path += ".{0!s}".format(comp) - thing = _dot_lookup(thing, comp, import_path) - return thing - - -class _patch(object): - def __init__(self, target, attribute, new, spec, create): - self.target = target - self.attribute = attribute - self.new = new - self.spec = spec - self.create = create - self.has_local = False - - - def __call__(self, func): - if hasattr(func, 'patchings'): - func.patchings.append(self) - return func - - def patched(*args, **keywargs): - # don't use a with here (backwards compatability with 2.5) - extra_args = [] - for patching in patched.patchings: - arg = patching.__enter__() - if patching.new is DEFAULT: - extra_args.append(arg) - args += tuple(extra_args) - try: - return func(*args, **keywargs) - finally: - for patching in getattr(patched, 'patchings', []): - patching.__exit__() - - patched.patchings = [self] - patched.__name__ = func.__name__ - patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno", - func.func_code.co_firstlineno) - return patched - - - def get_original(self): - target = self.target - name = self.attribute - create = self.create - - original = DEFAULT - if _has_local_attr(target, name): - try: - original = target.__dict__[name] - except AttributeError: - # for instances of classes with slots, they have no __dict__ - original = getattr(target, name) - elif not create and not hasattr(target, name): - raise AttributeError("{0!s} does not have the attribute {1!r}".format(target, name)) - return original - - - def __enter__(self): - new, spec, = self.new, self.spec - original = self.get_original() - if new is DEFAULT: - # XXXX what if original is DEFAULT - shouldn't use it as a spec - inherit = False - if spec == True: - # set spec to the object we are replacing - spec = original - if isinstance(spec, (type, ClassType)): - inherit = True - new = Mock(spec=spec) - if inherit: - new.return_value = Mock(spec=spec) - self.temp_original = original - setattr(self.target, self.attribute, new) - return new - - - def __exit__(self, *_): - if self.temp_original is not DEFAULT: - setattr(self.target, self.attribute, self.temp_original) - else: - delattr(self.target, self.attribute) - del self.temp_original - - -def patch_object(target, attribute, new=DEFAULT, spec=None, create=False): - return _patch(target, attribute, new, spec, create) - - -def patch(target, new=DEFAULT, spec=None, create=False): - try: - target, attribute = target.rsplit('.', 1) - except (TypeError, ValueError): - raise TypeError("Need a valid target to patch. You supplied: {0!r}".format(target,)) - target = _importer(target) - return _patch(target, attribute, new, spec, create) - - - -def _has_local_attr(obj, name): - try: - return name in vars(obj) - except TypeError: - # objects without a __dict__ - return hasattr(obj, name) diff --git a/python2/run.bat b/python2/run.bat deleted file mode 100755 index 40eaa792d..000000000 --- a/python2/run.bat +++ /dev/null @@ -1,45 +0,0 @@ -@echo off - -REM This is how you run it from the command line. -REM You don't actually need this script! -SET RUN_KOANS=python.exe -B contemplate_koans.py - -REM Set this to your python folder: -SET PYTHON_PATH=C:\Python27 - -set SCRIPT= - -:loop - -REM Hunt around for python -IF EXIST "python.exe" ( - SET SCRIPT=%RUN_KOANS% -) ELSE ( - IF EXIST "%PYTHON_PATH%" ( - SET SCRIPT=%PYTHON_PATH%\%RUN_KOANS% - ) ELSE ( - IF EXIST %PYTHON% SET SCRIPT=%PYTHON%\%RUN_KOANS% - ) -) - -IF NOT "" == "%SCRIPT%" ( - %SCRIPT% - pause -) ELSE ( - echo. - echo Python.exe is not in the path! - echo. - echo Fix the path and try again. - echo Or better yet, run this with the correct python path: - echo. - echo python.exe contemplate_koans.py - pause -) - -Set /p keepgoing="Test again? Y or N - " -if "%keepgoing%" == "y" ( - goto loop - ) - - -:end diff --git a/python2/run.sh b/python2/run.sh deleted file mode 100755 index 1fdcb7a99..000000000 --- a/python2/run.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -if [ -x /usr/bin/python2 ]; then - python2 -B contemplate_koans.py -else - python -B contemplate_koans.py -fi diff --git a/python2/runner/__init__.py b/python2/runner/__init__.py deleted file mode 100644 index 655c3567d..000000000 --- a/python2/runner/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Namespace: runner - diff --git a/python2/runner/helper.py b/python2/runner/helper.py deleted file mode 100644 index ccc4f8db1..000000000 --- a/python2/runner/helper.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -def cls_name(obj): - return obj.__class__.__name__ \ No newline at end of file diff --git a/python2/runner/koan.py b/python2/runner/koan.py deleted file mode 100644 index e9a0080bd..000000000 --- a/python2/runner/koan.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import unittest -import re - -# Starting a classname or attribute with an underscore normally implies Private scope. -# However, we are making an exception for __ and ___. - -__all__ = [ "__", "___", "____", "_____", "Koan" ] - -__ = "-=> FILL ME IN! <=-" - -class ___(Exception): - pass - -____ = "-=> TRUE OR FALSE? <=-" - -_____ = 0 - - -class Koan(unittest.TestCase): - def assertMatch(self, pattern, string, msg=None): - """ - Throw an exception if the regular expresson pattern is matched - """ - # Not part of unittest, but convenient for some koans tests - m = re.search(pattern, string) - if not m or not m.group(0): - raise self.failureException, \ - (msg or '{0!r} does not match {1!r}'.format(pattern, string)) - - def assertNoMatch(self, pattern, string, msg=None): - """ - Throw an exception if the regular expresson pattern is not matched - """ - m = re.search(pattern, string) - if m and m.group(0): - raise self.failureException, \ - (msg or '{0!r} matches {1!r}'.format(pattern, string)) diff --git a/python2/runner/mockable_test_result.py b/python2/runner/mockable_test_result.py deleted file mode 100644 index be1aca300..000000000 --- a/python2/runner/mockable_test_result.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import unittest - -# Needed to stop unittest.TestResult itself getting Mocked out of existence, -# which is a problem when testing the helper classes! (It confuses the runner) - -class MockableTestResult(unittest.TestResult): - pass \ No newline at end of file diff --git a/python2/runner/mountain.py b/python2/runner/mountain.py deleted file mode 100644 index 32bf364d4..000000000 --- a/python2/runner/mountain.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import unittest -import sys - -import path_to_enlightenment -from sensei import Sensei -from writeln_decorator import WritelnDecorator - - -class Mountain: - def __init__(self): - self.stream = WritelnDecorator(sys.stdout) - self.tests = path_to_enlightenment.koans() - self.lesson = Sensei(self.stream) - - def walk_the_path(self, args=None): - """Run the koans tests with a custom runner output.""" - - if args and len(args) >= 2: - args.pop(0) - test_names = ["koans." + test_name for test_name in args] - self.tests = unittest.TestLoader().loadTestsFromNames(test_names) - self.tests(self.lesson) - self.lesson.learn() - return self.lesson diff --git a/python2/runner/path_to_enlightenment.py b/python2/runner/path_to_enlightenment.py deleted file mode 100644 index b6c2fa55f..000000000 --- a/python2/runner/path_to_enlightenment.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -''' -Functions to load the test cases ("koans") that make up the -Path to Enlightenment. -''' - -import io -import unittest - - -# The path to enlightenment starts with the following: -KOANS_FILENAME = 'koans.txt' - - -def filter_koan_names(lines): - ''' - Strips leading and trailing whitespace, then filters out blank - lines and comment lines. - ''' - for line in lines: - line = line.strip() - if line.startswith('#'): - continue - if line: - yield line - return - - -def names_from_file(filename): - ''' - Opens the given ``filename`` and yields the fully-qualified names - of TestCases found inside (one per line). - ''' - with io.open(filename, 'rt', encoding='utf8') as names_file: - for name in filter_koan_names(names_file): - yield name - return - - -def koans_suite(names): - ''' - Returns a ``TestSuite`` loaded with all tests found in the given - ``names``, preserving the order in which they are found. - ''' - suite = unittest.TestSuite() - loader = unittest.TestLoader() - loader.sortTestMethodsUsing = None - for name in names: - tests = loader.loadTestsFromName(name) - suite.addTests(tests) - return suite - - -def koans(filename=KOANS_FILENAME): - ''' - Returns a ``TestSuite`` loaded with all the koans (``TestCase``s) - listed in ``filename``. - ''' - names = names_from_file(filename) - return koans_suite(names) diff --git a/python2/runner/runner_tests/__init__.py b/python2/runner/runner_tests/__init__.py deleted file mode 100644 index 16f619ae2..000000000 --- a/python2/runner/runner_tests/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Namespace: helpers_tests diff --git a/python2/runner/runner_tests/test_helper.py b/python2/runner/runner_tests/test_helper.py deleted file mode 100644 index fef9b6026..000000000 --- a/python2/runner/runner_tests/test_helper.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import unittest - -from runner import helper - -class TestHelper(unittest.TestCase): - - def test_that_get_class_name_works_with_a_string_instance(self): - self.assertEqual("str", helper.cls_name(str())) - - def test_that_get_class_name_works_with_a_4(self): - self.assertEquals("int", helper.cls_name(4)) - - def test_that_get_class_name_works_with_a_tuple(self): - self.assertEquals("tuple", helper.cls_name((3,"pie", []))) diff --git a/python2/runner/runner_tests/test_mountain.py b/python2/runner/runner_tests/test_mountain.py deleted file mode 100644 index 5736f49ac..000000000 --- a/python2/runner/runner_tests/test_mountain.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import unittest -from libs.mock import * - -from runner.mountain import Mountain - -class TestMountain(unittest.TestCase): - - def setUp(self): - self.mountain = Mountain() - - def test_it_gets_test_results(self): - with patch_object(self.mountain.stream, 'writeln', Mock()): - with patch_object(self.mountain.lesson, 'learn', Mock()): - self.mountain.walk_the_path() - self.assertTrue(self.mountain.lesson.learn.called) diff --git a/python2/runner/runner_tests/test_path_to_enlightenment.py b/python2/runner/runner_tests/test_path_to_enlightenment.py deleted file mode 100644 index 25bff45e1..000000000 --- a/python2/runner/runner_tests/test_path_to_enlightenment.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import io -import unittest - -from runner import path_to_enlightenment as pte - - -class TestFilterKoanNames(unittest.TestCase): - - def test_empty_input_produces_empty_output(self): - infile = io.StringIO(u'') - expected = [] - received = list(pte.filter_koan_names(infile)) - self.assertListEqual(expected, received) - return - - def test_names_yielded_match_names_in_file(self): - names = [ - u'this.is.a.test', - u'this.is.only.a.test', - ] - infile = io.StringIO(u'\n'.join(names)) - received = list(pte.filter_koan_names(infile)) - self.assertListEqual(names, received) - return - - def test_whitespace_is_stripped(self): - names = [ - u'this.is.a.test', - u' white.space.should.be.stripped', - u'this.is.only.a.test', - u'white.space.should.be.stripped ', - ] - infile = io.StringIO(u'\n'.join(names)) - expected = [ - u'this.is.a.test', - u'white.space.should.be.stripped', - u'this.is.only.a.test', - u'white.space.should.be.stripped', - ] - received = list(pte.filter_koan_names(infile)) - self.assertListEqual(expected, received) - return - - def test_commented_out_names_are_excluded(self): - names = [ - u'this.is.a.test', - u'#this.is.a.comment', - u'this.is.only.a.test', - u' # this.is.also a.comment ', - ] - infile = io.StringIO(u'\n'.join(names)) - expected = [ - u'this.is.a.test', - u'this.is.only.a.test', - ] - received = list(pte.filter_koan_names(infile)) - self.assertListEqual(expected, received) - return - - def all_blank_or_comment_lines_produce_empty_output(self): - names = [ - u' ', - u'# This is a comment.', - u'\t', - u' # This is also a comment.', - ] - infile = io.StringIO(u'\n'.join(names)) - expected = [] - received = list(pte.filter_koan_names(infile)) - self.assertListEqual(expected, received) - return - - -class TestKoansSuite(unittest.TestCase): - - def test_empty_input_produces_empty_testsuite(self): - names = [] - suite = pte.koans_suite(names) - self.assertIsInstance(suite, unittest.TestSuite) - expected = [] - received = list(suite) - self.assertListEqual(expected, received) - return - - def test_testcase_names_appear_in_testsuite(self): - names = [ - 'koans.about_asserts.AboutAsserts', - 'koans.about_none.AboutNone', - 'koans.about_strings.AboutStrings', - ] - suite = pte.koans_suite(names) - self.assertIsInstance(suite, unittest.TestSuite) - expected = [ - 'AboutAsserts', - 'AboutNone', - 'AboutStrings', - ] - received = sorted(set(test.__class__.__name__ for test in suite)) - self.assertListEqual(expected, received) - return diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py deleted file mode 100644 index c4cb03f8b..000000000 --- a/python2/runner/runner_tests/test_sensei.py +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import unittest -import re - -from libs.mock import * - -from runner.sensei import Sensei -from runner.writeln_decorator import WritelnDecorator -from runner.mockable_test_result import MockableTestResult - -class AboutParrots: - pass -class AboutLumberjacks: - pass -class AboutTennis: - pass -class AboutTheKnightsWhoSayNi: - pass -class AboutMrGumby: - pass -class AboutMessiahs: - pass -class AboutGiantFeet: - pass -class AboutTrebuchets: - pass -class AboutFreemasons: - pass - -error_assertion_with_message = """Traceback (most recent call last): - File "/Users/Greg/hg/python_koans/koans/about_exploding_trousers.py", line 43, in test_durability - self.assertEqual("Steel","Lard", "Another fine mess you've got me into Stanley...") -AssertionError: Another fine mess you've got me into Stanley...""" - -error_assertion_equals = """ - -Traceback (most recent call last): - File "/Users/Greg/hg/python_koans/koans/about_exploding_trousers.py", line 49, in test_math - self.assertEqual(4,99) -AssertionError: 4 != 99 -""" - -error_assertion_true = """Traceback (most recent call last): - File "/Users/Greg/hg/python_koans/koans/about_armories.py", line 25, in test_weoponary - self.assertTrue("Pen" > "Sword") -AssertionError - -""" - -error_mess = """ -Traceback (most recent call last): - File "contemplate_koans.py", line 5, in - from runner.mountain import Mountain - File "/Users/Greg/hg/python_koans/runner/mountain.py", line 7, in - import path_to_enlightenment - File "/Users/Greg/hg/python_koans/runner/path_to_enlightenment.py", line 8, in - from koans import * - File "/Users/Greg/hg/python_koans/koans/about_asserts.py", line 20 - self.assertTrue(eoe"Pen" > "Sword", "nhnth") - ^ -SyntaxError: invalid syntax""" - -error_with_list = """Traceback (most recent call last): - File "/Users/Greg/hg/python_koans/koans/about_armories.py", line 84, in test_weoponary - self.assertEqual([1, 9], [1, 2]) -AssertionError: Lists differ: [1, 9] != [1, 2] - -First differing element 1: -9 -2 - -- [1, 9] -? ^ - -+ [1, 2] -? ^ - -""" - - -class TestSensei(unittest.TestCase): - - def setUp(self): - self.sensei = Sensei(WritelnDecorator(Mock())) - - def test_that_failures_are_handled_in_the_base_class(self): - with patch('runner.mockable_test_result.MockableTestResult.addFailure', Mock()): - self.sensei.addFailure(Mock(), Mock()) - self.assertTrue(MockableTestResult.addFailure.called) - - def test_that_it_successes_only_count_if_passes_are_currently_allowed(self): - with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()): - self.sensei.passesCount = Mock() - self.sensei.addSuccess(Mock()) - self.assertTrue(self.sensei.passesCount.called) - - def test_that_it_passes_on_add_successes_message(self): - with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()): - self.sensei.addSuccess(Mock()) - self.assertTrue(MockableTestResult.addSuccess.called) - - def test_that_it_increases_the_passes_on_every_success(self): - with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()): - pass_count = self.sensei.pass_count - self.sensei.addSuccess(Mock()) - self.assertEqual(pass_count + 1, self.sensei.pass_count) - - def test_that_nothing_is_returned_as_a_first_result_if_there_are_no_failures(self): - self.sensei.failures = [] - self.assertEqual(None, self.sensei.firstFailure()) - - def test_that_nothing_is_returned_as_sorted_result_if_there_are_no_failures(self): - self.sensei.failures = [] - self.assertEqual(None, self.sensei.sortFailures("AboutLife")) - - def test_that_nothing_is_returned_as_sorted_result_if_there_are_no_relevent_failures(self): - self.sensei.failures = [ - (AboutTheKnightsWhoSayNi(),"File 'about_the_knights_whn_say_ni.py', line 24"), - (AboutMessiahs(),"File 'about_messiahs.py', line 43"), - (AboutMessiahs(),"File 'about_messiahs.py', line 844") - ] - self.assertEqual(None, self.sensei.sortFailures("AboutLife")) - - def test_that_nothing_is_returned_as_sorted_result_if_there_are_3_shuffled_results(self): - self.sensei.failures = [ - (AboutTennis(),"File 'about_tennis.py', line 299"), - (AboutTheKnightsWhoSayNi(),"File 'about_the_knights_whn_say_ni.py', line 24"), - (AboutTennis(),"File 'about_tennis.py', line 30"), - (AboutMessiahs(),"File 'about_messiahs.py', line 43"), - (AboutTennis(),"File 'about_tennis.py', line 2"), - (AboutMrGumby(),"File 'about_mr_gumby.py', line odd"), - (AboutMessiahs(),"File 'about_messiahs.py', line 844") - ] - - results = self.sensei.sortFailures("AboutTennis") - self.assertEqual(3, len(results)) - self.assertEqual(2, results[0][0]) - self.assertEqual(30, results[1][0]) - self.assertEqual(299, results[2][0]) - - def test_that_it_will_choose_not_find_anything_with_non_standard_error_trace_string(self): - self.sensei.failures = [ - (AboutMrGumby(),"File 'about_mr_gumby.py', line MISSING"), - ] - self.assertEqual(None, self.sensei.sortFailures("AboutMrGumby")) - - - def test_that_it_will_choose_correct_first_result_with_lines_9_and_27(self): - self.sensei.failures = [ - (AboutTrebuchets(),"File 'about_trebuchets.py', line 27"), - (AboutTrebuchets(),"File 'about_trebuchets.py', line 9"), - (AboutTrebuchets(),"File 'about_trebuchets.py', line 73v") - ] - self.assertEqual("File 'about_trebuchets.py', line 9", self.sensei.firstFailure()[1]) - - def test_that_it_will_choose_correct_first_result_with_multiline_test_classes(self): - self.sensei.failures = [ - (AboutGiantFeet(),"File 'about_giant_feet.py', line 999"), - (AboutGiantFeet(),"File 'about_giant_feet.py', line 44"), - (AboutFreemasons(),"File 'about_freemasons.py', line 1"), - (AboutFreemasons(),"File 'about_freemasons.py', line 11") - ] - self.assertEqual("File 'about_giant_feet.py', line 44", self.sensei.firstFailure()[1]) - - def test_that_error_report_features_the_assertion_error(self): - self.sensei.scrapeAssertionError = Mock() - self.sensei.firstFailure = Mock() - self.sensei.firstFailure.return_value = (Mock(), "FAILED") - self.sensei.errorReport() - self.assertTrue(self.sensei.scrapeAssertionError.called) - - def test_that_error_report_features_a_stack_dump(self): - self.sensei.scrapeInterestingStackDump = Mock() - self.sensei.firstFailure = Mock() - self.sensei.firstFailure.return_value = (Mock(), "FAILED") - self.sensei.errorReport() - self.assertTrue(self.sensei.scrapeInterestingStackDump.called) - - def test_that_scraping_the_assertion_error_with_nothing_gives_you_a_blank_back(self): - self.assertEqual("", self.sensei.scrapeAssertionError(None)) - - def test_that_scraping_the_assertion_error_with_messaged_assert(self): - self.assertEqual(" AssertionError: Another fine mess you've got me into Stanley...", - self.sensei.scrapeAssertionError(error_assertion_with_message)) - - def test_that_scraping_the_assertion_error_with_assert_equals(self): - self.assertEqual(" AssertionError: 4 != 99", - self.sensei.scrapeAssertionError(error_assertion_equals)) - - def test_that_scraping_the_assertion_error_with_assert_true(self): - self.assertEqual(" AssertionError", - self.sensei.scrapeAssertionError(error_assertion_true)) - - def test_that_scraping_the_assertion_error_with_syntax_error(self): - self.assertEqual(" SyntaxError: invalid syntax", - self.sensei.scrapeAssertionError(error_mess)) - - def test_that_scraping_the_assertion_error_with_list_error(self): - self.assertEqual(""" AssertionError: Lists differ: [1, 9] != [1, 2] - - First differing element 1: - 9 - 2 - - - [1, 9] - ? ^ - - + [1, 2] - ? ^""", - self.sensei.scrapeAssertionError(error_with_list)) - - def test_that_scraping_a_non_existent_stack_dump_gives_you_nothing(self): - self.assertEqual("", self.sensei.scrapeInterestingStackDump(None)) - - def test_that_if_there_are_no_failures_say_the_final_zenlike_remark(self): - self.sensei.failures = None - words = self.sensei.say_something_zenlike() - - m = re.search("Spanish Inquisition", words) - self.assertTrue(m and m.group(0)) - - def test_that_if_there_are_0_successes_it_will_say_the_first_zen_of_python_koans(self): - self.sensei.pass_count = 0 - self.sensei.failures = Mock() - words = self.sensei.say_something_zenlike() - m = re.search("Beautiful is better than ugly", words) - self.assertTrue(m and m.group(0)) - - def test_that_if_there_is_1_success_it_will_say_the_second_zen_of_python_koans(self): - self.sensei.pass_count = 1 - self.sensei.failures = Mock() - words = self.sensei.say_something_zenlike() - m = re.search("Explicit is better than implicit", words) - self.assertTrue(m and m.group(0)) - - def test_that_if_there_are_10_successes_it_will_say_the_sixth_zen_of_python_koans(self): - self.sensei.pass_count = 10 - self.sensei.failures = Mock() - words = self.sensei.say_something_zenlike() - m = re.search("Sparse is better than dense", words) - self.assertTrue(m and m.group(0)) - - def test_that_if_there_are_36_successes_it_will_say_the_final_zen_of_python_koans(self): - self.sensei.failures = Mock() - self.sensei.pass_count = 36 - words = self.sensei.say_something_zenlike() - m = re.search("Namespaces are one honking great idea", words) - self.assertTrue(m and m.group(0)) - - def test_that_if_there_are_37_successes_it_will_say_the_first_zen_of_python_koans_again(self): - self.sensei.pass_count = 37 - self.sensei.failures = Mock() - words = self.sensei.say_something_zenlike() - m = re.search("Beautiful is better than ugly", words) - self.assertTrue(m and m.group(0)) - - def test_that_total_lessons_return_7_if_there_are_7_lessons(self): - self.sensei.filter_all_lessons = Mock() - self.sensei.filter_all_lessons.return_value = [1,2,3,4,5,6,7] - self.assertEqual(7, self.sensei.total_lessons()) - - def test_that_total_lessons_return_0_if_all_lessons_is_none(self): - self.sensei.filter_all_lessons = Mock() - self.sensei.filter_all_lessons.return_value = None - self.assertEqual(0, self.sensei.total_lessons()) - - def test_total_koans_return_43_if_there_are_43_test_cases(self): - self.sensei.tests.countTestCases = Mock() - self.sensei.tests.countTestCases.return_value = 43 - self.assertEqual(43, self.sensei.total_koans()) - - def test_filter_all_lessons_will_discover_test_classes_if_none_have_been_discovered_yet(self): - self.sensei.all_lessons = 0 - self.assertTrue(len(self.sensei.filter_all_lessons()) > 10) - self.assertTrue(len(self.sensei.all_lessons) > 10) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py deleted file mode 100644 index e598626a3..000000000 --- a/python2/runner/sensei.py +++ /dev/null @@ -1,269 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import unittest -import re -import sys -import os -import glob - -import helper -from mockable_test_result import MockableTestResult -from runner import path_to_enlightenment - -from libs.colorama import init, Fore, Style -init() # init colorama - -class Sensei(MockableTestResult): - def __init__(self, stream): - unittest.TestResult.__init__(self) - self.stream = stream - self.prevTestClassName = None - self.tests = path_to_enlightenment.koans() - self.pass_count = 0 - self.lesson_pass_count = 0 - self.all_lessons = None - - def startTest(self, test): - MockableTestResult.startTest(self, test) - - if helper.cls_name(test) != self.prevTestClassName: - self.prevTestClassName = helper.cls_name(test) - if not self.failures: - self.stream.writeln() - self.stream.writeln("{0}{1}Thinking {2}".format( - Fore.RESET, Style.NORMAL, helper.cls_name(test))) - if helper.cls_name(test) not in ['AboutAsserts', 'AboutExtraCredit']: - self.lesson_pass_count += 1 - - def addSuccess(self, test): - if self.passesCount(): - MockableTestResult.addSuccess(self, test) - self.stream.writeln( \ - " {0}{1}{2} has expanded your awareness.{3}{4}" \ - .format(Fore.GREEN, Style.BRIGHT, test._testMethodName, \ - Fore.RESET, Style.NORMAL)) - self.pass_count += 1 - - def addError(self, test, err): - # Having 1 list for errors and 1 list for failures would mess with - # the error sequence - self.addFailure(test, err) - - def passesCount(self): - return not (self.failures and helper.cls_name(self.failures[0][0]) != - self.prevTestClassName) - - def addFailure(self, test, err): - MockableTestResult.addFailure(self, test, err) - - def sortFailures(self, testClassName): - table = list() - for test, err in self.failures: - if helper.cls_name(test) == testClassName: - m = re.search("(?<= line )\d+" ,err) - if m: - tup = (int(m.group(0)), test, err) - table.append(tup) - - if table: - return sorted(table) - else: - return None - - def firstFailure(self): - if not self.failures: return None - - table = self.sortFailures(helper.cls_name(self.failures[0][0])) - - if table: - return (table[0][1], table[0][2]) - else: - return None - - def learn(self): - self.errorReport() - - self.stream.writeln("") - self.stream.writeln("") - self.stream.writeln(self.report_progress()) - if self.failures: - self.stream.writeln(self.report_remaining()) - self.stream.writeln("") - self.stream.writeln(self.say_something_zenlike()) - - if self.failures: sys.exit(-1) - self.stream.writeln( - "\n{0}**************************************************" \ - .format(Fore.RESET)) - self.stream.writeln("\n{0}That was the last one, well done!" \ - .format(Fore.MAGENTA)) - self.stream.writeln( - "\nIf you want more, take a look at about_extra_credit.py") - - def errorReport(self): - problem = self.firstFailure() - if not problem: return - test, err = problem - self.stream.writeln(" {0}{1}{2} has damaged your " - "karma.".format(Fore.RED, Style.BRIGHT, test._testMethodName)) - - self.stream.writeln("\n{0}{1}You have not yet reached enlightenment ..." \ - .format(Fore.RESET, Style.NORMAL)) - self.stream.writeln("{0}{1}{2}".format(Fore.RED, \ - Style.BRIGHT, self.scrapeAssertionError(err))) - self.stream.writeln("") - self.stream.writeln("{0}{1}Please meditate on the following code:" \ - .format(Fore.RESET, Style.NORMAL)) - self.stream.writeln("{0}{1}{2}{3}{4}".format(Fore.YELLOW, Style.BRIGHT, \ - self.scrapeInterestingStackDump(err), Fore.RESET, Style.NORMAL)) - - def scrapeAssertionError(self, err): - if not err: return "" - - error_text = "" - count = 0 - for line in err.splitlines(): - m = re.search("^[^^ ].*$",line) - if m and m.group(0): - count+=1 - - if count>1: - error_text += (" " + line.strip()).rstrip() + '\n' - return error_text.strip('\n') - - def scrapeInterestingStackDump(self, err): - if not err: - return "" - - lines = err.splitlines() - - sep = '@@@@@SEP@@@@@' - - stack_text = "" - for line in lines: - m = re.search("^ File .*$",line) - if m and m.group(0): - stack_text += '\n' + line - - m = re.search("^ \w(\w)+.*$",line) - if m and m.group(0): - stack_text += sep + line - - lines = stack_text.splitlines() - - stack_text = "" - for line in lines: - m = re.search("^.*[/\\\\]koans[/\\\\].*$",line) - if m and m.group(0): - stack_text += line + '\n' - - - stack_text = stack_text.replace(sep, '\n').strip('\n') - stack_text = re.sub(r'(about_\w+.py)', - r"{0}\1{1}".format(Fore.BLUE, Fore.YELLOW), stack_text) - stack_text = re.sub(r'(line \d+)', - r"{0}\1{1}".format(Fore.BLUE, Fore.YELLOW), stack_text) - return stack_text - - def report_progress(self): - return "You have completed {0} ({2} %) koans and " \ - "{1} (out of {3}) lessons.".format( - self.pass_count, - self.lesson_pass_count, - self.pass_count*100/self.total_koans(), - self.total_lessons()) - - def report_remaining(self): - koans_remaining = self.total_koans() - self.pass_count - lessons_remaining = self.total_lessons() - self.lesson_pass_count - - return "You are now {0} koans and {1} lessons away from " \ - "reaching enlightenment.".format( - koans_remaining, - lessons_remaining) - - # Hat's tip to Tim Peters for the zen statements from The 'Zen - # of Python' (http://www.python.org/dev/peps/pep-0020/) - # - # Also a hat's tip to Ara T. Howard for the zen statements from his - # metakoans Ruby Quiz (http://rubyquiz.com/quiz67.html) and - # Edgecase's later permutation in the Ruby Koans - def say_something_zenlike(self): - if self.failures: - turn = self.pass_count % 37 - - zenness = ""; - if turn == 0: - zenness = "Beautiful is better than ugly." - elif turn == 1 or turn == 2: - zenness = "Explicit is better than implicit." - elif turn == 3 or turn == 4: - zenness = "Simple is better than complex." - elif turn == 5 or turn == 6: - zenness = "Complex is better than complicated." - elif turn == 7 or turn == 8: - zenness = "Flat is better than nested." - elif turn == 9 or turn == 10: - zenness = "Sparse is better than dense." - elif turn == 11 or turn == 12: - zenness = "Readability counts." - elif turn == 13 or turn == 14: - zenness = "Special cases aren't special enough to " \ - "break the rules." - elif turn == 15 or turn == 16: - zenness = "Although practicality beats purity." - elif turn == 17 or turn == 18: - zenness = "Errors should never pass silently." - elif turn == 19 or turn == 20: - zenness = "Unless explicitly silenced." - elif turn == 21 or turn == 22: - zenness = "In the face of ambiguity, refuse the " \ - "temptation to guess." - elif turn == 23 or turn == 24: - zenness = "There should be one-- and preferably only " \ - "one --obvious way to do it." - elif turn == 25 or turn == 26: - zenness = "Although that way may not be obvious at " \ - "first unless you're Dutch." - elif turn == 27 or turn == 28: - zenness = "Now is better than never." - elif turn == 29 or turn == 30: - zenness = "Although never is often better than right " \ - "now." - elif turn == 31 or turn == 32: - zenness = "If the implementation is hard to explain, " \ - "it's a bad idea." - elif turn == 33 or turn == 34: - zenness = "If the implementation is easy to explain, " \ - "it may be a good idea." - else: - zenness = "Namespaces are one honking great idea -- " \ - "let's do more of those!" - return "{0}{1}{2}{3}".format(Fore.CYAN, zenness, Fore.RESET, Style.NORMAL); - else: - return "{0}Nobody ever expects the Spanish Inquisition." \ - .format(Fore.CYAN) - - # Hopefully this will never ever happen! - return "The temple is collapsing! Run!!!" - - def total_lessons(self): - all_lessons = self.filter_all_lessons() - - if all_lessons: - return len(all_lessons) - else: - return 0 - - def total_koans(self): - return self.tests.countTestCases() - - def filter_all_lessons(self): - cur_dir = os.path.split(os.path.realpath(__file__))[0] - if not self.all_lessons: - self.all_lessons = glob.glob('{0}/../koans/about*.py'.format(cur_dir)) - self.all_lessons = filter(lambda filename: - "about_extra_credit" not in filename, - self.all_lessons) - return self.all_lessons diff --git a/python2/runner/writeln_decorator.py b/python2/runner/writeln_decorator.py deleted file mode 100644 index ba19ecb62..000000000 --- a/python2/runner/writeln_decorator.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - - -# Taken from legacy python unittest -class WritelnDecorator: - """Used to decorate file-like objects with a handy 'writeln' method""" - def __init__(self, stream): - self.stream = stream - - def __getattr__(self, attr): - return getattr(self.stream,attr) - - def writeln(self, arg=None): - if arg: - self.write(arg) - self.write('\n') # text-mode streams translate to \r\n if needed - diff --git a/python2/scent.py b/python2/scent.py deleted file mode 100644 index bba14fbd9..000000000 --- a/python2/scent.py +++ /dev/null @@ -1,12 +0,0 @@ -from sniffer.api import * -import os - -watch_paths = ['.', 'koans/'] - -@file_validator -def py_files(filename): - return filename.endswith('.py') and not os.path.basename(filename).startswith('.') - -@runnable -def execute_koans(*args): - os.system('python -B contemplate_koans.py') From 8e2023e7002fc7d7a94f49fb8d4255664156fdd4 Mon Sep 17 00:00:00 2001 From: Pranav Salunke Date: Thu, 4 Mar 2021 11:40:45 +0530 Subject: [PATCH 59/91] Updates the comments section --- python3/koans/about_scoring_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/koans/about_scoring_project.py b/python3/koans/about_scoring_project.py index 2bd06c418..0fd055de2 100644 --- a/python3/koans/about_scoring_project.py +++ b/python3/koans/about_scoring_project.py @@ -4,7 +4,7 @@ from runner.koan import * # Greed is a dice game where you roll up to five dice to accumulate -# points. The following "score" function will be used calculate the +# points. The following "score" function will be used to calculate the # score of a single roll of the dice. # # A greed roll is scored as follows: @@ -69,4 +69,4 @@ def test_score_of_mixed_is_sum(self): def test_ones_not_left_out(self): self.assertEqual(300, score([1,2,2,2])) - self.assertEqual(350, score([1,5,2,2,2])) \ No newline at end of file + self.assertEqual(350, score([1,5,2,2,2])) From f56b91bc3baf3bc66d674bc954fad6b2a25992b6 Mon Sep 17 00:00:00 2001 From: Greg Date: Thu, 4 Mar 2021 18:30:02 -0500 Subject: [PATCH 60/91] Slight alteration to @chuaarons's PR: #166 to keep things simple --- README.rst | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index 9424f9756..d97125664 100644 --- a/README.rst +++ b/README.rst @@ -145,15 +145,11 @@ On Linux:: On Windows:: $ pip install pywin32 + + Also available here: -(If that failed, try:: - - $ pip install pypiwin32 - - then grab a proper version of pypiwin32 installer and install it:: - https://github.com/mhammond/pywin32/releases -) + On Mac OS X:: From 3d35ccca7e11c52f8b4566ae225fb9b639d73ccb Mon Sep 17 00:00:00 2001 From: jimmy878787 <68321354+jimmy878787@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:36:09 -0700 Subject: [PATCH 61/91] Update MIT-LICENSE --- MIT-LICENSE | 1 + 1 file changed, 1 insertion(+) diff --git a/MIT-LICENSE b/MIT-LICENSE index e3b0a3575..627695235 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,3 +1,4 @@ +use latest version now is 2020 Copyright (c) 2010-2018 Greg Malcolm and The Status Is Not Quo Permission is hereby granted, free of charge, to any person From 5687ddd90dd8e5b4a74e8e0982ebd6611e3cbbab Mon Sep 17 00:00:00 2001 From: jimmy878787 <68321354+jimmy878787@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:37:59 -0700 Subject: [PATCH 62/91] Update Contributor Notes.txt --- Contributor Notes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Contributor Notes.txt b/Contributor Notes.txt index b97fc6aea..ded1b7001 100644 --- a/Contributor Notes.txt +++ b/Contributor Notes.txt @@ -1,4 +1,4 @@ - +all things you need to update Testing a specific koan =================================== From 1cf806dce84277f45ad5bec885f1f60615679fed Mon Sep 17 00:00:00 2001 From: jimmy878787 <68321354+jimmy878787@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:39:22 -0700 Subject: [PATCH 63/91] Update Contributor Notes.txt --- Contributor Notes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Contributor Notes.txt b/Contributor Notes.txt index ded1b7001..03e3512a9 100644 --- a/Contributor Notes.txt +++ b/Contributor Notes.txt @@ -1,4 +1,4 @@ -all things you need to update +all things you need to update at notes Testing a specific koan =================================== From b4a2f9d709e191fb062e7b1db315f8acf34e8a09 Mon Sep 17 00:00:00 2001 From: jimmy878787 <68321354+jimmy878787@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:41:21 -0700 Subject: [PATCH 64/91] Update README.rst --- README.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/README.rst b/README.rst index 2c7ce5644..9fa4110e3 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,4 @@ +use the latest one ============ Python Koans ============ From 8474efd9f6a7f7e70970fff27ec4e226a983161e Mon Sep 17 00:00:00 2001 From: jimmy878787 <68321354+jimmy878787@users.noreply.github.com> Date: Thu, 1 Oct 2020 09:44:49 -0700 Subject: [PATCH 65/91] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e49fbf9c6..57b33f037 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +latest versioin of python use language: python python: From 01a65bbdda4a7b4d439e165f10ba61a238e8a7ce Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Thu, 4 Mar 2021 20:05:09 -0500 Subject: [PATCH 66/91] Took the hint and updated some versions --- .travis.yml | 6 +----- Contributor Notes.txt | 5 +---- MIT-LICENSE | 36 ++++++++++++++++-------------------- README.rst | 1 - 4 files changed, 18 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index 57b33f037..4ae0f9184 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,7 @@ -latest versioin of python use language: python python: - - 3.2 - - 3.3 - - 3.4 - - 3.5 + - 3.9 script: - PYTHON_VER=`python -c 'import sys; print(sys.version_info[0])'` diff --git a/Contributor Notes.txt b/Contributor Notes.txt index 03e3512a9..c14bb947a 100644 --- a/Contributor Notes.txt +++ b/Contributor Notes.txt @@ -1,4 +1,3 @@ -all things you need to update at notes Testing a specific koan =================================== @@ -6,10 +5,8 @@ This will help when adding/modifying koans Running a whole test case: - $ python contemplate_koans.py about_strings - or $ python3 contemplate_koans.py about_strings Running a single test: - $ python contemplate_koans.py about_strings.AboutStrings.test_triple_quoted_strings_need_less_escaping + $ python3 contemplate_koans.py about_strings.AboutStrings.test_triple_quoted_strings_need_less_escaping diff --git a/MIT-LICENSE b/MIT-LICENSE index 627695235..5e57f89fd 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,23 +1,19 @@ -use latest version now is 2020 -Copyright (c) 2010-2018 Greg Malcolm and The Status Is Not Quo +Copyright 2021 Greg Malcolm and The Status Is Not Quo -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.rst b/README.rst index 9fa4110e3..2c7ce5644 100644 --- a/README.rst +++ b/README.rst @@ -1,4 +1,3 @@ -use the latest one ============ Python Koans ============ From 3d677f6f438f072093a81e4f86997ae7574faf96 Mon Sep 17 00:00:00 2001 From: Scott Longley Date: Fri, 12 Feb 2021 10:29:36 -0500 Subject: [PATCH 67/91] documented python version should match what's in python3/contemplate_koans.py --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2c7ce5644..74352bee0 100644 --- a/README.rst +++ b/README.rst @@ -53,7 +53,7 @@ need to install the Python interpreter. At this time of writing, there are two versions of the Python Koans: * one for use with Python 2.7 (earlier versions are no longer supported) -* one for Python 3.1+ +* one for Python 3.3+ You should be able to work with newer Python versions, but older ones will likely give you problems. From fcb73fc36145d130c804cc992c96ebbc36868136 Mon Sep 17 00:00:00 2001 From: Scott Longley Date: Wed, 17 Feb 2021 20:50:01 -0500 Subject: [PATCH 68/91] travis probably doesn't need to test pre 3.3 either --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index e49fbf9c6..d8eba4299 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,11 @@ language: python python: +<<<<<<< HEAD - 3.2 +======= + - 2.7 +>>>>>>> travis probably doesn't need to test pre 3.3 either - 3.3 - 3.4 - 3.5 From 70cf31f8f0056a46177a5937987c71cb40585dc0 Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Thu, 4 Mar 2021 20:38:13 -0500 Subject: [PATCH 69/91] Updated the notes to reject that we support latest python3 --- README.rst | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 74352bee0..5f5f9a216 100644 --- a/README.rst +++ b/README.rst @@ -50,10 +50,8 @@ Installing Python Koans Aside from downloading or checking out the latest version of Python Koans, you need to install the Python interpreter. -At this time of writing, there are two versions of the Python Koans: - -* one for use with Python 2.7 (earlier versions are no longer supported) -* one for Python 3.3+ +At this time of writing, we support Python3. The policy is to try to keep +current with the latest production version. You should be able to work with newer Python versions, but older ones will likely give you problems. @@ -63,10 +61,8 @@ You can download Python from here: http://www.python.org/download After installing Python make sure the folder containing the python executable -is in the system path. In other words, you need to be able to run -Python from a command console. With Python 2 it will be called `python` -or `python.exe` depending on the operating system. For Python 3 it will either -be `python3` or for windows it will be `python.exe`. +is in the system path. In other words, you need to be able to run Python from a +command console. It will either be `python3` or for windows it will be `python.exe`. If you have problems, this may help: @@ -75,7 +71,7 @@ If you have problems, this may help: Windows users may also want to update the line in the batch file `run.bat` to set the python path:: - SET PYTHON_PATH=C:\Python37 + SET PYTHON_PATH=C:\Python39 Getting Started @@ -147,7 +143,7 @@ On Windows:: $ pip install pywin32 Also available here: - + https://github.com/mhammond/pywin32/releases On Mac OS X:: From c564effbf6444c682f79c3c960614b573ffa2968 Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Thu, 4 Mar 2021 20:55:08 -0500 Subject: [PATCH 70/91] Added notes about translations and thanks to my co-maintainers --- README.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.rst b/README.rst index 5f5f9a216..301b4c99c 100644 --- a/README.rst +++ b/README.rst @@ -197,6 +197,14 @@ koans activity on bitbucket. * Bitbucket koan projects: https://bitbucket.org/repo/all?name=koans +Translations +------------ + +Translations are always welcome! Feel free to add one to this README +if you happen to work on one: + +https://github.com/mswell/python_koans_br + Acknowledgments --------------- @@ -209,3 +217,6 @@ headstart by taking over a code base initiated by the combined Mikes of FPIP. So here's a little plug for their very cool Python podcast: http://frompythonimportpodcast.com/ + +A big thanks also to Mike Pirnat @pirnat and Kevin Chase @kjc have pitched in +as co-maintainers at various times \ No newline at end of file From a8674b1b38792b802b0f9058573ab7aebbd055e6 Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Thu, 4 Mar 2021 21:51:10 -0500 Subject: [PATCH 71/91] Move everything from python3 folder into root. Update links --- README.rst | 3 +-- python3/_runner_tests.py => _runner_tests.py | 0 python3/contemplate_koans.py => contemplate_koans.py | 0 python3/example_file.txt => example_file.txt | 0 python3/koans.txt => koans.txt | 0 {python3/koans => koans}/GREEDS_RULES.txt | 0 {python3/koans => koans}/__init__.py | 0 {python3/koans => koans}/a_package_folder/__init__.py | 0 {python3/koans => koans}/a_package_folder/a_module.py | 0 {python3/koans => koans}/about_asserts.py | 0 {python3/koans => koans}/about_attribute_access.py | 0 {python3/koans => koans}/about_class_attributes.py | 0 {python3/koans => koans}/about_classes.py | 0 {python3/koans => koans}/about_comprehension.py | 0 {python3/koans => koans}/about_control_statements.py | 0 {python3/koans => koans}/about_decorating_with_classes.py | 0 {python3/koans => koans}/about_decorating_with_functions.py | 0 {python3/koans => koans}/about_deleting_objects.py | 0 {python3/koans => koans}/about_dice_project.py | 0 {python3/koans => koans}/about_dictionaries.py | 0 {python3/koans => koans}/about_exceptions.py | 0 {python3/koans => koans}/about_extra_credit.py | 0 {python3/koans => koans}/about_generators.py | 0 {python3/koans => koans}/about_inheritance.py | 0 {python3/koans => koans}/about_iteration.py | 0 {python3/koans => koans}/about_lambdas.py | 0 {python3/koans => koans}/about_list_assignments.py | 0 {python3/koans => koans}/about_lists.py | 0 {python3/koans => koans}/about_method_bindings.py | 0 {python3/koans => koans}/about_methods.py | 0 {python3/koans => koans}/about_modules.py | 0 {python3/koans => koans}/about_monkey_patching.py | 0 {python3/koans => koans}/about_multiple_inheritance.py | 0 {python3/koans => koans}/about_none.py | 0 {python3/koans => koans}/about_packages.py | 0 {python3/koans => koans}/about_proxy_object_project.py | 0 {python3/koans => koans}/about_regex.py | 0 {python3/koans => koans}/about_scope.py | 0 {python3/koans => koans}/about_scoring_project.py | 0 {python3/koans => koans}/about_sets.py | 0 {python3/koans => koans}/about_string_manipulation.py | 0 {python3/koans => koans}/about_strings.py | 0 {python3/koans => koans}/about_triangle_project.py | 0 {python3/koans => koans}/about_triangle_project2.py | 0 {python3/koans => koans}/about_true_and_false.py | 0 {python3/koans => koans}/about_tuples.py | 0 {python3/koans => koans}/about_with_statements.py | 0 {python3/koans => koans}/another_local_module.py | 0 {python3/koans => koans}/jims.py | 0 {python3/koans => koans}/joes.py | 0 {python3/koans => koans}/local_module.py | 0 {python3/koans => koans}/local_module_with_all_defined.py | 0 {python3/koans => koans}/triangle.py | 0 {python3/libs => libs}/__init__.py | 0 {python3/libs => libs}/colorama/LICENSE-colorama | 0 {python3/libs => libs}/colorama/__init__.py | 0 {python3/libs => libs}/colorama/ansi.py | 0 {python3/libs => libs}/colorama/ansitowin32.py | 0 {python3/libs => libs}/colorama/initialise.py | 0 {python3/libs => libs}/colorama/win32.py | 0 {python3/libs => libs}/colorama/winterm.py | 0 {python3/libs => libs}/mock.py | 0 python3/run.bat => run.bat | 2 +- python3/run.sh => run.sh | 0 {python3/runner => runner}/__init__.py | 0 {python3/runner => runner}/helper.py | 0 {python3/runner => runner}/koan.py | 0 {python3/runner => runner}/mockable_test_result.py | 0 {python3/runner => runner}/mountain.py | 0 {python3/runner => runner}/path_to_enlightenment.py | 0 {python3/runner => runner}/runner_tests/__init__.py | 0 {python3/runner => runner}/runner_tests/test_helper.py | 0 {python3/runner => runner}/runner_tests/test_mountain.py | 0 .../runner_tests/test_path_to_enlightenment.py | 0 {python3/runner => runner}/runner_tests/test_sensei.py | 0 {python3/runner => runner}/sensei.py | 0 {python3/runner => runner}/writeln_decorator.py | 0 python3/scent.py => scent.py | 0 78 files changed, 2 insertions(+), 3 deletions(-) rename python3/_runner_tests.py => _runner_tests.py (100%) rename python3/contemplate_koans.py => contemplate_koans.py (100%) rename python3/example_file.txt => example_file.txt (100%) rename python3/koans.txt => koans.txt (100%) rename {python3/koans => koans}/GREEDS_RULES.txt (100%) rename {python3/koans => koans}/__init__.py (100%) rename {python3/koans => koans}/a_package_folder/__init__.py (100%) rename {python3/koans => koans}/a_package_folder/a_module.py (100%) rename {python3/koans => koans}/about_asserts.py (100%) rename {python3/koans => koans}/about_attribute_access.py (100%) rename {python3/koans => koans}/about_class_attributes.py (100%) rename {python3/koans => koans}/about_classes.py (100%) rename {python3/koans => koans}/about_comprehension.py (100%) rename {python3/koans => koans}/about_control_statements.py (100%) rename {python3/koans => koans}/about_decorating_with_classes.py (100%) rename {python3/koans => koans}/about_decorating_with_functions.py (100%) rename {python3/koans => koans}/about_deleting_objects.py (100%) rename {python3/koans => koans}/about_dice_project.py (100%) rename {python3/koans => koans}/about_dictionaries.py (100%) rename {python3/koans => koans}/about_exceptions.py (100%) rename {python3/koans => koans}/about_extra_credit.py (100%) rename {python3/koans => koans}/about_generators.py (100%) rename {python3/koans => koans}/about_inheritance.py (100%) rename {python3/koans => koans}/about_iteration.py (100%) rename {python3/koans => koans}/about_lambdas.py (100%) rename {python3/koans => koans}/about_list_assignments.py (100%) rename {python3/koans => koans}/about_lists.py (100%) rename {python3/koans => koans}/about_method_bindings.py (100%) rename {python3/koans => koans}/about_methods.py (100%) rename {python3/koans => koans}/about_modules.py (100%) rename {python3/koans => koans}/about_monkey_patching.py (100%) rename {python3/koans => koans}/about_multiple_inheritance.py (100%) rename {python3/koans => koans}/about_none.py (100%) rename {python3/koans => koans}/about_packages.py (100%) rename {python3/koans => koans}/about_proxy_object_project.py (100%) rename {python3/koans => koans}/about_regex.py (100%) rename {python3/koans => koans}/about_scope.py (100%) rename {python3/koans => koans}/about_scoring_project.py (100%) rename {python3/koans => koans}/about_sets.py (100%) rename {python3/koans => koans}/about_string_manipulation.py (100%) rename {python3/koans => koans}/about_strings.py (100%) rename {python3/koans => koans}/about_triangle_project.py (100%) rename {python3/koans => koans}/about_triangle_project2.py (100%) rename {python3/koans => koans}/about_true_and_false.py (100%) rename {python3/koans => koans}/about_tuples.py (100%) rename {python3/koans => koans}/about_with_statements.py (100%) rename {python3/koans => koans}/another_local_module.py (100%) rename {python3/koans => koans}/jims.py (100%) rename {python3/koans => koans}/joes.py (100%) rename {python3/koans => koans}/local_module.py (100%) rename {python3/koans => koans}/local_module_with_all_defined.py (100%) rename {python3/koans => koans}/triangle.py (100%) rename {python3/libs => libs}/__init__.py (100%) rename {python3/libs => libs}/colorama/LICENSE-colorama (100%) rename {python3/libs => libs}/colorama/__init__.py (100%) rename {python3/libs => libs}/colorama/ansi.py (100%) rename {python3/libs => libs}/colorama/ansitowin32.py (100%) rename {python3/libs => libs}/colorama/initialise.py (100%) rename {python3/libs => libs}/colorama/win32.py (100%) rename {python3/libs => libs}/colorama/winterm.py (100%) rename {python3/libs => libs}/mock.py (100%) rename python3/run.bat => run.bat (96%) rename python3/run.sh => run.sh (100%) rename {python3/runner => runner}/__init__.py (100%) rename {python3/runner => runner}/helper.py (100%) rename {python3/runner => runner}/koan.py (100%) rename {python3/runner => runner}/mockable_test_result.py (100%) rename {python3/runner => runner}/mountain.py (100%) rename {python3/runner => runner}/path_to_enlightenment.py (100%) rename {python3/runner => runner}/runner_tests/__init__.py (100%) rename {python3/runner => runner}/runner_tests/test_helper.py (100%) rename {python3/runner => runner}/runner_tests/test_mountain.py (100%) rename {python3/runner => runner}/runner_tests/test_path_to_enlightenment.py (100%) rename {python3/runner => runner}/runner_tests/test_sensei.py (100%) rename {python3/runner => runner}/sensei.py (100%) rename {python3/runner => runner}/writeln_decorator.py (100%) rename python3/scent.py => scent.py (100%) diff --git a/README.rst b/README.rst index 301b4c99c..4856c0fea 100644 --- a/README.rst +++ b/README.rst @@ -83,8 +83,7 @@ http://www.youtube.com/watch?v=e2WXgXEjbHY&list=PL5Up_u-XkWgNcunP_UrTJG_3EXgbK2B Or if you prefer to read: -From a \*nix terminal or windows command prompt go to the python -koans\\python_VERSION folder and run:: +From a \*nix terminal or windows command prompt run:: python contemplate_koans.py diff --git a/python3/_runner_tests.py b/_runner_tests.py similarity index 100% rename from python3/_runner_tests.py rename to _runner_tests.py diff --git a/python3/contemplate_koans.py b/contemplate_koans.py similarity index 100% rename from python3/contemplate_koans.py rename to contemplate_koans.py diff --git a/python3/example_file.txt b/example_file.txt similarity index 100% rename from python3/example_file.txt rename to example_file.txt diff --git a/python3/koans.txt b/koans.txt similarity index 100% rename from python3/koans.txt rename to koans.txt diff --git a/python3/koans/GREEDS_RULES.txt b/koans/GREEDS_RULES.txt similarity index 100% rename from python3/koans/GREEDS_RULES.txt rename to koans/GREEDS_RULES.txt diff --git a/python3/koans/__init__.py b/koans/__init__.py similarity index 100% rename from python3/koans/__init__.py rename to koans/__init__.py diff --git a/python3/koans/a_package_folder/__init__.py b/koans/a_package_folder/__init__.py similarity index 100% rename from python3/koans/a_package_folder/__init__.py rename to koans/a_package_folder/__init__.py diff --git a/python3/koans/a_package_folder/a_module.py b/koans/a_package_folder/a_module.py similarity index 100% rename from python3/koans/a_package_folder/a_module.py rename to koans/a_package_folder/a_module.py diff --git a/python3/koans/about_asserts.py b/koans/about_asserts.py similarity index 100% rename from python3/koans/about_asserts.py rename to koans/about_asserts.py diff --git a/python3/koans/about_attribute_access.py b/koans/about_attribute_access.py similarity index 100% rename from python3/koans/about_attribute_access.py rename to koans/about_attribute_access.py diff --git a/python3/koans/about_class_attributes.py b/koans/about_class_attributes.py similarity index 100% rename from python3/koans/about_class_attributes.py rename to koans/about_class_attributes.py diff --git a/python3/koans/about_classes.py b/koans/about_classes.py similarity index 100% rename from python3/koans/about_classes.py rename to koans/about_classes.py diff --git a/python3/koans/about_comprehension.py b/koans/about_comprehension.py similarity index 100% rename from python3/koans/about_comprehension.py rename to koans/about_comprehension.py diff --git a/python3/koans/about_control_statements.py b/koans/about_control_statements.py similarity index 100% rename from python3/koans/about_control_statements.py rename to koans/about_control_statements.py diff --git a/python3/koans/about_decorating_with_classes.py b/koans/about_decorating_with_classes.py similarity index 100% rename from python3/koans/about_decorating_with_classes.py rename to koans/about_decorating_with_classes.py diff --git a/python3/koans/about_decorating_with_functions.py b/koans/about_decorating_with_functions.py similarity index 100% rename from python3/koans/about_decorating_with_functions.py rename to koans/about_decorating_with_functions.py diff --git a/python3/koans/about_deleting_objects.py b/koans/about_deleting_objects.py similarity index 100% rename from python3/koans/about_deleting_objects.py rename to koans/about_deleting_objects.py diff --git a/python3/koans/about_dice_project.py b/koans/about_dice_project.py similarity index 100% rename from python3/koans/about_dice_project.py rename to koans/about_dice_project.py diff --git a/python3/koans/about_dictionaries.py b/koans/about_dictionaries.py similarity index 100% rename from python3/koans/about_dictionaries.py rename to koans/about_dictionaries.py diff --git a/python3/koans/about_exceptions.py b/koans/about_exceptions.py similarity index 100% rename from python3/koans/about_exceptions.py rename to koans/about_exceptions.py diff --git a/python3/koans/about_extra_credit.py b/koans/about_extra_credit.py similarity index 100% rename from python3/koans/about_extra_credit.py rename to koans/about_extra_credit.py diff --git a/python3/koans/about_generators.py b/koans/about_generators.py similarity index 100% rename from python3/koans/about_generators.py rename to koans/about_generators.py diff --git a/python3/koans/about_inheritance.py b/koans/about_inheritance.py similarity index 100% rename from python3/koans/about_inheritance.py rename to koans/about_inheritance.py diff --git a/python3/koans/about_iteration.py b/koans/about_iteration.py similarity index 100% rename from python3/koans/about_iteration.py rename to koans/about_iteration.py diff --git a/python3/koans/about_lambdas.py b/koans/about_lambdas.py similarity index 100% rename from python3/koans/about_lambdas.py rename to koans/about_lambdas.py diff --git a/python3/koans/about_list_assignments.py b/koans/about_list_assignments.py similarity index 100% rename from python3/koans/about_list_assignments.py rename to koans/about_list_assignments.py diff --git a/python3/koans/about_lists.py b/koans/about_lists.py similarity index 100% rename from python3/koans/about_lists.py rename to koans/about_lists.py diff --git a/python3/koans/about_method_bindings.py b/koans/about_method_bindings.py similarity index 100% rename from python3/koans/about_method_bindings.py rename to koans/about_method_bindings.py diff --git a/python3/koans/about_methods.py b/koans/about_methods.py similarity index 100% rename from python3/koans/about_methods.py rename to koans/about_methods.py diff --git a/python3/koans/about_modules.py b/koans/about_modules.py similarity index 100% rename from python3/koans/about_modules.py rename to koans/about_modules.py diff --git a/python3/koans/about_monkey_patching.py b/koans/about_monkey_patching.py similarity index 100% rename from python3/koans/about_monkey_patching.py rename to koans/about_monkey_patching.py diff --git a/python3/koans/about_multiple_inheritance.py b/koans/about_multiple_inheritance.py similarity index 100% rename from python3/koans/about_multiple_inheritance.py rename to koans/about_multiple_inheritance.py diff --git a/python3/koans/about_none.py b/koans/about_none.py similarity index 100% rename from python3/koans/about_none.py rename to koans/about_none.py diff --git a/python3/koans/about_packages.py b/koans/about_packages.py similarity index 100% rename from python3/koans/about_packages.py rename to koans/about_packages.py diff --git a/python3/koans/about_proxy_object_project.py b/koans/about_proxy_object_project.py similarity index 100% rename from python3/koans/about_proxy_object_project.py rename to koans/about_proxy_object_project.py diff --git a/python3/koans/about_regex.py b/koans/about_regex.py similarity index 100% rename from python3/koans/about_regex.py rename to koans/about_regex.py diff --git a/python3/koans/about_scope.py b/koans/about_scope.py similarity index 100% rename from python3/koans/about_scope.py rename to koans/about_scope.py diff --git a/python3/koans/about_scoring_project.py b/koans/about_scoring_project.py similarity index 100% rename from python3/koans/about_scoring_project.py rename to koans/about_scoring_project.py diff --git a/python3/koans/about_sets.py b/koans/about_sets.py similarity index 100% rename from python3/koans/about_sets.py rename to koans/about_sets.py diff --git a/python3/koans/about_string_manipulation.py b/koans/about_string_manipulation.py similarity index 100% rename from python3/koans/about_string_manipulation.py rename to koans/about_string_manipulation.py diff --git a/python3/koans/about_strings.py b/koans/about_strings.py similarity index 100% rename from python3/koans/about_strings.py rename to koans/about_strings.py diff --git a/python3/koans/about_triangle_project.py b/koans/about_triangle_project.py similarity index 100% rename from python3/koans/about_triangle_project.py rename to koans/about_triangle_project.py diff --git a/python3/koans/about_triangle_project2.py b/koans/about_triangle_project2.py similarity index 100% rename from python3/koans/about_triangle_project2.py rename to koans/about_triangle_project2.py diff --git a/python3/koans/about_true_and_false.py b/koans/about_true_and_false.py similarity index 100% rename from python3/koans/about_true_and_false.py rename to koans/about_true_and_false.py diff --git a/python3/koans/about_tuples.py b/koans/about_tuples.py similarity index 100% rename from python3/koans/about_tuples.py rename to koans/about_tuples.py diff --git a/python3/koans/about_with_statements.py b/koans/about_with_statements.py similarity index 100% rename from python3/koans/about_with_statements.py rename to koans/about_with_statements.py diff --git a/python3/koans/another_local_module.py b/koans/another_local_module.py similarity index 100% rename from python3/koans/another_local_module.py rename to koans/another_local_module.py diff --git a/python3/koans/jims.py b/koans/jims.py similarity index 100% rename from python3/koans/jims.py rename to koans/jims.py diff --git a/python3/koans/joes.py b/koans/joes.py similarity index 100% rename from python3/koans/joes.py rename to koans/joes.py diff --git a/python3/koans/local_module.py b/koans/local_module.py similarity index 100% rename from python3/koans/local_module.py rename to koans/local_module.py diff --git a/python3/koans/local_module_with_all_defined.py b/koans/local_module_with_all_defined.py similarity index 100% rename from python3/koans/local_module_with_all_defined.py rename to koans/local_module_with_all_defined.py diff --git a/python3/koans/triangle.py b/koans/triangle.py similarity index 100% rename from python3/koans/triangle.py rename to koans/triangle.py diff --git a/python3/libs/__init__.py b/libs/__init__.py similarity index 100% rename from python3/libs/__init__.py rename to libs/__init__.py diff --git a/python3/libs/colorama/LICENSE-colorama b/libs/colorama/LICENSE-colorama similarity index 100% rename from python3/libs/colorama/LICENSE-colorama rename to libs/colorama/LICENSE-colorama diff --git a/python3/libs/colorama/__init__.py b/libs/colorama/__init__.py similarity index 100% rename from python3/libs/colorama/__init__.py rename to libs/colorama/__init__.py diff --git a/python3/libs/colorama/ansi.py b/libs/colorama/ansi.py similarity index 100% rename from python3/libs/colorama/ansi.py rename to libs/colorama/ansi.py diff --git a/python3/libs/colorama/ansitowin32.py b/libs/colorama/ansitowin32.py similarity index 100% rename from python3/libs/colorama/ansitowin32.py rename to libs/colorama/ansitowin32.py diff --git a/python3/libs/colorama/initialise.py b/libs/colorama/initialise.py similarity index 100% rename from python3/libs/colorama/initialise.py rename to libs/colorama/initialise.py diff --git a/python3/libs/colorama/win32.py b/libs/colorama/win32.py similarity index 100% rename from python3/libs/colorama/win32.py rename to libs/colorama/win32.py diff --git a/python3/libs/colorama/winterm.py b/libs/colorama/winterm.py similarity index 100% rename from python3/libs/colorama/winterm.py rename to libs/colorama/winterm.py diff --git a/python3/libs/mock.py b/libs/mock.py similarity index 100% rename from python3/libs/mock.py rename to libs/mock.py diff --git a/python3/run.bat b/run.bat similarity index 96% rename from python3/run.bat rename to run.bat index 3f5e94c77..c6a5fba4b 100755 --- a/python3/run.bat +++ b/run.bat @@ -5,7 +5,7 @@ REM You don't actually need this script! SET RUN_KOANS=python.exe -B contemplate_koans.py REM Set this to your python folder: -SET PYTHON_PATH=C:\Python34 +SET PYTHON_PATH=C:\Python39 set SCRIPT= diff --git a/python3/run.sh b/run.sh similarity index 100% rename from python3/run.sh rename to run.sh diff --git a/python3/runner/__init__.py b/runner/__init__.py similarity index 100% rename from python3/runner/__init__.py rename to runner/__init__.py diff --git a/python3/runner/helper.py b/runner/helper.py similarity index 100% rename from python3/runner/helper.py rename to runner/helper.py diff --git a/python3/runner/koan.py b/runner/koan.py similarity index 100% rename from python3/runner/koan.py rename to runner/koan.py diff --git a/python3/runner/mockable_test_result.py b/runner/mockable_test_result.py similarity index 100% rename from python3/runner/mockable_test_result.py rename to runner/mockable_test_result.py diff --git a/python3/runner/mountain.py b/runner/mountain.py similarity index 100% rename from python3/runner/mountain.py rename to runner/mountain.py diff --git a/python3/runner/path_to_enlightenment.py b/runner/path_to_enlightenment.py similarity index 100% rename from python3/runner/path_to_enlightenment.py rename to runner/path_to_enlightenment.py diff --git a/python3/runner/runner_tests/__init__.py b/runner/runner_tests/__init__.py similarity index 100% rename from python3/runner/runner_tests/__init__.py rename to runner/runner_tests/__init__.py diff --git a/python3/runner/runner_tests/test_helper.py b/runner/runner_tests/test_helper.py similarity index 100% rename from python3/runner/runner_tests/test_helper.py rename to runner/runner_tests/test_helper.py diff --git a/python3/runner/runner_tests/test_mountain.py b/runner/runner_tests/test_mountain.py similarity index 100% rename from python3/runner/runner_tests/test_mountain.py rename to runner/runner_tests/test_mountain.py diff --git a/python3/runner/runner_tests/test_path_to_enlightenment.py b/runner/runner_tests/test_path_to_enlightenment.py similarity index 100% rename from python3/runner/runner_tests/test_path_to_enlightenment.py rename to runner/runner_tests/test_path_to_enlightenment.py diff --git a/python3/runner/runner_tests/test_sensei.py b/runner/runner_tests/test_sensei.py similarity index 100% rename from python3/runner/runner_tests/test_sensei.py rename to runner/runner_tests/test_sensei.py diff --git a/python3/runner/sensei.py b/runner/sensei.py similarity index 100% rename from python3/runner/sensei.py rename to runner/sensei.py diff --git a/python3/runner/writeln_decorator.py b/runner/writeln_decorator.py similarity index 100% rename from python3/runner/writeln_decorator.py rename to runner/writeln_decorator.py diff --git a/python3/scent.py b/scent.py similarity index 100% rename from python3/scent.py rename to scent.py From c8dcc9459abd4ad36075236dd23318e93234f48d Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Thu, 4 Mar 2021 21:52:39 -0500 Subject: [PATCH 72/91] Admitting we don't update bitbucket mirror anymore --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 4856c0fea..2664a3aed 100644 --- a/README.rst +++ b/README.rst @@ -37,7 +37,7 @@ Python Koans is available through git on Github: http://github.com/gregmalcolm/python_koans -It is also mirrored on bitbucket for Mercurial users: +It is also used to be mirrored on bitbucket for Mercurial users (deprecated): http://bitbucket.org/gregmalcolm/python_koans From d171baf1375fe84f9016fa3bbb38de3609d34e0a Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Thu, 4 Mar 2021 21:57:08 -0500 Subject: [PATCH 73/91] Dropping reference to bitbucket mirror. The url wasn't even right --- README.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.rst b/README.rst index 2664a3aed..3c74876fb 100644 --- a/README.rst +++ b/README.rst @@ -37,10 +37,6 @@ Python Koans is available through git on Github: http://github.com/gregmalcolm/python_koans -It is also used to be mirrored on bitbucket for Mercurial users (deprecated): - - http://bitbucket.org/gregmalcolm/python_koans - Either site will allow you to download the source as a zip/gz/bz2. From b835ef0dcb14bec7b75d6535057b2c2761cb1db6 Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Thu, 4 Mar 2021 22:00:54 -0500 Subject: [PATCH 74/91] No need for travis to travel to the koans folder any longer --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4ae0f9184..e8f7d64ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,6 @@ python: - 3.9 script: - - PYTHON_VER=`python -c 'import sys; print(sys.version_info[0])'` - - cd python$PYTHON_VER - python _runner_tests.py # - python contemplate_koans.py # Run all the koans # - python contemplate_koans.py about_asserts about_none # Run a subset of From e5c2d8bff46c92c1b26730340f79c4c3c8c403b7 Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:10:35 +0000 Subject: [PATCH 75/91] Fully automate dev setup with Gitpod This commit implements a fully-automated development setup using Gitpod.io, an online IDE for GitLab, GitHub, and Bitbucket that enables Dev-Environments-As-Code. This makes it easy for anyone to get a ready-to-code workspace for any branch, issue or pull request almost instantly with a single click. --- .gitpod.Dockerfile | 11 +++++++++++ .gitpod.yml | 14 ++++++++++++++ README.md | 2 ++ 3 files changed, 27 insertions(+) create mode 100644 .gitpod.Dockerfile create mode 100644 .gitpod.yml create mode 100644 README.md diff --git a/.gitpod.Dockerfile b/.gitpod.Dockerfile new file mode 100644 index 000000000..d6122b7f2 --- /dev/null +++ b/.gitpod.Dockerfile @@ -0,0 +1,11 @@ +# Install custom tools, runtimes, etc. +# For example "bastet", a command-line tetris clone: +# RUN brew install bastet +# +# More information: https://www.gitpod.io/docs/config-docker/ + +FROM gitpod/workspace-full:latest + +USER gitpod + +RUN pip3 install pytest==4.4.2 pytest-testdox mock \ No newline at end of file diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 000000000..94253242b --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,14 @@ +image: + file: .gitpod.Dockerfile + +tasks: + - command: python contemplate_koans.py + +github: + prebuilds: + # enable for the master/default branch (defaults to true) + master: true + # enable for pull requests coming from this repo (defaults to true) + pullRequests: false + # add a "Review in Gitpod" button as a comment to pull requests (defaults to true) + addComment: false diff --git a/README.md b/README.md new file mode 100644 index 000000000..90ea5a39a --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gregmalcolm/python_koans) + From c08ea92ef72ee5fd684d2c00a2539ee19bcbc690 Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:13:11 +0000 Subject: [PATCH 76/91] remove readme md to use the main readme --- README.md | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 README.md diff --git a/README.md b/README.md deleted file mode 100644 index 90ea5a39a..000000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gregmalcolm/python_koans) - From 244d38b43405a9e3d378fbbb67d6fceffe51a54e Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:16:31 +0000 Subject: [PATCH 77/91] added open in gitpod badge and button --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index 3c74876fb..0d7ba671d 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,10 @@ Python Koans .. image:: https://travis-ci.org/gregmalcolm/python_koans.png?branch=master :target: http://travis-ci.org/gregmalcolm/python_koans +[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gregmalcolm/python_koans) + + + Python Koans is a port of Edgecase's "Ruby Koans" which can be found at http://rubykoans.com/. From 679758decd3ce7399b8c76a466982529dc24cabc Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:17:53 +0000 Subject: [PATCH 78/91] corrected gitpod badge --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 0d7ba671d..9f5410926 100644 --- a/README.rst +++ b/README.rst @@ -5,7 +5,8 @@ Python Koans .. image:: https://travis-ci.org/gregmalcolm/python_koans.png?branch=master :target: http://travis-ci.org/gregmalcolm/python_koans -[![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/gregmalcolm/python_koans) +.. image:: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod + :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans From a59dbca517be924919b14cbe8241730b8f139bb2 Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:22:45 +0000 Subject: [PATCH 79/91] Corrected open in gitpod button and added description --- README.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 9f5410926..f45a51672 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,9 @@ Python Koans .. image:: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans - +This project is ready to code in gitpod. +.. image:: ttps://gitpod.io/button/open-in-gitpod.svg + :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans Python Koans is a port of Edgecase's "Ruby Koans" which can be found at http://rubykoans.com/. From 7ce5cb800e9824bea1b5a68727e5bd6ca8484084 Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:23:44 +0000 Subject: [PATCH 80/91] missed h in https --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f45a51672..e7a9a7ba3 100644 --- a/README.rst +++ b/README.rst @@ -9,7 +9,7 @@ Python Koans :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans This project is ready to code in gitpod. -.. image:: ttps://gitpod.io/button/open-in-gitpod.svg +.. image:: https://gitpod.io/button/open-in-gitpod.svg :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans Python Koans is a port of Edgecase's "Ruby Koans" which can be found From 115ada41e0cdddd242225f5b5f47873b0dacf088 Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:31:37 +0000 Subject: [PATCH 81/91] test button --- README.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e7a9a7ba3..f89c1c2a6 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,9 @@ Python Koans .. image:: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans -This project is ready to code in gitpod. +

One click installation:

+[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io#https://github.com/4GeeksAcademy/python-http-requests-api-tutorial-exercises.git) + .. image:: https://gitpod.io/button/open-in-gitpod.svg :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans From be32d6d5cace9410510090cee77c20a732286c99 Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:33:31 +0000 Subject: [PATCH 82/91] Testing one click installation title --- README.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/README.rst b/README.rst index f89c1c2a6..d7b20c651 100644 --- a/README.rst +++ b/README.rst @@ -9,7 +9,6 @@ Python Koans :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans

One click installation:

-[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io#https://github.com/4GeeksAcademy/python-http-requests-api-tutorial-exercises.git) .. image:: https://gitpod.io/button/open-in-gitpod.svg :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans From aa55169dd5d5d0f77643b6a6f0d9cb1e44e83418 Mon Sep 17 00:00:00 2001 From: Oaker Min Date: Fri, 28 May 2021 02:34:37 +0000 Subject: [PATCH 83/91] Correct format --- README.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d7b20c651..05bd1b9f5 100644 --- a/README.rst +++ b/README.rst @@ -8,7 +8,8 @@ Python Koans .. image:: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans -

One click installation:

+One click installation: +----------------------- .. image:: https://gitpod.io/button/open-in-gitpod.svg :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans From 7de04259b312d0aae6cb211acb8750e1d387dd30 Mon Sep 17 00:00:00 2001 From: Oaker Min <7734956+brootware@users.noreply.github.com> Date: Mon, 7 Jun 2021 09:29:45 +0800 Subject: [PATCH 84/91] Update README.rst Updated to point to my own forked repo for one click installation --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 05bd1b9f5..7b0eded99 100644 --- a/README.rst +++ b/README.rst @@ -6,13 +6,13 @@ Python Koans :target: http://travis-ci.org/gregmalcolm/python_koans .. image:: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod - :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans + :target: https://gitpod.io/#https://github.com/brootware/python_koans One click installation: ----------------------- .. image:: https://gitpod.io/button/open-in-gitpod.svg - :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans + :target: https://gitpod.io/#https://github.com/brootware/python_koans Python Koans is a port of Edgecase's "Ruby Koans" which can be found at http://rubykoans.com/. @@ -223,4 +223,4 @@ FPIP. So here's a little plug for their very cool Python podcast: http://frompythonimportpodcast.com/ A big thanks also to Mike Pirnat @pirnat and Kevin Chase @kjc have pitched in -as co-maintainers at various times \ No newline at end of file +as co-maintainers at various times From e35f2d6705a96f3d669dcb280d396f845dfd7e5c Mon Sep 17 00:00:00 2001 From: Oaker Min <7734956+brootware@users.noreply.github.com> Date: Mon, 9 Aug 2021 16:46:04 +0800 Subject: [PATCH 85/91] Update README.rst Added redhat codeready workspaces --- README.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.rst b/README.rst index 7b0eded99..a25d68057 100644 --- a/README.rst +++ b/README.rst @@ -7,13 +7,21 @@ Python Koans .. image:: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod :target: https://gitpod.io/#https://github.com/brootware/python_koans + +.. image:: https://www.eclipse.org/che/contribute.svg + :target: https://workspaces.openshift.com/f?url=https://github.com/brootware/python_koans One click installation: ----------------------- +.. image:: https://www.eclipse.org/che/contribute.svg + :target: https://workspaces.openshift.com/f?url=https://github.com/brootware/python_koans +| or .. image:: https://gitpod.io/button/open-in-gitpod.svg :target: https://gitpod.io/#https://github.com/brootware/python_koans +| + Python Koans is a port of Edgecase's "Ruby Koans" which can be found at http://rubykoans.com/. From a9c177cad5ac47d9fbd064f516b8d1ff1a65c676 Mon Sep 17 00:00:00 2001 From: Oaker Min <7734956+brootware@users.noreply.github.com> Date: Mon, 9 Aug 2021 16:49:26 +0800 Subject: [PATCH 86/91] updating to reference greg's original repo --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index a25d68057..e42a75926 100644 --- a/README.rst +++ b/README.rst @@ -6,19 +6,19 @@ Python Koans :target: http://travis-ci.org/gregmalcolm/python_koans .. image:: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod - :target: https://gitpod.io/#https://github.com/brootware/python_koans + :target: https://gitpod.io/#https://github.com/gregmalcolm/python_koans .. image:: https://www.eclipse.org/che/contribute.svg - :target: https://workspaces.openshift.com/f?url=https://github.com/brootware/python_koans + :target: https://workspaces.openshift.com/f?url=https://gitpod.io/#https://github.com/gregmalcolm/python_koans One click installation: ----------------------- .. image:: https://www.eclipse.org/che/contribute.svg - :target: https://workspaces.openshift.com/f?url=https://github.com/brootware/python_koans + :target: https://workspaces.openshift.com/f?url=https://gitpod.io/#https://github.com/gregmalcolm/python_koans | or .. image:: https://gitpod.io/button/open-in-gitpod.svg - :target: https://gitpod.io/#https://github.com/brootware/python_koans + :target: https://gitpod.io/#https://gitpod.io/#https://github.com/gregmalcolm/python_koans | From 7ec135707fb9f760490d382a7b8b29b27e97d9f5 Mon Sep 17 00:00:00 2001 From: 100cube <44786337+100cube@users.noreply.github.com> Date: Mon, 23 Aug 2021 23:28:22 +0100 Subject: [PATCH 87/91] Minor addition to list assignments (unpacking when there are fewer values) --- koans/about_list_assignments.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/koans/about_list_assignments.py b/koans/about_list_assignments.py index d32d89911..8a8d48090 100644 --- a/koans/about_list_assignments.py +++ b/koans/about_list_assignments.py @@ -23,6 +23,12 @@ def test_parallel_assignments_with_extra_values(self): self.assertEqual(__, first_names) self.assertEqual(__, last_name) + def test_parallel_assignments_with_fewer_values(self): + title, *first_names, last_name = ["Mr", "Bond"] + self.assertEqual(__, title) + self.assertEqual(__, first_names) + self.assertEqual(__, last_name) + def test_parallel_assignments_with_sublists(self): first_name, last_name = [["Willie", "Rae"], "Johnson"] self.assertEqual(__, first_name) From 087dea361d54894eb6ed9288f62d1cb9980e192c Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 20 Dec 2022 05:44:20 +0200 Subject: [PATCH 88/91] README: Update formatting and links (#265) --- README.rst | 94 +++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/README.rst b/README.rst index e42a75926..e2f303fe9 100644 --- a/README.rst +++ b/README.rst @@ -32,10 +32,14 @@ language by making tests pass. Most tests are *fixed* by filling the missing parts of assert functions. Eg: +.. code-block:: python + self.assertEqual(__, 1+2) which can be fixed by replacing the __ part with the appropriate code: +.. code-block:: python + self.assertEqual(3, 1+2) Occasionally you will encounter some failing tests that are already filled out. @@ -50,11 +54,11 @@ a taste of Test Driven Development (TDD). Downloading Python Koans ------------------------ -Python Koans is available through git on Github: +Python Koans is available on GitHub: - http://github.com/gregmalcolm/python_koans +* https://github.com/gregmalcolm/python_koans -Either site will allow you to download the source as a zip/gz/bz2. +You can clone with Git or download the source as a zip/gz/bz2. Installing Python Koans @@ -63,7 +67,7 @@ Installing Python Koans Aside from downloading or checking out the latest version of Python Koans, you need to install the Python interpreter. -At this time of writing, we support Python3. The policy is to try to keep +At this time of writing, we support Python 3. The policy is to try to keep current with the latest production version. You should be able to work with newer Python versions, but older ones will @@ -71,17 +75,17 @@ likely give you problems. You can download Python from here: - http://www.python.org/download +* https://www.python.org/downloads/ After installing Python make sure the folder containing the python executable is in the system path. In other words, you need to be able to run Python from a -command console. It will either be `python3` or for windows it will be `python.exe`. +command console. It will either be ``python3`` or for Windows it will be ``python.exe``. If you have problems, this may help: - http://www.python.org/about/gettingstarted +* https://www.python.org/about/gettingstarted/ -Windows users may also want to update the line in the batch file `run.bat` to +Windows users may also want to update the line in the batch file ``run.bat`` to set the python path:: SET PYTHON_PATH=C:\Python39 @@ -92,19 +96,23 @@ Getting Started Jake Hebbert has created a couple of screencasts available here: -http://www.youtube.com/watch?v=e2WXgXEjbHY&list=PL5Up_u-XkWgNcunP_UrTJG_3EXgbK2BQJ&index=1 +https://www.youtube.com/watch?v=e2WXgXEjbHY&list=PL5Up_u-XkWgNcunP_UrTJG_3EXgbK2BQJ&index=1 Or if you prefer to read: -From a \*nix terminal or windows command prompt run:: +From a \*nix terminal or Windows command prompt run:: + +.. code-block:: sh python contemplate_koans.py -or:: +or: + +.. code-block:: sh python3 contemplate_koans.py -In my case I'm using Python 3 with windows, so I fire up my command +In my case I'm using Python 3 with Windows, so I fire up my command shell (cmd.exe) and run this: .. image:: https://user-images.githubusercontent.com/2614930/28401747-f723ff00-6cd0-11e7-9b9a-a6993b753cf6.png @@ -114,11 +122,13 @@ Apparently a test failed:: AssertionError: False is not True It also tells me exactly where the problem is, it's an assert on line 12 -of .\\koans\\about_asserts.py. This one is easy, just change False to True to +of ``.\\koans\\about_asserts.py``. This one is easy, just change ``False`` to ``True`` to make the test pass. Sooner or later you will likely encounter tests where you are not sure what the -expected value should be. For example:: +expected value should be. For example: + +.. code-block:: python class Dog: pass @@ -138,40 +148,51 @@ Sniffer Support Sniffer allows you to run the tests continuously. If you modify any files files in the koans directory, it will rerun the tests. -To set this up, you need to install sniffer:: +To set this up, you need to install sniffer: + +.. code-block:: sh - $ pip install sniffer + python3 -m pip install sniffer You should also run one of these libraries depending on your system. This will automatically trigger sniffer when a file changes, otherwise sniffer will have to poll to see if the files have changed. -On Linux:: +On Linux: + +.. code-block:: sh - $ pip install pyinotify + python3 -m pip install pyinotify -On Windows:: +On Windows: - $ pip install pywin32 +.. code-block:: sh + + python3 -m pip install pywin32 Also available here: https://github.com/mhammond/pywin32/releases -On Mac OS X:: +On macOS: + +.. code-block:: sh + + python3 -m pip install MacFSEvents - $ pip install MacFSEvents +Once it is set up, you just run: -Once it is set up, you just run:: +.. code-block:: sh - $ sniffer + sniffer -Just modify one of the koans files and you'll see that the tests are triggered automatically. Sniffer is controlled by `scent.py` +Just modify one of the koans files and you'll see that the tests are triggered +automatically. Sniffer is controlled by ``scent.py``. Getting the Most From the Koans ------------------------------- -Quoting the Ruby Koans instructions:: +Quoting the Ruby Koans instructions: "In test-driven development the mantra has always been, red, green, refactor. Write a failing test and run it (red), make the test pass @@ -182,28 +203,15 @@ Quoting the Ruby Koans instructions:: and improve the code to better communicate its intent (refactor)." -Content -------- - -The Python Koans is a made up of about 2/3 Ruby Koans ported material and 1/3 -Python specific tests. The content ported from Ruby Koans includes all the -assignment projects. - -Content for Python 3 is a little different to the Python 2 flavor due to big -changes between the two different versions of the language. For example, in -the Python 2 variant the differences between old and new style classes are -covered. This loses relevance in in the Python 3 version, but there are some -extra tests covering new functionality. - Finding More Koan Projects -------------------------- There are number of other great Koan projects out there for various languages -and frameworks. Most of them can be found in github. Also there is a little -koans activity on bitbucket. +and frameworks. Most of them can be found in GitHub. Also there is a little +koans activity on Bitbucket. -* Github koan projects: +* GitHub koan projects: https://github.com/search?q=koans&ref=cmdform * Bitbucket koan projects: @@ -228,7 +236,7 @@ Also thanks to everyone who has contributed to Python Koans! I got a great headstart by taking over a code base initiated by the combined Mikes of FPIP. So here's a little plug for their very cool Python podcast: - http://frompythonimportpodcast.com/ +* https://www.frompythonimportpodcast.com/ A big thanks also to Mike Pirnat @pirnat and Kevin Chase @kjc have pitched in as co-maintainers at various times From 71bc33067e6fa417182bcb9994fecfd7f8b898ac Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Tue, 20 Dec 2022 05:47:05 +0200 Subject: [PATCH 89/91] Update min and max versions (#266) * Python 3.7 is the oldest supported * Python 3.11 is the latest --- contemplate_koans.py | 9 ++++----- run.bat | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/contemplate_koans.py b/contemplate_koans.py index b7d35d4b3..ddf992388 100644 --- a/contemplate_koans.py +++ b/contemplate_koans.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # # Acknowledgment: @@ -16,18 +15,18 @@ if sys.version_info < (3, 0): print("\nThis is the Python 3 version of Python Koans, but you are " + "running it with Python 2!\n\n" - "Did you accidentally use the wrong python script? \nTry:\n\n" + + "Did you accidentally use the wrong Python script? \nTry:\n\n" + " python3 contemplate_koans.py\n") else: - if sys.version_info < (3, 3): + if sys.version_info < (3, 7): print("\n" + "********************************************************\n" + "WARNING:\n" + "This version of Python Koans was designed for " + - "Python 3.3 or greater.\n" + + "Python 3.7 or greater.\n" + "Your version of Python is older, so you may run into " + "problems!\n\n" + - "But lets see how far we get...\n" + + "But let's see how far we get...\n" + "********************************************************\n") from runner.mountain import Mountain diff --git a/run.bat b/run.bat index c6a5fba4b..d965d4efe 100755 --- a/run.bat +++ b/run.bat @@ -5,7 +5,7 @@ REM You don't actually need this script! SET RUN_KOANS=python.exe -B contemplate_koans.py REM Set this to your python folder: -SET PYTHON_PATH=C:\Python39 +SET PYTHON_PATH=C:\Python311 set SCRIPT= From 71bcff7b1eb0079f1b48de745d6f1076988a7313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=ADcero=20Santos?= Date: Fri, 7 Apr 2023 13:38:57 -0300 Subject: [PATCH 90/91] Update about_tuples.py Fix typo. --- koans/about_tuples.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_tuples.py b/koans/about_tuples.py index 2d65ea8f1..36de2e4d1 100644 --- a/koans/about_tuples.py +++ b/koans/about_tuples.py @@ -47,7 +47,7 @@ def test_tuple_constructor_can_be_surprising(self): def test_creating_empty_tuples(self): self.assertEqual(__ , ()) - self.assertEqual(__ , tuple()) #Sometimes less confusing + self.assertEqual(__ , tuple()) # Sometimes less confusing def test_tuples_can_be_embedded(self): lat = (37, 14, 6, 'N') From 74e39145450076f7613a7a7a05eee39c03bb7c3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=ADcero=20Santos?= Date: Fri, 7 Apr 2023 20:26:43 -0300 Subject: [PATCH 91/91] Update koans/about_tuples.py Co-authored-by: Hugo van Kemenade --- koans/about_tuples.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koans/about_tuples.py b/koans/about_tuples.py index 36de2e4d1..1b38c8f7f 100644 --- a/koans/about_tuples.py +++ b/koans/about_tuples.py @@ -47,7 +47,7 @@ def test_tuple_constructor_can_be_surprising(self): def test_creating_empty_tuples(self): self.assertEqual(__ , ()) - self.assertEqual(__ , tuple()) # Sometimes less confusing + self.assertEqual(__ , tuple()) # Sometimes less confusing def test_tuples_can_be_embedded(self): lat = (37, 14, 6, 'N')