From 106e4476f0f83e58c3702f92ae53bfba537ebffa Mon Sep 17 00:00:00 2001 From: RJ Osborne Date: Sat, 22 Oct 2011 15:14:27 -0400 Subject: [PATCH 001/237] A bit better example for pop, proving by observation of the test result that the argument to pop is relative to the left of the list, not the end. --- python 2/koans/about_lists.py | 2 +- python 3/koans/about_lists.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python 2/koans/about_lists.py b/python 2/koans/about_lists.py index 94dfef4c3..ca998f3f6 100644 --- a/python 2/koans/about_lists.py +++ b/python 2/koans/about_lists.py @@ -71,7 +71,7 @@ def test_insertions(self): self.assertEqual(__, knight) def test_popping_lists(self): - stack = [10, 20, 30] + stack = [10, 20, 30, 40] stack.append('last') self.assertEqual(__, stack) diff --git a/python 3/koans/about_lists.py b/python 3/koans/about_lists.py index 474ecddc1..ae53fd153 100644 --- a/python 3/koans/about_lists.py +++ b/python 3/koans/about_lists.py @@ -72,7 +72,7 @@ def test_insertions(self): self.assertEqual(__, knight) def test_popping_lists(self): - stack = [10, 20, 30] + stack = [10, 20, 30, 40] stack.append('last') self.assertEqual(__, stack) From af143bfac366a136d6ad95c323c72a1ea229ba0e Mon Sep 17 00:00:00 2001 From: Lars Wiegman Date: Tue, 29 Nov 2011 12:05:47 +0100 Subject: [PATCH 002/237] Reformatted single-line functions to multi-line function to improve readability. --- python 2/koans/about_iteration.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/python 2/koans/about_iteration.py b/python 2/koans/about_iteration.py index b5a00a836..eb0aca2b9 100644 --- a/python 2/koans/about_iteration.py +++ b/python 2/koans/about_iteration.py @@ -40,7 +40,8 @@ def test_map_transforms_elements_of_a_list(self): self.assertEqual(__, mapped_seq) def test_filter_selects_certain_items_from_a_list(self): - def is_even(item): return (item % 2) == 0 + def is_even(item): + return (item % 2) == 0 seq = [1, 2, 3, 4, 5, 6] @@ -48,7 +49,8 @@ def is_even(item): return (item % 2) == 0 self.assertEqual(__, even_numbers) def test_just_return_first_item_found(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"] @@ -70,7 +72,7 @@ def add(self, accum, item): def multiply(self, accum, item): return accum * item - def test_reduce_will_blow_your_mind(self): + def test_reduce_will_blow_your_mind(self): result = reduce(self.add, [2, 3, 4]) self.assertEqual(__, result) @@ -82,7 +84,7 @@ def test_reduce_will_blow_your_mind(self): # ------------------------------------------------------------------ - def test_creating_lists_with_list_comprehensions(self): + def test_creating_lists_with_list_comprehensions(self): feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals', 'fruit bats'] comprehension = [delicacy.capitalize() for delicacy in feast] @@ -107,7 +109,8 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): # Files act like a collection of lines file = open("example_file.txt") - def make_upcase(line) : return line.strip().upper() + def make_upcase(line) : + return line.strip().upper() upcase_lines = map(make_upcase, file.readlines()) self.assertEqual(__, list(upcase_lines)) @@ -116,4 +119,5 @@ def make_upcase(line) : return line.strip().upper() finally: # Arg, this is ugly. # We will figure out how to fix this later. - if file: file.close() + if file: + file.close() From dac4856c2397f1c5e447c3d5514ced81f2174d67 Mon Sep 17 00:00:00 2001 From: Lars Wiegman Date: Tue, 29 Nov 2011 15:35:15 +0100 Subject: [PATCH 003/237] Reformatted single line functions for improved readability. --- python 3/koans/about_iteration.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/python 3/koans/about_iteration.py b/python 3/koans/about_iteration.py index 5d69651f7..d9d1e5ca2 100644 --- a/python 3/koans/about_iteration.py +++ b/python 3/koans/about_iteration.py @@ -53,7 +53,8 @@ def test_map_transforms_elements_of_a_list(self): # python 3. In python 2 map() would give you a list. def test_filter_selects_certain_items_from_a_list(self): - def is_even(item): return (item % 2) == 0 + def is_even(item): + return (item % 2) == 0 seq = [1, 2, 3, 4, 5, 6] even_numbers = list() @@ -64,7 +65,8 @@ def is_even(item): return (item % 2) == 0 self.assertEqual(__, even_numbers) def test_just_return_first_item_found(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"] name = None @@ -130,7 +132,8 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): # Files act like a collection of lines file = open("example_file.txt") - def make_upcase(line) : return line.strip().upper() + def make_upcase(line): + return line.strip().upper() upcase_lines = map(make_upcase, file.readlines()) self.assertEqual(__, list(upcase_lines)) @@ -139,4 +142,5 @@ def make_upcase(line) : return line.strip().upper() finally: # Arg, this is ugly. # We will figure out how to fix this later. - if file: file.close() + if file: + file.close() \ No newline at end of file From 08be471a32bee0fb2ca31e0fa9bda4d40553d92d Mon Sep 17 00:00:00 2001 From: Lars Wiegman Date: Tue, 29 Nov 2011 15:36:39 +0100 Subject: [PATCH 004/237] Improved formatting. --- python 2/koans/about_iteration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python 2/koans/about_iteration.py b/python 2/koans/about_iteration.py index eb0aca2b9..b24a9e7ba 100644 --- a/python 2/koans/about_iteration.py +++ b/python 2/koans/about_iteration.py @@ -109,7 +109,7 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): # Files act like a collection of lines file = open("example_file.txt") - def make_upcase(line) : + def make_upcase(line): return line.strip().upper() upcase_lines = map(make_upcase, file.readlines()) self.assertEqual(__, list(upcase_lines)) From 71dd0e579046849fd2c0640832cd18b2acce626a Mon Sep 17 00:00:00 2001 From: Lars Wiegman Date: Wed, 30 Nov 2011 12:15:49 +0100 Subject: [PATCH 005/237] Corrected example of package the koans hierarchy. --- python 2/koans/about_packages.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/python 2/koans/about_packages.py b/python 2/koans/about_packages.py index 245656dfa..a85f3c4c8 100644 --- a/python 2/koans/about_packages.py +++ b/python 2/koans/about_packages.py @@ -14,12 +14,11 @@ # contemplate_koans.py # koans/ # __init__.py -# __init__.py -# about_asserts.py -# about_attribute_access.py -# about_class_attributes.py -# about_classes.py -# ... +# about_asserts.py +# about_attribute_access.py +# about_class_attributes.py +# about_classes.py +# ... # a_package_folder/ # __init__.py # a_module.py From 270bbd6f2692d6803c34889664c2ae53bbfe7f12 Mon Sep 17 00:00:00 2001 From: Lars Wiegman Date: Wed, 30 Nov 2011 12:17:12 +0100 Subject: [PATCH 006/237] Corrected example of the koans package hierarchy. --- python 3/koans/about_packages.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/python 3/koans/about_packages.py b/python 3/koans/about_packages.py index 61f5c5fb5..e68a42d4c 100644 --- a/python 3/koans/about_packages.py +++ b/python 3/koans/about_packages.py @@ -14,12 +14,11 @@ # contemplate_koans.py # koans/ # __init__.py -# __init__.py -# about_asserts.py -# about_attribute_access.py -# about_class_attributes.py -# about_classes.py -# ... +# about_asserts.py +# about_attribute_access.py +# about_class_attributes.py +# about_classes.py +# ... # a_package_folder/ # __init__.py # a_module.py From afb69f5d885d5ff73c8e98f7a611852d4471c070 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Thu, 1 Dec 2011 23:14:01 -0500 Subject: [PATCH 007/237] Fixed bad regex assert in Python 3 flavor of AboutGenerators --- python 3/koans/about_generators.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python 3/koans/about_generators.py b/python 3/koans/about_generators.py index e22b677c7..19790b62b 100644 --- a/python 3/koans/about_generators.py +++ b/python 3/koans/about_generators.py @@ -114,7 +114,9 @@ def test_before_sending_a_value_to_a_generator_next_must_be_called(self): try: generator.send(1+2) except TypeError as ex: - self.assertMatch(__, ex[0]) + ex2 = ex + + self.assertRegexpMatches(ex2.args[0], __) # ------------------------------------------------------------------ From d65e6904712416c663abd2a67dcf2d71153015c2 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Fri, 10 Feb 2012 07:13:13 -0500 Subject: [PATCH 008/237] Merged generators fix from engored and pep8 fixes from sietsebb via bitbucket mirror --- python 2/koans/__init__.py | 2 +- python 2/koans/about_asserts.py | 15 +- python 2/koans/about_attribute_access.py | 128 ++++++++++-------- python 2/koans/about_class_attributes.py | 74 +++++----- python 2/koans/about_classes.py | 108 ++++++++------- python 2/koans/about_control_statements.py | 25 ++-- .../koans/about_decorating_with_classes.py | 23 ++-- .../koans/about_decorating_with_functions.py | 3 +- python 2/koans/about_deleting_objects.py | 12 +- python 2/koans/about_dice_project.py | 8 +- python 2/koans/about_dictionaries.py | 27 ++-- python 2/koans/about_exceptions.py | 1 + python 2/koans/about_extra_credit.py | 2 +- python 2/koans/about_generators.py | 25 ++-- python 2/koans/about_inheritance.py | 9 +- python 2/koans/about_iteration.py | 18 +-- python 2/koans/about_lambdas.py | 1 + python 2/koans/about_list_assignments.py | 1 + python 2/koans/about_lists.py | 3 +- python 2/koans/about_method_bindings.py | 13 +- python 2/koans/about_methods.py | 30 ++-- python 2/koans/about_modules.py | 23 ++-- python 2/koans/about_monkey_patching.py | 12 +- python 2/koans/about_multiple_inheritance.py | 62 ++++----- python 2/koans/about_new_style_classes.py | 8 +- python 2/koans/about_none.py | 11 +- python 2/koans/about_packages.py | 5 +- python 2/koans/about_proxy_object_project.py | 9 +- python 2/koans/about_regex.py | 112 +++++++++------ python 2/koans/about_scope.py | 8 +- python 2/koans/about_scoring_project.py | 38 +++--- python 2/koans/about_sets.py | 19 +-- python 2/koans/about_strings.py | 14 +- python 2/koans/about_triangle_project.py | 1 + python 2/koans/about_triangle_project2.py | 3 +- python 2/koans/about_true_and_false.py | 5 +- python 2/koans/about_tuples.py | 22 +-- python 2/koans/about_with_statements.py | 8 +- python 2/koans/another_local_module.py | 5 +- python 2/koans/jims.py | 1 + python 2/koans/joes.py | 1 + python 2/koans/local_module.py | 3 +- .../koans/local_module_with_all_defined.py | 5 +- python 2/koans/triangle.py | 4 +- python 3/koans/about_classes.py | 110 +++++++-------- 45 files changed, 554 insertions(+), 463 deletions(-) diff --git a/python 2/koans/__init__.py b/python 2/koans/__init__.py index 8d78ec0f1..a11870b25 100644 --- a/python 2/koans/__init__.py +++ b/python 2/koans/__init__.py @@ -1,4 +1,4 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# koans \ No newline at end of file +# koans diff --git a/python 2/koans/about_asserts.py b/python 2/koans/about_asserts.py index 3905498d3..1af8b4e8e 100644 --- a/python 2/koans/about_asserts.py +++ b/python 2/koans/about_asserts.py @@ -3,14 +3,15 @@ from runner.koan import * + class AboutAsserts(Koan): def test_assert_truth(self): """ We shall contemplate truth by testing reality, via 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. @@ -25,7 +26,8 @@ def test_fill_in_values(self): def test_assert_equality(self): """ - To understand reality, we must compare our expectations against reality. + To understand reality, we must compare our expectations against + reality. """ expected_value = __ actual_value = 1 + 1 @@ -37,14 +39,13 @@ def test_a_better_way_of_asserting_equality(self): """ 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): """ Knowing how things really work is half the battle """ - + # This throws an AssertionError exception assert False - diff --git a/python 2/koans/about_attribute_access.py b/python 2/koans/about_attribute_access.py index bcb293255..5e4fef063 100644 --- a/python 2/koans/about_attribute_access.py +++ b/python 2/koans/about_attribute_access.py @@ -7,20 +7,21 @@ 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(__, type(exception).__name__) self.assertMatch(__, exception[0]) - + def test_calling_getattribute_causes_an_attribute_error(self): typical = self.TypicalObject() @@ -28,109 +29,114 @@ def test_calling_getattribute_causes_an_attribute_error(self): 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" - + 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 - + 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_changes_to_the_getattribute_implementation_affects_getattr_function(self): + # + + 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). \ + 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 + stack_depth = 0 class RecursiveCatcher(object): def __init__(self): global stack_depth - stack_depth = 0 + stack_depth = 0 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__) - - global stack_depth # We need something that is outside the scope of this class + #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 - if stack_depth<=10: # to prevent a stack overflow + 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) + # Oops! We just accessed an attribute: no_of_getattribute_calls # Guess what happens when self.no_of_getattribute_calls is - # accessed? + # accessed? # Using 'object' directly because using super() here will also # trigger a __getattribute__() call. - return object.__getattribute__(self, attr_name) - + 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 + class DuffObject(object): + pass def __init__(self): self.no_of_getattr_calls = 0 @@ -138,7 +144,7 @@ def __init__(self): def __getattr__(self, attr_name): self.no_of_getattr_calls += 1 return self.DuffObject - + def my_method(self): pass @@ -147,62 +153,64 @@ def test_getattr_ignores_known_attributes(self): 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(__, type(catcher.give_me_duff_or_give_me_death()).__name__) - + self.assertEqual(__, catcher.no_of_getattr_calls) - + # ------------------------------------------------------------------ class PossessiveSetter(object): def __setattr__(self, attr_name, value): - new_attr_name = attr_name - + 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 + new_attr_name = "a_" + new_attr_name - object.__setattr__(self, new_attr_name, value) + 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) + + self.assertEqual(__, fanboy.a_pie) prefix = '__' - self.assertEqual("The Laminator, issue #1", getattr(fanboy, prefix + '_comic')) + self.assertEqual( + "The Laminator, issue #1", + getattr(fanboy, prefix + '_comic')) # ------------------------------------------------------------------ - class ScarySetter(object): + 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 - + 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() diff --git a/python 2/koans/about_class_attributes.py b/python 2/koans/about_class_attributes.py index dac8f59f4..d48211054 100644 --- a/python 2/koans/about_class_attributes.py +++ b/python 2/koans/about_class_attributes.py @@ -7,44 +7,45 @@ 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 it Python 3. - + fido = self.Dog() self.assertEqual(__, isinstance(fido, object)) def test_classes_are_types(self): - self.assertEqual(__, self.Dog.__class__ == type) - + 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() + 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' - + fido.wag = lambda: 'fidos wag' + self.assertEqual(__, fido.wag()) def test_other_objects_are_not_affected_by_these_singleton_functions(self): @@ -52,16 +53,16 @@ def test_other_objects_are_not_affected_by_these_singleton_functions(self): rover = self.Dog() def wag(): - return 'fidos 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' @@ -75,14 +76,14 @@ def growl(self): @staticmethod def bark(): return "staticmethod bark, arg: None" - + @classmethod 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): + 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()) @@ -94,9 +95,9 @@ def test_staticmethods_are_unbound_functions_housed_in_a_class(self): def test_staticmethods_also_overshadow_instance_methods(self): fido = self.Dog2() self.assertMatch(__, fido.bark()) - + # ------------------------------------------------------------------ - + class Dog3(object): def __init__(self): self._name = None @@ -106,40 +107,41 @@ def get_name_from_instance(self): def set_name_from_instance(self, name): self._name = name - - @classmethod + + @classmethod def get_name(cls): return cls._name - @classmethod + @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) - + 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' @@ -149,15 +151,15 @@ def a_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_heres_an_easy_way_to_explicitly_call_class_methods_from_instance_methods(self): + + 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/python 2/koans/about_classes.py b/python 2/koans/about_classes.py index d23b43f00..564554bba 100644 --- a/python 2/koans/about_classes.py +++ b/python 2/koans/about_classes.py @@ -3,76 +3,76 @@ 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_parenthesis(self): + + def test_instances_of_classes_can_be_created_adding_parentheses(self): fido = self.Dog() self.assertEqual(__, type(fido).__name__) - + def test_classes_have_docstrings(self): self.assertMatch(__, self.Dog.__doc__) - + # ------------------------------------------------------------------ - - class Dog2(object): - def __init__(self): + + 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): + + 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): + 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 - + + self.assertEqual(__, fido.get_name()) # access as method + self.assertEqual(__, fido.name) # access as property + # ------------------------------------------------------------------ - + class Dog4(object): - def __init__(self): + def __init__(self): self._name = None @property @@ -82,78 +82,76 @@ def name(self): @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): + 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") + fido = self.Dog5("Fido") self.assertEqual(__, fido.name) - + def test_args_must_match_init(self): - self.assertRaises(___, self.Dog5) # Evaluates self.Dog5() - + self.assertRaises(___, self.Dog5) # Evaluates self.Dog5() + # THINK ABOUT IT: # Why is this so? - + def test_different_objects_have_difference_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): 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! - + + 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] - + seq = [1, 2, 3] + self.assertEqual(__, str(seq)) self.assertEqual(__, repr(seq)) - + self.assertEqual(__, str("STRING")) self.assertEqual(__, repr("STRING")) - diff --git a/python 2/koans/about_control_statements.py b/python 2/koans/about_control_statements.py index 7b3d30c9a..921f0bf7f 100644 --- a/python 2/koans/about_control_statements.py +++ b/python 2/koans/about_control_statements.py @@ -3,6 +3,7 @@ from runner.koan import * + class AboutControlStatements(Koan): def test_if_then_else_statements(self): @@ -17,7 +18,7 @@ def test_if_then_statements(self): if True: result = 'true value' self.assertEqual(__, result) - + def test_while_statement(self): i = 1 result = 1 @@ -25,7 +26,7 @@ def test_while_statement(self): result = result * i i += 1 self.assertEqual(__, result) - + def test_break_statement(self): i = 1 result = 1 @@ -34,39 +35,39 @@ def test_break_statement(self): 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) + 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"), + ("Lancelot", "Blue"), ("Galahad", "I don't know!"), ("Robin", "Blue! I mean Green!"), ("Arthur", "Is that an African Swallow or Amazonian Swallow?") ] result = [] for knight, answer in round_table: - result.append("Contestant: '" + knight + "' Answer: '" + answer + "'") - + 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]) - \ No newline at end of file diff --git a/python 2/koans/about_decorating_with_classes.py b/python 2/koans/about_decorating_with_classes.py index 9617cf01e..bcbc29bc6 100644 --- a/python 2/koans/about_decorating_with_classes.py +++ b/python 2/koans/about_decorating_with_classes.py @@ -4,10 +4,11 @@ from runner.koan import * import functools - + + class AboutDecoratingWithClasses(Koan): def maximum(self, a, b): - if a>b: + if a > b: return a else: return b @@ -18,9 +19,9 @@ def test_partial_that_wrappers_no_args(self): the partial. """ max = functools.partial(self.maximum) - - self.assertEqual(__, max(7,23)) - self.assertEqual(__, max(10,-10)) + + self.assertEqual(__, max(7, 23)) + self.assertEqual(__, max(10, -10)) def test_partial_that_wrappers_first_arg(self): max0 = functools.partial(self.maximum, 0) @@ -28,7 +29,7 @@ def test_partial_that_wrappers_first_arg(self): self.assertEqual(__, max0(-4)) self.assertEqual(__, max0(5)) - def test_partial_that_wrappers_all_args(self): + def test_partial_that_wrappers_all_args(self): always99 = functools.partial(self.maximum, 99, 20) always20 = functools.partial(self.maximum, 9, 20) @@ -50,7 +51,7 @@ def __get__(self, obj, cls=None): return self else: # Decorating a bound method - return functools.partial(self, obj) + return functools.partial(self, obj) @doubleit def foo(self): @@ -70,7 +71,7 @@ def test_decorator_with_no_arguments(self): # ------------------------------------------------------------------ def sound_check(self): - #Note: no decorator + #Note: no decorator return "Testing..." def test_what_a_decorator_is_doing_to_a_function(self): @@ -98,10 +99,11 @@ def decorated_function(*args): @documenter("Increments a value by one. Kind of.") def count_badly(self, num): num += 1 - if num==3: - return 5 + if num == 3: + return 5 else: num + @documenter("Does nothing") def idler(self, num): "Idler" @@ -125,4 +127,3 @@ def homer(self): def test_we_can_chain_decorators(self): self.assertEqual(__, self.homer()) self.assertEqual(__, self.homer.__doc__) - \ No newline at end of file diff --git a/python 2/koans/about_decorating_with_functions.py b/python 2/koans/about_decorating_with_functions.py index 69cd02d93..c38a87faa 100644 --- a/python 2/koans/about_decorating_with_functions.py +++ b/python 2/koans/about_decorating_with_functions.py @@ -15,7 +15,7 @@ def mediocre_song(self): def test_decorators_can_modify_a_function(self): self.assertMatch(__, self.mediocre_song()) - self.assertEqual(__, self.mediocre_song.wow_factor) + 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/python 2/koans/about_deleting_objects.py b/python 2/koans/about_deleting_objects.py index c47583051..ac1da15b8 100644 --- a/python 2/koans/about_deleting_objects.py +++ b/python 2/koans/about_deleting_objects.py @@ -3,6 +3,7 @@ from runner.koan import * + class AboutDeletingObjects(Koan): def test_del_can_remove_slices(self): lottery_nums = [4, 8, 15, 16, 23, 42] @@ -17,10 +18,10 @@ def test_del_can_remove_entire_lists(self): try: win = lottery_nums except Exception as e: - pass + pass self.assertMatch(__, e[0]) - # ==================================================================== + # -------------------------------------------------------------------- class ClosingSale(object): def __init__(self): @@ -54,7 +55,7 @@ def test_del_can_remove_attributes(self): self.assertMatch(__, err_msg1) self.assertMatch(__, err_msg2) - # ==================================================================== + # -------------------------------------------------------------------- class ClintEastwood(object): def __init__(self): @@ -83,8 +84,7 @@ def test_del_works_with_properties(self): del cowboy.name self.assertEqual(__, cowboy.name) - - # ==================================================================== + # -------------------------------------------------------------------- class Prisoner(object): def __init__(self): @@ -110,7 +110,7 @@ def test_another_way_to_make_a_deletable_property(self): del citizen.name self.assertEqual(__, citizen.name) - # ==================================================================== + # -------------------------------------------------------------------- class MoreOrganisedClosingSale(ClosingSale): def __init__(self): diff --git a/python 2/koans/about_dice_project.py b/python 2/koans/about_dice_project.py index f16deed7b..830f4c8df 100644 --- a/python 2/koans/about_dice_project.py +++ b/python 2/koans/about_dice_project.py @@ -5,11 +5,12 @@ import random + class DiceSet(object): def __init__(self): self._values = None - @property + @property def values(self): return self._values @@ -18,6 +19,7 @@ def roll(self, n): # 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() @@ -30,7 +32,9 @@ def test_rolling_the_dice_returns_a_set_of_integers_between_1_and_6(self): 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") + 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() diff --git a/python 2/koans/about_dictionaries.py b/python 2/koans/about_dictionaries.py index 37a21716f..25c13062a 100644 --- a/python 2/koans/about_dictionaries.py +++ b/python 2/koans/about_dictionaries.py @@ -7,6 +7,7 @@ from runner.koan import * + class AboutDictionaries(Koan): def test_creating_dictionaries(self): empty_dict = dict() @@ -15,45 +16,47 @@ def test_creating_dictionaries(self): self.assertEqual(__, len(empty_dict)) def test_dictionary_literals(self): - babel_fish = { 'one': "uno", 'two': "dos" } + babel_fish = {'one': "uno", 'two': "dos"} self.assertEqual(__, len(babel_fish)) def test_accessing_dictionaries(self): - babel_fish = { 'one': "uno", 'two': "dos" } + 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': "uno", 'two': "dos"} babel_fish['one'] = "eins" - expected = { 'two': "dos", 'one': __ } + 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" } + dict1 = {'one': "uno", 'two': "dos"} + dict2 = {'two': "dos", 'one': "uno"} self.assertEqual(____, dict1 == dict2) def test_dictionary_keys(self): - babel_fish = { 'one': "uno", 'two': "dos" } + babel_fish = {'one': "uno", 'two': "dos"} self.assertEqual(__, len(babel_fish.keys())) - self.assertEqual(__, 'one' in babel_fish) - self.assertEqual(__, 'two' in babel_fish) + self.assertEqual(__, 'one' in babel_fish) + self.assertEqual(__, 'two' in babel_fish) self.assertEqual(list, babel_fish.keys().__class__) def test_dictionary_values(self): - babel_fish = { 'one': "uno", 'two': "dos" } + babel_fish = {'one': "uno", 'two': "dos"} self.assertEqual(__, len(babel_fish.values())) self.assertEqual(__, 'uno' in babel_fish.values()) self.assertEqual(__, 'dos' in babel_fish.values()) self.assertEqual(list, babel_fish.values().__class__) 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) + 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/python 2/koans/about_exceptions.py b/python 2/koans/about_exceptions.py index 22d94a7c6..c8bae3b44 100644 --- a/python 2/koans/about_exceptions.py +++ b/python 2/koans/about_exceptions.py @@ -3,6 +3,7 @@ from runner.koan import * + class AboutExceptions(Koan): class MySpecialError(RuntimeError): diff --git a/python 2/koans/about_extra_credit.py b/python 2/koans/about_extra_credit.py index 54baef4ea..f37732154 100644 --- a/python 2/koans/about_extra_credit.py +++ b/python 2/koans/about_extra_credit.py @@ -12,9 +12,9 @@ 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 - \ No newline at end of file diff --git a/python 2/koans/about_generators.py b/python 2/koans/about_generators.py index 9cc11212a..1b10ad90c 100644 --- a/python 2/koans/about_generators.py +++ b/python 2/koans/about_generators.py @@ -10,28 +10,31 @@ 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']) + 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)) + 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.assertRaises(___, num_generator, [0]) # Evaluates num_generator[0] + self.assertRaises(___, num_generator[0]) # Evaluates num_generator[0] self.assertEqual(__, list(num_generator)[0]) # This works though - # 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. + # 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 @@ -71,7 +74,7 @@ def square_me(self, seq): yield x * x def test_generator_method_with_parameter(self): - result = self.square_me(range(2,5)) + result = self.square_me(range(2, 5)) self.assertEqual(__, list(result)) # ------------------------------------------------------------------ @@ -84,7 +87,7 @@ def sum_it(self, seq): yield value def test_generator_keeps_track_of_local_variables(self): - result = self.sum_it(range(2,5)) + result = self.sum_it(range(2, 5)) self.assertEqual(__, list(result)) # ------------------------------------------------------------------ @@ -109,7 +112,7 @@ def test_before_sending_a_value_to_a_generator_next_must_be_called(self): generator = self.generator_with_coroutine() try: - generator.send(1+2) + generator.send(1 + 2) except TypeError as ex: self.assertMatch(__, ex[0]) @@ -137,5 +140,3 @@ def test_send_none_is_equivelant_to_next(self): next(generator) # 'next(generator)' is exactly equivelant to 'generator.send(None)' self.assertEqual(__, generator.send(None)) - - diff --git a/python 2/koans/about_inheritance.py b/python 2/koans/about_inheritance.py index bebb0f93f..774f865f9 100644 --- a/python 2/koans/about_inheritance.py +++ b/python 2/koans/about_inheritance.py @@ -3,9 +3,10 @@ from runner.koan import * + class AboutInheritance(Koan): class Dog(object): - def __init__(self, name): + def __init__(self, name): self._name = name @property @@ -72,11 +73,11 @@ def test_super_works_across_methods(self): # --------------------------------------------------------- class Pug(Dog): - def __init__(self, name): + def __init__(self, name): pass class Greyhound(Dog): - def __init__(self, name): + def __init__(self, name): super(AboutInheritance.Greyhound, self).__init__(name) def test_base_init_does_not_get_called_automatically(self): @@ -88,4 +89,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/python 2/koans/about_iteration.py b/python 2/koans/about_iteration.py index b24a9e7ba..af4598a50 100644 --- a/python 2/koans/about_iteration.py +++ b/python 2/koans/about_iteration.py @@ -3,20 +3,21 @@ from runner.koan import * + class AboutIteration(Koan): def test_iterators_are_a_type(self): - it = iter(range(1,6)) + it = iter(range(1, 6)) fib = 0 for num in it: fib += num - self.assertEqual(__ , fib) + self.assertEqual(__, fib) def test_iterating_with_next(self): - stages = iter(['alpha','beta','gamma']) + stages = iter(['alpha', 'beta', 'gamma']) try: self.assertEqual(__, next(stages)) @@ -73,10 +74,10 @@ def multiply(self, accum, item): return accum * item def test_reduce_will_blow_your_mind(self): - result = reduce(self.add, [2, 3, 4]) + result = reduce(self.add, [2, 3, 4]) self.assertEqual(__, result) - result2 = reduce(self.multiply, [2, 3, 4], 1) + result2 = reduce(self.multiply, [2, 3, 4], 1) self.assertEqual(__, result2) # Extra Credit: @@ -85,7 +86,8 @@ def test_reduce_will_blow_your_mind(self): # ------------------------------------------------------------------ def test_creating_lists_with_list_comprehensions(self): - feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals', 'fruit bats'] + feast = ['lambs', 'sloths', 'orangutans', 'breakfast cereals', + 'fruit bats'] comprehension = [delicacy.capitalize() for delicacy in feast] @@ -93,7 +95,7 @@ def test_creating_lists_with_list_comprehensions(self): self.assertEqual(__, comprehension[2]) def test_use_pass_for_iterations_with_no_body(self): - for num in range(1,5): + for num in range(1, 5): pass self.assertEqual(__, num) @@ -102,7 +104,7 @@ def test_use_pass_for_iterations_with_no_body(self): def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): # Ranges are an iteratable sequence - result = map(self.add_ten, range(1,4)) + result = map(self.add_ten, range(1, 4)) self.assertEqual(__, list(result)) try: diff --git a/python 2/koans/about_lambdas.py b/python 2/koans/about_lambdas.py index 2268e6c65..a6f5611e6 100644 --- a/python 2/koans/about_lambdas.py +++ b/python 2/koans/about_lambdas.py @@ -7,6 +7,7 @@ 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 diff --git a/python 2/koans/about_list_assignments.py b/python 2/koans/about_list_assignments.py index d7e2e8998..812a862ec 100644 --- a/python 2/koans/about_list_assignments.py +++ b/python 2/koans/about_list_assignments.py @@ -7,6 +7,7 @@ from runner.koan import * + class AboutListAssignments(Koan): def test_non_parallel_assignment(self): names = ["John", "Smith"] diff --git a/python 2/koans/about_lists.py b/python 2/koans/about_lists.py index ca998f3f6..6a0a7847e 100644 --- a/python 2/koans/about_lists.py +++ b/python 2/koans/about_lists.py @@ -7,6 +7,7 @@ from runner.koan import * + class AboutLists(Koan): def test_creating_lists(self): empty_list = list() @@ -68,7 +69,7 @@ def test_insertions(self): self.assertEqual(__, knight) knight.insert(0, 'Arthur') - self.assertEqual(__, knight) + self.assertEqual(__, knight) def test_popping_lists(self): stack = [10, 20, 30, 40] diff --git a/python 2/koans/about_method_bindings.py b/python 2/koans/about_method_bindings.py index 8762ff1ee..b82872bb0 100644 --- a/python 2/koans/about_method_bindings.py +++ b/python 2/koans/about_method_bindings.py @@ -3,18 +3,22 @@ from runner.koan import * + def function(): return "pineapple" + def function2(): return "tractor" + class Class(object): def method(self): - return "parrot" + return "parrot" + class AboutMethodBindings(Koan): - def test_methods_are_bound_to_an_object(self): + def test_methods_are_bound_to_an_object(self): obj = Class() self.assertEqual(__, obj.method.im_self == obj) @@ -56,7 +60,7 @@ def test_inner_functions_are_unbound(self): try: cls = function2.get_fruit.im_self except AttributeError as ex: - self.assertMatch(__, ex[0]) + self.assertMatch(__, ex[0]) # ------------------------------------------------------------------ @@ -88,8 +92,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) - diff --git a/python 2/koans/about_methods.py b/python 2/koans/about_methods.py index 08c133286..7279d8c2a 100644 --- a/python 2/koans/about_methods.py +++ b/python 2/koans/about_methods.py @@ -7,12 +7,14 @@ from runner.koan import * -def my_global_function(a,b): + +def my_global_function(a, b): return a + b + class AboutMethods(Koan): def test_calling_an_global_function(self): - self.assertEqual(__, my_global_function(2,3)) + self.assertEqual(__, my_global_function(2, 3)) # NOTE: Wrong number of arguments is not a SYNTAX error, but a # runtime error. @@ -22,15 +24,15 @@ def test_calling_functions_with_wrong_number_of_arguments(self): except Exception as exception: self.assertEqual(__, type(exception).__name__) self.assertMatch( - r'my_global_function\(\) takes exactly 2 arguments \(0 given\)' - , exception[0]) + 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]) + self.assertMatch(__, e[0]) # ------------------------------------------------------------------ @@ -58,7 +60,7 @@ def method_with_var_args(self, *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(('one', ), self.method_with_var_args('one')) self.assertEqual(__, self.method_with_var_args('one', 'two')) # ------------------------------------------------------------------ @@ -70,13 +72,13 @@ 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)) + 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)) + self.assertEqual(__, self.function_with_the_same_name(3, 4)) # ------------------------------------------------------------------ @@ -111,7 +113,8 @@ def test_pass_does_nothing_at_all(self): # ------------------------------------------------------------------ - def one_line_method(self): return 'Madagascar' + def one_line_method(self): + return 'Madagascar' def test_no_indentation_required_for_one_line_statement_bodies(self): self.assertEqual(__, self.one_line_method()) @@ -136,7 +139,7 @@ def _tail(self): return "wagging" def __password(self): - return 'password' # Genius! + return 'password' # Genius! def test_calling_methods_in_other_objects(self): rover = self.Dog() @@ -148,11 +151,13 @@ def test_private_access_is_implied_but_not_enforced(self): # This is a little rude, but legal self.assertEqual(__, rover._tail()) - def test_attributes_with_double_underscore_prefixes_are_subject_to_name_mangling(self): + 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() + password = rover.__password() except Exception as ex: self.assertEqual(__, type(ex).__name__) @@ -161,4 +166,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/python 2/koans/about_modules.py b/python 2/koans/about_modules.py index 37aad480a..a375229a7 100644 --- a/python 2/koans/about_modules.py +++ b/python 2/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): - import local_module # local_module.py + 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 other_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() @@ -51,18 +53,17 @@ def test_modules_hide_attributes_prefixed_by_underscores(self): self.assertMatch(__, ex[0]) 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_modules_XallX_statement_limits_what_wildcards_will_match(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) diff --git a/python 2/koans/about_monkey_patching.py b/python 2/koans/about_monkey_patching.py index c88f85bf4..d5aec7c12 100644 --- a/python 2/koans/about_monkey_patching.py +++ b/python 2/koans/about_monkey_patching.py @@ -7,6 +7,7 @@ from runner.koan import * + class AboutMonkeyPatching(Koan): class Dog(object): def bark(self): @@ -18,9 +19,11 @@ def test_as_defined_dogs_do_bark(self): # ------------------------------------------------------------------ - # Add a new method to an existing class. + # Add a new method to an existing class. def test_after_patching_dogs_can_both_wag_and_bark(self): - def wag(self): return "HAPPY" + def wag(self): + return "HAPPY" + self.Dog.wag = wag fido = self.Dog() @@ -37,12 +40,11 @@ def test_most_built_in_classes_cannot_be_monkey_patched(self): # ------------------------------------------------------------------ - class MyInt(int): pass + 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()) - - \ No newline at end of file diff --git a/python 2/koans/about_multiple_inheritance.py b/python 2/koans/about_multiple_inheritance.py index 3b99a20bd..b204c85c5 100644 --- a/python 2/koans/about_multiple_inheritance.py +++ b/python 2/koans/about_multiple_inheritance.py @@ -7,6 +7,7 @@ from runner.koan import * + class AboutMultipleInheritance(Koan): class Nameable(object): def __init__(self): @@ -14,20 +15,20 @@ def __init__(self): def set_name(self, new_name): self._name = new_name - + def here(self): return "In Nameable class" - - class Animal(object): + + 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__() @@ -36,13 +37,13 @@ def __init__(self): @property def name(self): return self._name - + def speak(self): return "OINK" - + def color(self): - return 'pink' - + return 'pink' + def here(self): return "In Pig class" @@ -68,23 +69,23 @@ 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: + + # + # Hierarchy: # Animal - # / \ - # Pig Spider Nameable + # / \ + # Pig Spider Nameable # \ | / # Spiderpig - # + # # ------------------------------------------------------------------ - + def test_normal_methods_are_available_in_the_object(self): jeff = self.Spiderpig() self.assertMatch(__, jeff.speak()) @@ -96,14 +97,14 @@ def test_base_class_methods_are_also_available_in_the_object(self): 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()) @@ -117,25 +118,24 @@ 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__) + 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) + + 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/python 2/koans/about_new_style_classes.py b/python 2/koans/about_new_style_classes.py index 9ecd47b97..173acb686 100644 --- a/python 2/koans/about_new_style_classes.py +++ b/python 2/koans/about_new_style_classes.py @@ -3,6 +3,7 @@ from runner.koan import * + class AboutNewStyleClasses(Koan): class OldStyleClass: "An old style class" @@ -26,7 +27,8 @@ def test_new_style_classes_have_more_attributes(self): self.assertEqual(__, self.OldStyleClass.__module__) self.assertEqual(__, len(dir(self.NewStyleClass))) - # To examine the available attributes, run 'dir()' + # To examine the available attributes, run + # 'dir()' # from a python console # ------------------------------------------------------------------ @@ -44,7 +46,9 @@ 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(__, type(self.NewStyleClass).__name__) - self.assertEqual(__, type(self.NewStyleClass) == self.NewStyleClass.__class__) + self.assertEqual( + __, + type(self.NewStyleClass) == self.NewStyleClass.__class__) # ------------------------------------------------------------------ diff --git a/python 2/koans/about_none.py b/python 2/koans/about_none.py index f8418f775..beeab8274 100644 --- a/python 2/koans/about_none.py +++ b/python 2/koans/about_none.py @@ -7,6 +7,7 @@ from runner.koan import * + class AboutNone(Koan): def test_none_is_an_object(self): @@ -17,14 +18,16 @@ 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_on_None(self): + 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. + 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 + Don't worry about what 'try' and 'except' do, we'll talk about + this later """ try: None.some_method_none_does_not_know_about() @@ -42,5 +45,3 @@ def test_none_is_distinct(self): """ self.assertEqual(____, None is not 0) self.assertEqual(____, None is not False) - - diff --git a/python 2/koans/about_packages.py b/python 2/koans/about_packages.py index a85f3c4c8..30d618c49 100644 --- a/python 2/koans/about_packages.py +++ b/python 2/koans/about_packages.py @@ -18,11 +18,12 @@ # 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 @@ -60,7 +61,7 @@ def test_use_absolute_imports_to_import_upper_level_modules(self): # 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_folder_using_an_absolute_path(self): + 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 diff --git a/python 2/koans/about_proxy_object_project.py b/python 2/koans/about_proxy_object_project.py index 7a8ca80ae..27b89363f 100644 --- a/python 2/koans/about_proxy_object_project.py +++ b/python 2/koans/about_proxy_object_project.py @@ -18,6 +18,7 @@ from runner.koan import * + class Proxy(object): def __init__(self, target_object): # WRITE CODE HERE @@ -25,7 +26,8 @@ def __init__(self, target_object): #initialize '_obj' attribute last. Trust me on this! self._obj = target_object - # WRITE CODE HERE + # WRITE CODE HERE + # The proxy object should pass the following Koan: # @@ -64,7 +66,6 @@ def test_proxy_handles_invalid_messages(self): self.assertEqual(AttributeError, type(ex)) - def test_proxy_reports_methods_have_been_called(self): tv = Proxy(Television()) @@ -97,6 +98,7 @@ def test_proxy_can_record_more_than_just_tv_objects(self): 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. @@ -113,7 +115,7 @@ def channel(self): @channel.setter def channel(self, value): - self._channel = value + self._channel = value def power(self): if self._power == 'on': @@ -124,6 +126,7 @@ def power(self): 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): diff --git a/python 2/koans/about_regex.py b/python 2/koans/about_regex.py index 13db11a82..95678d2eb 100755 --- a/python 2/koans/about_regex.py +++ b/python 2/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 extression 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 extression 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, 20), __) self.assertEqual(re.findall("felix", string, 10), __) - + 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" \ @@ -83,17 +102,22 @@ def test_matching_set_character(self): + "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 + + "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) + self.assertEquals( + len(re.findall(change_this_search_string, string)), + 3) def test_anything_but_matching(self): """ - Lesson 2 Using character set ranges - Occsionally, 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" \ @@ -107,10 +131,10 @@ def test_anything_but_matching(self): + "na1.xls\n" \ + "na2.xls\n" \ + "sa1.xls\n" \ - + "ca1.xls" + + "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']) diff --git a/python 2/koans/about_scope.py b/python 2/koans/about_scope.py index 9fd7501e3..f290e6319 100644 --- a/python 2/koans/about_scope.py +++ b/python 2/koans/about_scope.py @@ -3,10 +3,11 @@ from runner.koan import * -import jims +import jims import joes -counter = 0 # Global +counter = 0 # Global + class AboutScope(Koan): # @@ -19,7 +20,7 @@ def test_dog_is_not_available_in_the_current_scope(self): try: fido = Dog() except Exception as ex: - self.assertMatch(__, ex[0]) + self.assertMatch(__, ex[0]) def test_you_can_reference_nested_classes_using_the_scope_operator(self): fido = jims.Dog() @@ -89,4 +90,3 @@ def test_incrementing_with_global_counter(self): def test_global_attributes_can_be_created_in_the_middle_of_a_class(self): self.assertEqual(__, deadly_bingo[5]) - \ No newline at end of file diff --git a/python 2/koans/about_scoring_project.py b/python 2/koans/about_scoring_project.py index 393af55b5..8b2503e37 100644 --- a/python 2/koans/about_scoring_project.py +++ b/python 2/koans/about_scoring_project.py @@ -3,6 +3,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 # score of a single roll of the dice. @@ -10,7 +11,7 @@ # 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). # @@ -23,10 +24,10 @@ # # 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 +# 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: # @@ -36,6 +37,7 @@ 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([])) @@ -47,26 +49,26 @@ 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])) + 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])) + 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])) + 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])) + 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])) + 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])) \ No newline at end of file + self.assertEqual(300, score([1, 2, 2, 2])) + self.assertEqual(350, score([1, 5, 2, 2, 2])) diff --git a/python 2/koans/about_sets.py b/python 2/koans/about_sets.py index cf207b031..277cd1c46 100644 --- a/python 2/koans/about_sets.py +++ b/python 2/koans/about_sets.py @@ -3,9 +3,11 @@ from runner.koan import * + class AboutSets(Koan): def test_sets_make_keep_lists_unique(self): - highlanders = ['MacLeod', 'Ramirez', 'MacLeod', 'Matunas', 'MacLeod', 'Malcolm', 'MacLeod'] + highlanders = ['MacLeod', 'Ramirez', 'MacLeod', 'Matunas', + 'MacLeod', 'Malcolm', 'MacLeod'] there_can_only_be_only_one = set(highlanders) @@ -17,7 +19,6 @@ def test_sets_are_unordered(self): def test_convert_the_set_into_a_list_to_sort_it(self): self.assertEqual(__, sorted(set('13245'))) - # ------------------------------------------------------------------ def chars_in(self, a_set): @@ -27,19 +28,19 @@ def test_set_have_arithmetic_operators(self): good_guy = set('macleod') bad_guy = set('mutunas') - self.assertEqual(__, self.chars_in( good_guy - bad_guy) ) - self.assertEqual(__, self.chars_in( good_guy | bad_guy )) - self.assertEqual(__, self.chars_in( good_guy & bad_guy )) - self.assertEqual(__, self.chars_in( good_guy ^ bad_guy )) + self.assertEqual(__, self.chars_in(good_guy - bad_guy)) + self.assertEqual(__, self.chars_in(good_guy | bad_guy)) + self.assertEqual(__, self.chars_in(good_guy & bad_guy)) + self.assertEqual(__, self.chars_in(good_guy ^ bad_guy)) # ------------------------------------------------------------------ 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') ) + 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').issubset(set('cherry cake'))) self.assertEqual(__, set('cake') > set('pie')) diff --git a/python 2/koans/about_strings.py b/python 2/koans/about_strings.py index 8b6ed0def..d978c5c10 100644 --- a/python 2/koans/about_strings.py +++ b/python 2/koans/about_strings.py @@ -3,6 +3,7 @@ from runner.koan import * + class AboutStrings(Koan): def test_double_quoted_strings_are_strings(self): @@ -55,7 +56,7 @@ def test_triple_quoted_strings_need_less_escaping(self): b = """Hello "world".""" self.assertEqual(__, (a == b)) - def but_you_still_have_to_be_careful_at_the_end_of_a_triple_quoted_string(self): + def but_quotes_at_the_end_of_a_triple_quoted_string_are_still_tricky(self): string = """Hello "world\"""" def test_plus_concatenates_strings(self): @@ -105,7 +106,7 @@ def test_formatted_values_con_be_shown_in_any_order_or_be_repeated(self): self.assertEqual(__, string) def test_any_python_expression_may_be_interpolated(self): - import math # import a standard python module with math functions + 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), \ @@ -121,7 +122,7 @@ def test_you_can_get_a_single_character_from_a_string(self): self.assertEqual(__, string[1]) def test_single_characters_can_be_represented_by_integers(self): - self.assertEqual(__, ord('a')) + self.assertEqual(__, ord('a')) self.assertEqual(__, ord('b') == (ord('a') + 1)) def test_strings_can_be_split(self): @@ -130,7 +131,7 @@ def test_strings_can_be_split(self): self.assertEqual([__, __, __], words) def test_strings_can_be_split_with_different_patterns(self): - import re #import python regular expression library + import re # import python regular expression library string = "the,rain;in,spain" pattern = re.compile(',|;') @@ -139,7 +140,8 @@ def test_strings_can_be_split_with_different_patterns(self): self.assertEqual([__, __, __, __], words) - # Pattern is a Python regular expression pattern which matches ',' or ';' + # `pattern` is a Python regular expression pattern which matches + # ',' or ';' def test_raw_strings_do_not_interpret_escape_characters(self): string = r'\n' @@ -147,7 +149,7 @@ def test_raw_strings_do_not_interpret_escape_characters(self): self.assertEqual(__, string) self.assertEqual(__, len(string)) - # Useful in regular expressions, file paths, URLs, etc. + # Useful in regular expressions, file paths, URLs, etc. def test_strings_can_be_joined(self): words = ["Now", "is", "the", "time"] diff --git a/python 2/koans/about_triangle_project.py b/python 2/koans/about_triangle_project.py index 6c254768f..6f3abc909 100644 --- a/python 2/koans/about_triangle_project.py +++ b/python 2/koans/about_triangle_project.py @@ -6,6 +6,7 @@ # 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)) diff --git a/python 2/koans/about_triangle_project2.py b/python 2/koans/about_triangle_project2.py index ffff4ac00..0afe0724b 100644 --- a/python 2/koans/about_triangle_project2.py +++ b/python 2/koans/about_triangle_project2.py @@ -6,6 +6,7 @@ # 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. @@ -15,4 +16,4 @@ def test_illegal_triangles_throw_exceptions(self): self.assertRaises(TriangleError, triangle, 3, 4, -5) self.assertRaises(TriangleError, triangle, 1, 1, 3) - self.assertRaises(TriangleError, triangle, 2, 4, 2) + self.assertRaises(TriangleError, triangle, 2, 4, 2) diff --git a/python 2/koans/about_true_and_false.py b/python 2/koans/about_true_and_false.py index 9b6639641..e29823cb6 100644 --- a/python 2/koans/about_true_and_false.py +++ b/python 2/koans/about_true_and_false.py @@ -3,6 +3,7 @@ from runner.koan import * + class AboutTrueAndFalse(Koan): def truth_value(self, condition): if condition: @@ -34,5 +35,7 @@ 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("Python is named after Monty Python")) self.assertEqual(__, self.truth_value(' ')) diff --git a/python 2/koans/about_tuples.py b/python 2/koans/about_tuples.py index ae5e614e2..5773c0ad6 100644 --- a/python 2/koans/about_tuples.py +++ b/python 2/koans/about_tuples.py @@ -3,33 +3,34 @@ from runner.koan import * + class AboutTuples(Koan): def test_creating_a_tuple(self): - count_of_three = (1, 2, 5) + 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) + 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) + 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. + # 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) + count_of_three = (1, 2, 5) list_count = list(count_of_three) list_count.append("boom") @@ -46,8 +47,8 @@ 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 + self.assertEqual(__, ()) + self.assertEqual(__, tuple()) # Sometimes less confusing def test_tuples_can_be_embedded(self): lat = (37, 14, 6, 'N') @@ -61,10 +62,9 @@ def test_tuples_are_good_for_representing_records(self): ("Stargate B", (41, 10, 43.92, 'N'), (1, 49, 34.29, 'W')), ] - locations.append( ("Cthulu", (26, 40, 1, 'N'), (70, 45, 7, '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/python 2/koans/about_with_statements.py b/python 2/koans/about_with_statements.py index bb4db2ddf..df0c5e3cc 100644 --- a/python 2/koans/about_with_statements.py +++ b/python 2/koans/about_with_statements.py @@ -7,7 +7,8 @@ from runner.koan import * -import re # For regular expression string comparisons +import re # For regular expression string comparisons + class AboutWithStatements(Koan): def count_lines(self, file_name): @@ -30,7 +31,8 @@ def find_line(self, file_name): try: for line in file.readlines(): match = re.search('e', line) - if match: return line + if match: + return line finally: if file: file.close() @@ -100,7 +102,7 @@ def count_lines3(self, file_name): with open(file_name) as file: count = 0 for line in file.readlines(): - count += 1 + count += 1 return count def test_open_already_has_its_own_built_in_context_manager(self): diff --git a/python 2/koans/another_local_module.py b/python 2/koans/another_local_module.py index c7358947b..2b2abf2d4 100644 --- a/python 2/koans/another_local_module.py +++ b/python 2/koans/another_local_module.py @@ -1,17 +1,20 @@ #!/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" \ No newline at end of file + return "Mr Anonymous" diff --git a/python 2/koans/jims.py b/python 2/koans/jims.py index 06a6f0d13..761882f13 100644 --- a/python 2/koans/jims.py +++ b/python 2/koans/jims.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- + class Dog(object): def identify(self): return "jims dog" diff --git a/python 2/koans/joes.py b/python 2/koans/joes.py index 491de31ff..7cab94866 100644 --- a/python 2/koans/joes.py +++ b/python 2/koans/joes.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- + class Dog(object): def identify(self): return "joes dog" diff --git a/python 2/koans/local_module.py b/python 2/koans/local_module.py index 1d9195800..762a55a5e 100644 --- a/python 2/koans/local_module.py +++ b/python 2/koans/local_module.py @@ -1,9 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- + class Duck(object): def __init__(self): - self._password = 'password' # Genius! + self._password = 'password' # Genius! @property def name(self): diff --git a/python 2/koans/local_module_with_all_defined.py b/python 2/koans/local_module_with_all_defined.py index 6ac36b2a2..90488cd60 100644 --- a/python 2/koans/local_module_with_all_defined.py +++ b/python 2/koans/local_module_with_all_defined.py @@ -2,20 +2,23 @@ # -*- coding: utf-8 -*- __all__ = ( - 'Goat', + '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): diff --git a/python 2/koans/triangle.py b/python 2/koans/triangle.py index b71c2dd77..8f3faeed3 100644 --- a/python 2/koans/triangle.py +++ b/python 2/koans/triangle.py @@ -3,7 +3,8 @@ # Triangle Project Code. -# Triangle analyzes the lengths of the sides of a triangle + +# 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: @@ -20,6 +21,7 @@ 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/python 3/koans/about_classes.py b/python 3/koans/about_classes.py index fdc67e17a..2adbd5801 100644 --- a/python 3/koans/about_classes.py +++ b/python 3/koans/about_classes.py @@ -3,79 +3,79 @@ from runner.koan import * + class AboutClasses(Koan): class Dog: "Dogs need regular walkies. Never, ever let them drive." - - def test_instances_of_classes_can_be_created_adding_parenthesis(self): + + def test_instances_of_classes_can_be_created_adding_parentheses(self): fido = self.Dog() self.assertEqual(__, type(fido).__name__) - + def test_classes_have_docstrings(self): self.assertRegexpMatches(self.Dog.__doc__, __) - + # ------------------------------------------------------------------ - - class Dog2: - def __init__(self): + + class Dog2: + 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): + + 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: - def __init__(self): + 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") - + # access as method self.assertEqual(__, fido.get_name()) - + # access as property self.assertEqual(__, fido.name) - + # ------------------------------------------------------------------ - + class Dog4: - def __init__(self): + def __init__(self): self._name = None @property @@ -85,79 +85,79 @@ def name(self): @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: - def __init__(self, initial_name): + 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") + fido = self.Dog5("Fido") self.assertEqual(__, fido.name) - + def test_args_must_match_init(self): - with self.assertRaises(___): self.Dog5() - + with self.assertRaises(___): + self.Dog5() + # THINK ABOUT IT: # Why is this so? - + def test_different_objects_have_difference_instance_variables(self): fido = self.Dog5("Fido") rover = self.Dog5("Rover") - + self.assertEqual(__, rover.name == fido.name) - + # ------------------------------------------------------------------ - + class Dog6: def __init__(self, initial_name): self._name = initial_name - + def get_self(self): return self - + def __str__(self): 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! - + + 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] - + seq = [1, 2, 3] + self.assertEqual(__, str(seq)) self.assertEqual(__, repr(seq)) - + self.assertEqual(__, str("STRING")) self.assertEqual(__, repr("STRING")) - From 0042d792ebc691db3023c576f52efaa28bf4a3bb Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sat, 17 Mar 2012 13:11:54 -0400 Subject: [PATCH 009/237] Merge from bitbucket mirror: 'gpiancastelli - Fix for issue #21 and some other tweaks' --- .../koans/about_decorating_with_classes.py | 2 +- python 2/koans/about_iteration.py | 29 ++++++------ python 2/koans/about_with_statements.py | 44 +++++++++++-------- .../koans/about_decorating_with_classes.py | 4 +- python 3/koans/about_iteration.py | 27 ++++++------ python 3/koans/about_with_statements.py | 35 +++++++++------ 6 files changed, 78 insertions(+), 63 deletions(-) diff --git a/python 2/koans/about_decorating_with_classes.py b/python 2/koans/about_decorating_with_classes.py index bcbc29bc6..c892b31ac 100644 --- a/python 2/koans/about_decorating_with_classes.py +++ b/python 2/koans/about_decorating_with_classes.py @@ -102,7 +102,7 @@ def count_badly(self, num): if num == 3: return 5 else: - num + return num @documenter("Does nothing") def idler(self, num): diff --git a/python 2/koans/about_iteration.py b/python 2/koans/about_iteration.py index af4598a50..79604a696 100644 --- a/python 2/koans/about_iteration.py +++ b/python 2/koans/about_iteration.py @@ -108,18 +108,17 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): self.assertEqual(__, list(result)) try: - # Files act like a collection of lines - file = open("example_file.txt") - - def make_upcase(line): - return line.strip().upper() - upcase_lines = map(make_upcase, file.readlines()) - self.assertEqual(__, list(upcase_lines)) - - # NOTE: You can create your own collections that work with each, - # map, select, etc. - finally: - # Arg, this is ugly. - # We will figure out how to fix this later. - if file: - file.close() + 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/python 2/koans/about_with_statements.py b/python 2/koans/about_with_statements.py index df0c5e3cc..562ba128a 100644 --- a/python 2/koans/about_with_statements.py +++ b/python 2/koans/about_with_statements.py @@ -12,14 +12,18 @@ class AboutWithStatements(Koan): def count_lines(self, file_name): - file = open(file_name) try: - count = 0 - for line in file.readlines(): - count += 1 - return count - finally: - if file: file.close() + f = open(file_name) + try: + count = 0 + for line in f.readlines(): + count += 1 + return count + finally: + f.close() + except IOError: + # should never happen + self.fail() def test_counting_lines(self): self.assertEqual(__, self.count_lines("example_file.txt")) @@ -27,14 +31,18 @@ def test_counting_lines(self): # ------------------------------------------------------------------ def find_line(self, file_name): - file = open(file_name) try: - for line in file.readlines(): - match = re.search('e', line) - if match: - return line - finally: - if file: file.close() + 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")) @@ -77,9 +85,9 @@ def __exit__(self, cls, value, tb): # Now we write: def count_lines2(self, file_name): - with self.FileContextManager(file_name) as file: + with self.FileContextManager(file_name) as f: count = 0 - for line in file.readlines(): + for line in f.readlines(): count += 1 return count @@ -99,9 +107,9 @@ def test_finding_lines2(self): # ------------------------------------------------------------------ def count_lines3(self, file_name): - with open(file_name) as file: + with open(file_name) as f: count = 0 - for line in file.readlines(): + for line in f.readlines(): count += 1 return count diff --git a/python 3/koans/about_decorating_with_classes.py b/python 3/koans/about_decorating_with_classes.py index 358488c4c..3466bc1d4 100644 --- a/python 3/koans/about_decorating_with_classes.py +++ b/python 3/koans/about_decorating_with_classes.py @@ -101,7 +101,7 @@ def count_badly(self, num): if num==3: return 5 else: - num + return num @documenter("Does nothing") def idler(self, num): "Idler" @@ -125,4 +125,4 @@ def homer(self): def test_we_can_chain_decorators(self): self.assertEqual(__, self.homer()) self.assertEqual(__, self.homer.__doc__) - \ No newline at end of file + diff --git a/python 3/koans/about_iteration.py b/python 3/koans/about_iteration.py index d9d1e5ca2..40cc751f4 100644 --- a/python 3/koans/about_iteration.py +++ b/python 3/koans/about_iteration.py @@ -129,18 +129,17 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): self.assertEqual(__, list(result)) try: - # Files act like a collection of lines file = open("example_file.txt") - - def make_upcase(line): - return line.strip().upper() - upcase_lines = map(make_upcase, file.readlines()) - self.assertEqual(__, list(upcase_lines)) - - # NOTE: You can create your own collections that work with each, - # map, select, etc. - finally: - # Arg, this is ugly. - # We will figure out how to fix this later. - if file: - file.close() \ No newline at end of file + + 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() diff --git a/python 3/koans/about_with_statements.py b/python 3/koans/about_with_statements.py index 66f0a912e..9dd0a5f49 100644 --- a/python 3/koans/about_with_statements.py +++ b/python 3/koans/about_with_statements.py @@ -11,14 +11,18 @@ class AboutWithStatements(Koan): def count_lines(self, file_name): - file = open(file_name) try: - count = 0 - for line in file.readlines(): - count += 1 - return count - finally: - if file: file.close() + file = open(file_name) + try: + count = 0 + for line in file.readlines(): + count += 1 + return count + finally: + file.close() + except IOError: + # should never happen + self.fail() def test_counting_lines(self): self.assertEqual(__, self.count_lines("example_file.txt")) @@ -26,13 +30,18 @@ def test_counting_lines(self): # ------------------------------------------------------------------ def find_line(self, file_name): - file = open(file_name) try: - for line in file.readlines(): - match = re.search('e', line) - if match: return line - finally: - if file: file.close() + file = open(file_name) + try: + for line in file.readlines(): + match = re.search('e', line) + if match: + return line + finally: + file.close() + except IOError: + # should never happen + self.fail() def test_finding_lines(self): self.assertEqual(__, self.find_line("example_file.txt")) From 79ca184af5d64d7051851635707d55253f91efc1 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sat, 17 Mar 2012 15:21:50 -0400 Subject: [PATCH 010/237] Merge from bitbucket mirror: 'gpiancastelli - Fix for issue #21 and some other tweaks' --- .../koans/about_decorating_with_classes.py | 2 +- python 2/koans/about_iteration.py | 29 ++++++------ python 2/koans/about_with_statements.py | 44 +++++++++++-------- .../koans/about_decorating_with_classes.py | 4 +- python 3/koans/about_iteration.py | 27 ++++++------ python 3/koans/about_with_statements.py | 35 +++++++++------ 6 files changed, 78 insertions(+), 63 deletions(-) diff --git a/python 2/koans/about_decorating_with_classes.py b/python 2/koans/about_decorating_with_classes.py index bcbc29bc6..c892b31ac 100644 --- a/python 2/koans/about_decorating_with_classes.py +++ b/python 2/koans/about_decorating_with_classes.py @@ -102,7 +102,7 @@ def count_badly(self, num): if num == 3: return 5 else: - num + return num @documenter("Does nothing") def idler(self, num): diff --git a/python 2/koans/about_iteration.py b/python 2/koans/about_iteration.py index af4598a50..79604a696 100644 --- a/python 2/koans/about_iteration.py +++ b/python 2/koans/about_iteration.py @@ -108,18 +108,17 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): self.assertEqual(__, list(result)) try: - # Files act like a collection of lines - file = open("example_file.txt") - - def make_upcase(line): - return line.strip().upper() - upcase_lines = map(make_upcase, file.readlines()) - self.assertEqual(__, list(upcase_lines)) - - # NOTE: You can create your own collections that work with each, - # map, select, etc. - finally: - # Arg, this is ugly. - # We will figure out how to fix this later. - if file: - file.close() + 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/python 2/koans/about_with_statements.py b/python 2/koans/about_with_statements.py index df0c5e3cc..562ba128a 100644 --- a/python 2/koans/about_with_statements.py +++ b/python 2/koans/about_with_statements.py @@ -12,14 +12,18 @@ class AboutWithStatements(Koan): def count_lines(self, file_name): - file = open(file_name) try: - count = 0 - for line in file.readlines(): - count += 1 - return count - finally: - if file: file.close() + f = open(file_name) + try: + count = 0 + for line in f.readlines(): + count += 1 + return count + finally: + f.close() + except IOError: + # should never happen + self.fail() def test_counting_lines(self): self.assertEqual(__, self.count_lines("example_file.txt")) @@ -27,14 +31,18 @@ def test_counting_lines(self): # ------------------------------------------------------------------ def find_line(self, file_name): - file = open(file_name) try: - for line in file.readlines(): - match = re.search('e', line) - if match: - return line - finally: - if file: file.close() + 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")) @@ -77,9 +85,9 @@ def __exit__(self, cls, value, tb): # Now we write: def count_lines2(self, file_name): - with self.FileContextManager(file_name) as file: + with self.FileContextManager(file_name) as f: count = 0 - for line in file.readlines(): + for line in f.readlines(): count += 1 return count @@ -99,9 +107,9 @@ def test_finding_lines2(self): # ------------------------------------------------------------------ def count_lines3(self, file_name): - with open(file_name) as file: + with open(file_name) as f: count = 0 - for line in file.readlines(): + for line in f.readlines(): count += 1 return count diff --git a/python 3/koans/about_decorating_with_classes.py b/python 3/koans/about_decorating_with_classes.py index 358488c4c..3466bc1d4 100644 --- a/python 3/koans/about_decorating_with_classes.py +++ b/python 3/koans/about_decorating_with_classes.py @@ -101,7 +101,7 @@ def count_badly(self, num): if num==3: return 5 else: - num + return num @documenter("Does nothing") def idler(self, num): "Idler" @@ -125,4 +125,4 @@ def homer(self): def test_we_can_chain_decorators(self): self.assertEqual(__, self.homer()) self.assertEqual(__, self.homer.__doc__) - \ No newline at end of file + diff --git a/python 3/koans/about_iteration.py b/python 3/koans/about_iteration.py index d9d1e5ca2..40cc751f4 100644 --- a/python 3/koans/about_iteration.py +++ b/python 3/koans/about_iteration.py @@ -129,18 +129,17 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): self.assertEqual(__, list(result)) try: - # Files act like a collection of lines file = open("example_file.txt") - - def make_upcase(line): - return line.strip().upper() - upcase_lines = map(make_upcase, file.readlines()) - self.assertEqual(__, list(upcase_lines)) - - # NOTE: You can create your own collections that work with each, - # map, select, etc. - finally: - # Arg, this is ugly. - # We will figure out how to fix this later. - if file: - file.close() \ No newline at end of file + + 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() diff --git a/python 3/koans/about_with_statements.py b/python 3/koans/about_with_statements.py index 66f0a912e..9dd0a5f49 100644 --- a/python 3/koans/about_with_statements.py +++ b/python 3/koans/about_with_statements.py @@ -11,14 +11,18 @@ class AboutWithStatements(Koan): def count_lines(self, file_name): - file = open(file_name) try: - count = 0 - for line in file.readlines(): - count += 1 - return count - finally: - if file: file.close() + file = open(file_name) + try: + count = 0 + for line in file.readlines(): + count += 1 + return count + finally: + file.close() + except IOError: + # should never happen + self.fail() def test_counting_lines(self): self.assertEqual(__, self.count_lines("example_file.txt")) @@ -26,13 +30,18 @@ def test_counting_lines(self): # ------------------------------------------------------------------ def find_line(self, file_name): - file = open(file_name) try: - for line in file.readlines(): - match = re.search('e', line) - if match: return line - finally: - if file: file.close() + file = open(file_name) + try: + for line in file.readlines(): + match = re.search('e', line) + if match: + return line + finally: + file.close() + except IOError: + # should never happen + self.fail() def test_finding_lines(self): self.assertEqual(__, self.find_line("example_file.txt")) From 269873ac6def07461b31ccd247d23f545dbf2f5f Mon Sep 17 00:00:00 2001 From: Steve Bedford Date: Mon, 7 May 2012 23:34:01 -0400 Subject: [PATCH 011/237] Demonstrate empty dictionary literals --- python 2/koans/about_dictionaries.py | 2 ++ python 3/koans/about_dictionaries.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/python 2/koans/about_dictionaries.py b/python 2/koans/about_dictionaries.py index 25c13062a..e2ba91637 100644 --- a/python 2/koans/about_dictionaries.py +++ b/python 2/koans/about_dictionaries.py @@ -16,6 +16,8 @@ def test_creating_dictionaries(self): 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)) diff --git a/python 3/koans/about_dictionaries.py b/python 3/koans/about_dictionaries.py index 41e26c5fc..01995e168 100644 --- a/python 3/koans/about_dictionaries.py +++ b/python 3/koans/about_dictionaries.py @@ -15,6 +15,8 @@ def test_creating_dictionaries(self): 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)) From 979e43acf96c8f5e3927c9dcda3503ed727212ad Mon Sep 17 00:00:00 2001 From: DhilipSiva Date: Thu, 5 Jul 2012 19:50:06 +0530 Subject: [PATCH 012/237] Rename .txt to .rst for better rendering --- README.txt => README.rst | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.txt => README.rst (100%) diff --git a/README.txt b/README.rst similarity index 100% rename from README.txt rename to README.rst From 75cdfc6f5c65f4e9cbb361bd2c4dd5cc14af869b Mon Sep 17 00:00:00 2001 From: Sergio Ezequiel Gutierrez Alvarez Date: Wed, 18 Jul 2012 02:10:41 -0500 Subject: [PATCH 013/237] Corrected message example of method exception --- python 3/koans/about_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python 3/koans/about_methods.py b/python 3/koans/about_methods.py index eb4c56cf3..643d83425 100644 --- a/python 3/koans/about_methods.py +++ b/python 3/koans/about_methods.py @@ -23,7 +23,7 @@ def test_calling_functions_with_wrong_number_of_arguments(self): msg = exception.args[0] self.assertRegexpMatches(msg, - r'my_global_function\(\) takes exactly 2 positional ' + + r'my_global_function\(\) takes exactly 2 ' + r'arguments \(0 given\)') try: From 67cf9f5ec30e4d11bceb39efebdaed085a17fff3 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Fri, 27 Jul 2012 07:55:06 -0400 Subject: [PATCH 014/237] Fixed a typo. Thanks to tmagrino for pointing it out --- python 3/koans/about_lists.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python 3/koans/about_lists.py b/python 3/koans/about_lists.py index ae53fd153..19f939d1b 100644 --- a/python 3/koans/about_lists.py +++ b/python 3/koans/about_lists.py @@ -106,5 +106,5 @@ def test_making_queues(self): # Note, for Python 2 popping from the left hand side of a list is # inefficient. Use collections.deque instead. - # This is not as issue for Python 3 through + # This is not an issue for Python 3 through From bebd92ae68b8bf7f1bd563c2738f8ac23eff3f11 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Fri, 27 Jul 2012 21:45:48 -0400 Subject: [PATCH 015/237] Got rid of a confusing Generator test --- python 2/koans/about_generators.py | 3 +-- python 3/koans/about_generators.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/python 2/koans/about_generators.py b/python 2/koans/about_generators.py index 1b10ad90c..cb32a50ec 100644 --- a/python 2/koans/about_generators.py +++ b/python 2/koans/about_generators.py @@ -28,8 +28,7 @@ def test_generators_are_different_to_list_comprehensions(self): self.assertEqual(2, num_list[0]) # A generator has to be iterated through. - self.assertRaises(___, num_generator[0]) # Evaluates num_generator[0] - self.assertEqual(__, list(num_generator)[0]) # This works though + self.assertEqual(__, list(num_generator)[0]) # Both list comprehensions and generators can be iterated # though. However, a generator function is only called on the diff --git a/python 3/koans/about_generators.py b/python 3/koans/about_generators.py index 19790b62b..244ea1e6b 100644 --- a/python 3/koans/about_generators.py +++ b/python 3/koans/about_generators.py @@ -30,7 +30,7 @@ def test_generators_are_different_to_list_comprehensions(self): # A generator has to be iterated through. with self.assertRaises(___): num = num_generator[0] - self.assertEqual(__, list(num_generator)[0]) # This works though + 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 From 5c4ba919e52cbe5d2a00cd86f14cf3adedbe2f34 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Fri, 27 Jul 2012 21:56:17 -0400 Subject: [PATCH 016/237] Removed the space from 'python 2' and 'python 3' folders --- README.rst | 10 +++++----- {python 2 => python2}/_runner_tests.py | 0 {python 2 => python2}/contemplate_koans.py | 0 {python 2 => python2}/example_file.txt | 0 {python 2 => python2}/koans/GREEDS_RULES.txt | 0 {python 2 => python2}/koans/__init__.py | 0 .../koans/a_normal_folder/a_module.py | 0 .../koans/a_package_folder/__init__.py | 0 .../koans/a_package_folder/a_module.py | 0 {python 2 => python2}/koans/about_asserts.py | 0 {python 2 => python2}/koans/about_attribute_access.py | 0 {python 2 => python2}/koans/about_class_attributes.py | 0 {python 2 => python2}/koans/about_classes.py | 0 .../koans/about_control_statements.py | 0 .../koans/about_decorating_with_classes.py | 0 .../koans/about_decorating_with_functions.py | 0 {python 2 => python2}/koans/about_deleting_objects.py | 0 {python 2 => python2}/koans/about_dice_project.py | 0 {python 2 => python2}/koans/about_dictionaries.py | 0 {python 2 => python2}/koans/about_exceptions.py | 0 {python 2 => python2}/koans/about_extra_credit.py | 0 {python 2 => python2}/koans/about_generators.py | 0 {python 2 => python2}/koans/about_inheritance.py | 0 {python 2 => python2}/koans/about_iteration.py | 0 {python 2 => python2}/koans/about_lambdas.py | 0 {python 2 => python2}/koans/about_list_assignments.py | 0 {python 2 => python2}/koans/about_lists.py | 0 {python 2 => python2}/koans/about_method_bindings.py | 0 {python 2 => python2}/koans/about_methods.py | 0 {python 2 => python2}/koans/about_modules.py | 0 {python 2 => python2}/koans/about_monkey_patching.py | 0 .../koans/about_multiple_inheritance.py | 0 {python 2 => python2}/koans/about_new_style_classes.py | 0 {python 2 => python2}/koans/about_none.py | 0 {python 2 => python2}/koans/about_packages.py | 0 .../koans/about_proxy_object_project.py | 0 {python 2 => python2}/koans/about_regex.py | 0 {python 2 => python2}/koans/about_scope.py | 0 {python 2 => python2}/koans/about_scoring_project.py | 0 {python 2 => python2}/koans/about_sets.py | 0 {python 2 => python2}/koans/about_strings.py | 0 {python 2 => python2}/koans/about_triangle_project.py | 0 {python 2 => python2}/koans/about_triangle_project2.py | 0 {python 2 => python2}/koans/about_true_and_false.py | 0 {python 2 => python2}/koans/about_tuples.py | 0 {python 2 => python2}/koans/about_with_statements.py | 0 {python 2 => python2}/koans/another_local_module.py | 0 {python 2 => python2}/koans/jims.py | 0 {python 2 => python2}/koans/joes.py | 0 {python 2 => python2}/koans/local_module.py | 0 .../koans/local_module_with_all_defined.py | 0 {python 2 => python2}/koans/triangle.py | 0 {python 2 => python2}/libs/__init__.py | 0 {python 2 => python2}/libs/colorama/LICENSE-colorama | 0 {python 2 => python2}/libs/colorama/__init__.py | 0 {python 2 => python2}/libs/colorama/ansi.py | 0 {python 2 => python2}/libs/colorama/ansitowin32.py | 0 {python 2 => python2}/libs/colorama/initialise.py | 0 {python 2 => python2}/libs/colorama/win32.py | 0 {python 2 => python2}/libs/colorama/winterm.py | 0 {python 2 => python2}/libs/mock.py | 0 {python 2 => python2}/run.bat | 0 {python 2 => python2}/run.sh | 0 {python 2 => python2}/runner/__init__.py | 0 {python 2 => python2}/runner/helper.py | 0 {python 2 => python2}/runner/koan.py | 0 {python 2 => python2}/runner/mockable_test_result.py | 0 {python 2 => python2}/runner/mountain.py | 0 {python 2 => python2}/runner/path_to_enlightenment.py | 0 {python 2 => python2}/runner/runner_tests/__init__.py | 0 .../runner/runner_tests/test_helper.py | 0 .../runner/runner_tests/test_mountain.py | 0 .../runner/runner_tests/test_sensei.py | 0 {python 2 => python2}/runner/sensei.py | 0 {python 2 => python2}/runner/writeln_decorator.py | 0 {python 3 => python3}/_runner_tests.py | 0 {python 3 => python3}/contemplate_koans.py | 0 {python 3 => python3}/example_file.txt | 0 {python 3 => python3}/koans/GREEDS_RULES.txt | 0 {python 3 => python3}/koans/__init__.py | 0 .../koans/a_normal_folder/a_module.py | 0 .../koans/a_package_folder/__init__.py | 0 .../koans/a_package_folder/a_module.py | 0 {python 3 => python3}/koans/about_asserts.py | 0 {python 3 => python3}/koans/about_attribute_access.py | 0 {python 3 => python3}/koans/about_class_attributes.py | 0 {python 3 => python3}/koans/about_classes.py | 0 .../koans/about_control_statements.py | 0 .../koans/about_decorating_with_classes.py | 0 .../koans/about_decorating_with_functions.py | 0 {python 3 => python3}/koans/about_deleting_objects.py | 0 {python 3 => python3}/koans/about_dice_project.py | 0 {python 3 => python3}/koans/about_dictionaries.py | 0 {python 3 => python3}/koans/about_exceptions.py | 0 {python 3 => python3}/koans/about_extra_credit.py | 0 {python 3 => python3}/koans/about_generators.py | 0 {python 3 => python3}/koans/about_inheritance.py | 0 {python 3 => python3}/koans/about_iteration.py | 0 {python 3 => python3}/koans/about_lambdas.py | 0 {python 3 => python3}/koans/about_list_assignments.py | 0 {python 3 => python3}/koans/about_lists.py | 0 {python 3 => python3}/koans/about_method_bindings.py | 0 {python 3 => python3}/koans/about_methods.py | 0 {python 3 => python3}/koans/about_modules.py | 0 {python 3 => python3}/koans/about_monkey_patching.py | 0 .../koans/about_multiple_inheritance.py | 0 {python 3 => python3}/koans/about_none.py | 0 {python 3 => python3}/koans/about_packages.py | 0 .../koans/about_proxy_object_project.py | 0 {python 3 => python3}/koans/about_regex.py | 0 {python 3 => python3}/koans/about_scope.py | 0 {python 3 => python3}/koans/about_scoring_project.py | 0 {python 3 => python3}/koans/about_sets.py | 0 {python 3 => python3}/koans/about_strings.py | 0 {python 3 => python3}/koans/about_triangle_project.py | 0 {python 3 => python3}/koans/about_triangle_project2.py | 0 {python 3 => python3}/koans/about_true_and_false.py | 0 {python 3 => python3}/koans/about_tuples.py | 0 {python 3 => python3}/koans/about_with_statements.py | 0 {python 3 => python3}/koans/another_local_module.py | 0 {python 3 => python3}/koans/jims.py | 0 {python 3 => python3}/koans/joes.py | 0 {python 3 => python3}/koans/local_module.py | 0 .../koans/local_module_with_all_defined.py | 0 {python 3 => python3}/koans/triangle.py | 0 {python 3 => python3}/libs/__init__.py | 0 {python 3 => python3}/libs/colorama/LICENSE-colorama | 0 {python 3 => python3}/libs/colorama/__init__.py | 0 {python 3 => python3}/libs/colorama/ansi.py | 0 {python 3 => python3}/libs/colorama/ansitowin32.py | 0 {python 3 => python3}/libs/colorama/initialise.py | 0 {python 3 => python3}/libs/colorama/win32.py | 0 {python 3 => python3}/libs/colorama/winterm.py | 0 {python 3 => python3}/libs/mock.py | 0 {python 3 => python3}/run.bat | 0 {python 3 => python3}/run.sh | 0 {python 3 => python3}/runner/__init__.py | 0 {python 3 => python3}/runner/helper.py | 0 {python 3 => python3}/runner/koan.py | 0 {python 3 => python3}/runner/mockable_test_result.py | 0 {python 3 => python3}/runner/mountain.py | 0 {python 3 => python3}/runner/path_to_enlightenment.py | 0 {python 3 => python3}/runner/runner_tests/__init__.py | 0 .../runner/runner_tests/test_helper.py | 0 .../runner/runner_tests/test_mountain.py | 0 .../runner/runner_tests/test_sensei.py | 0 {python 3 => python3}/runner/sensei.py | 0 {python 3 => python3}/runner/writeln_decorator.py | 0 148 files changed, 5 insertions(+), 5 deletions(-) rename {python 2 => python2}/_runner_tests.py (100%) rename {python 2 => python2}/contemplate_koans.py (100%) rename {python 2 => python2}/example_file.txt (100%) rename {python 2 => python2}/koans/GREEDS_RULES.txt (100%) rename {python 2 => python2}/koans/__init__.py (100%) rename {python 2 => python2}/koans/a_normal_folder/a_module.py (100%) rename {python 2 => python2}/koans/a_package_folder/__init__.py (100%) rename {python 2 => python2}/koans/a_package_folder/a_module.py (100%) rename {python 2 => python2}/koans/about_asserts.py (100%) rename {python 2 => python2}/koans/about_attribute_access.py (100%) rename {python 2 => python2}/koans/about_class_attributes.py (100%) rename {python 2 => python2}/koans/about_classes.py (100%) rename {python 2 => python2}/koans/about_control_statements.py (100%) rename {python 2 => python2}/koans/about_decorating_with_classes.py (100%) rename {python 2 => python2}/koans/about_decorating_with_functions.py (100%) rename {python 2 => python2}/koans/about_deleting_objects.py (100%) rename {python 2 => python2}/koans/about_dice_project.py (100%) rename {python 2 => python2}/koans/about_dictionaries.py (100%) rename {python 2 => python2}/koans/about_exceptions.py (100%) rename {python 2 => python2}/koans/about_extra_credit.py (100%) rename {python 2 => python2}/koans/about_generators.py (100%) rename {python 2 => python2}/koans/about_inheritance.py (100%) rename {python 2 => python2}/koans/about_iteration.py (100%) rename {python 2 => python2}/koans/about_lambdas.py (100%) rename {python 2 => python2}/koans/about_list_assignments.py (100%) rename {python 2 => python2}/koans/about_lists.py (100%) rename {python 2 => python2}/koans/about_method_bindings.py (100%) rename {python 2 => python2}/koans/about_methods.py (100%) rename {python 2 => python2}/koans/about_modules.py (100%) rename {python 2 => python2}/koans/about_monkey_patching.py (100%) rename {python 2 => python2}/koans/about_multiple_inheritance.py (100%) rename {python 2 => python2}/koans/about_new_style_classes.py (100%) rename {python 2 => python2}/koans/about_none.py (100%) rename {python 2 => python2}/koans/about_packages.py (100%) rename {python 2 => python2}/koans/about_proxy_object_project.py (100%) rename {python 2 => python2}/koans/about_regex.py (100%) rename {python 2 => python2}/koans/about_scope.py (100%) rename {python 2 => python2}/koans/about_scoring_project.py (100%) rename {python 2 => python2}/koans/about_sets.py (100%) rename {python 2 => python2}/koans/about_strings.py (100%) rename {python 2 => python2}/koans/about_triangle_project.py (100%) rename {python 2 => python2}/koans/about_triangle_project2.py (100%) rename {python 2 => python2}/koans/about_true_and_false.py (100%) rename {python 2 => python2}/koans/about_tuples.py (100%) rename {python 2 => python2}/koans/about_with_statements.py (100%) rename {python 2 => python2}/koans/another_local_module.py (100%) rename {python 2 => python2}/koans/jims.py (100%) rename {python 2 => python2}/koans/joes.py (100%) rename {python 2 => python2}/koans/local_module.py (100%) rename {python 2 => python2}/koans/local_module_with_all_defined.py (100%) rename {python 2 => python2}/koans/triangle.py (100%) rename {python 2 => python2}/libs/__init__.py (100%) rename {python 2 => python2}/libs/colorama/LICENSE-colorama (100%) rename {python 2 => python2}/libs/colorama/__init__.py (100%) rename {python 2 => python2}/libs/colorama/ansi.py (100%) rename {python 2 => python2}/libs/colorama/ansitowin32.py (100%) rename {python 2 => python2}/libs/colorama/initialise.py (100%) rename {python 2 => python2}/libs/colorama/win32.py (100%) rename {python 2 => python2}/libs/colorama/winterm.py (100%) rename {python 2 => python2}/libs/mock.py (100%) rename {python 2 => python2}/run.bat (100%) rename {python 2 => python2}/run.sh (100%) rename {python 2 => python2}/runner/__init__.py (100%) rename {python 2 => python2}/runner/helper.py (100%) rename {python 2 => python2}/runner/koan.py (100%) rename {python 2 => python2}/runner/mockable_test_result.py (100%) rename {python 2 => python2}/runner/mountain.py (100%) rename {python 2 => python2}/runner/path_to_enlightenment.py (100%) rename {python 2 => python2}/runner/runner_tests/__init__.py (100%) rename {python 2 => python2}/runner/runner_tests/test_helper.py (100%) rename {python 2 => python2}/runner/runner_tests/test_mountain.py (100%) rename {python 2 => python2}/runner/runner_tests/test_sensei.py (100%) rename {python 2 => python2}/runner/sensei.py (100%) rename {python 2 => python2}/runner/writeln_decorator.py (100%) rename {python 3 => python3}/_runner_tests.py (100%) rename {python 3 => python3}/contemplate_koans.py (100%) rename {python 3 => python3}/example_file.txt (100%) rename {python 3 => python3}/koans/GREEDS_RULES.txt (100%) rename {python 3 => python3}/koans/__init__.py (100%) rename {python 3 => python3}/koans/a_normal_folder/a_module.py (100%) rename {python 3 => python3}/koans/a_package_folder/__init__.py (100%) rename {python 3 => python3}/koans/a_package_folder/a_module.py (100%) rename {python 3 => python3}/koans/about_asserts.py (100%) rename {python 3 => python3}/koans/about_attribute_access.py (100%) rename {python 3 => python3}/koans/about_class_attributes.py (100%) rename {python 3 => python3}/koans/about_classes.py (100%) rename {python 3 => python3}/koans/about_control_statements.py (100%) rename {python 3 => python3}/koans/about_decorating_with_classes.py (100%) rename {python 3 => python3}/koans/about_decorating_with_functions.py (100%) rename {python 3 => python3}/koans/about_deleting_objects.py (100%) rename {python 3 => python3}/koans/about_dice_project.py (100%) rename {python 3 => python3}/koans/about_dictionaries.py (100%) rename {python 3 => python3}/koans/about_exceptions.py (100%) rename {python 3 => python3}/koans/about_extra_credit.py (100%) rename {python 3 => python3}/koans/about_generators.py (100%) rename {python 3 => python3}/koans/about_inheritance.py (100%) rename {python 3 => python3}/koans/about_iteration.py (100%) rename {python 3 => python3}/koans/about_lambdas.py (100%) rename {python 3 => python3}/koans/about_list_assignments.py (100%) rename {python 3 => python3}/koans/about_lists.py (100%) rename {python 3 => python3}/koans/about_method_bindings.py (100%) rename {python 3 => python3}/koans/about_methods.py (100%) rename {python 3 => python3}/koans/about_modules.py (100%) rename {python 3 => python3}/koans/about_monkey_patching.py (100%) rename {python 3 => python3}/koans/about_multiple_inheritance.py (100%) rename {python 3 => python3}/koans/about_none.py (100%) rename {python 3 => python3}/koans/about_packages.py (100%) rename {python 3 => python3}/koans/about_proxy_object_project.py (100%) rename {python 3 => python3}/koans/about_regex.py (100%) rename {python 3 => python3}/koans/about_scope.py (100%) rename {python 3 => python3}/koans/about_scoring_project.py (100%) rename {python 3 => python3}/koans/about_sets.py (100%) rename {python 3 => python3}/koans/about_strings.py (100%) rename {python 3 => python3}/koans/about_triangle_project.py (100%) rename {python 3 => python3}/koans/about_triangle_project2.py (100%) rename {python 3 => python3}/koans/about_true_and_false.py (100%) rename {python 3 => python3}/koans/about_tuples.py (100%) rename {python 3 => python3}/koans/about_with_statements.py (100%) rename {python 3 => python3}/koans/another_local_module.py (100%) rename {python 3 => python3}/koans/jims.py (100%) rename {python 3 => python3}/koans/joes.py (100%) rename {python 3 => python3}/koans/local_module.py (100%) rename {python 3 => python3}/koans/local_module_with_all_defined.py (100%) rename {python 3 => python3}/koans/triangle.py (100%) rename {python 3 => python3}/libs/__init__.py (100%) rename {python 3 => python3}/libs/colorama/LICENSE-colorama (100%) rename {python 3 => python3}/libs/colorama/__init__.py (100%) rename {python 3 => python3}/libs/colorama/ansi.py (100%) rename {python 3 => python3}/libs/colorama/ansitowin32.py (100%) rename {python 3 => python3}/libs/colorama/initialise.py (100%) rename {python 3 => python3}/libs/colorama/win32.py (100%) rename {python 3 => python3}/libs/colorama/winterm.py (100%) rename {python 3 => python3}/libs/mock.py (100%) rename {python 3 => python3}/run.bat (100%) rename {python 3 => python3}/run.sh (100%) rename {python 3 => python3}/runner/__init__.py (100%) rename {python 3 => python3}/runner/helper.py (100%) rename {python 3 => python3}/runner/koan.py (100%) rename {python 3 => python3}/runner/mockable_test_result.py (100%) rename {python 3 => python3}/runner/mountain.py (100%) rename {python 3 => python3}/runner/path_to_enlightenment.py (100%) rename {python 3 => python3}/runner/runner_tests/__init__.py (100%) rename {python 3 => python3}/runner/runner_tests/test_helper.py (100%) rename {python 3 => python3}/runner/runner_tests/test_mountain.py (100%) rename {python 3 => python3}/runner/runner_tests/test_sensei.py (100%) rename {python 3 => python3}/runner/sensei.py (100%) rename {python 3 => python3}/runner/writeln_decorator.py (100%) diff --git a/README.rst b/README.rst index cac80571f..6c92e2dcf 100644 --- a/README.rst +++ b/README.rst @@ -64,8 +64,8 @@ or In my case I'm using Python 3 with windows, so I fire up my command shell (cmd.exe) and run this: - C:\>cd "c:\hg\python_koans\python 3" - C:\hg\python_koans\python 3_1>python contemplate_koans.py + C:\>cd "c:\hg\python_koans\python3" + C:\hg\python_koans\python3>python contemplate_koans.py Thinking AboutAsserts test_assert_truth has damaged your karma. @@ -74,13 +74,13 @@ In my case I'm using Python 3 with windows, so I fire up my command shell (cmd.e AssertionError: False is not True Please meditate on the following code: - File "C:\hg\python_koans\python 3\koans\about_asserts.py", line 12, in test_ + File "C:\hg\python_koans\python3\koans\about_asserts.py", line 12, in test_ assert_truth self.assertTrue(False) # This should be true Beautiful is better than ugly. - C:\hg\python_koans\python 3> + C:\hg\python_koans\python3> Apparently a test failed: @@ -99,7 +99,7 @@ Sooner or later you will likely encounter tests where you are not sure what the 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: - C:\hg\python_koans\python 3>python + C:\hg\python_koans\python3>python Python 3.1.2 (r312:79149, Mar 21 2010, 00:41:52) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. diff --git a/python 2/_runner_tests.py b/python2/_runner_tests.py similarity index 100% rename from python 2/_runner_tests.py rename to python2/_runner_tests.py diff --git a/python 2/contemplate_koans.py b/python2/contemplate_koans.py similarity index 100% rename from python 2/contemplate_koans.py rename to python2/contemplate_koans.py diff --git a/python 2/example_file.txt b/python2/example_file.txt similarity index 100% rename from python 2/example_file.txt rename to python2/example_file.txt diff --git a/python 2/koans/GREEDS_RULES.txt b/python2/koans/GREEDS_RULES.txt similarity index 100% rename from python 2/koans/GREEDS_RULES.txt rename to python2/koans/GREEDS_RULES.txt diff --git a/python 2/koans/__init__.py b/python2/koans/__init__.py similarity index 100% rename from python 2/koans/__init__.py rename to python2/koans/__init__.py diff --git a/python 2/koans/a_normal_folder/a_module.py b/python2/koans/a_normal_folder/a_module.py similarity index 100% rename from python 2/koans/a_normal_folder/a_module.py rename to python2/koans/a_normal_folder/a_module.py diff --git a/python 2/koans/a_package_folder/__init__.py b/python2/koans/a_package_folder/__init__.py similarity index 100% rename from python 2/koans/a_package_folder/__init__.py rename to python2/koans/a_package_folder/__init__.py diff --git a/python 2/koans/a_package_folder/a_module.py b/python2/koans/a_package_folder/a_module.py similarity index 100% rename from python 2/koans/a_package_folder/a_module.py rename to python2/koans/a_package_folder/a_module.py diff --git a/python 2/koans/about_asserts.py b/python2/koans/about_asserts.py similarity index 100% rename from python 2/koans/about_asserts.py rename to python2/koans/about_asserts.py diff --git a/python 2/koans/about_attribute_access.py b/python2/koans/about_attribute_access.py similarity index 100% rename from python 2/koans/about_attribute_access.py rename to python2/koans/about_attribute_access.py diff --git a/python 2/koans/about_class_attributes.py b/python2/koans/about_class_attributes.py similarity index 100% rename from python 2/koans/about_class_attributes.py rename to python2/koans/about_class_attributes.py diff --git a/python 2/koans/about_classes.py b/python2/koans/about_classes.py similarity index 100% rename from python 2/koans/about_classes.py rename to python2/koans/about_classes.py diff --git a/python 2/koans/about_control_statements.py b/python2/koans/about_control_statements.py similarity index 100% rename from python 2/koans/about_control_statements.py rename to python2/koans/about_control_statements.py diff --git a/python 2/koans/about_decorating_with_classes.py b/python2/koans/about_decorating_with_classes.py similarity index 100% rename from python 2/koans/about_decorating_with_classes.py rename to python2/koans/about_decorating_with_classes.py diff --git a/python 2/koans/about_decorating_with_functions.py b/python2/koans/about_decorating_with_functions.py similarity index 100% rename from python 2/koans/about_decorating_with_functions.py rename to python2/koans/about_decorating_with_functions.py diff --git a/python 2/koans/about_deleting_objects.py b/python2/koans/about_deleting_objects.py similarity index 100% rename from python 2/koans/about_deleting_objects.py rename to python2/koans/about_deleting_objects.py diff --git a/python 2/koans/about_dice_project.py b/python2/koans/about_dice_project.py similarity index 100% rename from python 2/koans/about_dice_project.py rename to python2/koans/about_dice_project.py diff --git a/python 2/koans/about_dictionaries.py b/python2/koans/about_dictionaries.py similarity index 100% rename from python 2/koans/about_dictionaries.py rename to python2/koans/about_dictionaries.py diff --git a/python 2/koans/about_exceptions.py b/python2/koans/about_exceptions.py similarity index 100% rename from python 2/koans/about_exceptions.py rename to python2/koans/about_exceptions.py diff --git a/python 2/koans/about_extra_credit.py b/python2/koans/about_extra_credit.py similarity index 100% rename from python 2/koans/about_extra_credit.py rename to python2/koans/about_extra_credit.py diff --git a/python 2/koans/about_generators.py b/python2/koans/about_generators.py similarity index 100% rename from python 2/koans/about_generators.py rename to python2/koans/about_generators.py diff --git a/python 2/koans/about_inheritance.py b/python2/koans/about_inheritance.py similarity index 100% rename from python 2/koans/about_inheritance.py rename to python2/koans/about_inheritance.py diff --git a/python 2/koans/about_iteration.py b/python2/koans/about_iteration.py similarity index 100% rename from python 2/koans/about_iteration.py rename to python2/koans/about_iteration.py diff --git a/python 2/koans/about_lambdas.py b/python2/koans/about_lambdas.py similarity index 100% rename from python 2/koans/about_lambdas.py rename to python2/koans/about_lambdas.py diff --git a/python 2/koans/about_list_assignments.py b/python2/koans/about_list_assignments.py similarity index 100% rename from python 2/koans/about_list_assignments.py rename to python2/koans/about_list_assignments.py diff --git a/python 2/koans/about_lists.py b/python2/koans/about_lists.py similarity index 100% rename from python 2/koans/about_lists.py rename to python2/koans/about_lists.py diff --git a/python 2/koans/about_method_bindings.py b/python2/koans/about_method_bindings.py similarity index 100% rename from python 2/koans/about_method_bindings.py rename to python2/koans/about_method_bindings.py diff --git a/python 2/koans/about_methods.py b/python2/koans/about_methods.py similarity index 100% rename from python 2/koans/about_methods.py rename to python2/koans/about_methods.py diff --git a/python 2/koans/about_modules.py b/python2/koans/about_modules.py similarity index 100% rename from python 2/koans/about_modules.py rename to python2/koans/about_modules.py diff --git a/python 2/koans/about_monkey_patching.py b/python2/koans/about_monkey_patching.py similarity index 100% rename from python 2/koans/about_monkey_patching.py rename to python2/koans/about_monkey_patching.py diff --git a/python 2/koans/about_multiple_inheritance.py b/python2/koans/about_multiple_inheritance.py similarity index 100% rename from python 2/koans/about_multiple_inheritance.py rename to python2/koans/about_multiple_inheritance.py diff --git a/python 2/koans/about_new_style_classes.py b/python2/koans/about_new_style_classes.py similarity index 100% rename from python 2/koans/about_new_style_classes.py rename to python2/koans/about_new_style_classes.py diff --git a/python 2/koans/about_none.py b/python2/koans/about_none.py similarity index 100% rename from python 2/koans/about_none.py rename to python2/koans/about_none.py diff --git a/python 2/koans/about_packages.py b/python2/koans/about_packages.py similarity index 100% rename from python 2/koans/about_packages.py rename to python2/koans/about_packages.py diff --git a/python 2/koans/about_proxy_object_project.py b/python2/koans/about_proxy_object_project.py similarity index 100% rename from python 2/koans/about_proxy_object_project.py rename to python2/koans/about_proxy_object_project.py diff --git a/python 2/koans/about_regex.py b/python2/koans/about_regex.py similarity index 100% rename from python 2/koans/about_regex.py rename to python2/koans/about_regex.py diff --git a/python 2/koans/about_scope.py b/python2/koans/about_scope.py similarity index 100% rename from python 2/koans/about_scope.py rename to python2/koans/about_scope.py diff --git a/python 2/koans/about_scoring_project.py b/python2/koans/about_scoring_project.py similarity index 100% rename from python 2/koans/about_scoring_project.py rename to python2/koans/about_scoring_project.py diff --git a/python 2/koans/about_sets.py b/python2/koans/about_sets.py similarity index 100% rename from python 2/koans/about_sets.py rename to python2/koans/about_sets.py diff --git a/python 2/koans/about_strings.py b/python2/koans/about_strings.py similarity index 100% rename from python 2/koans/about_strings.py rename to python2/koans/about_strings.py diff --git a/python 2/koans/about_triangle_project.py b/python2/koans/about_triangle_project.py similarity index 100% rename from python 2/koans/about_triangle_project.py rename to python2/koans/about_triangle_project.py diff --git a/python 2/koans/about_triangle_project2.py b/python2/koans/about_triangle_project2.py similarity index 100% rename from python 2/koans/about_triangle_project2.py rename to python2/koans/about_triangle_project2.py diff --git a/python 2/koans/about_true_and_false.py b/python2/koans/about_true_and_false.py similarity index 100% rename from python 2/koans/about_true_and_false.py rename to python2/koans/about_true_and_false.py diff --git a/python 2/koans/about_tuples.py b/python2/koans/about_tuples.py similarity index 100% rename from python 2/koans/about_tuples.py rename to python2/koans/about_tuples.py diff --git a/python 2/koans/about_with_statements.py b/python2/koans/about_with_statements.py similarity index 100% rename from python 2/koans/about_with_statements.py rename to python2/koans/about_with_statements.py diff --git a/python 2/koans/another_local_module.py b/python2/koans/another_local_module.py similarity index 100% rename from python 2/koans/another_local_module.py rename to python2/koans/another_local_module.py diff --git a/python 2/koans/jims.py b/python2/koans/jims.py similarity index 100% rename from python 2/koans/jims.py rename to python2/koans/jims.py diff --git a/python 2/koans/joes.py b/python2/koans/joes.py similarity index 100% rename from python 2/koans/joes.py rename to python2/koans/joes.py diff --git a/python 2/koans/local_module.py b/python2/koans/local_module.py similarity index 100% rename from python 2/koans/local_module.py rename to python2/koans/local_module.py diff --git a/python 2/koans/local_module_with_all_defined.py b/python2/koans/local_module_with_all_defined.py similarity index 100% rename from python 2/koans/local_module_with_all_defined.py rename to python2/koans/local_module_with_all_defined.py diff --git a/python 2/koans/triangle.py b/python2/koans/triangle.py similarity index 100% rename from python 2/koans/triangle.py rename to python2/koans/triangle.py diff --git a/python 2/libs/__init__.py b/python2/libs/__init__.py similarity index 100% rename from python 2/libs/__init__.py rename to python2/libs/__init__.py diff --git a/python 2/libs/colorama/LICENSE-colorama b/python2/libs/colorama/LICENSE-colorama similarity index 100% rename from python 2/libs/colorama/LICENSE-colorama rename to python2/libs/colorama/LICENSE-colorama diff --git a/python 2/libs/colorama/__init__.py b/python2/libs/colorama/__init__.py similarity index 100% rename from python 2/libs/colorama/__init__.py rename to python2/libs/colorama/__init__.py diff --git a/python 2/libs/colorama/ansi.py b/python2/libs/colorama/ansi.py similarity index 100% rename from python 2/libs/colorama/ansi.py rename to python2/libs/colorama/ansi.py diff --git a/python 2/libs/colorama/ansitowin32.py b/python2/libs/colorama/ansitowin32.py similarity index 100% rename from python 2/libs/colorama/ansitowin32.py rename to python2/libs/colorama/ansitowin32.py diff --git a/python 2/libs/colorama/initialise.py b/python2/libs/colorama/initialise.py similarity index 100% rename from python 2/libs/colorama/initialise.py rename to python2/libs/colorama/initialise.py diff --git a/python 2/libs/colorama/win32.py b/python2/libs/colorama/win32.py similarity index 100% rename from python 2/libs/colorama/win32.py rename to python2/libs/colorama/win32.py diff --git a/python 2/libs/colorama/winterm.py b/python2/libs/colorama/winterm.py similarity index 100% rename from python 2/libs/colorama/winterm.py rename to python2/libs/colorama/winterm.py diff --git a/python 2/libs/mock.py b/python2/libs/mock.py similarity index 100% rename from python 2/libs/mock.py rename to python2/libs/mock.py diff --git a/python 2/run.bat b/python2/run.bat similarity index 100% rename from python 2/run.bat rename to python2/run.bat diff --git a/python 2/run.sh b/python2/run.sh similarity index 100% rename from python 2/run.sh rename to python2/run.sh diff --git a/python 2/runner/__init__.py b/python2/runner/__init__.py similarity index 100% rename from python 2/runner/__init__.py rename to python2/runner/__init__.py diff --git a/python 2/runner/helper.py b/python2/runner/helper.py similarity index 100% rename from python 2/runner/helper.py rename to python2/runner/helper.py diff --git a/python 2/runner/koan.py b/python2/runner/koan.py similarity index 100% rename from python 2/runner/koan.py rename to python2/runner/koan.py diff --git a/python 2/runner/mockable_test_result.py b/python2/runner/mockable_test_result.py similarity index 100% rename from python 2/runner/mockable_test_result.py rename to python2/runner/mockable_test_result.py diff --git a/python 2/runner/mountain.py b/python2/runner/mountain.py similarity index 100% rename from python 2/runner/mountain.py rename to python2/runner/mountain.py diff --git a/python 2/runner/path_to_enlightenment.py b/python2/runner/path_to_enlightenment.py similarity index 100% rename from python 2/runner/path_to_enlightenment.py rename to python2/runner/path_to_enlightenment.py diff --git a/python 2/runner/runner_tests/__init__.py b/python2/runner/runner_tests/__init__.py similarity index 100% rename from python 2/runner/runner_tests/__init__.py rename to python2/runner/runner_tests/__init__.py diff --git a/python 2/runner/runner_tests/test_helper.py b/python2/runner/runner_tests/test_helper.py similarity index 100% rename from python 2/runner/runner_tests/test_helper.py rename to python2/runner/runner_tests/test_helper.py diff --git a/python 2/runner/runner_tests/test_mountain.py b/python2/runner/runner_tests/test_mountain.py similarity index 100% rename from python 2/runner/runner_tests/test_mountain.py rename to python2/runner/runner_tests/test_mountain.py diff --git a/python 2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py similarity index 100% rename from python 2/runner/runner_tests/test_sensei.py rename to python2/runner/runner_tests/test_sensei.py diff --git a/python 2/runner/sensei.py b/python2/runner/sensei.py similarity index 100% rename from python 2/runner/sensei.py rename to python2/runner/sensei.py diff --git a/python 2/runner/writeln_decorator.py b/python2/runner/writeln_decorator.py similarity index 100% rename from python 2/runner/writeln_decorator.py rename to python2/runner/writeln_decorator.py diff --git a/python 3/_runner_tests.py b/python3/_runner_tests.py similarity index 100% rename from python 3/_runner_tests.py rename to python3/_runner_tests.py diff --git a/python 3/contemplate_koans.py b/python3/contemplate_koans.py similarity index 100% rename from python 3/contemplate_koans.py rename to python3/contemplate_koans.py diff --git a/python 3/example_file.txt b/python3/example_file.txt similarity index 100% rename from python 3/example_file.txt rename to python3/example_file.txt diff --git a/python 3/koans/GREEDS_RULES.txt b/python3/koans/GREEDS_RULES.txt similarity index 100% rename from python 3/koans/GREEDS_RULES.txt rename to python3/koans/GREEDS_RULES.txt diff --git a/python 3/koans/__init__.py b/python3/koans/__init__.py similarity index 100% rename from python 3/koans/__init__.py rename to python3/koans/__init__.py diff --git a/python 3/koans/a_normal_folder/a_module.py b/python3/koans/a_normal_folder/a_module.py similarity index 100% rename from python 3/koans/a_normal_folder/a_module.py rename to python3/koans/a_normal_folder/a_module.py diff --git a/python 3/koans/a_package_folder/__init__.py b/python3/koans/a_package_folder/__init__.py similarity index 100% rename from python 3/koans/a_package_folder/__init__.py rename to python3/koans/a_package_folder/__init__.py diff --git a/python 3/koans/a_package_folder/a_module.py b/python3/koans/a_package_folder/a_module.py similarity index 100% rename from python 3/koans/a_package_folder/a_module.py rename to python3/koans/a_package_folder/a_module.py diff --git a/python 3/koans/about_asserts.py b/python3/koans/about_asserts.py similarity index 100% rename from python 3/koans/about_asserts.py rename to python3/koans/about_asserts.py diff --git a/python 3/koans/about_attribute_access.py b/python3/koans/about_attribute_access.py similarity index 100% rename from python 3/koans/about_attribute_access.py rename to python3/koans/about_attribute_access.py diff --git a/python 3/koans/about_class_attributes.py b/python3/koans/about_class_attributes.py similarity index 100% rename from python 3/koans/about_class_attributes.py rename to python3/koans/about_class_attributes.py diff --git a/python 3/koans/about_classes.py b/python3/koans/about_classes.py similarity index 100% rename from python 3/koans/about_classes.py rename to python3/koans/about_classes.py diff --git a/python 3/koans/about_control_statements.py b/python3/koans/about_control_statements.py similarity index 100% rename from python 3/koans/about_control_statements.py rename to python3/koans/about_control_statements.py diff --git a/python 3/koans/about_decorating_with_classes.py b/python3/koans/about_decorating_with_classes.py similarity index 100% rename from python 3/koans/about_decorating_with_classes.py rename to python3/koans/about_decorating_with_classes.py diff --git a/python 3/koans/about_decorating_with_functions.py b/python3/koans/about_decorating_with_functions.py similarity index 100% rename from python 3/koans/about_decorating_with_functions.py rename to python3/koans/about_decorating_with_functions.py diff --git a/python 3/koans/about_deleting_objects.py b/python3/koans/about_deleting_objects.py similarity index 100% rename from python 3/koans/about_deleting_objects.py rename to python3/koans/about_deleting_objects.py diff --git a/python 3/koans/about_dice_project.py b/python3/koans/about_dice_project.py similarity index 100% rename from python 3/koans/about_dice_project.py rename to python3/koans/about_dice_project.py diff --git a/python 3/koans/about_dictionaries.py b/python3/koans/about_dictionaries.py similarity index 100% rename from python 3/koans/about_dictionaries.py rename to python3/koans/about_dictionaries.py diff --git a/python 3/koans/about_exceptions.py b/python3/koans/about_exceptions.py similarity index 100% rename from python 3/koans/about_exceptions.py rename to python3/koans/about_exceptions.py diff --git a/python 3/koans/about_extra_credit.py b/python3/koans/about_extra_credit.py similarity index 100% rename from python 3/koans/about_extra_credit.py rename to python3/koans/about_extra_credit.py diff --git a/python 3/koans/about_generators.py b/python3/koans/about_generators.py similarity index 100% rename from python 3/koans/about_generators.py rename to python3/koans/about_generators.py diff --git a/python 3/koans/about_inheritance.py b/python3/koans/about_inheritance.py similarity index 100% rename from python 3/koans/about_inheritance.py rename to python3/koans/about_inheritance.py diff --git a/python 3/koans/about_iteration.py b/python3/koans/about_iteration.py similarity index 100% rename from python 3/koans/about_iteration.py rename to python3/koans/about_iteration.py diff --git a/python 3/koans/about_lambdas.py b/python3/koans/about_lambdas.py similarity index 100% rename from python 3/koans/about_lambdas.py rename to python3/koans/about_lambdas.py diff --git a/python 3/koans/about_list_assignments.py b/python3/koans/about_list_assignments.py similarity index 100% rename from python 3/koans/about_list_assignments.py rename to python3/koans/about_list_assignments.py diff --git a/python 3/koans/about_lists.py b/python3/koans/about_lists.py similarity index 100% rename from python 3/koans/about_lists.py rename to python3/koans/about_lists.py diff --git a/python 3/koans/about_method_bindings.py b/python3/koans/about_method_bindings.py similarity index 100% rename from python 3/koans/about_method_bindings.py rename to python3/koans/about_method_bindings.py diff --git a/python 3/koans/about_methods.py b/python3/koans/about_methods.py similarity index 100% rename from python 3/koans/about_methods.py rename to python3/koans/about_methods.py diff --git a/python 3/koans/about_modules.py b/python3/koans/about_modules.py similarity index 100% rename from python 3/koans/about_modules.py rename to python3/koans/about_modules.py diff --git a/python 3/koans/about_monkey_patching.py b/python3/koans/about_monkey_patching.py similarity index 100% rename from python 3/koans/about_monkey_patching.py rename to python3/koans/about_monkey_patching.py diff --git a/python 3/koans/about_multiple_inheritance.py b/python3/koans/about_multiple_inheritance.py similarity index 100% rename from python 3/koans/about_multiple_inheritance.py rename to python3/koans/about_multiple_inheritance.py diff --git a/python 3/koans/about_none.py b/python3/koans/about_none.py similarity index 100% rename from python 3/koans/about_none.py rename to python3/koans/about_none.py diff --git a/python 3/koans/about_packages.py b/python3/koans/about_packages.py similarity index 100% rename from python 3/koans/about_packages.py rename to python3/koans/about_packages.py diff --git a/python 3/koans/about_proxy_object_project.py b/python3/koans/about_proxy_object_project.py similarity index 100% rename from python 3/koans/about_proxy_object_project.py rename to python3/koans/about_proxy_object_project.py diff --git a/python 3/koans/about_regex.py b/python3/koans/about_regex.py similarity index 100% rename from python 3/koans/about_regex.py rename to python3/koans/about_regex.py diff --git a/python 3/koans/about_scope.py b/python3/koans/about_scope.py similarity index 100% rename from python 3/koans/about_scope.py rename to python3/koans/about_scope.py diff --git a/python 3/koans/about_scoring_project.py b/python3/koans/about_scoring_project.py similarity index 100% rename from python 3/koans/about_scoring_project.py rename to python3/koans/about_scoring_project.py diff --git a/python 3/koans/about_sets.py b/python3/koans/about_sets.py similarity index 100% rename from python 3/koans/about_sets.py rename to python3/koans/about_sets.py diff --git a/python 3/koans/about_strings.py b/python3/koans/about_strings.py similarity index 100% rename from python 3/koans/about_strings.py rename to python3/koans/about_strings.py diff --git a/python 3/koans/about_triangle_project.py b/python3/koans/about_triangle_project.py similarity index 100% rename from python 3/koans/about_triangle_project.py rename to python3/koans/about_triangle_project.py diff --git a/python 3/koans/about_triangle_project2.py b/python3/koans/about_triangle_project2.py similarity index 100% rename from python 3/koans/about_triangle_project2.py rename to python3/koans/about_triangle_project2.py diff --git a/python 3/koans/about_true_and_false.py b/python3/koans/about_true_and_false.py similarity index 100% rename from python 3/koans/about_true_and_false.py rename to python3/koans/about_true_and_false.py diff --git a/python 3/koans/about_tuples.py b/python3/koans/about_tuples.py similarity index 100% rename from python 3/koans/about_tuples.py rename to python3/koans/about_tuples.py diff --git a/python 3/koans/about_with_statements.py b/python3/koans/about_with_statements.py similarity index 100% rename from python 3/koans/about_with_statements.py rename to python3/koans/about_with_statements.py diff --git a/python 3/koans/another_local_module.py b/python3/koans/another_local_module.py similarity index 100% rename from python 3/koans/another_local_module.py rename to python3/koans/another_local_module.py diff --git a/python 3/koans/jims.py b/python3/koans/jims.py similarity index 100% rename from python 3/koans/jims.py rename to python3/koans/jims.py diff --git a/python 3/koans/joes.py b/python3/koans/joes.py similarity index 100% rename from python 3/koans/joes.py rename to python3/koans/joes.py diff --git a/python 3/koans/local_module.py b/python3/koans/local_module.py similarity index 100% rename from python 3/koans/local_module.py rename to python3/koans/local_module.py diff --git a/python 3/koans/local_module_with_all_defined.py b/python3/koans/local_module_with_all_defined.py similarity index 100% rename from python 3/koans/local_module_with_all_defined.py rename to python3/koans/local_module_with_all_defined.py diff --git a/python 3/koans/triangle.py b/python3/koans/triangle.py similarity index 100% rename from python 3/koans/triangle.py rename to python3/koans/triangle.py diff --git a/python 3/libs/__init__.py b/python3/libs/__init__.py similarity index 100% rename from python 3/libs/__init__.py rename to python3/libs/__init__.py diff --git a/python 3/libs/colorama/LICENSE-colorama b/python3/libs/colorama/LICENSE-colorama similarity index 100% rename from python 3/libs/colorama/LICENSE-colorama rename to python3/libs/colorama/LICENSE-colorama diff --git a/python 3/libs/colorama/__init__.py b/python3/libs/colorama/__init__.py similarity index 100% rename from python 3/libs/colorama/__init__.py rename to python3/libs/colorama/__init__.py diff --git a/python 3/libs/colorama/ansi.py b/python3/libs/colorama/ansi.py similarity index 100% rename from python 3/libs/colorama/ansi.py rename to python3/libs/colorama/ansi.py diff --git a/python 3/libs/colorama/ansitowin32.py b/python3/libs/colorama/ansitowin32.py similarity index 100% rename from python 3/libs/colorama/ansitowin32.py rename to python3/libs/colorama/ansitowin32.py diff --git a/python 3/libs/colorama/initialise.py b/python3/libs/colorama/initialise.py similarity index 100% rename from python 3/libs/colorama/initialise.py rename to python3/libs/colorama/initialise.py diff --git a/python 3/libs/colorama/win32.py b/python3/libs/colorama/win32.py similarity index 100% rename from python 3/libs/colorama/win32.py rename to python3/libs/colorama/win32.py diff --git a/python 3/libs/colorama/winterm.py b/python3/libs/colorama/winterm.py similarity index 100% rename from python 3/libs/colorama/winterm.py rename to python3/libs/colorama/winterm.py diff --git a/python 3/libs/mock.py b/python3/libs/mock.py similarity index 100% rename from python 3/libs/mock.py rename to python3/libs/mock.py diff --git a/python 3/run.bat b/python3/run.bat similarity index 100% rename from python 3/run.bat rename to python3/run.bat diff --git a/python 3/run.sh b/python3/run.sh similarity index 100% rename from python 3/run.sh rename to python3/run.sh diff --git a/python 3/runner/__init__.py b/python3/runner/__init__.py similarity index 100% rename from python 3/runner/__init__.py rename to python3/runner/__init__.py diff --git a/python 3/runner/helper.py b/python3/runner/helper.py similarity index 100% rename from python 3/runner/helper.py rename to python3/runner/helper.py diff --git a/python 3/runner/koan.py b/python3/runner/koan.py similarity index 100% rename from python 3/runner/koan.py rename to python3/runner/koan.py diff --git a/python 3/runner/mockable_test_result.py b/python3/runner/mockable_test_result.py similarity index 100% rename from python 3/runner/mockable_test_result.py rename to python3/runner/mockable_test_result.py diff --git a/python 3/runner/mountain.py b/python3/runner/mountain.py similarity index 100% rename from python 3/runner/mountain.py rename to python3/runner/mountain.py diff --git a/python 3/runner/path_to_enlightenment.py b/python3/runner/path_to_enlightenment.py similarity index 100% rename from python 3/runner/path_to_enlightenment.py rename to python3/runner/path_to_enlightenment.py diff --git a/python 3/runner/runner_tests/__init__.py b/python3/runner/runner_tests/__init__.py similarity index 100% rename from python 3/runner/runner_tests/__init__.py rename to python3/runner/runner_tests/__init__.py diff --git a/python 3/runner/runner_tests/test_helper.py b/python3/runner/runner_tests/test_helper.py similarity index 100% rename from python 3/runner/runner_tests/test_helper.py rename to python3/runner/runner_tests/test_helper.py diff --git a/python 3/runner/runner_tests/test_mountain.py b/python3/runner/runner_tests/test_mountain.py similarity index 100% rename from python 3/runner/runner_tests/test_mountain.py rename to python3/runner/runner_tests/test_mountain.py diff --git a/python 3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py similarity index 100% rename from python 3/runner/runner_tests/test_sensei.py rename to python3/runner/runner_tests/test_sensei.py diff --git a/python 3/runner/sensei.py b/python3/runner/sensei.py similarity index 100% rename from python 3/runner/sensei.py rename to python3/runner/sensei.py diff --git a/python 3/runner/writeln_decorator.py b/python3/runner/writeln_decorator.py similarity index 100% rename from python 3/runner/writeln_decorator.py rename to python3/runner/writeln_decorator.py From 431cb58bcb40f50232a046865c980cdf3de25e53 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Fri, 27 Jul 2012 22:25:22 -0400 Subject: [PATCH 017/237] Do rst images work? --- README.rst | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 6c92e2dcf..1e634e935 100644 --- a/README.rst +++ b/README.rst @@ -4,6 +4,8 @@ Python Koans Python Koans is a port of Edgecase's "Ruby Koans". +.. image:: http://i442.photobucket.com/albums/qq150/gregmalcolm/PythonKoansScreenshot.png + Python Koans is an interactive tutorial for learning Python by making tests pass. Most tests are 'fixed' by filling the missing parts of assert functions. Eg: @@ -22,13 +24,13 @@ As well as being a great way to learn some Python, it is also a good way to get Downloading Python Koans ------------------------ -Python Koans is available through Mercurial on bitbucket: +Python Koans is available through git on Github: - http://bitbucket.org/gregmalcolm/python_koans + http://wiki.github.com/gregmalcolm/python_koans -It is also mirrored on github for Git users : +It is also mirrored on bitbucet for Mercurial users : - http://wiki.github.com/gregmalcolm/python_koans + http://bitbucket.org/gregmalcolm/python_koans Either site will allow you to download the source as a zip/gz/bz2. @@ -56,14 +58,17 @@ Getting Started From a *nix terminal or windows command prompt go to the python koans\python_VERSION folder and run: +:: python contemplate_koans.py or +:: python3 contemplate_koans.py In my case I'm using Python 3 with windows, so I fire up my command shell (cmd.exe) and run this: +:: C:\>cd "c:\hg\python_koans\python3" C:\hg\python_koans\python3>python contemplate_koans.py @@ -78,18 +83,19 @@ In my case I'm using Python 3 with windows, so I fire up my command shell (cmd.e assert_truth self.assertTrue(False) # This should be true - Beautiful is better than ugly. C:\hg\python_koans\python3> Apparently a test failed: +:: AssertionError: False is not True It also tells me exactly where the problem in, its an assert on line 12 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: +:: class Dog: pass @@ -99,6 +105,7 @@ Sooner or later you will likely encounter tests where you are not sure what the 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: +:: C:\hg\python_koans\python3>python Python 3.1.2 (r312:79149, Mar 21 2010, 00:41:52) [MSC v.1500 32 bit (Intel)] on win32 @@ -110,6 +117,7 @@ This is where the Python Command Line can come in handy. in this case I can fire True >>> + Getting the Most From the Koans ------------------------------- @@ -139,7 +147,6 @@ Acknowledgments Thanks go to Jim Weirich and Joe O'Brien for the original Ruby Koans that Python Koans is based on! Also the Ruby Koans in turn borrows from Metakoans so thanks also go to Ara Howard for that! - Also thanks to everyone who helped with the Python Koans conversion! In particular I got a great headstart on the project by forking from this Python Koans startup project: http://bitbucket.org/mcrute/python_koans/ From 80153984eeab400d0ed28cca1b4ea298650e4ccb Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Fri, 27 Jul 2012 22:32:04 -0400 Subject: [PATCH 018/237] Better... or worse? --- README.rst | 44 +++++++------------------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/README.rst b/README.rst index 1e634e935..76e2e280c 100644 --- a/README.rst +++ b/README.rst @@ -26,7 +26,7 @@ Downloading Python Koans Python Koans is available through git on Github: - http://wiki.github.com/gregmalcolm/python_koans + http://github.com/gregmalcolm/python_koans It is also mirrored on bitbucet for Mercurial users : @@ -56,46 +56,26 @@ If you have problems, this may help: Getting Started --------------- -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 go to the python koans\python_VERSION folder and run:: -:: python contemplate_koans.py -or +or:: -:: python3 contemplate_koans.py In my case I'm using Python 3 with windows, so I fire up my command shell (cmd.exe) and run this: -:: - C:\>cd "c:\hg\python_koans\python3" - C:\hg\python_koans\python3>python contemplate_koans.py - - Thinking AboutAsserts - test_assert_truth has damaged your karma. +.. image:: http://i442.photobucket.com/albums/qq150/gregmalcolm/GettingStarted.png - You have not yet reached enlightenment ... - AssertionError: False is not True +Apparently a test failed:: - Please meditate on the following code: - File "C:\hg\python_koans\python3\koans\about_asserts.py", line 12, in test_ - assert_truth - self.assertTrue(False) # This should be true - - Beautiful is better than ugly. - C:\hg\python_koans\python3> - -Apparently a test failed: - -:: AssertionError: False is not True It also tells me exactly where the problem in, its an assert on line 12 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: +Sooner or later you will likely encounter tests where you are not sure what the expected value should be. For example:: -:: class Dog: pass @@ -105,17 +85,7 @@ Sooner or later you will likely encounter tests where you are not sure what the 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: -:: - C:\hg\python_koans\python3>python - Python 3.1.2 (r312:79149, Mar 21 2010, 00:41:52) [MSC v.1500 32 bit (Intel)] on - win32 - Type "help", "copyright", "credits" or "license" for more information. - >>> class Dog: pass - ... - >>> fido = Dog() - >>> isinstance(fido, object) - True - >>> +.. image:: http://i442.photobucket.com/albums/qq150/gregmalcolm/DebuggingPython.png Getting the Most From the Koans From 5bac40a112363ca077faa4c34080977b771019af Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Fri, 27 Jul 2012 22:37:36 -0400 Subject: [PATCH 019/237] Bitbucket, Y U No render Content paragraph properly? --- README.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 76e2e280c..ef1f017af 100644 --- a/README.rst +++ b/README.rst @@ -91,11 +91,10 @@ This is where the Python Command Line can come in handy. in this case I can fire 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 (green), then refactor it (that is look at the code and see if you can make it any better. In this case you will need to run the koan and see it fail (red), make the test pass (green), then take a moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor)." - Content ------- From 018cf37254cd084bd9e60fd4cd2e727c1f716249 Mon Sep 17 00:00:00 2001 From: mikelietz Date: Sun, 29 Jul 2012 14:19:31 -0300 Subject: [PATCH 020/237] All the other 'world's are lowercased. --- python2/koans/about_strings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_strings.py b/python2/koans/about_strings.py index d978c5c10..af8671b44 100644 --- a/python2/koans/about_strings.py +++ b/python2/koans/about_strings.py @@ -64,7 +64,7 @@ def test_plus_concatenates_strings(self): self.assertEqual(__, string) def test_adjacent_strings_are_concatenated_automatically(self): - string = "Hello" ", " "World" + string = "Hello" ", " "world" self.assertEqual(__, string) def test_plus_will_not_modify_original_strings(self): From 73ab6d2576ccecbd2cf8f229e00937bd60cb1d37 Mon Sep 17 00:00:00 2001 From: Boyan Alexandrov Date: Sun, 29 Jul 2012 13:23:59 -0400 Subject: [PATCH 021/237] enclose string literals of dictionary values with single quotes for consistency --- python2/koans/about_dictionaries.py | 26 +++++++++++++------------- python3/koans/about_dictionaries.py | 24 ++++++++++++------------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/python2/koans/about_dictionaries.py b/python2/koans/about_dictionaries.py index e2ba91637..49ac268da 100644 --- a/python2/koans/about_dictionaries.py +++ b/python2/koans/about_dictionaries.py @@ -18,36 +18,36 @@ def test_creating_dictionaries(self): def test_dictionary_literals(self): empty_dict = {} self.assertEqual(dict, type(empty_dict)) - babel_fish = {'one': "uno", 'two': "dos"} + babel_fish = {'one': 'uno', 'two': 'dos'} self.assertEqual(__, len(babel_fish)) def test_accessing_dictionaries(self): - babel_fish = {'one': "uno", 'two': "dos"} + 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" + babel_fish = {'one': 'uno', 'two': 'dos'} + babel_fish['one'] = 'eins' - expected = {'two': "dos", 'one': __} + 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"} + dict1 = {'one': 'uno', 'two': 'dos'} + dict2 = {'two': 'dos', 'one': 'uno'} self.assertEqual(____, dict1 == dict2) def test_dictionary_keys(self): - babel_fish = {'one': "uno", 'two': "dos"} + babel_fish = {'one': 'uno', 'two': 'dos'} self.assertEqual(__, len(babel_fish.keys())) self.assertEqual(__, 'one' in babel_fish) self.assertEqual(__, 'two' in babel_fish) self.assertEqual(list, babel_fish.keys().__class__) def test_dictionary_values(self): - babel_fish = {'one': "uno", 'two': "dos"} + babel_fish = {'one': 'uno', 'two': 'dos'} self.assertEqual(__, len(babel_fish.values())) self.assertEqual(__, 'uno' in babel_fish.values()) self.assertEqual(__, 'dos' in babel_fish.values()) @@ -55,10 +55,10 @@ def test_dictionary_values(self): def test_making_a_dictionary_from_a_sequence_of_keys(self): cards = {}.fromkeys( - ("red warrior", "green elf", "blue valkyrie", "yellow dwarf", - "confused looking zebra"), + ('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"]) + self.assertEqual(__, cards['green elf']) + self.assertEqual(__, cards['yellow dwarf']) diff --git a/python3/koans/about_dictionaries.py b/python3/koans/about_dictionaries.py index 01995e168..bfafcafb6 100644 --- a/python3/koans/about_dictionaries.py +++ b/python3/koans/about_dictionaries.py @@ -17,45 +17,45 @@ def test_creating_dictionaries(self): def test_dictionary_literals(self): empty_dict = {} self.assertEqual(dict, type(empty_dict)) - babel_fish = { 'one': "uno", 'two': "dos" } + babel_fish = { 'one': 'uno', 'two': 'dos' } self.assertEqual(__, len(babel_fish)) def test_accessing_dictionaries(self): - babel_fish = { 'one': "uno", 'two': "dos" } + 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" + babel_fish = { 'one': 'uno', 'two': 'dos' } + babel_fish['one'] = 'eins' - expected = { 'two': "dos", 'one': __ } + expected = { 'two': 'dos', 'one': __ } self.assertDictEqual(expected, babel_fish) def test_dictionary_is_unordered(self): - dict1 = { 'one': "uno", 'two': "dos" } - dict2 = { 'two': "dos", 'one': "uno" } + dict1 = { 'one': 'uno', 'two': 'dos' } + dict2 = { 'two': 'dos', 'one': 'uno' } self.assertEqual(__, dict1 == dict2) def test_dictionary_keys(self): - babel_fish = { 'one': "uno", 'two': "dos" } + babel_fish = { 'one': 'uno', 'two': 'dos' } self.assertEqual(__, len(babel_fish.keys())) self.assertEqual(__, 'one' in babel_fish) self.assertEqual(__, 'two' in babel_fish) self.assertEqual('dict_keys', babel_fish.keys().__class__.__name__) def test_dictionary_values(self): - babel_fish = { 'one': "uno", 'two': "dos" } + babel_fish = { 'one': 'uno', 'two': 'dos' } self.assertEqual(__, len(babel_fish.values())) self.assertEqual(__, 'uno' in babel_fish.values()) self.assertEqual(__, 'dos' in babel_fish.values()) self.assertEqual('dict_values', babel_fish.values().__class__.__name__) 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) + 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"]) + self.assertEqual(__, cards['green elf']) + self.assertEqual(__, cards['yellow dwarf']) From d60690a64a296fa859cade1f57c82de6b16ae03c Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 29 Jul 2012 13:33:36 -0400 Subject: [PATCH 022/237] Do same for python3 flavor --- python3/koans/about_strings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_strings.py b/python3/koans/about_strings.py index 8e60cf290..3b85eebdb 100644 --- a/python3/koans/about_strings.py +++ b/python3/koans/about_strings.py @@ -63,7 +63,7 @@ def test_plus_concatenates_strings(self): self.assertEqual(__, string) def test_adjacent_strings_are_concatenated_automatically(self): - string = "Hello" ", " "World" + string = "Hello" ", " "world" self.assertEqual(__, string) def test_plus_will_not_modify_original_strings(self): From a6d699798107c2ff637990ca000ad5b4cbf17a21 Mon Sep 17 00:00:00 2001 From: Aaron Baker Date: Sun, 29 Jul 2012 13:54:04 -0400 Subject: [PATCH 023/237] changed about_dictionaries.py to combine keys and values to one test to more easily show the difference between keys and values --- python2/koans/about_dictionaries.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/python2/koans/about_dictionaries.py b/python2/koans/about_dictionaries.py index 49ac268da..320212f34 100644 --- a/python2/koans/about_dictionaries.py +++ b/python2/koans/about_dictionaries.py @@ -39,20 +39,17 @@ def test_dictionary_is_unordered(self): self.assertEqual(____, dict1 == dict2) - def test_dictionary_keys(self): + def test_dictionary_keys_and_values(self): babel_fish = {'one': 'uno', 'two': 'dos'} self.assertEqual(__, len(babel_fish.keys())) - self.assertEqual(__, 'one' in babel_fish) - self.assertEqual(__, 'two' in babel_fish) - self.assertEqual(list, babel_fish.keys().__class__) - - def test_dictionary_values(self): - babel_fish = {'one': 'uno', 'two': 'dos'} self.assertEqual(__, len(babel_fish.values())) - self.assertEqual(__, 'uno' in 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()) + self.assertEqual(list, babel_fish.keys().__class__) self.assertEqual(list, babel_fish.values().__class__) - + def test_making_a_dictionary_from_a_sequence_of_keys(self): cards = {}.fromkeys( ('red warrior', 'green elf', 'blue valkyrie', 'yellow dwarf', From 6c4eb824b8f6d375798313dd11f3489cb5fba785 Mon Sep 17 00:00:00 2001 From: Aaron Baker Date: Sun, 29 Jul 2012 14:05:26 -0400 Subject: [PATCH 024/237] changed python2 and python3 about_dictionaries.py to better explain the difference between values and keys in dictionaries --- python2/koans/about_dictionaries.py | 2 ++ python3/koans/about_dictionaries.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/python2/koans/about_dictionaries.py b/python2/koans/about_dictionaries.py index 320212f34..ef1c136d9 100644 --- a/python2/koans/about_dictionaries.py +++ b/python2/koans/about_dictionaries.py @@ -48,7 +48,9 @@ def test_dictionary_keys_and_values(self): self.assertEqual(__, 'uno' in babel_fish.keys()) self.assertEqual(__, 'dos' in babel_fish.values()) self.assertEqual(list, babel_fish.keys().__class__) + self.assertEqual('dict_keys', babel_fish.keys().__class__.__name__) self.assertEqual(list, babel_fish.values().__class__) + self.assertEqual('dict_values', babel_fish.values().__class__.__name__) def test_making_a_dictionary_from_a_sequence_of_keys(self): cards = {}.fromkeys( diff --git a/python3/koans/about_dictionaries.py b/python3/koans/about_dictionaries.py index bfafcafb6..051fa9be2 100644 --- a/python3/koans/about_dictionaries.py +++ b/python3/koans/about_dictionaries.py @@ -38,20 +38,20 @@ def test_dictionary_is_unordered(self): self.assertEqual(__, dict1 == dict2) - def test_dictionary_keys(self): - babel_fish = { 'one': 'uno', 'two': 'dos' } + + def test_dictionary_keys_and_values(self): + babel_fish = {'one': 'uno', 'two': 'dos'} self.assertEqual(__, len(babel_fish.keys())) - self.assertEqual(__, 'one' in babel_fish) - self.assertEqual(__, 'two' in babel_fish) - self.assertEqual('dict_keys', babel_fish.keys().__class__.__name__) - - def test_dictionary_values(self): - babel_fish = { 'one': 'uno', 'two': 'dos' } self.assertEqual(__, len(babel_fish.values())) - self.assertEqual(__, 'uno' in 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()) + self.assertEqual(list, babel_fish.keys().__class__) + self.assertEqual('dict_keys', babel_fish.keys().__class__.__name__) + self.assertEqual(lis, babel_fish.values().__class__) self.assertEqual('dict_values', babel_fish.values().__class__.__name__) - + 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) From ef36871e685a542aa28a1c75e44d92320c4cd397 Mon Sep 17 00:00:00 2001 From: mikelietz Date: Sun, 29 Jul 2012 14:21:42 -0400 Subject: [PATCH 025/237] Call 'a' global method, not 'an' global method. Python3 had it right. --- python2/koans/about_methods.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_methods.py b/python2/koans/about_methods.py index 7279d8c2a..39da18065 100644 --- a/python2/koans/about_methods.py +++ b/python2/koans/about_methods.py @@ -13,7 +13,7 @@ def my_global_function(a, b): class AboutMethods(Koan): - def test_calling_an_global_function(self): + 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 From 20811df0e6e12d04c51c0a800fb0729463c8a91e Mon Sep 17 00:00:00 2001 From: mikelietz Date: Sun, 29 Jul 2012 14:43:55 -0400 Subject: [PATCH 026/237] A one line method should be one line, right? Python3 had it right. --- python2/koans/about_methods.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python2/koans/about_methods.py b/python2/koans/about_methods.py index 39da18065..173cd0ce3 100644 --- a/python2/koans/about_methods.py +++ b/python2/koans/about_methods.py @@ -113,8 +113,7 @@ def test_pass_does_nothing_at_all(self): # ------------------------------------------------------------------ - def one_line_method(self): - return 'Madagascar' + def one_line_method(self): return 'Madagascar' def test_no_indentation_required_for_one_line_statement_bodies(self): self.assertEqual(__, self.one_line_method()) From 9316cec757aa262a4180bf775952cb97913cfa5c Mon Sep 17 00:00:00 2001 From: mikelietz Date: Sun, 29 Jul 2012 14:48:00 -0400 Subject: [PATCH 027/237] A one line method should be one line, right? Python3 had it right. --- python2/koans/about_methods.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python2/koans/about_methods.py b/python2/koans/about_methods.py index 7279d8c2a..65fa8b06f 100644 --- a/python2/koans/about_methods.py +++ b/python2/koans/about_methods.py @@ -113,8 +113,7 @@ def test_pass_does_nothing_at_all(self): # ------------------------------------------------------------------ - def one_line_method(self): - return 'Madagascar' + def one_line_method(self): return 'Madagascar' def test_no_indentation_required_for_one_line_statement_bodies(self): self.assertEqual(__, self.one_line_method()) From 6f562204298a932a7d8f059b1b68bdaf74732b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Ezequiel=20Gutierrez=20=C3=81lvarez?= Date: Thu, 2 Aug 2012 23:23:38 -0500 Subject: [PATCH 028/237] Fixing syntax error: equivelant -> equivalent --- 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 cb32a50ec..dd31b91f9 100644 --- a/python2/koans/about_generators.py +++ b/python2/koans/about_generators.py @@ -133,9 +133,9 @@ def test_generators_can_see_if_they_have_been_called_with_a_value(self): next(generator2) self.assertEqual(__, next(generator2)) - def test_send_none_is_equivelant_to_next(self): + def test_send_none_is_equivalent_to_next(self): generator = self.yield_tester() next(generator) - # 'next(generator)' is exactly equivelant to 'generator.send(None)' + # 'next(generator)' is exactly equivalent to 'generator.send(None)' self.assertEqual(__, generator.send(None)) diff --git a/python3/koans/about_generators.py b/python3/koans/about_generators.py index 244ea1e6b..5986cf1fa 100644 --- a/python3/koans/about_generators.py +++ b/python3/koans/about_generators.py @@ -136,11 +136,11 @@ def test_generators_can_see_if_they_have_been_called_with_a_value(self): next(generator2) self.assertEqual(__, next(generator2)) - def test_send_none_is_equivelant_to_next(self): + def test_send_none_is_equivalent_to_next(self): generator = self.yield_tester() next(generator) - # 'next(generator)' is exactly equivelant to 'generator.send(None)' + # 'next(generator)' is exactly equivalent to 'generator.send(None)' self.assertEqual(__, generator.send(None)) From 3f3c31975762a3a7ea6d83a453921ea0b65024a9 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Mon, 6 Aug 2012 15:12:19 -0400 Subject: [PATCH 029/237] Removed some confusing tests in about_dictionaries --- python2/koans/about_dictionaries.py | 4 ---- python3/koans/about_dictionaries.py | 4 ---- 2 files changed, 8 deletions(-) diff --git a/python2/koans/about_dictionaries.py b/python2/koans/about_dictionaries.py index ef1c136d9..518ea54bf 100644 --- a/python2/koans/about_dictionaries.py +++ b/python2/koans/about_dictionaries.py @@ -47,10 +47,6 @@ def test_dictionary_keys_and_values(self): self.assertEqual(__, 'two' in babel_fish.values()) self.assertEqual(__, 'uno' in babel_fish.keys()) self.assertEqual(__, 'dos' in babel_fish.values()) - self.assertEqual(list, babel_fish.keys().__class__) - self.assertEqual('dict_keys', babel_fish.keys().__class__.__name__) - self.assertEqual(list, babel_fish.values().__class__) - self.assertEqual('dict_values', babel_fish.values().__class__.__name__) def test_making_a_dictionary_from_a_sequence_of_keys(self): cards = {}.fromkeys( diff --git a/python3/koans/about_dictionaries.py b/python3/koans/about_dictionaries.py index 051fa9be2..0ef64cf84 100644 --- a/python3/koans/about_dictionaries.py +++ b/python3/koans/about_dictionaries.py @@ -47,10 +47,6 @@ def test_dictionary_keys_and_values(self): self.assertEqual(__, 'two' in babel_fish.values()) self.assertEqual(__, 'uno' in babel_fish.keys()) self.assertEqual(__, 'dos' in babel_fish.values()) - self.assertEqual(list, babel_fish.keys().__class__) - self.assertEqual('dict_keys', babel_fish.keys().__class__.__name__) - self.assertEqual(lis, babel_fish.values().__class__) - self.assertEqual('dict_values', babel_fish.values().__class__.__name__) 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) From 654a80f185d7fd171e9a06f220c15b3a3944d0ff Mon Sep 17 00:00:00 2001 From: Mechanical snail Date: Sat, 11 Aug 2012 04:58:49 +0000 Subject: [PATCH 030/237] Fix punctuation error in comment `it's` -> `its` --- python2/koans/about_proxy_object_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_proxy_object_project.py b/python2/koans/about_proxy_object_project.py index 27b89363f..2fe65a6c8 100644 --- a/python2/koans/about_proxy_object_project.py +++ b/python2/koans/about_proxy_object_project.py @@ -13,7 +13,7 @@ # 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 that it's Ruby Koans counterpart, but you +# Note: This is a bit trickier that its Ruby Koans counterpart, but you # can do it! from runner.koan import * From d4a0ab9eb4a685e728b2f84953931ad007a793b8 Mon Sep 17 00:00:00 2001 From: Akshay Date: Tue, 18 Sep 2012 15:10:00 -0300 Subject: [PATCH 031/237] Update python2/koans/about_proxy_object_project.py Editing the tests so that they check for the 'channel' string instead of the 'channel=' string. This is more consistent with Python functionality and the '=' sign is unnecessary in the test unlike in the ruby koans. --- python2/koans/about_proxy_object_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_proxy_object_project.py b/python2/koans/about_proxy_object_project.py index 27b89363f..7eb93fd69 100644 --- a/python2/koans/about_proxy_object_project.py +++ b/python2/koans/about_proxy_object_project.py @@ -53,7 +53,7 @@ def test_proxy_records_messages_sent_to_tv(self): tv.power() tv.channel = 10 - self.assertEqual(['power', 'channel='], tv.messages()) + self.assertEqual(['power', 'channel'], tv.messages()) def test_proxy_handles_invalid_messages(self): tv = Proxy(Television()) @@ -83,7 +83,7 @@ def test_proxy_counts_method_calls(self): tv.power() self.assertEqual(2, tv.number_of_times_called('power')) - self.assertEqual(1, tv.number_of_times_called('channel=')) + 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): From 2e66e539e0f97a1112fe08512c70fc71eea9c43f Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 19 Sep 2012 01:37:48 -0300 Subject: [PATCH 032/237] Update python3/koans/about_proxy_object_project.py --- python3/koans/about_proxy_object_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/koans/about_proxy_object_project.py b/python3/koans/about_proxy_object_project.py index e1dd6f024..ef8a8c06b 100644 --- a/python3/koans/about_proxy_object_project.py +++ b/python3/koans/about_proxy_object_project.py @@ -51,7 +51,7 @@ def test_proxy_records_messages_sent_to_tv(self): tv.power() tv.channel = 10 - self.assertEqual(['power', 'channel='], tv.messages()) + self.assertEqual(['power', 'channel'], tv.messages()) def test_proxy_handles_invalid_messages(self): tv = Proxy(Television()) @@ -78,7 +78,7 @@ def test_proxy_counts_method_calls(self): tv.power() self.assertEqual(2, tv.number_of_times_called('power')) - self.assertEqual(1, tv.number_of_times_called('channel=')) + 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): From 137647226d157f75605e9feab523255179f6602b Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 19 Sep 2012 07:26:44 -0400 Subject: [PATCH 033/237] Accepting the grammar advice of snails --- python3/koans/about_proxy_object_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_proxy_object_project.py b/python3/koans/about_proxy_object_project.py index ef8a8c06b..bb5c45620 100644 --- a/python3/koans/about_proxy_object_project.py +++ b/python3/koans/about_proxy_object_project.py @@ -13,7 +13,7 @@ # 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 that it's Ruby Koans counterpart, but you +# Note: This is a bit trickier that its Ruby Koans counterpart, but you # can do it! from runner.koan import * From 3560b055feabdb1ea5d10bbc2cc91e052215dfb0 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 19 Sep 2012 07:45:37 -0400 Subject: [PATCH 034/237] Added screencast info --- README.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ef1f017af..5969e6daf 100644 --- a/README.rst +++ b/README.rst @@ -56,7 +56,14 @@ If you have problems, this may help: Getting Started --------------- -From a *nix terminal or windows command prompt go to the python koans\python_VERSION folder and run:: +Jake Hebbert has created a couple of screencasts available here: + +.. "Getting started using Python Koans": http://vimeo.com/48330033 +.. "Python Koans about_asserts.py": http://vimeo.com/48387395 + +Or if you prefer to read: + +From a *nix terminal or windows command prompt go to the python koans\python_**VERSION** folder and run:: python contemplate_koans.py From a357cde58c643ded21e444d1511dacd7d339b3c2 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 19 Sep 2012 07:47:35 -0400 Subject: [PATCH 035/237] Trying again --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 5969e6daf..f06e58c34 100644 --- a/README.rst +++ b/README.rst @@ -58,12 +58,12 @@ Getting Started Jake Hebbert has created a couple of screencasts available here: -.. "Getting started using Python Koans": http://vimeo.com/48330033 -.. "Python Koans about_asserts.py": http://vimeo.com/48387395 +.. _Getting started using Python Koans: http://vimeo.com/48330033 +.. _Python Koans about_asserts.py: http://vimeo.com/48387395 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 go to the python koans\python_VERSION folder and run:: python contemplate_koans.py From 8f533da9b8161c39a68c0ac6ab6beb4810b69625 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 19 Sep 2012 07:52:07 -0400 Subject: [PATCH 036/237] and again... --- README.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index f06e58c34..bdaa21ca1 100644 --- a/README.rst +++ b/README.rst @@ -58,8 +58,11 @@ Getting Started Jake Hebbert has created a couple of screencasts available here: -.. _Getting started using Python Koans: http://vimeo.com/48330033 -.. _Python Koans about_asserts.py: http://vimeo.com/48387395 + `Getting started using Python Koan` _vimeo_getting_started + `Python Koans about_asserts.py` _vimeo_about_asserts + +.. _vimeo_getting_started: http://vimeo.com/48330033 +.. _vimeo_about_asserts: http://vimeo.com/48387395 Or if you prefer to read: From f4f699355e2e12d05cd778ddd2d8f0df8fef9ac2 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 19 Sep 2012 07:55:13 -0400 Subject: [PATCH 037/237] and again... --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index bdaa21ca1..d996726ad 100644 --- a/README.rst +++ b/README.rst @@ -58,8 +58,8 @@ Getting Started Jake Hebbert has created a couple of screencasts available here: - `Getting started using Python Koan` _vimeo_getting_started - `Python Koans about_asserts.py` _vimeo_about_asserts + `Getting started using Python Koan`_vimeo_getting_started + `Python Koans about_asserts.py`_vimeo_about_asserts .. _vimeo_getting_started: http://vimeo.com/48330033 .. _vimeo_about_asserts: http://vimeo.com/48387395 From 13c876f02f753a46fbbf8f317ede069ed557dfe1 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 19 Sep 2012 07:56:16 -0400 Subject: [PATCH 038/237] and again... --- README.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index d996726ad..8560f5607 100644 --- a/README.rst +++ b/README.rst @@ -58,11 +58,8 @@ Getting Started Jake Hebbert has created a couple of screencasts available here: - `Getting started using Python Koan`_vimeo_getting_started - `Python Koans about_asserts.py`_vimeo_about_asserts - -.. _vimeo_getting_started: http://vimeo.com/48330033 -.. _vimeo_about_asserts: http://vimeo.com/48387395 + http://vimeo.com/48330033 + http://vimeo.com/48387395 Or if you prefer to read: From 5dc46fe17008e540848a7eeff33d380b3259358c Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 19 Sep 2012 07:56:57 -0400 Subject: [PATCH 039/237] and finally? --- README.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 8560f5607..ecb6c3bd5 100644 --- a/README.rst +++ b/README.rst @@ -58,8 +58,9 @@ Getting Started Jake Hebbert has created a couple of screencasts available here: - http://vimeo.com/48330033 - http://vimeo.com/48387395 +http://vimeo.com/48330033 + +http://vimeo.com/48387395 Or if you prefer to read: From 6ae4ca21b18450d642d70f6684141e3b765ac82f Mon Sep 17 00:00:00 2001 From: Ymbirtt Date: Sat, 27 Oct 2012 21:39:49 +0200 Subject: [PATCH 040/237] Change sets for set operators to be more intuitive Using actual people for these sets makes it much clearer what the -, |, & and ^ symbols actually mean. --- python2/koans/about_sets.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/python2/koans/about_sets.py b/python2/koans/about_sets.py index 277cd1c46..c10e6123c 100644 --- a/python2/koans/about_sets.py +++ b/python2/koans/about_sets.py @@ -21,17 +21,14 @@ def test_convert_the_set_into_a_list_to_sort_it(self): # ------------------------------------------------------------------ - def chars_in(self, a_set): - return ''.join(sorted(a_set)) - def test_set_have_arithmetic_operators(self): - good_guy = set('macleod') - bad_guy = set('mutunas') - - self.assertEqual(__, self.chars_in(good_guy - bad_guy)) - self.assertEqual(__, self.chars_in(good_guy | bad_guy)) - self.assertEqual(__, self.chars_in(good_guy & bad_guy)) - self.assertEqual(__, self.chars_in(good_guy ^ bad_guy)) + 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) # ------------------------------------------------------------------ From 4740e1a717ece0e2bef3dfe45b624f6e8d9f4c4a Mon Sep 17 00:00:00 2001 From: Ymbirtt Date: Sat, 27 Oct 2012 22:10:18 +0100 Subject: [PATCH 041/237] Change sets in about_sets.py so set operators are more intuitive Using something more human-readable for these sets makes it clearer what -, |, & and ^ mean. --- python2/koans/about_sets.py | 17 +++++++---------- python3/koans/about_sets.py | 17 +++++++---------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/python2/koans/about_sets.py b/python2/koans/about_sets.py index 277cd1c46..f4130ed1f 100644 --- a/python2/koans/about_sets.py +++ b/python2/koans/about_sets.py @@ -21,17 +21,14 @@ def test_convert_the_set_into_a_list_to_sort_it(self): # ------------------------------------------------------------------ - def chars_in(self, a_set): - return ''.join(sorted(a_set)) - def test_set_have_arithmetic_operators(self): - good_guy = set('macleod') - bad_guy = set('mutunas') - - self.assertEqual(__, self.chars_in(good_guy - bad_guy)) - self.assertEqual(__, self.chars_in(good_guy | bad_guy)) - self.assertEqual(__, self.chars_in(good_guy & bad_guy)) - self.assertEqual(__, self.chars_in(good_guy ^ bad_guy)) + 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) # ------------------------------------------------------------------ diff --git a/python3/koans/about_sets.py b/python3/koans/about_sets.py index 2fd2410ca..86fd5dc77 100644 --- a/python3/koans/about_sets.py +++ b/python3/koans/about_sets.py @@ -32,17 +32,14 @@ def test_convert_the_set_into_a_list_to_sort_it(self): # ------------------------------------------------------------------ - def chars_in(self, a_set): - return ''.join(sorted(a_set)) - def test_set_have_arithmetic_operators(self): - good_guy = set('macleod') - bad_guy = set('mutunas') - - self.assertEqual(__, self.chars_in( good_guy - bad_guy) ) - self.assertEqual(__, self.chars_in( good_guy | bad_guy )) - self.assertEqual(__, self.chars_in( good_guy & bad_guy )) - self.assertEqual(__, self.chars_in( good_guy ^ bad_guy )) + 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) # ------------------------------------------------------------------ From 4ba91299fb416e302710ffe10ac24c5723dfd49a Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Sat, 27 Oct 2012 17:47:05 -0400 Subject: [PATCH 042/237] quote fix --- python2/koans/about_sets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_sets.py b/python2/koans/about_sets.py index 292ea4c3f..86403d5d5 100644 --- a/python2/koans/about_sets.py +++ b/python2/koans/about_sets.py @@ -22,8 +22,8 @@ def test_convert_the_set_into_a_list_to_sort_it(self): # ------------------------------------------------------------------ def test_set_have_arithmetic_operators(self): - scotsmen = set(['MacLeod', "Wallace', 'Willie']) - warriors = set(['MacLeod', "Wallace', 'Leonidas']) + scotsmen = set(['MacLeod', 'Wallace', 'Willie']) + warriors = set(['MacLeod', 'Wallace', 'Leonidas']) self.assertEqual(__, scotsmen - warriors) self.assertEqual(__, scotsmen | warriors) From f3d83ba2c86675065b9d06b356b481a18882e3c0 Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Sat, 27 Oct 2012 17:57:51 -0400 Subject: [PATCH 043/237] Quote fix py3 side of house --- python3/koans/about_sets.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python3/koans/about_sets.py b/python3/koans/about_sets.py index 86fd5dc77..06400f6a2 100644 --- a/python3/koans/about_sets.py +++ b/python3/koans/about_sets.py @@ -6,7 +6,7 @@ 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) @@ -20,7 +20,7 @@ def test_dictionaries_and_sets_use_same_curly_braces(self): self.assertEqual(__, type({1, 2, 3}).__name__) self.assertEqual(__, type({'one': 1, 'two': 2}).__name__) - + self.assertEqual(__, type({}).__name__) def test_creating_sets_using_strings(self): @@ -29,12 +29,12 @@ def test_creating_sets_using_strings(self): def test_convert_the_set_into_a_list_to_sort_it(self): self.assertEqual(__, sorted(set('12345'))) - + # ------------------------------------------------------------------ def test_set_have_arithmetic_operators(self): - scotsmen = set(['MacLeod', "Wallace', 'Willie']) - warriors = set(['MacLeod', "Wallace', 'Leonidas']) + scotsmen = set(['MacLeod', 'Wallace', 'Willie']) + warriors = set(['MacLeod', 'Wallace', 'Leonidas']) self.assertEqual(__, scotsmen - warriors) self.assertEqual(__, scotsmen | warriors) @@ -46,9 +46,9 @@ def test_set_have_arithmetic_operators(self): def test_we_can_query_set_membership(self): self.assertEqual(__, 127 in {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')) From 3516037d97667144edc453550741ae44d545a253 Mon Sep 17 00:00:00 2001 From: Greg Malcolm Date: Sat, 27 Oct 2012 18:07:11 -0400 Subject: [PATCH 044/237] Seeing as it's python3, let's use braces for the Set definitions --- python3/koans/about_sets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/koans/about_sets.py b/python3/koans/about_sets.py index 06400f6a2..337097c24 100644 --- a/python3/koans/about_sets.py +++ b/python3/koans/about_sets.py @@ -33,8 +33,8 @@ def test_convert_the_set_into_a_list_to_sort_it(self): # ------------------------------------------------------------------ def test_set_have_arithmetic_operators(self): - scotsmen = set(['MacLeod', 'Wallace', 'Willie']) - warriors = set(['MacLeod', 'Wallace', 'Leonidas']) + scotsmen = {'MacLeod', 'Wallace', 'Willie'} + warriors = {'MacLeod', 'Wallace', 'Leonidas'} self.assertEqual(__, scotsmen - warriors) self.assertEqual(__, scotsmen | warriors) From c98c999f3619d15047764f5ca8a26fae73b7c685 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Oct 2012 23:14:10 -0400 Subject: [PATCH 045/237] Added some extra clarifaction on what to do on the test_setattr_intercepts_attribute_assignments koans --- python2/koans/about_attribute_access.py | 4 + python3/koans/about_attribute_access.py | 100 ++++++++++++------------ 2 files changed, 56 insertions(+), 48 deletions(-) diff --git a/python2/koans/about_attribute_access.py b/python2/koans/about_attribute_access.py index 5e4fef063..72b1aa94f 100644 --- a/python2/koans/about_attribute_access.py +++ b/python2/koans/about_attribute_access.py @@ -185,6 +185,10 @@ def test_setattr_intercepts_attribute_assignments(self): self.assertEqual(__, fanboy.a_pie) + # + # NOTE: Change the prefix to make this next assert pass + # + prefix = '__' self.assertEqual( "The Laminator, issue #1", diff --git a/python3/koans/about_attribute_access.py b/python3/koans/about_attribute_access.py index 4eabb76f9..4783195be 100644 --- a/python3/koans/about_attribute_access.py +++ b/python3/koans/about_attribute_access.py @@ -8,91 +8,91 @@ from runner.koan import * class AboutAttributeAccess(Koan): - + class TypicalObject: pass - + def test_calling_undefined_functions_normally_results_in_errors(self): typical = self.TypicalObject() - + with self.assertRaises(___): typical.foobar() - + def test_calling_getattribute_causes_an_attribute_error(self): typical = self.TypicalObject() with self.assertRaises(___): typical.__getattribute__('foobar') - + # THINK ABOUT IT: # # If the method __getattribute__() causes the AttributeError, then # what would happen if we redefine __getattribute__()? - + # ------------------------------------------------------------------ - + class CatchAllAttributeReads: 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.assertRegexpMatches(catcher.foobar, __) def test_intercepting_return_values_can_disrupt_the_call_chain(self): catcher = self.CatchAllAttributeReads() self.assertRegexpMatches(catcher.foobaz, __) # This is fine - + try: catcher.foobaz(1) except TypeError as ex: err_msg = ex.args[0] - + self.assertRegexpMatches(err_msg, __) - + # 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_changes_to_the_getattribute_implementation_affects_getattr_function(self): catcher = self.CatchAllAttributeReads() - + self.assertRegexpMatches(getattr(catcher, 'any_attribute'), __) - + # ------------------------------------------------------------------ - + class WellBehavedFooCatcher: def __getattribute__(self, attr_name): if attr_name[:3] == "foo": return "Foo to you too" else: return super().__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() - + with self.assertRaises(___): catcher.normal_undefined_attribute # ------------------------------------------------------------------ - + global stack_depth - stack_depth = 0 + stack_depth = 0 class RecursiveCatcher: def __init__(self): global stack_depth - stack_depth = 0 + stack_depth = 0 self.no_of_getattribute_calls = 0 - - def __getattribute__(self, attr_name): + + def __getattribute__(self, attr_name): global stack_depth # We need something that is outside the scope of this class stack_depth += 1 @@ -100,21 +100,21 @@ def __getattribute__(self, attr_name): 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? + # accessed? # Using 'object' directly because using super() here will also # trigger a __getattribute__() call. - return object.__getattribute__(self, attr_name) - + 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: @@ -126,7 +126,7 @@ def __init__(self): def __getattr__(self, attr_name): self.no_of_getattr_calls += 1 return self.DuffObject - + def my_method(self): pass @@ -135,62 +135,66 @@ def test_getattr_ignores_known_attributes(self): 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(__, type(catcher.give_me_duff_or_give_me_death()).__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 + new_attr_name = "a_" + new_attr_name - object.__setattr__(self, new_attr_name, value) + 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) + + 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: + class ScarySetter: 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() From 5e5c64e676dddadb8fc02201b20ecc455cded0f2 Mon Sep 17 00:00:00 2001 From: Ryan Braganza Date: Wed, 28 Nov 2012 19:41:09 +1100 Subject: [PATCH 046/237] fix typo bitbucet -> bitbucket --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index ecb6c3bd5..7b7b84006 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,7 @@ Python Koans is available through git on Github: http://github.com/gregmalcolm/python_koans -It is also mirrored on bitbucet for Mercurial users : +It is also mirrored on bitbucket for Mercurial users : http://bitbucket.org/gregmalcolm/python_koans From 3d3018bba51c6bf4e4fcce477581df3a73d82b66 Mon Sep 17 00:00:00 2001 From: DeK Date: Mon, 7 Jan 2013 18:00:20 +0100 Subject: [PATCH 047/237] Fixes issue #35: as of Python 3.3, importing a subfolder without the __init__ method does not raise any exception in test_subfolders_without_an_init_module_are_not_part_of_the_package. Trying to import something from it does the trick. Signed-off-by: DeK --- python3/koans/about_packages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_packages.py b/python3/koans/about_packages.py index e68a42d4c..9596ba54d 100644 --- a/python3/koans/about_packages.py +++ b/python3/koans/about_packages.py @@ -39,7 +39,7 @@ def test_subfolders_become_modules_if_they_have_an_init_module(self): def test_subfolders_without_an_init_module_are_not_part_of_the_package(self): # Import ./a_normal_folder/ - with self.assertRaises(___): from . import a_normal_folder + with self.assertRaises(___): from a_normal_folder import Duck # ------------------------------------------------------------------ From a0f303e63bb61d4c398d8d1ed3fa1bf9c664aec3 Mon Sep 17 00:00:00 2001 From: t-kl Date: Mon, 11 Feb 2013 23:54:28 +0100 Subject: [PATCH 048/237] removed duplicate "the" in comment --- python2/koans/about_with_statements.py | 4 ++-- python3/koans/about_with_statements.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python2/koans/about_with_statements.py b/python2/koans/about_with_statements.py index 562ba128a..b5113bccd 100644 --- a/python2/koans/about_with_statements.py +++ b/python2/koans/about_with_statements.py @@ -54,8 +54,8 @@ def test_finding_lines(self): ## 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 - ## the bread part of the sandwich almost always goes together, but + ## 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, diff --git a/python3/koans/about_with_statements.py b/python3/koans/about_with_statements.py index 9dd0a5f49..761ee79e1 100644 --- a/python3/koans/about_with_statements.py +++ b/python3/koans/about_with_statements.py @@ -53,8 +53,8 @@ def test_finding_lines(self): ## 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 - ## the bread part of the sandwich almost always goes together, but + ## 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, From 17c4d777cd6ff856a8fccd3a390b6092a743dfcd Mon Sep 17 00:00:00 2001 From: hebbertja Date: Mon, 11 Feb 2013 20:02:11 -0600 Subject: [PATCH 049/237] Update README.rst --- README.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 7b7b84006..a8d96cabb 100644 --- a/README.rst +++ b/README.rst @@ -58,9 +58,7 @@ Getting Started Jake Hebbert has created a couple of screencasts available here: -http://vimeo.com/48330033 - -http://vimeo.com/48387395 +http://www.youtube.com/watch?v=e2WXgXEjbHY&list=PL5Up_u-XkWgNcunP_UrTJG_3EXgbK2BQJ&index=1 Or if you prefer to read: From 4c88ac6b1da6ddb127a67d297a28aeba0234e733 Mon Sep 17 00:00:00 2001 From: robotsmack Date: Mon, 11 Feb 2013 21:02:09 -0700 Subject: [PATCH 050/237] Update python2/koans/about_strings.py Changed the 'con' to 'can' in the function name line 102. --- python2/koans/about_strings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_strings.py b/python2/koans/about_strings.py index af8671b44..c60f7c615 100644 --- a/python2/koans/about_strings.py +++ b/python2/koans/about_strings.py @@ -99,7 +99,7 @@ def test_use_format_to_interpolate_variables(self): string = "The values are {0} and {1}".format(value1, value2) self.assertEqual(__, string) - def test_formatted_values_con_be_shown_in_any_order_or_be_repeated(self): + 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) From 384f397f8089742bc23d741c89ea3a29343db408 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 12 Feb 2013 16:02:00 +0100 Subject: [PATCH 051/237] Respect exit codes when there are still koans left to finish --- python2/runner/sensei.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index 7519e17fa..597285d41 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -3,6 +3,7 @@ import unittest import re +import sys import glob import helper @@ -88,7 +89,7 @@ def learn(self): self.stream.writeln("") self.stream.writeln(self.say_something_zenlike()) - if self.failures: return + if self.failures: sys.exit(-1) self.stream.writeln( "\n{0}**************************************************" \ .format(Fore.RESET)) From 0597fcef2f5a9c3f26b60330a512faa18766bad1 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 12 Feb 2013 16:33:00 +0100 Subject: [PATCH 052/237] Adding integration with Travis-CI for automatic Zen illumination --- python2/.travis.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 python2/.travis.yml diff --git a/python2/.travis.yml b/python2/.travis.yml new file mode 100644 index 000000000..07703f73c --- /dev/null +++ b/python2/.travis.yml @@ -0,0 +1,13 @@ +language: python +python: + - "2.7" +script: + - python contemplate_koans.py about_asserts + # The rest of the koans required to complete session5 of @SciLifeLab http://github.com/pythonkurs + # + # about_none about_lists about_list_assignments about_dictionaries + # about_strings about_tuples about_methods about_control_statements + # about_true_and_false about_sets + +notifications: + email: false From 61f08edf881ab5e632989a81d118043774beb5cc Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 12 Feb 2013 16:40:13 +0100 Subject: [PATCH 053/237] Bad karma with travis koans --- python2/.travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/python2/.travis.yml b/python2/.travis.yml index 07703f73c..384a9bd4a 100644 --- a/python2/.travis.yml +++ b/python2/.travis.yml @@ -1,13 +1,15 @@ language: python python: - - "2.7" + - 2.7 + script: - - python contemplate_koans.py about_asserts - # The rest of the koans required to complete session5 of @SciLifeLab http://github.com/pythonkurs + - python contemplate_koans.py about_asserts # add further koans here separated by spaces + + # Some other koans (see runner/sensei.py or "ls koans" to see the light): # # about_none about_lists about_list_assignments about_dictionaries # about_strings about_tuples about_methods about_control_statements # about_true_and_false about_sets notifications: - email: false + email: false From b7c95c89f0571caa813c0beaaf9fe0453e81fb1f Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 12 Feb 2013 16:58:49 +0100 Subject: [PATCH 054/237] Travis does not enlighten itself, why? --- python2/.travis.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/python2/.travis.yml b/python2/.travis.yml index 384a9bd4a..34128db4a 100644 --- a/python2/.travis.yml +++ b/python2/.travis.yml @@ -1,15 +1,14 @@ language: python + python: - 2.7 - script: - python contemplate_koans.py about_asserts # add further koans here separated by spaces - - # Some other koans (see runner/sensei.py or "ls koans" to see the light): - # - # about_none about_lists about_list_assignments about_dictionaries - # about_strings about_tuples about_methods about_control_statements - # about_true_and_false about_sets - notifications: email: false + +# Some other koans (see runner/sensei.py or "ls koans" to see the light): +# +# about_none about_lists about_list_assignments about_dictionaries +# about_strings about_tuples about_methods about_control_statements +# about_true_and_false about_sets ... From 2096b7d7bbdec8fb2946c1988c41c0dae91988e4 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 12 Feb 2013 17:06:36 +0100 Subject: [PATCH 055/237] Of course, .travis.yml should be on the top of the mountain to see the sky --- python2/.travis.yml => .travis.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python2/.travis.yml => .travis.yml (100%) diff --git a/python2/.travis.yml b/.travis.yml similarity index 100% rename from python2/.travis.yml rename to .travis.yml From d98eb1d3581dbb8101864b812ef868d4c225cd73 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 12 Feb 2013 20:30:58 +0100 Subject: [PATCH 056/237] where is the monk? --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 34128db4a..f9e8309f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: python python: - 2.7 script: + - ls - python contemplate_koans.py about_asserts # add further koans here separated by spaces notifications: email: false From b4ea09dbeb535126cfc8e6ebce37cb90351a3c43 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Tue, 12 Feb 2013 20:36:22 +0100 Subject: [PATCH 057/237] entering python2 temple for illumination --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f9e8309f5..3720cb5e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: python python: - 2.7 script: - - ls + - cd python2 - python contemplate_koans.py about_asserts # add further koans here separated by spaces notifications: email: false From 03c0352e991dd476f21b423b9ab48aedffacb808 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Wed, 13 Feb 2013 09:08:27 +0100 Subject: [PATCH 058/237] Testing total illumination with Travis for basic assert koans --- python2/koans/about_asserts.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index 1af8b4e8e..d3aec2d76 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -10,26 +10,26 @@ def test_assert_truth(self): """ We shall contemplate truth by testing reality, via asserts. """ - self.assertTrue(False) # This should be true + self.assertTrue(True) # 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(True, "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) + self.assertEqual(2, 1 + 1) def test_assert_equality(self): """ To understand reality, we must compare our expectations against reality. """ - expected_value = __ + expected_value = 2 actual_value = 1 + 1 self.assertTrue(expected_value == actual_value) @@ -37,7 +37,7 @@ def test_a_better_way_of_asserting_equality(self): """ Some ways of asserting equality are better than others. """ - expected_value = __ + expected_value = 2 actual_value = 1 + 1 self.assertEqual(expected_value, actual_value) @@ -48,4 +48,4 @@ def test_that_unittest_asserts_work_the_same_way_as_python_asserts(self): """ # This throws an AssertionError exception - assert False + assert True From 15527344476e9b64daa0764020db63953a7631a6 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Wed, 13 Feb 2013 12:26:47 +0100 Subject: [PATCH 059/237] Allow for several koans when calling contemplate koan, needs some refactoring --- python2/runner/mountain.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python2/runner/mountain.py b/python2/runner/mountain.py index 4ad479a9c..2f24de700 100644 --- a/python2/runner/mountain.py +++ b/python2/runner/mountain.py @@ -18,8 +18,9 @@ def walk_the_path(self, args=None): "Run the koans tests with a custom runner output." if args and len(args) >=2: - self.tests = unittest.TestLoader().loadTestsFromName("koans." + args[1]) - - self.tests(self.lesson) - self.lesson.learn() + args.pop(0) + for arg in args: + self.tests = unittest.TestLoader().loadTestsFromName("koans." + arg) + self.tests(self.lesson) + self.lesson.learn() return self.lesson From e2bd99a72e4a4e0b6699ae0e357928bc3fe69eb8 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Thu, 14 Feb 2013 16:34:52 +0100 Subject: [PATCH 060/237] Reverting passing asserts --- python2/koans/about_asserts.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index d3aec2d76..1af8b4e8e 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -10,26 +10,26 @@ def test_assert_truth(self): """ We shall contemplate truth by testing reality, via asserts. """ - self.assertTrue(True) # 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(True, "This should be true -- Please fix this") + 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(2, 1 + 1) + self.assertEqual(__, 1 + 1) def test_assert_equality(self): """ To understand reality, we must compare our expectations against reality. """ - expected_value = 2 + expected_value = __ actual_value = 1 + 1 self.assertTrue(expected_value == actual_value) @@ -37,7 +37,7 @@ def test_a_better_way_of_asserting_equality(self): """ Some ways of asserting equality are better than others. """ - expected_value = 2 + expected_value = __ actual_value = 1 + 1 self.assertEqual(expected_value, actual_value) @@ -48,4 +48,4 @@ def test_that_unittest_asserts_work_the_same_way_as_python_asserts(self): """ # This throws an AssertionError exception - assert True + assert False From 158b936bf240491b9a4b27bed1722a3a7b844cbf Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Fri, 15 Feb 2013 07:24:59 -0500 Subject: [PATCH 061/237] Fixed running of contemplate_koans with 0 arguments. Made it so you multiple arguments run as one suite of tests --- python2/runner/mountain.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python2/runner/mountain.py b/python2/runner/mountain.py index 2f24de700..b988c1291 100644 --- a/python2/runner/mountain.py +++ b/python2/runner/mountain.py @@ -13,14 +13,14 @@ 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) - for arg in args: - self.tests = unittest.TestLoader().loadTestsFromName("koans." + arg) - self.tests(self.lesson) - self.lesson.learn() + 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 From 5b5c6082016c37bb87172d6285c10a23f473dbf2 Mon Sep 17 00:00:00 2001 From: Jennifer Hamon Date: Fri, 15 Feb 2013 21:41:13 -0800 Subject: [PATCH 062/237] Modified: python*/runner/sensei.py to fix progress message. The previous sensei message tells the user they are "{completed}/ {total} lessons away from enlightenment." This is not a true statement since your fractional progress is not equal to your distance from enlightenment. I have modified the report_progress function to return a two line string. The first line reports the total progress and the second line tells them they are {total- completed} koans away from enlightenment. I modified report_progress() in both python2/runner/sensei.py and python3/runner/sensei.py --- python2/runner/sensei.py | 15 ++++++++++----- python3/runner/sensei.py | 15 ++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index 597285d41..5c69b9b58 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -157,11 +157,16 @@ def scrapeInterestingStackDump(self, err): return scrape.replace(sep, '\n').strip('\n') def report_progress(self): - return ("You are now {0}/{1} koans and {2}/{3} lessons away from " \ - "reaching enlightenment".format(self.pass_count, - self.total_koans(), - self.lesson_pass_count, - self.total_lessons())) + koans_complete = self.pass_count + lessons_complete = self.lesson_pass_count + koans_remaining = self.total_koans() - koans_complete + lessons_remaining = self.total_lessons() - lessons_complete + + sent1 = "You have completed {0} koans and " \ + "{1} lessons.\n".format(koans_complete, lessons_complete) + sent2 = "You are now {0} koans and {1} lessons away from " \ + "reaching enlightenment.".format(koans_remaining, lessons_remaining) + return sent1+sent2 # Hat's tip to Tim Peters for the zen statements from The Zen # of Python (http://www.python.org/dev/peps/pep-0020/) diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index 8e8e14815..7674b0602 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -156,11 +156,16 @@ def scrapeInterestingStackDump(self, err): return scrape.replace(sep, '\n').strip('\n') def report_progress(self): - return ("You are now {0}/{1} koans and {2}/{3} lessons away from " \ - "reaching enlightenment".format(self.pass_count, - self.total_koans(), - self.lesson_pass_count, - self.total_lessons())) + koans_complete = self.pass_count + lessons_complete = self.lesson_pass_count + koans_remaining = self.total_koans() - koans_complete + lessons_remaining = self.total_lessons() - lessons_complete + + sent1 = "You have completed {0} koans and " \ + "{1} lessons.\n".format(koans_complete, lessons_complete) + sent2 = "You are now {0} koans and {1} lessons away from " \ + "reaching enlightenment.".format(koans_remaining, lessons_remaining) + return sent1+sent2 # Hat's tip to Tim Peters for the zen statements from The Zen # of Python (http://www.python.org/dev/peps/pep-0020/) From 6c3d97be5c195dea38f501c4a9b97d378206b1e3 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Sun, 17 Feb 2013 16:34:26 +0100 Subject: [PATCH 063/237] Ruby Koans quotation cannot be read properly [ci skip] --- README.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index a8d96cabb..80064a03e 100644 --- a/README.rst +++ b/README.rst @@ -99,7 +99,9 @@ Getting the Most From the Koans 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 (green), then refactor it (that is look at the code and see if you can make it any better. In this case you will need to run the koan and see it fail (red), make the test pass (green), then take a moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor)." +``` +In test-driven development the mantra has always been, red, green, refactor. Write a failing test and run it (red), make the test pass (green), then refactor it (that is look at the code and see if you can make it any better. In this case you will need to run the koan and see it fail (red), make the test pass (green), then take a moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor)." +``` Content ------- From 02def4316cbba1d625985691a980607a5da5ac52 Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Sun, 17 Feb 2013 16:37:11 +0100 Subject: [PATCH 064/237] Rst is not markdown, trying with html tags.. --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 80064a03e..ffd5f8027 100644 --- a/README.rst +++ b/README.rst @@ -99,9 +99,9 @@ Getting the Most From the Koans 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 (green), then refactor it (that is look at the code and see if you can make it any better. In this case you will need to run the koan and see it fail (red), make the test pass (green), then take a moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor)." -``` +
Content ------- From 4153c43855834a66b44b3afd96454f04a9c3fb4d Mon Sep 17 00:00:00 2001 From: Roman Valls Guimera Date: Sun, 17 Feb 2013 16:39:38 +0100 Subject: [PATCH 065/237] Just tabs maybe? --- README.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index ffd5f8027..ac516f339 100644 --- a/README.rst +++ b/README.rst @@ -99,9 +99,13 @@ Getting the Most From the Koans 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 (green), then refactor it (that is look at the code and see if you can make it any better. In this case you will need to run the koan and see it fail (red), make the test pass (green), then take a moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor)." -
+ "In test-driven development the mantra has always been, red, green, + refactor. Write a failing test and run it (red), make the test pass + (green), then refactor it (that is look at the code and see if you + can make it any better. In this case you will need to run the koan + and see it fail (red), make the test pass (green), then take a + moment and reflect upon the test to see what it is teaching you + and improve the code to better communicate its intent (refactor)." Content ------- From aaedbfcb96f8b4c974c92cdc920d5c147660c8fa Mon Sep 17 00:00:00 2001 From: Kristofer M White Date: Sun, 10 Mar 2013 03:25:23 -0500 Subject: [PATCH 066/237] Correcting typo in comments --- python3/koans/about_lists.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_lists.py b/python3/koans/about_lists.py index 19f939d1b..e43f52d08 100644 --- a/python3/koans/about_lists.py +++ b/python3/koans/about_lists.py @@ -106,5 +106,5 @@ def test_making_queues(self): # Note, for Python 2 popping from the left hand side of a list is # inefficient. Use collections.deque instead. - # This is not an issue for Python 3 through + # This is not an issue for Python 3 though From 4366b50cf3db1217dc2e0d1e1536890dfba189a7 Mon Sep 17 00:00:00 2001 From: Matt Stevens Date: Mon, 11 Mar 2013 21:24:57 +0000 Subject: [PATCH 067/237] Fixes trailing whitespace --- .travis.yml | 4 +- Contributor Notes.txt | 2 +- README.rst | 8 +- python2/_runner_tests.py | 1 - python2/contemplate_koans.py | 4 +- .../koans/about_decorating_with_classes.py | 24 +++--- .../koans/about_decorating_with_functions.py | 12 +-- python2/koans/about_deleting_objects.py | 40 +++++----- python2/koans/about_dice_project.py | 24 +++--- python2/koans/about_dictionaries.py | 16 ++-- python2/koans/about_exceptions.py | 22 ++--- python2/koans/about_generators.py | 32 ++++---- python2/koans/about_inheritance.py | 38 ++++----- python2/koans/about_iteration.py | 44 +++++----- python2/koans/about_lambdas.py | 6 +- python2/koans/about_list_assignments.py | 6 +- python2/koans/about_lists.py | 36 ++++----- python2/koans/about_method_bindings.py | 10 +-- python2/koans/about_methods.py | 32 ++++---- python2/koans/about_modules.py | 20 ++--- python2/koans/about_monkey_patching.py | 12 +-- python2/koans/about_new_style_classes.py | 16 ++-- python2/koans/about_none.py | 10 +-- python2/koans/about_packages.py | 10 +-- python2/koans/about_proxy_object_project.py | 66 +++++++-------- python2/koans/about_scope.py | 30 +++---- python2/koans/about_scoring_project.py | 16 ++-- python2/koans/about_strings.py | 52 ++++++------ python2/koans/about_triangle_project.py | 4 +- python2/koans/about_triangle_project2.py | 2 +- python2/koans/about_true_and_false.py | 8 +- python2/koans/about_tuples.py | 22 ++--- python2/koans/about_with_statements.py | 34 ++++---- python2/koans/another_local_module.py | 2 +- python2/libs/colorama/ansitowin32.py | 2 +- python2/libs/mock.py | 62 +++++++------- python2/runner/runner_tests/test_helper.py | 4 +- python2/runner/runner_tests/test_mountain.py | 4 +- python2/runner/runner_tests/test_sensei.py | 78 +++++++++--------- python2/runner/sensei.py | 50 ++++++------ python3/_runner_tests.py | 1 - python3/contemplate_koans.py | 2 +- python3/koans/about_asserts.py | 10 +-- python3/koans/about_class_attributes.py | 60 +++++++------- python3/koans/about_control_statements.py | 21 +++-- .../koans/about_decorating_with_classes.py | 36 ++++----- .../koans/about_decorating_with_functions.py | 14 ++-- python3/koans/about_deleting_objects.py | 44 +++++----- python3/koans/about_dice_project.py | 28 +++---- python3/koans/about_dictionaries.py | 18 ++--- python3/koans/about_exceptions.py | 26 +++--- python3/koans/about_extra_credit.py | 1 - python3/koans/about_generators.py | 44 +++++----- python3/koans/about_inheritance.py | 46 +++++------ python3/koans/about_iteration.py | 58 +++++++------- python3/koans/about_lambdas.py | 6 +- python3/koans/about_list_assignments.py | 6 +- python3/koans/about_lists.py | 46 +++++------ python3/koans/about_method_bindings.py | 20 ++--- python3/koans/about_methods.py | 38 ++++----- python3/koans/about_modules.py | 20 ++--- python3/koans/about_monkey_patching.py | 19 +++-- python3/koans/about_multiple_inheritance.py | 58 +++++++------- python3/koans/about_none.py | 16 ++-- python3/koans/about_packages.py | 12 +-- python3/koans/about_proxy_object_project.py | 74 ++++++++--------- python3/koans/about_regex.py | 16 ++-- python3/koans/about_scope.py | 43 +++++----- python3/koans/about_scoring_project.py | 18 ++--- python3/koans/about_strings.py | 54 ++++++------- python3/koans/about_triangle_project.py | 4 +- python3/koans/about_triangle_project2.py | 6 +- python3/koans/about_true_and_false.py | 8 +- python3/koans/about_tuples.py | 28 +++---- python3/koans/about_with_statements.py | 36 ++++----- python3/koans/another_local_module.py | 2 +- .../koans/local_module_with_all_defined.py | 2 +- python3/libs/colorama/ansitowin32.py | 2 +- python3/libs/mock.py | 62 +++++++------- python3/runner/mountain.py | 4 +- python3/runner/runner_tests/test_helper.py | 4 +- python3/runner/runner_tests/test_mountain.py | 4 +- python3/runner/runner_tests/test_sensei.py | 80 +++++++++---------- python3/runner/sensei.py | 60 +++++++------- 84 files changed, 1008 insertions(+), 1014 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3720cb5e1..ecca9709f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,6 @@ notifications: # Some other koans (see runner/sensei.py or "ls koans" to see the light): # -# about_none about_lists about_list_assignments about_dictionaries -# about_strings about_tuples about_methods about_control_statements +# about_none about_lists about_list_assignments about_dictionaries +# about_strings about_tuples about_methods about_control_statements # about_true_and_false about_sets ... diff --git a/Contributor Notes.txt b/Contributor Notes.txt index c3cd6b256..23e32335a 100644 --- a/Contributor Notes.txt +++ b/Contributor Notes.txt @@ -9,7 +9,7 @@ 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 diff --git a/README.rst b/README.rst index ac516f339..8f633dd9d 100644 --- a/README.rst +++ b/README.rst @@ -6,7 +6,7 @@ Python Koans is a port of Edgecase's "Ruby Koans". .. image:: http://i442.photobucket.com/albums/qq150/gregmalcolm/PythonKoansScreenshot.png -Python Koans is an interactive tutorial for learning Python by making tests pass. +Python Koans is an interactive tutorial for learning Python by making tests pass. Most tests are 'fixed' by filling the missing parts of assert functions. Eg: @@ -40,7 +40,7 @@ Installing Python Koans Aside from downloading or checking out the latest version of Python Koans, all you need to install is Python. -At this time of writing there are two versions of the koans, one for use with Python 2.6 and one for Python 3.1. You should be able to work with newer Python versions, but older ones will likely give you problems. +At this time of writing there are two versions of the koans, one for use with Python 2.6 and one for Python 3.1. You should be able to work with newer Python versions, but older ones will likely give you problems. You can download Python from here: @@ -99,11 +99,11 @@ Getting the Most From the Koans Quoting the Ruby Koans instructions:: - "In test-driven development the mantra has always been, red, green, + "In test-driven development the mantra has always been, red, green, refactor. Write a failing test and run it (red), make the test pass (green), then refactor it (that is look at the code and see if you can make it any better. In this case you will need to run the koan - and see it fail (red), make the test pass (green), then take a + and see it fail (red), make the test pass (green), then take a moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor)." diff --git a/python2/_runner_tests.py b/python2/_runner_tests.py index 55ef5a12a..269513211 100644 --- a/python2/_runner_tests.py +++ b/python2/_runner_tests.py @@ -17,4 +17,3 @@ def suite(): if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite()) - \ No newline at end of file diff --git a/python2/contemplate_koans.py b/python2/contemplate_koans.py index 621119451..025ba9a08 100644 --- a/python2/contemplate_koans.py +++ b/python2/contemplate_koans.py @@ -14,7 +14,7 @@ import sys -if __name__ == '__main__': +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" @@ -31,7 +31,7 @@ "to work!\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/koans/about_decorating_with_classes.py b/python2/koans/about_decorating_with_classes.py index c892b31ac..b8f67a573 100644 --- a/python2/koans/about_decorating_with_classes.py +++ b/python2/koans/about_decorating_with_classes.py @@ -19,10 +19,10 @@ def test_partial_that_wrappers_no_args(self): 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) @@ -41,10 +41,10 @@ def test_partial_that_wrappers_all_args(self): 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 @@ -56,15 +56,15 @@ def __get__(self, obj, cls=None): @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')) @@ -77,7 +77,7 @@ def sound_check(self): 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()) # ------------------------------------------------------------------ @@ -85,17 +85,17 @@ def test_what_a_decorator_is_doing_to_a_function(self): 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 @@ -117,7 +117,7 @@ def test_documentor_which_already_has_a_docstring(self): self.assertEqual(__, self.idler.__doc__) # ------------------------------------------------------------------ - + @documenter("DOH!") @doubleit @doubleit diff --git a/python2/koans/about_decorating_with_functions.py b/python2/koans/about_decorating_with_functions.py index c38a87faa..c2bfe28f4 100644 --- a/python2/koans/about_decorating_with_functions.py +++ b/python2/koans/about_decorating_with_functions.py @@ -3,30 +3,30 @@ 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 index ac1da15b8..d2ee8be05 100644 --- a/python2/koans/about_deleting_objects.py +++ b/python2/koans/about_deleting_objects.py @@ -9,9 +9,9 @@ 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 @@ -20,28 +20,28 @@ def test_del_can_remove_entire_lists(self): 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: @@ -51,7 +51,7 @@ def test_del_can_remove_attributes(self): still_available = crazy_discounts.hamsters except AttributeError as e: err_msg2 = e.args[0] - + self.assertMatch(__, err_msg1) self.assertMatch(__, err_msg2) @@ -60,7 +60,7 @@ def test_del_can_remove_attributes(self): class ClintEastwood(object): def __init__(self): self._name = None - + def get_name(self): try: return self._name @@ -69,13 +69,13 @@ def get_name(self): 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' @@ -83,13 +83,13 @@ def test_del_works_with_properties(self): del cowboy.name self.assertEqual(__, cowboy.name) - + # -------------------------------------------------------------------- class Prisoner(object): def __init__(self): self._name = None - + @property def name(self): return self._name @@ -97,11 +97,11 @@ def name(self): @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" @@ -111,12 +111,12 @@ def test_another_way_to_make_a_deletable_property(self): 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 diff --git a/python2/koans/about_dice_project.py b/python2/koans/about_dice_project.py index 830f4c8df..c2710075f 100644 --- a/python2/koans/about_dice_project.py +++ b/python2/koans/about_dice_project.py @@ -9,11 +9,11 @@ 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 @@ -27,7 +27,7 @@ def test_can_create_a_dice_set(self): 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)) @@ -35,37 +35,37 @@ def test_rolling_the_dice_returns_a_set_of_integers_between_1_and_6(self): 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 index 518ea54bf..8591b5439 100644 --- a/python2/koans/about_dictionaries.py +++ b/python2/koans/about_dictionaries.py @@ -14,31 +14,31 @@ def test_creating_dictionaries(self): 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())) @@ -53,7 +53,7 @@ def test_making_a_dictionary_from_a_sequence_of_keys(self): ('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 index c8bae3b44..dd2b3823f 100644 --- a/python2/koans/about_exceptions.py +++ b/python2/koans/about_exceptions.py @@ -8,38 +8,38 @@ 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]) @@ -52,9 +52,9 @@ def test_else_clause(self): pass else: result = 'no damage done' - + self.assertEqual(__, result) - + def test_finally_clause(self): result = None try: @@ -64,5 +64,5 @@ def test_finally_clause(self): pass finally: result = 'always run' - + self.assertEqual(__, result) diff --git a/python2/koans/about_generators.py b/python2/koans/about_generators.py index dd31b91f9..5fc239cae 100644 --- a/python2/koans/about_generators.py +++ b/python2/koans/about_generators.py @@ -12,7 +12,7 @@ class AboutGenerators(Koan): - + def test_generating_values_on_the_fly(self): result = list() bacon_generator = (n + ' bacon' for \ @@ -20,16 +20,16 @@ def test_generating_values_on_the_fly(self): 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 @@ -42,18 +42,18 @@ def test_generator_expressions_are_a_one_shot_deal(self): attempt1 = list(dynamite) attempt2 = list(dynamite) - + self.assertEqual(__, list(attempt1)) self.assertEqual(__, list(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(): @@ -65,7 +65,7 @@ def test_coroutines_can_take_arguments(self): self.assertEqual(__, next(result)) self.assertEqual(__, next(result)) result.close() - + # ------------------------------------------------------------------ def square_me(self, seq): @@ -90,11 +90,11 @@ def test_generator_keeps_track_of_local_variables(self): self.assertEqual(__, list(result)) # ------------------------------------------------------------------ - + def generator_with_coroutine(self): result = yield yield result - + def test_generators_can_take_coroutines(self): generator = self.generator_with_coroutine() @@ -116,26 +116,26 @@ def test_before_sending_a_value_to_a_generator_next_must_be_called(self): 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 index 774f865f9..e4310ad9a 100644 --- a/python2/koans/about_inheritance.py +++ b/python2/koans/about_inheritance.py @@ -12,70 +12,70 @@ def __init__(self, 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) @@ -86,7 +86,7 @@ def test_base_init_does_not_get_called_automatically(self): 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 index 79604a696..2bf446f41 100644 --- a/python2/koans/about_iteration.py +++ b/python2/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 - + for num in it: fib += num - + self.assertEqual(__, fib) def test_iterating_with_next(self): @@ -26,7 +26,7 @@ def test_iterating_with_next(self): next(stages) except StopIteration as ex: err_msg = 'Ran out of iterations' - + self.assertMatch(__, err_msg) # ------------------------------------------------------------------ @@ -36,29 +36,29 @@ def add_ten(self, item): 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): @@ -72,36 +72,36 @@ def add(self, 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_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_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 iteratable sequence result = map(self.add_ten, range(1, 4)) @@ -110,7 +110,7 @@ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): try: f = open("example_file.txt") - try: + try: def make_upcase(line): return line.strip().upper() upcase_lines = map(make_upcase, f.readlines()) diff --git a/python2/koans/about_lambdas.py b/python2/koans/about_lambdas.py index a6f5611e6..dfc72f9e6 100644 --- a/python2/koans/about_lambdas.py +++ b/python2/koans/about_lambdas.py @@ -14,14 +14,14 @@ def test_lambdas_can_be_assigned_to_variables_and_called_explicitly(self): 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)) diff --git a/python2/koans/about_list_assignments.py b/python2/koans/about_list_assignments.py index 812a862ec..2c0267805 100644 --- a/python2/koans/about_list_assignments.py +++ b/python2/koans/about_list_assignments.py @@ -12,17 +12,17 @@ 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" diff --git a/python2/koans/about_lists.py b/python2/koans/about_lists.py index 6a0a7847e..4d2588272 100644 --- a/python2/koans/about_lists.py +++ b/python2/koans/about_lists.py @@ -17,27 +17,27 @@ def test_creating_lists(self): 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]) @@ -51,7 +51,7 @@ def test_slicing_to_the_edge(self): self.assertEqual(__, noms[2:]) self.assertEqual(__, noms[:2]) - + def test_lists_and_ranges(self): self.assertEqual(list, type(range(5))) self.assertEqual(__, range(5)) @@ -70,37 +70,37 @@ def test_insertions(self): 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 index b82872bb0..129465c92 100644 --- a/python2/koans/about_method_bindings.py +++ b/python2/koans/about_method_bindings.py @@ -30,7 +30,7 @@ def test_methods_are_also_bound_to_a_function(self): 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))) @@ -45,12 +45,12 @@ def test_setting_attributes_on_a_bound_method_directly(self): 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()) @@ -69,7 +69,7 @@ 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__(): @@ -91,7 +91,7 @@ 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' diff --git a/python2/koans/about_methods.py b/python2/koans/about_methods.py index 173cd0ce3..d11255829 100644 --- a/python2/koans/about_methods.py +++ b/python2/koans/about_methods.py @@ -15,7 +15,7 @@ def my_global_function(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): @@ -26,16 +26,16 @@ def test_calling_functions_with_wrong_number_of_arguments(self): 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 @@ -43,7 +43,7 @@ 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'): @@ -67,13 +67,13 @@ def test_calling_with_variable_arguments(self): 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 @@ -84,9 +84,9 @@ def function_with_the_same_name(a, b): 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 @@ -114,7 +114,7 @@ def test_pass_does_nothing_at_all(self): # ------------------------------------------------------------------ def one_line_method(self): return 'Madagascar' - + def test_no_indentation_required_for_one_line_statement_bodies(self): self.assertEqual(__, self.one_line_method()) @@ -123,7 +123,7 @@ def test_no_indentation_required_for_one_line_statement_bodies(self): 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__) @@ -132,7 +132,7 @@ def test_the_documentation_can_be_viewed_with_the_doc_method(self): class Dog(object): def name(self): return "Fido" - + def _tail(self): # Prefixing a method with an underscore implies private scope return "wagging" @@ -143,7 +143,7 @@ def __password(self): 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() @@ -159,9 +159,9 @@ def test_double_underscore_attribute_prefixes_cause_name_mangling(self): password = rover.__password() except Exception as ex: self.assertEqual(__, type(ex).__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 index a375229a7..ddd1be9ff 100644 --- a/python2/koans/about_modules.py +++ b/python2/koans/about_modules.py @@ -15,19 +15,19 @@ 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()) @@ -39,13 +39,13 @@ def test_importing_all_module_attributes_at_once(self): 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() @@ -54,12 +54,12 @@ def test_modules_hide_attributes_prefixed_by_underscores(self): 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_modules_XallX_statement_limits_what_wildcards_will_match(self): """Examine results of from local_module_with_all_defined import *""" @@ -70,7 +70,7 @@ def test_a_modules_XallX_statement_limits_what_wildcards_will_match(self): # How about velociraptors? lizard = _Velociraptor() self.assertEqual(__, lizard.name) - + # SecretDuck? Never heard of her! try: duck = SecretDuck() diff --git a/python2/koans/about_monkey_patching.py b/python2/koans/about_monkey_patching.py index d5aec7c12..65bd461d9 100644 --- a/python2/koans/about_monkey_patching.py +++ b/python2/koans/about_monkey_patching.py @@ -12,13 +12,13 @@ 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): @@ -29,9 +29,9 @@ def wag(self): 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 @@ -42,9 +42,9 @@ def test_most_built_in_classes_cannot_be_monkey_patched(self): 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_new_style_classes.py b/python2/koans/about_new_style_classes.py index 173acb686..a14d8b041 100644 --- a/python2/koans/about_new_style_classes.py +++ b/python2/koans/about_new_style_classes.py @@ -8,7 +8,7 @@ class AboutNewStyleClasses(Koan): class OldStyleClass: "An old style class" # Original class style have been phased out in Python 3. - + class NewStyleClass(object): "A new style class" # Introduced in Python 2.2 @@ -20,12 +20,12 @@ class NewStyleClass(object): 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()' @@ -35,23 +35,23 @@ def test_new_style_classes_have_more_attributes(self): def test_old_style_classes_have_type_but_no_class_attribute(self): self.assertEqual(__, type(self.OldStyleClass).__name__) - + try: cls = self.OldStyleClass.__class__ except Exception as ex: pass - + self.assertMatch(__, ex[0]) - + def test_new_style_classes_have_same_class_as_type(self): new_style = self.NewStyleClass() self.assertEqual(__, type(self.NewStyleClass).__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(__, type(old_style).__name__) diff --git a/python2/koans/about_none.py b/python2/koans/about_none.py index beeab8274..556360eed 100644 --- a/python2/koans/about_none.py +++ b/python2/koans/about_none.py @@ -13,7 +13,7 @@ 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) @@ -22,10 +22,10 @@ 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 """ @@ -34,11 +34,11 @@ def test_what_exception_do_you_get_when_calling_nonexistent_methods(self): except Exception as ex: # What exception has been caught? self.assertEqual(__, ex.__class__.__name__) - + # 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. diff --git a/python2/koans/about_packages.py b/python2/koans/about_packages.py index 30d618c49..99293ebd7 100644 --- a/python2/koans/about_packages.py +++ b/python2/koans/about_packages.py @@ -28,16 +28,16 @@ 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: @@ -52,7 +52,7 @@ def test_use_absolute_imports_to_import_upper_level_modules(self): import contemplate_koans self.assertEqual(__, contemplate_koans.__name__) - + # contemplate_koans.py is the root module in this package because its # the first python module called in koans. # diff --git a/python2/koans/about_proxy_object_project.py b/python2/koans/about_proxy_object_project.py index 5971301d0..50a949496 100644 --- a/python2/koans/about_proxy_object_project.py +++ b/python2/koans/about_proxy_object_project.py @@ -22,7 +22,7 @@ class Proxy(object): def __init__(self, target_object): # WRITE CODE HERE - + #initialize '_obj' attribute last. Trust me on this! self._obj = target_object @@ -35,29 +35,29 @@ 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() @@ -65,34 +65,34 @@ def test_proxy_handles_invalid_messages(self): 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) @@ -108,7 +108,7 @@ class Television(object): def __init__(self): self._channel = None self._power = None - + @property def channel(self): return self._channel @@ -116,13 +116,13 @@ def channel(self): @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' @@ -131,33 +131,33 @@ def is_on(self): 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_scope.py b/python2/koans/about_scope.py index f290e6319..0e7666124 100644 --- a/python2/koans/about_scope.py +++ b/python2/koans/about_scope.py @@ -15,42 +15,42 @@ class AboutScope(Koan): # 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 jim.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. @@ -66,11 +66,11 @@ def test_constants_are_assumed_by_convention_only(self): 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 @@ -82,11 +82,11 @@ def test_incrementing_with_global_counter(self): 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 index 8b2503e37..da51563b4 100644 --- a/python2/koans/about_scoring_project.py +++ b/python2/koans/about_scoring_project.py @@ -41,34 +41,34 @@ def score(dice): 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_strings.py b/python2/koans/about_strings.py index c60f7c615..9a1c37cd3 100644 --- a/python2/koans/about_strings.py +++ b/python2/koans/about_strings.py @@ -5,15 +5,15 @@ 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)) @@ -25,15 +25,15 @@ def test_triple_single_quotes_work_too(self): 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"' @@ -43,22 +43,22 @@ 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 but_quotes_at_the_end_of_a_triple_quoted_string_are_still_tricky(self): string = """Hello "world\"""" - + def test_plus_concatenates_strings(self): string = "Hello, " + "world" self.assertEqual(__, string) @@ -66,20 +66,20 @@ def test_plus_concatenates_strings(self): 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 @@ -92,7 +92,7 @@ def test_most_strings_interpret_escape_characters(self): self.assertEqual('\n', string) self.assertEqual("""\n""", string) self.assertEqual(__, len(string)) - + def test_use_format_to_interpolate_variables(self): value1 = 'one' value2 = 2 @@ -104,42 +104,42 @@ def test_formatted_values_can_be_shown_in_any_order_or_be_repeated(self): 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 ';' @@ -150,7 +150,7 @@ def test_raw_strings_do_not_interpret_escape_characters(self): 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)) diff --git a/python2/koans/about_triangle_project.py b/python2/koans/about_triangle_project.py index 6f3abc909..065e4ab37 100644 --- a/python2/koans/about_triangle_project.py +++ b/python2/koans/about_triangle_project.py @@ -11,13 +11,13 @@ 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)) diff --git a/python2/koans/about_triangle_project2.py b/python2/koans/about_triangle_project2.py index 0afe0724b..6b6184657 100644 --- a/python2/koans/about_triangle_project2.py +++ b/python2/koans/about_triangle_project2.py @@ -13,7 +13,7 @@ class AboutTriangleProject2(Koan): def test_illegal_triangles_throw_exceptions(self): # Calls triangle(0, 0, 0) self.assertRaises(TriangleError, triangle, 0, 0, 0) - + self.assertRaises(TriangleError, triangle, 3, 4, -5) self.assertRaises(TriangleError, triangle, 1, 1, 3) self.assertRaises(TriangleError, triangle, 2, 4, 2) diff --git a/python2/koans/about_true_and_false.py b/python2/koans/about_true_and_false.py index e29823cb6..89250353c 100644 --- a/python2/koans/about_true_and_false.py +++ b/python2/koans/about_true_and_false.py @@ -10,13 +10,13 @@ def truth_value(self, 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)) @@ -31,7 +31,7 @@ def test_empty_collections_are_treated_as_false(self): 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(1,)) diff --git a/python2/koans/about_tuples.py b/python2/koans/about_tuples.py index 5773c0ad6..ea132f1a7 100644 --- a/python2/koans/about_tuples.py +++ b/python2/koans/about_tuples.py @@ -8,48 +8,48 @@ 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__.__name__) self.assertEqual(__, (1,).__class__.__name__) self.assertEqual(__, ("Hello comma!", )) - + 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') @@ -61,10 +61,10 @@ def test_tuples_are_good_for_representing_records(self): ("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( + + 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 index b5113bccd..15cfbaf69 100644 --- a/python2/koans/about_with_statements.py +++ b/python2/koans/about_with_statements.py @@ -24,12 +24,12 @@ def count_lines(self, file_name): 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) @@ -43,10 +43,10 @@ def find_line(self, file_name): except IOError: # should never happen self.fail() - + def test_finding_lines(self): self.assertEqual(__, self.find_line("example_file.txt")) - + ## ------------------------------------------------------------------ ## THINK ABOUT IT: ## @@ -69,49 +69,49 @@ def test_finding_lines(self): ## 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: count = 0 for line in f.readlines(): count += 1 return count - + def test_counting_lines2(self): self.assertEqual(__, self.count_lines2("example_file.txt")) - + # ------------------------------------------------------------------ - + def find_line2(self, file_name): # Rewrite find_line using the Context Manager. pass - + def test_finding_lines2(self): self.assertEqual(__, self.find_line2("example_file.txt")) self.assertNotEqual(None, self.find_line2("example_file.txt")) - + # ------------------------------------------------------------------ - + def count_lines3(self, file_name): with open(file_name) as f: count = 0 for line in f.readlines(): count += 1 return count - + 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 index 2b2abf2d4..e27c53dde 100644 --- a/python2/koans/another_local_module.py +++ b/python2/koans/another_local_module.py @@ -13,7 +13,7 @@ class Hamster(object): def name(self): return "Phil" - + class _SecretSquirrel(object): @property def name(self): diff --git a/python2/libs/colorama/ansitowin32.py b/python2/libs/colorama/ansitowin32.py index 9ce77dd6f..5c39a480e 100644 --- a/python2/libs/colorama/ansitowin32.py +++ b/python2/libs/colorama/ansitowin32.py @@ -118,7 +118,7 @@ def write(self, text): self.wrapped.flush() if self.autoreset: self.reset_all() - + def reset_all(self): if self.convert: diff --git a/python2/libs/mock.py b/python2/libs/mock.py index c01875bf3..38c446db2 100644 --- a/python2/libs/mock.py +++ b/python2/libs/mock.py @@ -26,7 +26,7 @@ class SentinelObject(object): def __init__(self, name): self.name = name - + def __repr__(self): return ''.format(self.name) @@ -34,11 +34,11 @@ def __repr__(self): class Sentinel(object): def __init__(self): self._sentinels = {} - + def __getattr__(self, name): return self._sentinels.setdefault(name, SentinelObject(name)) - - + + sentinel = Sentinel() DEFAULT = sentinel.DEFAULT @@ -58,21 +58,21 @@ def _copy(value): class Mock(object): - def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, + 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 @@ -84,16 +84,16 @@ def reset_mock(self): 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) @@ -102,7 +102,7 @@ def __call__(self, *args, **kwargs): 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: @@ -111,44 +111,44 @@ def __call__(self, *args, **kwargs): 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 + 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: @@ -199,8 +199,8 @@ def patched(*args, **keywargs): patching.__exit__() patched.patchings = [self] - patched.__name__ = func.__name__ - patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno", + patched.__name__ = func.__name__ + patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno", func.func_code.co_firstlineno) return patched @@ -209,7 +209,7 @@ def get_original(self): target = self.target name = self.attribute create = self.create - + original = DEFAULT if _has_local_attr(target, name): try: @@ -221,7 +221,7 @@ def get_original(self): 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() @@ -247,15 +247,15 @@ def __exit__(self, *_): 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) + 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) diff --git a/python2/runner/runner_tests/test_helper.py b/python2/runner/runner_tests/test_helper.py index ea3ee00c3..fef9b6026 100644 --- a/python2/runner/runner_tests/test_helper.py +++ b/python2/runner/runner_tests/test_helper.py @@ -6,10 +6,10 @@ 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)) diff --git a/python2/runner/runner_tests/test_mountain.py b/python2/runner/runner_tests/test_mountain.py index 18fcc3167..0f8d08ccc 100644 --- a/python2/runner/runner_tests/test_mountain.py +++ b/python2/runner/runner_tests/test_mountain.py @@ -13,9 +13,9 @@ 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) - + diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index 481d7e166..b19d057ac 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -89,35 +89,35 @@ def setUp(self): path_to_enlightenment.koans = Mock() self.tests = Mock() self.tests.countTestCases = Mock() - + def test_that_it_delegates_testing_to_test_cases(self): MockableTestResult.startTest = Mock() self.sensei.startTest(Mock()) self.assertTrue(MockableTestResult.startTest.called) - + def test_that_user_is_notified_if_test_involves_a_different_test_class_to_last_time(self): MockableTestResult.startTest = Mock() - + self.sensei.prevTestClassName == 'AboutLumberjacks' nextTest = AboutParrots() - + self.sensei.startTest(nextTest) self.assertTrue(self.sensei.stream.writeln.called) - + def test_that_user_is_not_notified_about_test_class_repeats(self): MockableTestResult.startTest = Mock() - + self.sensei.prevTestClassName == 'AboutParrots' nextTest = AboutParrots() - + self.sensei.startTest(nextTest) self.assertTrue(self.sensei.stream.writeln.called) - + def test_that_cached_classname_updates_after_the_test(self): self.assertEqual(None, self.sensei.prevTestClassName) self.sensei.startTest(Mock()) self.assertNotEqual(None, self.sensei.prevTestClassName) - + def test_that_errors_are_diverted_to_the_failures_list(self): MockableTestResult.addFailure = Mock() self.sensei.addError(Mock(), Mock()) @@ -133,7 +133,7 @@ def test_that_it_successes_only_count_if_passes_are_currently_allowed(self): MockableTestResult.addSuccess = Mock() self.sensei.addSuccess(Mock()) self.assertTrue(self.sensei.passesCount.called) - + def test_that_if_there_are_failures_and_the_prev_class_is_different_successes_are_not_allowed(self): self.sensei.failures = [(AboutLumberjacks(), Mock())] self.sensei.prevTestClassName = "AboutTheMinitry" @@ -153,7 +153,7 @@ def test_that_it_passes_on_add_successes_message(self): 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() @@ -164,15 +164,15 @@ def test_that_it_displays_each_success(self): MockableTestResult.addSuccess = Mock() self.sensei.addSuccess(Mock()) self.assertTrue(self.sensei.stream.writeln.called) - + 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"), @@ -180,7 +180,7 @@ def test_that_nothing_is_returned_as_sorted_result_if_there_are_no_relevent_fail (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"), @@ -191,26 +191,26 @@ def test_that_nothing_is_returned_as_sorted_result_if_there_are_3_shuffled_resul (AboutMrGumby(),"File 'about_mr_gumby.py', line odd"), (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]) 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"), @@ -218,7 +218,7 @@ def test_that_it_will_choose_correct_first_result_with_lines_9_and_27(self): (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"), @@ -227,7 +227,7 @@ def test_that_it_will_choose_correct_first_result_with_multiline_test_classes(se (AboutFreemasons(),"File 'about_freemasons.py', line 11") ] self.assertEqual("File 'about_giant_feet.py', line 44", self.sensei.firstFailure()[1]) - + def test_that_end_report_displays_something(self): self.sensei.learn() self.assertTrue(self.sensei.stream.writeln.called) @@ -239,7 +239,7 @@ def test_that_end_report_shows_student_progress(self): self.sensei.learn() self.assertTrue(self.sensei.total_lessons.called) - self.assertTrue(self.sensei.total_koans.called) + self.assertTrue(self.sensei.total_koans.called) def test_that_end_report_shows_the_failure_report(self): self.sensei.errorReport = Mock() @@ -262,7 +262,7 @@ def test_that_error_report_does_not_show_anything_if_there_is_no_failure(self): self.sensei.firstFailure.return_value = None self.sensei.errorReport() self.assertFalse(self.sensei.stream.writeln.called) - + def test_that_error_report_features_the_assertion_error(self): self.sensei.scrapeAssertionError = Mock() self.sensei.firstFailure = Mock() @@ -279,19 +279,19 @@ def test_that_error_report_features_a_stack_dump(self): 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)) @@ -312,7 +312,7 @@ def test_that_scraping_the_assertion_error_with_list_error(self): def test_that_scraping_a_non_existent_stack_dump_gives_you_nothing(self): self.assertEqual("", self.sensei.scrapeInterestingStackDump(None)) - + def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_messaged_assert(self): expected = """ 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...")""" @@ -336,27 +336,27 @@ def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_syntax_er self.assertTrue(eoe"Pen" > "Sword", "nhnth")""" self.assertEqual(expected, self.sensei.scrapeInterestingStackDump(error_mess)) - + 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_successes_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)) @@ -364,7 +364,7 @@ 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)) @@ -372,7 +372,7 @@ 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)) @@ -380,7 +380,7 @@ 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)) @@ -399,7 +399,7 @@ def test_that_total_lessons_return_0_if_all_lessons_is_none(self): 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/python2/runner/sensei.py b/python2/runner/sensei.py index 5c69b9b58..bf8b93898 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -18,7 +18,7 @@ def __init__(self, stream): unittest.TestResult.__init__(self) self.stream = stream self.prevTestClassName = None - self.tests = path_to_enlightenment.koans() + self.tests = path_to_enlightenment.koans() self.pass_count = 0 self.lesson_pass_count = 0 self.all_lessons = None @@ -36,12 +36,12 @@ def startTest(self, test): self.lesson_pass_count += 1 def addSuccess(self, test): - if self.passesCount(): + 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)) + Fore.RESET, Style.NORMAL)) self.pass_count += 1 def addError(self, test, err): @@ -52,7 +52,7 @@ def addError(self, 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) @@ -64,31 +64,31 @@ def sortFailures(self, testClassName): 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()) self.stream.writeln("") self.stream.writeln(self.say_something_zenlike()) - + if self.failures: sys.exit(-1) self.stream.writeln( "\n{0}**************************************************" \ @@ -97,13 +97,13 @@ def learn(self): .format(Fore.MAGENTA)) self.stream.writeln( "\nIf you want more, take a look at about_extra_credit_task.py") - + def errorReport(self): problem = self.firstFailure() - if not problem: return - test, err = problem + if not problem: return + test, err = problem self.stream.writeln(" {0}{1}{2} has damaged your " - "karma.".format(Fore.RED, Style.BRIGHT, test._testMethodName)) + "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)) @@ -124,7 +124,7 @@ def scrapeAssertionError(self, err): 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') @@ -134,9 +134,9 @@ def scrapeInterestingStackDump(self, err): return "" lines = err.splitlines() - + sep = '@@@@@SEP@@@@@' - + scrape = "" for line in lines: m = re.search("^ File .*$",line) @@ -146,9 +146,9 @@ def scrapeInterestingStackDump(self, err): m = re.search("^ \w(\w)+.*$",line) if m and m.group(0): scrape += sep + line - + lines = scrape.splitlines() - + scrape = "" for line in lines: m = re.search("^.*[/\\\\]koans[/\\\\].*$",line) @@ -179,7 +179,7 @@ def say_something_zenlike(self): turn = self.pass_count % 37 zenness = ""; - if turn == 0: + if turn == 0: zenness = "Beautiful is better than ugly." elif turn == 1 or turn == 2: zenness = "Explicit is better than implicit." @@ -222,14 +222,14 @@ def say_something_zenlike(self): elif turn == 33 or turn == 34: zenness = "If the implementation is easy to explain, " \ "it may be a good idea." - else: + 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); + 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 in collapsing! Run!!!" @@ -249,5 +249,5 @@ def filter_all_lessons(self): self.all_lessons = filter(lambda filename: "about_extra_credit" not in filename, self.all_lessons) - + return self.all_lessons diff --git a/python3/_runner_tests.py b/python3/_runner_tests.py index 55ef5a12a..269513211 100644 --- a/python3/_runner_tests.py +++ b/python3/_runner_tests.py @@ -17,4 +17,3 @@ def suite(): if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(suite()) - \ No newline at end of file diff --git a/python3/contemplate_koans.py b/python3/contemplate_koans.py index 496c85313..a4c50518a 100644 --- a/python3/contemplate_koans.py +++ b/python3/contemplate_koans.py @@ -19,7 +19,7 @@ "running it with Python 2 or older!\n\n" "Did you accidentally use the wrong python script? \nTry:\n\n" + " python3 contemplate_koans.py\n") - else: + else: from runner.mountain import Mountain Mountain().walk_the_path(sys.argv) diff --git a/python3/koans/about_asserts.py b/python3/koans/about_asserts.py index 3905498d3..fe4f81949 100644 --- a/python3/koans/about_asserts.py +++ b/python3/koans/about_asserts.py @@ -10,7 +10,7 @@ def test_assert_truth(self): We shall contemplate truth by testing reality, via asserts. """ self.assertTrue(False) # This should be true - + def test_assert_with_message(self): """ Enlightenment may be more easily achieved with appropriate messages. @@ -37,14 +37,14 @@ def test_a_better_way_of_asserting_equality(self): """ 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): """ Knowing how things really work is half the battle """ - + # This throws an AssertionError exception assert False - + diff --git a/python3/koans/about_class_attributes.py b/python3/koans/about_class_attributes.py index bdf0ea70a..f4b3d751f 100644 --- a/python3/koans/about_class_attributes.py +++ b/python3/koans/about_class_attributes.py @@ -10,38 +10,38 @@ class AboutClassAttributes(Koan): class Dog: pass - + def test_objects_are_objects(self): 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() + 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): @@ -49,13 +49,13 @@ def test_other_objects_are_not_affected_by_these_singleton_functions(self): rover = self.Dog() def wag(): - return 'fidos wag' + return 'fidos wag' fido.wag = wag - + with self.assertRaises(___): rover.wag() - + # ------------------------------------------------------------------ - + class Dog2: def wag(self): return 'instance wag' @@ -69,14 +69,14 @@ def growl(self): @staticmethod def bark(): return "staticmethod bark, arg: None" - + @classmethod def growl(cls): - return "classmethod growl, arg: cls=" + cls.__name__ - + 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(), __) - + def test_classmethods_are_not_independent_of_instance_methods(self): fido = self.Dog2() self.assertRegexpMatches(fido.growl(), __) @@ -88,9 +88,9 @@ def test_staticmethods_are_unbound_functions_housed_in_a_class(self): def test_staticmethods_also_overshadow_instance_methods(self): fido = self.Dog2() self.assertRegexpMatches(fido.bark(), __) - + # ------------------------------------------------------------------ - + class Dog3: def __init__(self): self._name = None @@ -100,37 +100,37 @@ def get_name_from_instance(self): def set_name_from_instance(self, name): self._name = name - - @classmethod + + @classmethod def get_name(cls): return cls._name - @classmethod + @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() with self.assertRaises(___): fido.name = "Fido" - + 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: def a_class_method(cls): return 'dogs class method' @@ -140,15 +140,15 @@ def a_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_heres_an_easy_way_to_explicitly_call_class_methods_from_instance_methods(self): fido = self.Dog4() self.assertEqual(__, fido.__class__.a_class_method()) diff --git a/python3/koans/about_control_statements.py b/python3/koans/about_control_statements.py index f1cb5c0bd..ade8ce22c 100644 --- a/python3/koans/about_control_statements.py +++ b/python3/koans/about_control_statements.py @@ -17,7 +17,7 @@ def test_if_then_statements(self): if True: result = 'true value' self.assertEqual(__, result) - + def test_while_statement(self): i = 1 result = 1 @@ -25,7 +25,7 @@ def test_while_statement(self): result = result * i i += 1 self.assertEqual(__, result) - + def test_break_statement(self): i = 1 result = 1 @@ -34,26 +34,26 @@ def test_break_statement(self): 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) + 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"), + ("Lancelot", "Blue"), ("Galahad", "I don't know!"), ("Robin", "Blue! I mean Green!"), ("Arthur", "Is that an African Swallow or Amazonian Swallow?") @@ -61,12 +61,11 @@ def test_for_statement_with_tuples(self): result = [] for knight, answer in round_table: result.append("Contestant: '" + knight + "' Answer: '" + answer + "'") - + text = __ - + self.assertRegexpMatches(result[2], text) - + self.assertNoRegexpMatches(result[0], text) self.assertNoRegexpMatches(result[1], text) self.assertNoRegexpMatches(result[3], text) - \ No newline at end of file diff --git a/python3/koans/about_decorating_with_classes.py b/python3/koans/about_decorating_with_classes.py index 3466bc1d4..00bd5fe90 100644 --- a/python3/koans/about_decorating_with_classes.py +++ b/python3/koans/about_decorating_with_classes.py @@ -4,7 +4,7 @@ from runner.koan import * import functools - + class AboutDecoratingWithClasses(Koan): def maximum(self, a, b): if a>b: @@ -18,17 +18,17 @@ def test_partial_that_wrappers_no_args(self): 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): + def test_partial_that_wrappers_all_args(self): always99 = functools.partial(self.maximum, 99, 20) always20 = functools.partial(self.maximum, 9, 20) @@ -40,43 +40,43 @@ def test_partial_that_wrappers_all_args(self): class doubleit: 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) + 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 + #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()) # ------------------------------------------------------------------ @@ -84,22 +84,22 @@ def test_what_a_decorator_is_doing_to_a_function(self): class documenter: 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 + return 5 else: return num @documenter("Does nothing") @@ -115,7 +115,7 @@ def test_documentor_which_already_has_a_docstring(self): self.assertEqual(__, self.idler.__doc__) # ------------------------------------------------------------------ - + @documenter("DOH!") @doubleit @doubleit @@ -125,4 +125,4 @@ def homer(self): def test_we_can_chain_decorators(self): self.assertEqual(__, self.homer()) self.assertEqual(__, self.homer.__doc__) - + diff --git a/python3/koans/about_decorating_with_functions.py b/python3/koans/about_decorating_with_functions.py index def65098c..260ad12ac 100644 --- a/python3/koans/about_decorating_with_functions.py +++ b/python3/koans/about_decorating_with_functions.py @@ -3,31 +3,31 @@ 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.assertRegexpMatches(self.mediocre_song(), __) - self.assertEqual(__, self.mediocre_song.wow_factor) - + 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/python3/koans/about_deleting_objects.py b/python3/koans/about_deleting_objects.py index 87eea9a23..bec3e9e29 100644 --- a/python3/koans/about_deleting_objects.py +++ b/python3/koans/about_deleting_objects.py @@ -8,36 +8,36 @@ 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 with self.assertRaises(___): win = lottery_nums - + # ==================================================================== - + class ClosingSale: 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: @@ -47,7 +47,7 @@ def test_del_can_remove_attributes(self): still_available = crazy_discounts.hamsters except AttributeError as e: err_msg2 = e.args[0] - + self.assertRegexpMatches(err_msg1, __) self.assertRegexpMatches(err_msg2, __) @@ -56,7 +56,7 @@ def test_del_can_remove_attributes(self): class ClintEastwood: def __init__(self): self._name = None - + def get_name(self): try: return self._name @@ -65,13 +65,13 @@ def get_name(self): 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' @@ -79,14 +79,14 @@ def test_del_works_with_properties(self): del cowboy.name self.assertEqual(__, cowboy.name) - - - # ==================================================================== + + + # ==================================================================== class Prisoner: def __init__(self): self._name = None - + @property def name(self): return self._name @@ -94,11 +94,11 @@ def name(self): @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" @@ -108,12 +108,12 @@ def test_another_way_to_make_a_deletable_property(self): self.assertEqual(__, citizen.name) # ==================================================================== - + class MoreOrganisedClosingSale(ClosingSale): def __init__(self): self.last_deletion = None super().__init__() - + def __delattr__(self, attr_name): self.last_deletion = attr_name diff --git a/python3/koans/about_dice_project.py b/python3/koans/about_dice_project.py index c9bdc44fe..27bc54a24 100644 --- a/python3/koans/about_dice_project.py +++ b/python3/koans/about_dice_project.py @@ -8,15 +8,15 @@ class DiceSet: def __init__(self): self._values = None - - @property + + @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 + pass class AboutDiceProject(Koan): def test_can_create_a_dice_set(self): @@ -25,43 +25,43 @@ def test_can_create_a_dice_set(self): 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/python3/koans/about_dictionaries.py b/python3/koans/about_dictionaries.py index 0ef64cf84..da1ed6bfe 100644 --- a/python3/koans/about_dictionaries.py +++ b/python3/koans/about_dictionaries.py @@ -13,32 +13,32 @@ def test_creating_dictionaries(self): self.assertEqual(dict, type(empty_dict)) self.assertDictEqual({}, 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.assertDictEqual(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())) @@ -50,7 +50,7 @@ def test_dictionary_keys_and_values(self): 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/python3/koans/about_exceptions.py b/python3/koans/about_exceptions.py index 956f45f24..d321bbc50 100644 --- a/python3/koans/about_exceptions.py +++ b/python3/koans/about_exceptions.py @@ -7,33 +7,33 @@ 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 Exception as ex: result = 'exception handled' - + ex2 = ex - + self.assertEqual(__, result) - + self.assertEqual(__, isinstance(ex2, Exception)) self.assertEqual(__, isinstance(ex2, RuntimeError)) - + self.assertTrue(issubclass(RuntimeError, Exception), \ "RuntimeError is a subclass of Exception") - + self.assertEqual(__, ex2.args[0]) - + def test_raising_a_specific_error(self): result = None try: @@ -41,10 +41,10 @@ def test_raising_a_specific_error(self): except self.MySpecialError as ex: result = 'exception handled' msg = ex.args[0] - + self.assertEqual(__, result) self.assertEqual(__, msg) - + def test_else_clause(self): result = None try: @@ -54,10 +54,10 @@ def test_else_clause(self): pass else: result = 'no damage done' - + self.assertEqual(__, result) - + def test_finally_clause(self): result = None try: @@ -67,5 +67,5 @@ def test_finally_clause(self): pass finally: result = 'always run' - + self.assertEqual(__, result) diff --git a/python3/koans/about_extra_credit.py b/python3/koans/about_extra_credit.py index 54baef4ea..cb5a67702 100644 --- a/python3/koans/about_extra_credit.py +++ b/python3/koans/about_extra_credit.py @@ -17,4 +17,3 @@ class AboutExtraCredit(Koan): # test suite in runner/path_to_enlightenment.py def test_extra_credit_task(self): pass - \ No newline at end of file diff --git a/python3/koans/about_generators.py b/python3/koans/about_generators.py index 5986cf1fa..f623d0070 100644 --- a/python3/koans/about_generators.py +++ b/python3/koans/about_generators.py @@ -11,27 +11,27 @@ 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. with self.assertRaises(___): num = num_generator[0] - + 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. @@ -43,18 +43,18 @@ def test_generator_expressions_are_a_one_shot_deal(self): attempt1 = list(dynamite) attempt2 = list(dynamite) - + self.assertEqual(__, list(attempt1)) self.assertEqual(__, list(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(): @@ -66,7 +66,7 @@ def test_coroutines_can_take_arguments(self): self.assertEqual(__, next(result)) self.assertEqual(__, next(result)) result.close() - + # ------------------------------------------------------------------ def square_me(self, seq): @@ -91,11 +91,11 @@ def test_generator_keeps_track_of_local_variables(self): self.assertEqual(__, list(result)) # ------------------------------------------------------------------ - + def generator_with_coroutine(self): result = yield yield result - + def test_generators_can_take_coroutines(self): generator = self.generator_with_coroutine() @@ -115,32 +115,32 @@ def test_before_sending_a_value_to_a_generator_next_must_be_called(self): generator.send(1+2) except TypeError as ex: ex2 = ex - + self.assertRegexpMatches(ex2.args[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/python3/koans/about_inheritance.py b/python3/koans/about_inheritance.py index ac9cf0f62..c7b02923c 100644 --- a/python3/koans/about_inheritance.py +++ b/python3/koans/about_inheritance.py @@ -5,85 +5,85 @@ class AboutInheritance(Koan): class Dog: - def __init__(self, name): + 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_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 # to inherit from a built in class or object explicitly - + 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()) - + fido = self.Dog("Fido") with self.assertRaises(___): fido.wag() - + 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().bark() + ", GRR" # Note, super() is much simpler to use in Python 3! - + 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().bark() + ", GROWL" - + def test_super_works_across_methods(self): george = self.GreatDane("George") self.assertEqual(__, george.growl()) # --------------------------------------------------------- - + class Pug(Dog): - def __init__(self, name): + def __init__(self, name): pass - + class Greyhound(Dog): - def __init__(self, name): + def __init__(self, name): super().__init__(name) def test_base_init_does_not_get_called_automatically(self): snoopy = self.Pug("Snoopy") with self.assertRaises(___): name = snoopy.name - + def test_base_init_has_to_be_called_explicitly(self): boxer = self.Greyhound("Boxer") self.assertEqual(__, boxer.name) \ No newline at end of file diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index 40cc751f4..fdb80295b 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -7,12 +7,12 @@ 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): @@ -25,8 +25,8 @@ def test_iterating_with_next(self): next(stages) except StopIteration as ex: err_msg = 'Ran out of iterations' - - self.assertRegexpMatches(err_msg, __) + + self.assertRegexpMatches(err_msg, __) # ------------------------------------------------------------------ @@ -36,38 +36,38 @@ def add_ten(self, item): def test_map_transforms_elements_of_a_list(self): seq = [1, 2, 3] mapped_seq = list() - + mapping = map(self.add_ten, seq) - + self.assertNotEqual(list, type(mapping).__name__) self.assertEqual(__, type(mapping).__name__) # In Python 3 built in iterator funcs return iteratable view objects # instead of lists - + for item in mapping: mapped_seq.append(item) - + self.assertEqual(__, mapped_seq) - + # None, iterator methods actually return objects of iter type in # python 3. In python 2 map() would give you a list. - + 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 = list() - + for item in filter(is_even, seq): even_numbers.append(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 @@ -78,7 +78,7 @@ def is_big_name(item): msg = 'Ran out of big names' self.assertEqual(__, name) - + # ------------------------------------------------------------------ @@ -87,42 +87,42 @@ def add(self,accum,item): def multiply(self,accum,item): return accum * item - + def test_reduce_will_blow_your_mind(self): import functools # As of Python 3 reduce() has been demoted from a builtin function # to the functools module. - + result = functools.reduce(self.add, [2, 3, 4]) self.assertEqual(__, type(result).__name__) # Reduce() syntax is same as Python 2 - + self.assertEqual(__, result) - - result2 = functools.reduce(self.multiply, [2, 3, 4], 1) + + result2 = functools.reduce(self.multiply, [2, 3, 4], 1) self.assertEqual(__, result2) - + # Extra Credit: # Describe in your own words what reduce does. - + # ------------------------------------------------------------------ - def test_creating_lists_with_list_comprehensions(self): + 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_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 iteratable sequence result = map(self.add_ten, range(1,4)) diff --git a/python3/koans/about_lambdas.py b/python3/koans/about_lambdas.py index 2268e6c65..c1e688094 100644 --- a/python3/koans/about_lambdas.py +++ b/python3/koans/about_lambdas.py @@ -13,14 +13,14 @@ def test_lambdas_can_be_assigned_to_variables_and_called_explicitly(self): 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)) diff --git a/python3/koans/about_list_assignments.py b/python3/koans/about_list_assignments.py index 2c8e8639c..d32d89911 100644 --- a/python3/koans/about_list_assignments.py +++ b/python3/koans/about_list_assignments.py @@ -11,7 +11,7 @@ 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) @@ -22,12 +22,12 @@ def test_parallel_assignments_with_extra_values(self): 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) self.assertEqual(__, last_name) - + def test_swapping_with_parallel_assignment(self): first_name = "Roy" last_name = "Rob" diff --git a/python3/koans/about_lists.py b/python3/koans/about_lists.py index e43f52d08..493953345 100644 --- a/python3/koans/about_lists.py +++ b/python3/koans/about_lists.py @@ -16,27 +16,27 @@ def test_creating_lists(self): def test_list_literals(self): nums = list() self.assertEqual([], nums) - + nums[0:] = [1] self.assertEqual([1], nums) - + nums[1:] = [2] self.assertListEqual([1, __], nums) - + nums.append(333) self.assertListEqual([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]) @@ -50,7 +50,7 @@ def test_slicing_to_the_edge(self): self.assertEqual(__, noms[2:]) self.assertEqual(__, noms[:2]) - + def test_lists_and_ranges(self): self.assertEqual(range, type(range(5))) self.assertNotEqual([1, 2, 3, 4, 5], range(1,6)) @@ -67,44 +67,44 @@ def test_insertions(self): knight = ['you', 'shall', 'pass'] knight.insert(2, 'not') self.assertEqual(__, knight) - + knight.insert(0, 'Arthur') - self.assertEqual(__, knight) - + 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_making_queues(self): queue = [1, 2] queue.append('last') - + self.assertEqual(__, queue) - + popped_value = queue.pop(0) self.assertEqual(__, popped_value) self.assertEqual(__, queue) - + # Note, for Python 2 popping from the left hand side of a list is # inefficient. Use collections.deque instead. - + # This is not an issue for Python 3 though - + diff --git a/python3/koans/about_method_bindings.py b/python3/koans/about_method_bindings.py index 45f09177b..f45058113 100644 --- a/python3/koans/about_method_bindings.py +++ b/python3/koans/about_method_bindings.py @@ -11,10 +11,10 @@ def function2(): class Class: def method(self): - return "parrot" + return "parrot" class AboutMethodBindings(Koan): - def test_methods_are_bound_to_an_object(self): + def test_methods_are_bound_to_an_object(self): obj = Class() self.assertEqual(__, obj.method.__self__ == obj) @@ -22,12 +22,12 @@ def test_methods_are_also_bound_to_a_function(self): obj = Class() self.assertEqual(__, obj.method()) self.assertEqual(__, obj.method.__func__(obj)) - + def test_functions_have_attributes(self): obj = Class() self.assertEqual(__, len(dir(function))) self.assertEqual(__, dir(function) == dir(obj.method.__func__)) - + def test_methods_have_different_attributes(self): obj = Class() self.assertEqual(__, len(dir(obj.method))) @@ -38,13 +38,13 @@ def test_setting_attributes_on_an_unbound_function(self): def test_setting_attributes_on_a_bound_method_directly(self): obj = Class() - with self.assertRaises(___): obj.method.cherries = 3 - + with self.assertRaises(___): obj.method.cherries = 3 + def test_setting_attributes_on_methods_by_accessing_the_inner_function(self): obj = Class() obj.method.__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()) @@ -60,7 +60,7 @@ 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__(): @@ -82,9 +82,9 @@ def __set__(self, obj, val): self.choice = val color = SuperColor() - + def test_set_descriptor_changes_behavior_of_attribute_assignment_changes(self): self.assertEqual(None, self.color.choice) self.color = 'purple' self.assertEqual(__, self.color.choice) - + diff --git a/python3/koans/about_methods.py b/python3/koans/about_methods.py index 643d83425..e069bbb63 100644 --- a/python3/koans/about_methods.py +++ b/python3/koans/about_methods.py @@ -13,7 +13,7 @@ def my_global_function(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): @@ -25,17 +25,17 @@ def test_calling_functions_with_wrong_number_of_arguments(self): self.assertRegexpMatches(msg, r'my_global_function\(\) takes exactly 2 ' + r'arguments \(0 given\)') - + try: my_global_function(1, 2, 3) except Exception as e: msg = e.args[0] - + # Note, watch out for parenthesis. They need slashes in front! - self.assertRegexpMatches(msg, __) - + self.assertRegexpMatches(msg, __) + # ------------------------------------------------------------------ - + def pointless_method(self, a, b): sum = a + b @@ -43,7 +43,7 @@ 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'): @@ -67,13 +67,13 @@ def test_calling_with_variable_arguments(self): 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 @@ -84,9 +84,9 @@ def function_with_the_same_name(a, b): 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 @@ -114,7 +114,7 @@ def test_pass_does_nothing_at_all(self): # ------------------------------------------------------------------ def one_line_method(self): return 'Madagascar' - + def test_no_indentation_required_for_one_line_statement_bodies(self): self.assertEqual(__, self.one_line_method()) @@ -123,16 +123,16 @@ def test_no_indentation_required_for_one_line_statement_bodies(self): 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.assertRegexpMatches(self.method_with_documentation.__doc__, __) # ------------------------------------------------------------------ - class Dog: + class Dog: def name(self): return "Fido" - + def _tail(self): # Prefixing a method with an underscore implies private scope return "wagging" @@ -143,7 +143,7 @@ def __password(self): 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() @@ -152,11 +152,11 @@ def test_private_access_is_implied_but_not_enforced(self): def test_attributes_with_double_underscore_prefixes_are_subject_to_name_mangling(self): rover = self.Dog() - with self.assertRaises(___): password = rover.__password() - + with self.assertRaises(___): password = rover.__password() + # 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/python3/koans/about_modules.py b/python3/koans/about_modules.py index 4974fa245..cf3af2fe5 100644 --- a/python3/koans/about_modules.py +++ b/python3/koans/about_modules.py @@ -14,19 +14,19 @@ class AboutModules(Koan): def test_importing_other_python_scripts_as_modules(self): from . 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): from . import jims, joes - + jims_dog = jims.Dog() joes_dog = joes.Dog() self.assertEqual(__, jims_dog.identify()) @@ -37,24 +37,24 @@ def test_importing_all_module_attributes_at_once(self): # from .other_local_module import * # # 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): with self.assertRaises(___): private_squirrel = _SecretSquirrel() 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_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 * @@ -66,6 +66,6 @@ def test_a_module_can_choose_which_attributes_are_available_to_wildcards(self): # How about velociraptors? lizard = _Velociraptor() self.assertEqual(__, lizard.name) - + # SecretDuck? Never heard of her! with self.assertRaises(___): duck = SecretDuck() diff --git a/python3/koans/about_monkey_patching.py b/python3/koans/about_monkey_patching.py index 40dd5598c..a7e738418 100644 --- a/python3/koans/about_monkey_patching.py +++ b/python3/koans/about_monkey_patching.py @@ -11,14 +11,14 @@ class AboutMonkeyPatching(Koan): class Dog: 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. + + # 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 @@ -26,25 +26,24 @@ def wag(self): return "HAPPY" 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 Exception as ex: err_msg = ex.args[0] - + self.assertRegexpMatches(err_msg, __) # ------------------------------------------------------------------ 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()) - - \ No newline at end of file + diff --git a/python3/koans/about_multiple_inheritance.py b/python3/koans/about_multiple_inheritance.py index 37a68701c..9af59fc48 100644 --- a/python3/koans/about_multiple_inheritance.py +++ b/python3/koans/about_multiple_inheritance.py @@ -14,20 +14,20 @@ def __init__(self): def set_name(self, new_name): self._name = new_name - + def here(self): return "In Nameable class" - - class Animal: + + class Animal: 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().__init__() @@ -36,13 +36,13 @@ def __init__(self): @property def name(self): return self._name - + def speak(self): return "OINK" - + def color(self): - return 'pink' - + return 'pink' + def here(self): return "In Pig class" @@ -68,23 +68,23 @@ 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: + + # + # Hierarchy: # Animal - # / \ - # Pig Spider Nameable + # / \ + # Pig Spider Nameable # \ | / # Spiderpig - # + # # ------------------------------------------------------------------ - + def test_normal_methods_are_available_in_the_object(self): jeff = self.Spiderpig() self.assertRegexpMatches(jeff.speak(), __) @@ -96,14 +96,14 @@ def test_base_class_methods_are_also_available_in_the_object(self): 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()) @@ -119,23 +119,23 @@ def test_we_can_inspect_the_method_resolution_order(self): 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__) + 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.assertRegexpMatches(jeff.here(), 'Spiderpig') - - next = super(AboutMultipleInheritance.Spiderpig, jeff) + + next = super(AboutMultipleInheritance.Spiderpig, jeff) self.assertRegexpMatches(next.here(), 'Pig') next = super(AboutMultipleInheritance.Pig, jeff) self.assertRegexpMatches(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 c75e5a2d9..a0ada8b3e 100644 --- a/python3/koans/about_none.py +++ b/python3/koans/about_none.py @@ -12,7 +12,7 @@ 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) @@ -21,28 +21,28 @@ def test_what_exception_do_you_get_when_calling_nonexistent_methods_on_None(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: ex2 = ex - + # What exception has been caught? self.assertEqual(__, ex2.__class__.__name__) - + # What message was attached to the exception? # (HINT: replace __ with part of the error message.) self.assertRegexpMatches(ex2.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/python3/koans/about_packages.py b/python3/koans/about_packages.py index 9596ba54d..d33d8fa38 100644 --- a/python3/koans/about_packages.py +++ b/python3/koans/about_packages.py @@ -18,7 +18,7 @@ # about_attribute_access.py # about_class_attributes.py # about_classes.py -# ... +# ... # a_package_folder/ # __init__.py # a_module.py @@ -27,16 +27,16 @@ 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/ with self.assertRaises(___): from a_normal_folder import Duck @@ -48,7 +48,7 @@ def test_use_absolute_imports_to_import_upper_level_modules(self): import contemplate_koans self.assertEqual(__, contemplate_koans.__name__) - + # contemplate_koans.py is the root module in this package because its # the first python module called in koans. # diff --git a/python3/koans/about_proxy_object_project.py b/python3/koans/about_proxy_object_project.py index bb5c45620..165585849 100644 --- a/python3/koans/about_proxy_object_project.py +++ b/python3/koans/about_proxy_object_project.py @@ -21,11 +21,11 @@ class Proxy: def __init__(self, target_object): # WRITE CODE HERE - + #initialize '_obj' attribute last. Trust me on this! self._obj = target_object - - # WRITE CODE HERE + + # WRITE CODE HERE # The proxy object should pass the following Koan: # @@ -33,61 +33,61 @@ 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 with self.assertRaises(AttributeError): tv.no_such_method() - - + + 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) @@ -102,21 +102,21 @@ class Television: 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 - + 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' @@ -124,33 +124,33 @@ def is_on(self): 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/python3/koans/about_regex.py b/python3/koans/about_regex.py index 13db11a82..eb930644d 100755 --- a/python3/koans/about_regex.py +++ b/python3/koans/about_regex.py @@ -29,7 +29,7 @@ def test_matching_literal_text_how_many(self): 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. - + """ 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 @@ -49,7 +49,7 @@ def test_matching_literal_text_not_case_sensitivity(self): self.assertEqual(re.findall("felix", string, 20), __) self.assertEqual(re.findall("felix", string, 10), __) - + def test_matching_any_character(self): """ Lesson 1 Matching any character @@ -64,7 +64,7 @@ def test_matching_any_character(self): + "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) @@ -83,7 +83,7 @@ def test_matching_set_character(self): + "na1.xls\n" \ + "na2.xls\n" \ + "sa1.xls\n" \ - + "ca1.xls" + + "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' @@ -92,7 +92,7 @@ def test_matching_set_character(self): def test_anything_but_matching(self): """ Lesson 2 Using character set ranges - Occsionally, you'll want a list of characters that you don't want to match. + Occsionally, you'll want a list of characters that you don't want to match. Character sets can be negated using the ^ metacharacter. """ @@ -107,10 +107,10 @@ def test_anything_but_matching(self): + "na1.xls\n" \ + "na2.xls\n" \ + "sa1.xls\n" \ - + "ca1.xls" + + "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']) diff --git a/python3/koans/about_scope.py b/python3/koans/about_scope.py index b2d0d6614..9118a98d5 100644 --- a/python3/koans/about_scope.py +++ b/python3/koans/about_scope.py @@ -3,7 +3,7 @@ from runner.koan import * -from . import jims +from . import jims from . import joes counter = 0 # Global @@ -14,39 +14,39 @@ class AboutScope(Koan): # 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): with self.assertRaises(___): fido = Dog() - + def test_you_can_reference_nested_classes_using_the_scope_operator(self): fido = jims.Dog() # name 'jims' module name is taken from jim.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: 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. @@ -62,11 +62,11 @@ def test_constants_are_assumed_by_convention_only(self): def increment_using_local_counter(self, counter): counter = counter + 1 - + def increment_using_global_counter(self): global counter - counter = counter + 1 - + counter = counter + 1 + def test_incrementing_with_local_counter(self): global counter start = counter @@ -87,25 +87,24 @@ def from_the_league(): stuff = 'this is a local shop for local people' return stuff return from_the_league() - + def nonlocal_access(self): - stuff = 'eels' + stuff = 'eels' def from_the_boosh(): nonlocal stuff return stuff return from_the_boosh() - + def test_getting_something_locally(self): self.assertEqual(__, self.local_access()) - + def test_getting_something_nonlocally(self): self.assertEqual(__, self.nonlocal_access()) - + # ------------------------------------------------------------------ - + 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]) - \ No newline at end of file diff --git a/python3/koans/about_scoring_project.py b/python3/koans/about_scoring_project.py index 393af55b5..2bd06c418 100644 --- a/python3/koans/about_scoring_project.py +++ b/python3/koans/about_scoring_project.py @@ -10,7 +10,7 @@ # 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). # @@ -39,34 +39,34 @@ def score(dice): 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])) \ No newline at end of file diff --git a/python3/koans/about_strings.py b/python3/koans/about_strings.py index 3b85eebdb..8cd1a885c 100644 --- a/python3/koans/about_strings.py +++ b/python3/koans/about_strings.py @@ -4,15 +4,15 @@ from runner.koan import * class AboutStrings(Koan): - + def test_double_quoted_strings_are_strings(self): string = "Hello, world." self.assertEqual(__, isinstance(string, str)) - + def test_single_quoted_strings_are_also_strings(self): string = 'Goodbye, world.' self.assertEqual(__, isinstance(string, str)) - + def test_triple_quote_strings_are_also_strings(self): string = """Howdy, world!""" self.assertEqual(__, isinstance(string, str)) @@ -28,11 +28,11 @@ def test_raw_strings_are_also_strings(self): 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"' @@ -42,22 +42,22 @@ 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 but_you_still_have_to_be_careful_at_the_end_of_a_triple_quoted_string(self): string = """Hello "world\"""" - + def test_plus_concatenates_strings(self): string = "Hello, " + "world" self.assertEqual(__, string) @@ -65,20 +65,20 @@ def test_plus_concatenates_strings(self): 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 @@ -91,7 +91,7 @@ def test_most_strings_interpret_escape_characters(self): self.assertEqual('\n', string) self.assertEqual("""\n""", string) self.assertEqual(__, len(string)) - + def test_use_format_to_interpolate_variables(self): value1 = 'one' value2 = 2 @@ -103,42 +103,42 @@ def test_formatted_values_con_be_shown_in_any_order_or_be_repeated(self): 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('a')) self.assertEqual(__, ord('b') == (ord('a') + 1)) - + def test_strings_can_be_split(self): string = "Sausage Egg Cheese" words = string.split() self.assertListEqual([__, __, __], 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.assertListEqual([__, __, __, __], words) - + # Pattern is a Python regular expression pattern which matches ',' or ';' def test_raw_strings_do_not_interpret_escape_characters(self): @@ -147,8 +147,8 @@ def test_raw_strings_do_not_interpret_escape_characters(self): self.assertEqual(__, string) self.assertEqual(__, len(string)) - # Useful in regular expressions, file paths, URLs, etc. - + # Useful in regular expressions, file paths, URLs, etc. + def test_strings_can_be_joined(self): words = ["Now", "is", "the", "time"] self.assertEqual(__, ' '.join(words)) diff --git a/python3/koans/about_triangle_project.py b/python3/koans/about_triangle_project.py index 60da2c2ea..ad2485909 100644 --- a/python3/koans/about_triangle_project.py +++ b/python3/koans/about_triangle_project.py @@ -10,13 +10,13 @@ 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)) diff --git a/python3/koans/about_triangle_project2.py b/python3/koans/about_triangle_project2.py index 3e2f2edf7..d31dd60a5 100644 --- a/python3/koans/about_triangle_project2.py +++ b/python3/koans/about_triangle_project2.py @@ -16,10 +16,10 @@ def test_illegal_triangles_throw_exceptions(self): with self.assertRaises(TriangleError): triangle(3, 4, -5) - with self.assertRaises(TriangleError): + with self.assertRaises(TriangleError): triangle(1, 1, 3) - + with self.assertRaises(TriangleError): triangle(2, 4, 2) - + diff --git a/python3/koans/about_true_and_false.py b/python3/koans/about_true_and_false.py index 9b6639641..c6585567f 100644 --- a/python3/koans/about_true_and_false.py +++ b/python3/koans/about_true_and_false.py @@ -9,13 +9,13 @@ def truth_value(self, 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)) @@ -30,7 +30,7 @@ def test_empty_collections_are_treated_as_false(self): 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(1,)) diff --git a/python3/koans/about_tuples.py b/python3/koans/about_tuples.py index f206b717b..cd6034427 100644 --- a/python3/koans/about_tuples.py +++ b/python3/koans/about_tuples.py @@ -7,46 +7,46 @@ class AboutTuples(Koan): def test_creating_a_tuple(self): count_of_three = (1, 2, 5) self.assertEqual(5, __) - + 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: msg = ex.args[0] - + # Note, assertRegexpMatches() uses regular expression pattern matching, - # so you don't have to copy the whole message. + # so you don't have to copy the whole message. self.assertRegexpMatches(msg, __) - + def test_tuples_are_immutable_so_appending_is_not_possible(self): count_of_three = (1, 2, 5) with self.assertRaises(___): count_of_three.append("boom") - + # 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__.__name__) self.assertEqual(__, (1,).__class__.__name__) self.assertEqual(__, ("Hello comma!", )) - + 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') @@ -58,11 +58,11 @@ def test_tuples_are_good_for_representing_records(self): ("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( ("Cthulu", (26, 40, 1, 'N'), (70, 45, 7, 'W')) ) - + self.assertEqual(__, locations[2][0]) self.assertEqual(__, locations[0][1][2]) - - - + + + diff --git a/python3/koans/about_with_statements.py b/python3/koans/about_with_statements.py index 761ee79e1..a224e8264 100644 --- a/python3/koans/about_with_statements.py +++ b/python3/koans/about_with_statements.py @@ -23,12 +23,12 @@ def count_lines(self, file_name): 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: file = open(file_name) @@ -42,10 +42,10 @@ def find_line(self, file_name): except IOError: # should never happen self.fail() - + def test_finding_lines(self): self.assertEqual(__, self.find_line("example_file.txt")) - + ## ------------------------------------------------------------------ ## THINK ABOUT IT: ## @@ -68,49 +68,49 @@ def test_finding_lines(self): ## 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 file: count = 0 for line in file.readlines(): count += 1 return count - + def test_counting_lines2(self): self.assertEqual(__, self.count_lines2("example_file.txt")) - + # ------------------------------------------------------------------ - + def find_line2(self, file_name): - # Rewrite find_line using the Context Manager. + # Rewrite find_line using the Context Manager. pass - + def test_finding_lines2(self): self.assertEqual(__, self.find_line2("example_file.txt")) self.assertNotEqual(__, self.find_line2("example_file.txt")) - + # ------------------------------------------------------------------ - + def count_lines3(self, file_name): with open(file_name) as file: count = 0 for line in file.readlines(): count += 1 return count - + def test_open_already_has_its_own_built_in_context_manager(self): self.assertEqual(__, self.count_lines3("example_file.txt")) diff --git a/python3/koans/another_local_module.py b/python3/koans/another_local_module.py index 3b3660cf5..242daaa79 100644 --- a/python3/koans/another_local_module.py +++ b/python3/koans/another_local_module.py @@ -10,7 +10,7 @@ class Hamster: @property def name(self): return "Phil" - + class _SecretSquirrel: @property def name(self): diff --git a/python3/koans/local_module_with_all_defined.py b/python3/koans/local_module_with_all_defined.py index 5293f0933..a84ae8307 100644 --- a/python3/koans/local_module_with_all_defined.py +++ b/python3/koans/local_module_with_all_defined.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- __all__ = ( - 'Goat', + 'Goat', '_Velociraptor' ) diff --git a/python3/libs/colorama/ansitowin32.py b/python3/libs/colorama/ansitowin32.py index 9ce77dd6f..5c39a480e 100644 --- a/python3/libs/colorama/ansitowin32.py +++ b/python3/libs/colorama/ansitowin32.py @@ -118,7 +118,7 @@ def write(self, text): self.wrapped.flush() if self.autoreset: self.reset_all() - + def reset_all(self): if self.convert: diff --git a/python3/libs/mock.py b/python3/libs/mock.py index c01875bf3..38c446db2 100644 --- a/python3/libs/mock.py +++ b/python3/libs/mock.py @@ -26,7 +26,7 @@ class SentinelObject(object): def __init__(self, name): self.name = name - + def __repr__(self): return ''.format(self.name) @@ -34,11 +34,11 @@ def __repr__(self): class Sentinel(object): def __init__(self): self._sentinels = {} - + def __getattr__(self, name): return self._sentinels.setdefault(name, SentinelObject(name)) - - + + sentinel = Sentinel() DEFAULT = sentinel.DEFAULT @@ -58,21 +58,21 @@ def _copy(value): class Mock(object): - def __init__(self, spec=None, side_effect=None, return_value=DEFAULT, + 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 @@ -84,16 +84,16 @@ def reset_mock(self): 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) @@ -102,7 +102,7 @@ def __call__(self, *args, **kwargs): 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: @@ -111,44 +111,44 @@ def __call__(self, *args, **kwargs): 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 + 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: @@ -199,8 +199,8 @@ def patched(*args, **keywargs): patching.__exit__() patched.patchings = [self] - patched.__name__ = func.__name__ - patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno", + patched.__name__ = func.__name__ + patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno", func.func_code.co_firstlineno) return patched @@ -209,7 +209,7 @@ def get_original(self): target = self.target name = self.attribute create = self.create - + original = DEFAULT if _has_local_attr(target, name): try: @@ -221,7 +221,7 @@ def get_original(self): 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() @@ -247,15 +247,15 @@ def __exit__(self, *_): 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) + 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) diff --git a/python3/runner/mountain.py b/python3/runner/mountain.py index eabb55862..dab3b415f 100644 --- a/python3/runner/mountain.py +++ b/python3/runner/mountain.py @@ -13,10 +13,10 @@ 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: self.tests = unittest.TestLoader().loadTestsFromName("koans." + args[1]) diff --git a/python3/runner/runner_tests/test_helper.py b/python3/runner/runner_tests/test_helper.py index ea3ee00c3..fef9b6026 100644 --- a/python3/runner/runner_tests/test_helper.py +++ b/python3/runner/runner_tests/test_helper.py @@ -6,10 +6,10 @@ 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)) diff --git a/python3/runner/runner_tests/test_mountain.py b/python3/runner/runner_tests/test_mountain.py index 18fcc3167..0f8d08ccc 100644 --- a/python3/runner/runner_tests/test_mountain.py +++ b/python3/runner/runner_tests/test_mountain.py @@ -13,9 +13,9 @@ 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) - + diff --git a/python3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py index c6eac74bd..3c60d4ce0 100644 --- a/python3/runner/runner_tests/test_sensei.py +++ b/python3/runner/runner_tests/test_sensei.py @@ -89,36 +89,36 @@ def setUp(self): self.sensei.stream.writeln = Mock() path_to_enlightenment.koans = Mock() self.tests = Mock() - self.tests.countTestCases = Mock() - + self.tests.countTestCases = Mock() + def test_that_it_delegates_testing_to_test_cases(self): MockableTestResult.startTest = Mock() self.sensei.startTest(Mock()) self.assertTrue(MockableTestResult.startTest.called) - + def test_that_user_is_notified_if_test_involves_a_different_test_class_to_last_time(self): MockableTestResult.startTest = Mock() - + self.sensei.prevTestClassName == 'AboutLumberjacks' nextTest = AboutParrots() - + self.sensei.startTest(nextTest) self.assertTrue(self.sensei.stream.writeln.called) - + def test_that_user_is_not_notified_about_test_class_repeats(self): MockableTestResult.startTest = Mock() - + self.sensei.prevTestClassName == 'AboutParrots' nextTest = AboutParrots() - + self.sensei.startTest(nextTest) self.assertTrue(self.sensei.stream.writeln.called) - + def test_that_cached_classname_updates_after_the_test(self): self.assertEqual(None, self.sensei.prevTestClassName) self.sensei.startTest(Mock()) self.assertNotEqual(None, self.sensei.prevTestClassName) - + def test_that_errors_are_diverted_to_the_failures_list(self): MockableTestResult.addFailure = Mock() self.sensei.addError(Mock(), Mock()) @@ -134,7 +134,7 @@ def test_that_it_successes_only_count_if_passes_are_currently_allowed(self): MockableTestResult.addSuccess = Mock() self.sensei.addSuccess(Mock()) self.assertTrue(self.sensei.passesCount.called) - + def test_that_if_there_are_failures_and_the_prev_class_is_different_successes_are_not_allowed(self): self.sensei.failures = [(AboutLumberjacks(), Mock())] self.sensei.prevTestClassName = "AboutTheMinitry" @@ -154,7 +154,7 @@ def test_that_it_passes_on_add_successes_message(self): 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() @@ -165,15 +165,15 @@ def test_that_it_displays_each_success(self): MockableTestResult.addSuccess = Mock() self.sensei.addSuccess(Mock()) self.assertTrue(self.sensei.stream.writeln.called) - + 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"), @@ -181,7 +181,7 @@ def test_that_nothing_is_returned_as_sorted_result_if_there_are_no_relevent_fail (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"), @@ -192,26 +192,26 @@ def test_that_nothing_is_returned_as_sorted_result_if_there_are_3_shuffled_resul (AboutMrGumby(),"File 'about_mr_gumby.py', line odd"), (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]) 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"), @@ -219,7 +219,7 @@ def test_that_it_will_choose_correct_first_result_with_lines_9_and_27(self): (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"), @@ -228,7 +228,7 @@ def test_that_it_will_choose_correct_first_result_with_multiline_test_classes(se (AboutFreemasons(),"File 'about_freemasons.py', line 11") ] self.assertEqual("File 'about_giant_feet.py', line 44", self.sensei.firstFailure()[1]) - + def test_that_end_report_displays_something(self): self.sensei.learn() self.assertTrue(self.sensei.stream.writeln.called) @@ -240,7 +240,7 @@ def test_that_end_report_shows_student_progress(self): self.sensei.learn() self.assertTrue(self.sensei.total_lessons.called) - self.assertTrue(self.sensei.total_koans.called) + self.assertTrue(self.sensei.total_koans.called) def test_that_end_report_shows_the_failure_report(self): self.sensei.errorReport = Mock() @@ -263,7 +263,7 @@ def test_that_error_report_does_not_show_anything_if_there_is_no_failure(self): self.sensei.firstFailure.return_value = None self.sensei.errorReport() self.assertFalse(self.sensei.stream.writeln.called) - + def test_that_error_report_features_the_assertion_error(self): self.sensei.scrapeAssertionError = Mock() self.sensei.firstFailure = Mock() @@ -280,19 +280,19 @@ def test_that_error_report_features_a_stack_dump(self): 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)) @@ -313,7 +313,7 @@ def test_that_scraping_the_assertion_error_with_list_error(self): def test_that_scraping_a_non_existent_stack_dump_gives_you_nothing(self): self.assertEqual("", self.sensei.scrapeInterestingStackDump(None)) - + def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_messaged_assert(self): expected = """ 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...")""" @@ -341,23 +341,23 @@ def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_syntax_er 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_successes_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)) @@ -365,7 +365,7 @@ 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)) @@ -373,7 +373,7 @@ 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)) @@ -381,7 +381,7 @@ 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)) @@ -400,10 +400,10 @@ def test_that_total_lessons_return_0_if_all_lessons_is_none(self): 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) + self.assertTrue(len(self.sensei.all_lessons) > 10) diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index 7674b0602..3c6692be4 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -17,7 +17,7 @@ def __init__(self, stream): unittest.TestResult.__init__(self) self.stream = stream self.prevTestClassName = None - self.tests = path_to_enlightenment.koans() + self.tests = path_to_enlightenment.koans() self.pass_count = 0 self.lesson_pass_count = 0 self.all_lessons = None @@ -32,15 +32,15 @@ def startTest(self, test): self.stream.writeln("{0}{1}Thinking {2}".format( Fore.RESET, Style.NORMAL, helper.cls_name(test))) if helper.cls_name(test) != 'AboutAsserts': - self.lesson_pass_count += 1 + self.lesson_pass_count += 1 def addSuccess(self, test): - if self.passesCount(): + 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)) + Fore.RESET, Style.NORMAL)) self.pass_count += 1 def addError(self, test, err): @@ -50,7 +50,7 @@ def addError(self, 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) @@ -62,31 +62,31 @@ def sortFailures(self, testClassName): 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()) - self.stream.writeln("") + self.stream.writeln("") self.stream.writeln(self.say_something_zenlike()) - + if self.failures: return self.stream.writeln( "\n{0}**************************************************" \ @@ -95,14 +95,14 @@ def learn(self): .format(Fore.MAGENTA)) self.stream.writeln( "\nIf you want more, take a look at about_extra_credit_task.py{0}{1}" \ - .format(Fore.RESET, Style.NORMAL)) - + .format(Fore.RESET, Style.NORMAL)) + def errorReport(self): problem = self.firstFailure() - if not problem: return - test, err = problem + if not problem: return + test, err = problem self.stream.writeln(" {0}{1}{2} has damaged your " - "karma.".format(Fore.RED, Style.BRIGHT, test._testMethodName)) + "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)) @@ -123,7 +123,7 @@ def scrapeAssertionError(self, err): 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') @@ -133,9 +133,9 @@ def scrapeInterestingStackDump(self, err): return "" lines = err.splitlines() - + sep = '@@@@@SEP@@@@@' - + scrape = "" for line in lines: m = re.search("^ File .*$",line) @@ -145,9 +145,9 @@ def scrapeInterestingStackDump(self, err): m = re.search("^ \w(\w)+.*$",line) if m and m.group(0): scrape += sep + line - + lines = scrape.splitlines() - + scrape = "" for line in lines: m = re.search("^.*[/\\\\]koans[/\\\\].*$",line) @@ -165,7 +165,7 @@ def report_progress(self): "{1} lessons.\n".format(koans_complete, lessons_complete) sent2 = "You are now {0} koans and {1} lessons away from " \ "reaching enlightenment.".format(koans_remaining, lessons_remaining) - return sent1+sent2 + return sent1+sent2 # Hat's tip to Tim Peters for the zen statements from The Zen # of Python (http://www.python.org/dev/peps/pep-0020/) @@ -176,9 +176,9 @@ def report_progress(self): def say_something_zenlike(self): if self.failures: turn = self.pass_count % 37 - + zenness = ""; - if turn == 0: + if turn == 0: zenness = "Beautiful is better than ugly." elif turn == 1 or turn == 2: zenness = "Explicit is better than implicit." @@ -221,14 +221,14 @@ def say_something_zenlike(self): elif turn == 33 or turn == 34: zenness = "If the implementation is easy to explain, " \ "it may be a good idea." - else: + 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); + 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 in collapsing! Run!!!" @@ -249,4 +249,4 @@ def filter_all_lessons(self): "about_extra_credit" not in filename, self.all_lessons)) - return self.all_lessons + return self.all_lessons From 296466c3f34b439c4eaebd5f3e2687e8b27c86e7 Mon Sep 17 00:00:00 2001 From: Matt Stevens Date: Tue, 12 Mar 2013 00:29:51 +0000 Subject: [PATCH 068/237] Fixes the run.sh for Python2 in Arch Linux Arch linux defaults to Python 3, so `python2/run.sh` didn't work. --- python2/run.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python2/run.sh b/python2/run.sh index d247987bc..fda73be7d 100755 --- a/python2/run.sh +++ b/python2/run.sh @@ -1,3 +1,7 @@ #!/bin/sh -python contemplate_koans.py +if [ -x /usr/bin/python2 ]; then + python2 contemplate_koans.py +else + python contemplate_koans.py +fi From aa189dd4deb5327e87d9458dd92508a38208c807 Mon Sep 17 00:00:00 2001 From: dongweiming <61966225@qq.com> Date: Tue, 12 Mar 2013 18:41:44 +0800 Subject: [PATCH 069/237] Modify sensei display the information in the directory of python2 / 3, the remaining number of courses error. the glob module to get the user to execute the current directory, rather than where the program directory --- python2/runner/sensei.py | 6 ++++-- python3/runner/sensei.py | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index bf8b93898..95703c024 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -4,6 +4,7 @@ import unittest import re import sys +import os import glob import helper @@ -235,6 +236,7 @@ def say_something_zenlike(self): def total_lessons(self): all_lessons = self.filter_all_lessons() + if all_lessons: return len(all_lessons) else: @@ -244,10 +246,10 @@ 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('koans/about*.py') + 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/python3/runner/sensei.py b/python3/runner/sensei.py index 3c6692be4..2ffbbaeb4 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -3,6 +3,7 @@ import unittest import re +import os import glob from . import helper @@ -243,8 +244,9 @@ 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('koans/about*.py') + self.all_lessons = glob.glob('{0}/../koans/about*.py'.format(cur_dir)) self.all_lessons = list(filter(lambda filename: "about_extra_credit" not in filename, self.all_lessons)) From 55cdce7cf413ae80290323e59ebd23a447974384 Mon Sep 17 00:00:00 2001 From: Dominique Plante Date: Wed, 24 Apr 2013 21:12:52 -0700 Subject: [PATCH 070/237] fix some typos --- python2/runner/sensei.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index bf8b93898..d900ce2e8 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -168,12 +168,12 @@ def report_progress(self): "reaching enlightenment.".format(koans_remaining, lessons_remaining) return sent1+sent2 - # Hat's tip to Tim Peters for the zen statements from The Zen - # of Python (http://www.python.org/dev/peps/pep-0020/) + # 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 permatation in the Ruby Koans + # Edgecase's later permutation in the Ruby Koans def say_something_zenlike(self): if self.failures: turn = self.pass_count % 37 @@ -231,7 +231,7 @@ def say_something_zenlike(self): .format(Fore.CYAN) # Hopefully this will never ever happen! - return "The temple in collapsing! Run!!!" + return "The temple is collapsing! Run!!!" def total_lessons(self): all_lessons = self.filter_all_lessons() From a86e2a42cbf12a860ca9a0d9a16562c86ada8663 Mon Sep 17 00:00:00 2001 From: Dominique Plante Date: Thu, 25 Apr 2013 20:54:42 -0700 Subject: [PATCH 071/237] improve wording, add links, etc.. --- README.rst | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/README.rst b/README.rst index 8f633dd9d..383d9e366 100644 --- a/README.rst +++ b/README.rst @@ -2,11 +2,11 @@ Python Koans ============ -Python Koans is a port of Edgecase's "Ruby 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 -Python Koans is an interactive tutorial for learning Python by making tests pass. +Python Koans is an interactive tutorial for learning the Python programming language by making tests pass. Most tests are 'fixed' by filling the missing parts of assert functions. Eg: @@ -28,7 +28,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 mirrored on bitbucket for Mercurial users: http://bitbucket.org/gregmalcolm/python_koans @@ -38,20 +38,29 @@ Either site will allow you to download the source as a zip/gz/bz2. Installing Python Koans ----------------------- -Aside from downloading or checking out the latest version of Python Koans, all you need to install is Python. +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 koans, one for use with Python 2.6 and one for Python 3.1. You should be able to work with newer Python versions, but older ones will likely give you problems. +At this time of writing, there are two versions of the Python Koans: + +* one for use with Python 2.6 (it also works with Python 2.7) +* one for Python 3.1. + +You should be able to work with newer Python versions, but older ones will likely give you problems. You can download Python from here: http://www.python.org/download -On 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 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'. +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 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'. If you have problems, this may help: http://www.python.org/about/gettingstarted +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 + Getting Started --------------- @@ -107,26 +116,41 @@ Quoting the Ruby Koans instructions:: moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor)." + Content ------- -Python 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. +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 2 different languages. 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. +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 -------------------------- -Right now there are a lot of spinoff Koan projects out there for a great number of languages and frameworks. Many of them do not have that much content, but contributing to them is a great way to learn. At the moment most of them can be found by searching for 'koans' on github. +Right now there are a lot of spinoff Koan projects out there for a great number of languages and frameworks. Many of them do not have that much content, but contributing to them is a great way to learn. At the moment, most of them can be found by searching for 'koans' on github. + +A couple of promising projects include: + +* C# Koans - https://bitbucket.org/srtsolutions/csharpkoans + Mentioned here: http://labs.srtsolutions.com/c-koans + +* F# Koans - https://github.com/ChrisMarinos/FSharpKoans + Mentioned here: http://labs.srtsolutions.com/f-koans + +* Scala Koans - http://scalakoans.org/ + Mentioned here: http://labs.srtsolutions.com/koans -A couple of promising projects include DotNetKoans and TestMongoKoans. +* DotNetKoans - https://github.com/CoryFoy/DotNetKoans + Mentioned here: http://blog.coryfoy.com/2009/12/dotnet-koans/ + +* TestMongoKoans. Acknowledgments --------------- -Thanks go to Jim Weirich and Joe O'Brien for the original Ruby Koans that Python Koans is based on! Also the Ruby Koans in turn borrows from Metakoans so thanks also go to Ara Howard for that! +Thanks go to Jim Weirich and Joe O'Brien for the original Ruby Koans that the Python Koans is based on! Also the Ruby Koans in turn borrows from Metakoans so thanks also go to Ara Howard for that! Also thanks to everyone who helped with the Python Koans conversion! In particular I got a great headstart on the project by forking from this Python Koans startup project: From bfd8cf2fd85e58e96fff4071c5dc93932a91eeae Mon Sep 17 00:00:00 2001 From: Dominique Plante Date: Thu, 25 Apr 2013 22:09:08 -0700 Subject: [PATCH 072/237] add missing period --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 383d9e366..9c3378414 100644 --- a/README.rst +++ b/README.rst @@ -122,7 +122,7 @@ 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. +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 From edc86abe4382cc819003ac20df7b6c399405f2ad Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 18:33:12 -0400 Subject: [PATCH 073/237] Modernized the koan links at the end of the README --- README.rst | 90 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/README.rst b/README.rst index 9c3378414..189fdde35 100644 --- a/README.rst +++ b/README.rst @@ -2,11 +2,13 @@ Python Koans ============ -Python Koans is a port of Edgecase's "Ruby Koans" which can be found at http://rubykoans.com/. +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 -Python Koans is an interactive tutorial for learning the Python programming language by making tests pass. +Python Koans is an interactive tutorial for learning the Python programming +language by making tests pass. Most tests are 'fixed' by filling the missing parts of assert functions. Eg: @@ -16,9 +18,13 @@ which can be fixed by replacing the __ part with the appropriate code: self.assertEqual(3, 1+2) -Occasionally you will encounter some failing tests that are already filled out. In these cases you will need to finish implementing some code to progress. For example, there is an exercise for writing some code that will tell you if a triangle is equilateral, isosceles or scalene. +Occasionally you will encounter some failing tests that are already filled out. +In these cases you will need to finish implementing some code to progress. For +example, there is an exercise for writing some code that will tell you if a +triangle is equilateral, isosceles or scalene. -As well as being a great way to learn some Python, it is also a good way to get a taste of Test Driven Development (TDD). +As well as being a great way to learn some Python, it is also a good way to get +a taste of Test Driven Development (TDD). Downloading Python Koans @@ -38,26 +44,33 @@ Either site will allow you to download the source as a zip/gz/bz2. Installing Python Koans ----------------------- -Aside from downloading or checking out the latest version of Python Koans, you need to install the Python interpreter. +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.6 (it also works with Python 2.7) -* one for Python 3.1. +* one for Python 3.1. -You should be able to work with newer Python versions, but older ones will likely give you problems. +You should be able to work with newer Python versions, but older ones will +likely give you problems. 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 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'. +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 +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'. If you have problems, this may help: http://www.python.org/about/gettingstarted -Windows users may also want to update the line in the batch file run.bat to set the python path: +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 @@ -71,7 +84,8 @@ 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 go to the python +koans\python_VERSION folder and run:: python contemplate_koans.py @@ -79,7 +93,8 @@ or:: python3 contemplate_koans.py -In my case I'm using Python 3 with windows, so I fire up my command shell (cmd.exe) and run this: +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 @@ -87,9 +102,12 @@ Apparently a test failed:: AssertionError: False is not True -It also tells me exactly where the problem in, its an assert on line 12 of .\koans\about_asserts.py. This one is easy, just change False to True to make the test pass. +It also tells me exactly where the problem in, its an assert on line 12 +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:: +Sooner or later you will likely encounter tests where you are not sure what the +expected value should be. For example:: class Dog: pass @@ -98,7 +116,8 @@ Sooner or later you will likely encounter tests where you are not sure what the fido = self.Dog() self.assertEqual(__, isinstance(fido, object)) -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: +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 @@ -120,38 +139,39 @@ Quoting the Ruby Koans instructions:: 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. +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. +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 -------------------------- -Right now there are a lot of spinoff Koan projects out there for a great number of languages and frameworks. Many of them do not have that much content, but contributing to them is a great way to learn. At the moment, most of them can be found by searching for 'koans' on github. +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. -A couple of promising projects include: - -* C# Koans - https://bitbucket.org/srtsolutions/csharpkoans - Mentioned here: http://labs.srtsolutions.com/c-koans - -* F# Koans - https://github.com/ChrisMarinos/FSharpKoans - Mentioned here: http://labs.srtsolutions.com/f-koans - -* Scala Koans - http://scalakoans.org/ - Mentioned here: http://labs.srtsolutions.com/koans - -* DotNetKoans - https://github.com/CoryFoy/DotNetKoans - Mentioned here: http://blog.coryfoy.com/2009/12/dotnet-koans/ - -* TestMongoKoans. +* Github koan projects: + https://github.com/search?q=koans&ref=cmdform +* Bitbucket koan projects: + https://bitbucket.org/repo/all?name=koans Acknowledgments --------------- -Thanks go to Jim Weirich and Joe O'Brien for the original Ruby Koans that the Python Koans is based on! Also the Ruby Koans in turn borrows from Metakoans so thanks also go to Ara Howard for that! +Thanks go to Jim Weirich and Joe O'Brien for the original Ruby Koans that the +Python Koans is based on! Also the Ruby Koans in turn borrows from Metakoans +so thanks also go to Ara Howard for that! -Also thanks to everyone who helped with the Python Koans conversion! In particular I got a great headstart on the project by forking from this Python Koans startup project: +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://bitbucket.org/mcrute/python_koans/ + http://frompythonimportpodcast.com/ From 16b6b9bd1af85ee9737ee2b636ed00dbe2a569ba Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 19:39:09 -0400 Subject: [PATCH 074/237] Removed some really crappy tests. I was young and foolish when I wrote them... :) --- python2/runner/runner_tests/test_sensei.py | 88 ----------------- python3/runner/runner_tests/test_sensei.py | 109 --------------------- 2 files changed, 197 deletions(-) diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index b19d057ac..5aa1d7815 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -90,39 +90,6 @@ def setUp(self): self.tests = Mock() self.tests.countTestCases = Mock() - def test_that_it_delegates_testing_to_test_cases(self): - MockableTestResult.startTest = Mock() - self.sensei.startTest(Mock()) - self.assertTrue(MockableTestResult.startTest.called) - - def test_that_user_is_notified_if_test_involves_a_different_test_class_to_last_time(self): - MockableTestResult.startTest = Mock() - - self.sensei.prevTestClassName == 'AboutLumberjacks' - nextTest = AboutParrots() - - self.sensei.startTest(nextTest) - self.assertTrue(self.sensei.stream.writeln.called) - - def test_that_user_is_not_notified_about_test_class_repeats(self): - MockableTestResult.startTest = Mock() - - self.sensei.prevTestClassName == 'AboutParrots' - nextTest = AboutParrots() - - self.sensei.startTest(nextTest) - self.assertTrue(self.sensei.stream.writeln.called) - - def test_that_cached_classname_updates_after_the_test(self): - self.assertEqual(None, self.sensei.prevTestClassName) - self.sensei.startTest(Mock()) - self.assertNotEqual(None, self.sensei.prevTestClassName) - - def test_that_errors_are_diverted_to_the_failures_list(self): - MockableTestResult.addFailure = Mock() - self.sensei.addError(Mock(), Mock()) - self.assertTrue(MockableTestResult.addFailure.called) - def test_that_failures_are_handled_in_the_base_class(self): MockableTestResult.addFailure = Mock() self.sensei.addFailure(Mock(), Mock()) @@ -134,21 +101,6 @@ def test_that_it_successes_only_count_if_passes_are_currently_allowed(self): self.sensei.addSuccess(Mock()) self.assertTrue(self.sensei.passesCount.called) - def test_that_if_there_are_failures_and_the_prev_class_is_different_successes_are_not_allowed(self): - self.sensei.failures = [(AboutLumberjacks(), Mock())] - self.sensei.prevTestClassName = "AboutTheMinitry" - self.assertFalse(self.sensei.passesCount()) - - def test_that_if_there_are_failures_and_the_prev_class_is_the_same_successes_are_allowed(self): - self.sensei.failures = [(AboutLumberjacks(), Mock())] - self.sensei.prevTestClassName = "AboutLumberjacks" - self.assertTrue(self.sensei.passesCount()) - - def test_that_if_there_are_no_failures_successes_are_allowed(self): - self.sensei.failures = None - self.sensei.prevTestClassName = "AboutLumberjacks" - self.assertTrue(self.sensei.passesCount()) - def test_that_it_passes_on_add_successes_message(self): MockableTestResult.addSuccess = Mock() self.sensei.addSuccess(Mock()) @@ -160,11 +112,6 @@ def test_that_it_increases_the_passes_on_every_success(self): self.sensei.addSuccess(Mock()) self.assertEqual(pass_count + 1, self.sensei.pass_count) - def test_that_it_displays_each_success(self): - MockableTestResult.addSuccess = Mock() - self.sensei.addSuccess(Mock()) - self.assertTrue(self.sensei.stream.writeln.called) - 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()) @@ -228,41 +175,6 @@ def test_that_it_will_choose_correct_first_result_with_multiline_test_classes(se ] self.assertEqual("File 'about_giant_feet.py', line 44", self.sensei.firstFailure()[1]) - def test_that_end_report_displays_something(self): - self.sensei.learn() - self.assertTrue(self.sensei.stream.writeln.called) - - def test_that_end_report_shows_student_progress(self): - self.sensei.errorReport = Mock() - self.sensei.total_lessons = Mock() - self.sensei.total_koans = Mock() - - self.sensei.learn() - self.assertTrue(self.sensei.total_lessons.called) - self.assertTrue(self.sensei.total_koans.called) - - def test_that_end_report_shows_the_failure_report(self): - self.sensei.errorReport = Mock() - self.sensei.learn() - self.assertTrue(self.sensei.errorReport.called) - - def test_that_end_report_should_have_something_zenlike_on_it(self): - self.sensei.say_something_zenlike = Mock() - self.sensei.learn() - self.assertTrue(self.sensei.say_something_zenlike.called) - - def test_that_error_report_shows_something_if_there_is_a_failure(self): - self.sensei.firstFailure = Mock() - self.sensei.firstFailure.return_value = (Mock(), "FAILED Parrot is breathing, Line 42") - self.sensei.errorReport() - self.assertTrue(self.sensei.stream.writeln.called) - - def test_that_error_report_does_not_show_anything_if_there_is_no_failure(self): - self.sensei.firstFailure = Mock() - self.sensei.firstFailure.return_value = None - self.sensei.errorReport() - self.assertFalse(self.sensei.stream.writeln.called) - def test_that_error_report_features_the_assertion_error(self): self.sensei.scrapeAssertionError = Mock() self.sensei.firstFailure = Mock() diff --git a/python3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py index 3c60d4ce0..018d4ca22 100644 --- a/python3/runner/runner_tests/test_sensei.py +++ b/python3/runner/runner_tests/test_sensei.py @@ -91,85 +91,18 @@ def setUp(self): self.tests = Mock() self.tests.countTestCases = Mock() - def test_that_it_delegates_testing_to_test_cases(self): - MockableTestResult.startTest = Mock() - self.sensei.startTest(Mock()) - self.assertTrue(MockableTestResult.startTest.called) - - def test_that_user_is_notified_if_test_involves_a_different_test_class_to_last_time(self): - MockableTestResult.startTest = Mock() - - self.sensei.prevTestClassName == 'AboutLumberjacks' - nextTest = AboutParrots() - - self.sensei.startTest(nextTest) - self.assertTrue(self.sensei.stream.writeln.called) - - def test_that_user_is_not_notified_about_test_class_repeats(self): - MockableTestResult.startTest = Mock() - - self.sensei.prevTestClassName == 'AboutParrots' - nextTest = AboutParrots() - - self.sensei.startTest(nextTest) - self.assertTrue(self.sensei.stream.writeln.called) - - def test_that_cached_classname_updates_after_the_test(self): - self.assertEqual(None, self.sensei.prevTestClassName) - self.sensei.startTest(Mock()) - self.assertNotEqual(None, self.sensei.prevTestClassName) - - def test_that_errors_are_diverted_to_the_failures_list(self): - MockableTestResult.addFailure = Mock() - self.sensei.addError(Mock(), Mock()) - self.assertTrue(MockableTestResult.addFailure.called) - - def test_that_failures_are_handled_in_the_base_class(self): - 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) - def test_that_if_there_are_failures_and_the_prev_class_is_different_successes_are_not_allowed(self): - self.sensei.failures = [(AboutLumberjacks(), Mock())] - self.sensei.prevTestClassName = "AboutTheMinitry" - self.assertFalse(self.sensei.passesCount()) - - def test_that_if_there_are_failures_and_the_prev_class_is_the_same_successes_are_allowed(self): - self.sensei.failures = [(AboutLumberjacks(), Mock())] - self.sensei.prevTestClassName = "AboutLumberjacks" - self.assertTrue(self.sensei.passesCount()) - - def test_that_if_there_are_no_failures_successes_are_allowed(self): - self.sensei.failures = None - self.sensei.prevTestClassName = "AboutLumberjacks" - self.assertTrue(self.sensei.passesCount()) - - def test_that_it_passes_on_add_successes_message(self): - 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) - def test_that_it_displays_each_success(self): - MockableTestResult.addSuccess = Mock() - self.sensei.addSuccess(Mock()) - self.assertTrue(self.sensei.stream.writeln.called) - - 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")) @@ -229,48 +162,6 @@ def test_that_it_will_choose_correct_first_result_with_multiline_test_classes(se ] self.assertEqual("File 'about_giant_feet.py', line 44", self.sensei.firstFailure()[1]) - def test_that_end_report_displays_something(self): - self.sensei.learn() - self.assertTrue(self.sensei.stream.writeln.called) - - def test_that_end_report_shows_student_progress(self): - self.sensei.errorReport = Mock() - self.sensei.total_lessons = Mock() - self.sensei.total_koans = Mock() - - self.sensei.learn() - self.assertTrue(self.sensei.total_lessons.called) - self.assertTrue(self.sensei.total_koans.called) - - def test_that_end_report_shows_the_failure_report(self): - self.sensei.errorReport = Mock() - self.sensei.learn() - self.assertTrue(self.sensei.errorReport.called) - - def test_that_end_report_should_have_something_zenlike_on_it(self): - self.sensei.say_something_zenlike = Mock() - self.sensei.learn() - self.assertTrue(self.sensei.say_something_zenlike.called) - - def test_that_error_report_shows_something_if_there_is_a_failure(self): - self.sensei.firstFailure = Mock() - self.sensei.firstFailure.return_value = (Mock(), "FAILED Parrot is breathing, Line 42") - self.sensei.errorReport() - self.assertTrue(self.sensei.stream.writeln.called) - - def test_that_error_report_does_not_show_anything_if_there_is_no_failure(self): - self.sensei.firstFailure = Mock() - self.sensei.firstFailure.return_value = None - self.sensei.errorReport() - self.assertFalse(self.sensei.stream.writeln.called) - - 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() From 0854580a9a1f3443b9785c2b4e039c8ece46e9a1 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 21:40:07 -0400 Subject: [PATCH 075/237] Experimenting with travis --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index ecca9709f..e7db13baa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,14 @@ language: python python: + - 2.6 - 2.7 + - 3.2 + - 3.3 script: - cd python2 - python contemplate_koans.py about_asserts # add further koans here separated by spaces + - python _runner_tests.py notifications: email: false From 7437834af3c3383298f7b640d6e6a6d5436d0af7 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 22:09:36 -0400 Subject: [PATCH 076/237] Test --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e7db13baa..3db66abce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ python: - 2.7 - 3.2 - 3.3 + script: - cd python2 - python contemplate_koans.py about_asserts # add further koans here separated by spaces From f0e163d65f29a672962d1fc450ad8674ec3d3c83 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 22:24:19 -0400 Subject: [PATCH 077/237] Use the correct koans folder peas --- .travis.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3db66abce..7c7401e8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,17 @@ python: - 3.3 script: - - cd python2 - - python contemplate_koans.py about_asserts # add further koans here separated by spaces + - 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 +# # koans +# +# Working through Python Koans in a fork? Want to use Travis CI to show which +# koans you've passed? Then comment out one of the above "contemplate_koans" +# lines above! +# notifications: email: false From 53776f4aba0c2b128b16e447da762001f21b9e94 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 22:31:27 -0400 Subject: [PATCH 078/237] Testing travis setup with test failures --- python2/runner/runner_tests/test_sensei.py | 2 ++ python3/runner/runner_tests/test_sensei.py | 1 + 2 files changed, 3 insertions(+) diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index 5aa1d7815..fc818b35b 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -150,12 +150,14 @@ def test_that_nothing_is_returned_as_sorted_result_if_there_are_3_shuffled_resul self.assertEqual(2, results[0][0]) self.assertEqual(30, results[1][0]) self.assertEqual(299, results[2][0]) + self.assertTrue(false) 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")) + self.assertFalse(true) def test_that_it_will_choose_correct_first_result_with_lines_9_and_27(self): diff --git a/python3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py index 018d4ca22..b09731879 100644 --- a/python3/runner/runner_tests/test_sensei.py +++ b/python3/runner/runner_tests/test_sensei.py @@ -298,3 +298,4 @@ def test_filter_all_lessons_will_discover_test_classes_if_none_have_been_discove self.sensei.all_lessons = 0 self.assertTrue(len(self.sensei.filter_all_lessons()) > 10) self.assertTrue(len(self.sensei.all_lessons) > 10) + self.assertEqual(42, 1+1) From 75fa699493c4c5a82795bd567966fe16e3f04b6c Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 22:49:22 -0400 Subject: [PATCH 079/237] Not all the test runners were returning exit codes. They are now --- python2/_runner_tests.py | 3 ++- python3/_runner_tests.py | 3 ++- python3/runner/sensei.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/python2/_runner_tests.py b/python2/_runner_tests.py index 269513211..ad0ad6847 100644 --- a/python2/_runner_tests.py +++ b/python2/_runner_tests.py @@ -16,4 +16,5 @@ def suite(): return suite if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) + res = unittest.TextTestRunner(verbosity=2).run(suite()) + sys.exit(not res.wasSuccessful()) diff --git a/python3/_runner_tests.py b/python3/_runner_tests.py index 269513211..ad0ad6847 100644 --- a/python3/_runner_tests.py +++ b/python3/_runner_tests.py @@ -16,4 +16,5 @@ def suite(): return suite if __name__ == '__main__': - unittest.TextTestRunner(verbosity=2).run(suite()) + res = unittest.TextTestRunner(verbosity=2).run(suite()) + sys.exit(not res.wasSuccessful()) diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index 2ffbbaeb4..cc20c4e0b 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -88,7 +88,7 @@ def learn(self): self.stream.writeln("") self.stream.writeln(self.say_something_zenlike()) - if self.failures: return + if self.failures: sys.exit(-1) self.stream.writeln( "\n{0}**************************************************" \ .format(Fore.RESET)) From 676ba3790c7ebfe9cafaf4d9cd190e61d1247c00 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 22:54:11 -0400 Subject: [PATCH 080/237] Fixed internal tests again, re-testing koans --- .travis.yml | 2 +- python2/runner/runner_tests/test_sensei.py | 2 -- python3/runner/runner_tests/test_sensei.py | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7c7401e8e..8cd267f1c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ 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 # Run all the koans # - python contemplate_koans.py about_asserts about_none # Run a subset of # # koans # diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index fc818b35b..5aa1d7815 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -150,14 +150,12 @@ def test_that_nothing_is_returned_as_sorted_result_if_there_are_3_shuffled_resul self.assertEqual(2, results[0][0]) self.assertEqual(30, results[1][0]) self.assertEqual(299, results[2][0]) - self.assertTrue(false) 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")) - self.assertFalse(true) def test_that_it_will_choose_correct_first_result_with_lines_9_and_27(self): diff --git a/python3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py index b09731879..018d4ca22 100644 --- a/python3/runner/runner_tests/test_sensei.py +++ b/python3/runner/runner_tests/test_sensei.py @@ -298,4 +298,3 @@ def test_filter_all_lessons_will_discover_test_classes_if_none_have_been_discove self.sensei.all_lessons = 0 self.assertTrue(len(self.sensei.filter_all_lessons()) > 10) self.assertTrue(len(self.sensei.all_lessons) > 10) - self.assertEqual(42, 1+1) From 0ed2d68d15147476dcfce1f7f3c8cca9122c8c3b Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 23:00:18 -0400 Subject: [PATCH 081/237] Testing with koans passing but inner tests failing --- .travis.yml | 2 +- python2/koans/about_asserts.py | 78 +++++++++++----------- python2/runner/runner_tests/test_sensei.py | 2 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8cd267f1c..191c5ab9a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ 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 # Run all the koans # - python contemplate_koans.py about_asserts about_none # Run a subset of # # koans # diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index 1af8b4e8e..3ab731591 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -10,42 +10,42 @@ def test_assert_truth(self): """ We shall contemplate truth by testing reality, via 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): - """ - Knowing how things really work is half the battle - """ - - # This throws an AssertionError exception - assert False + self.assertTrue(True) # 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): + #""" + #Knowing how things really work is half the battle + #""" + + ## This throws an AssertionError exception + #assert False diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index 5aa1d7815..5b0dafc76 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -317,4 +317,4 @@ def test_total_koans_return_43_if_there_are_43_test_cases(self): 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) + self.assertTrue(len(self.sensei.all_lessons) < 10) From 34c14449c4cf5910b90066fc164b04c8f776ef0a Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 23:03:07 -0400 Subject: [PATCH 082/237] Restore --- .travis.yml | 2 +- python2/koans/about_asserts.py | 78 +++++++++++----------- python2/runner/runner_tests/test_sensei.py | 2 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/.travis.yml b/.travis.yml index 191c5ab9a..7c7401e8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ script: - PYTHON_VER=`python -c 'import sys; print(sys.version_info[0])'` - cd python$PYTHON_VER - python _runner_tests.py - - python contemplate_koans.py about_asserts # Run all the koans +# - python contemplate_koans.py # Run all the koans # - python contemplate_koans.py about_asserts about_none # Run a subset of # # koans # diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index 3ab731591..1af8b4e8e 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -10,42 +10,42 @@ def test_assert_truth(self): """ We shall contemplate truth by testing reality, via asserts. """ - self.assertTrue(True) # 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): - #""" - #Knowing how things really work is half the battle - #""" - - ## This throws an AssertionError exception - #assert False + 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): + """ + Knowing how things really work is half the battle + """ + + # This throws an AssertionError exception + assert False diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index 5b0dafc76..5aa1d7815 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -317,4 +317,4 @@ def test_total_koans_return_43_if_there_are_43_test_cases(self): 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) + self.assertTrue(len(self.sensei.all_lessons) > 10) From 9eaf0a5ae95f7bb678d1adf8a2cd898128e1122e Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 23:12:58 -0400 Subject: [PATCH 083/237] Added a Travis CI badge --- README.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.rst b/README.rst index 189fdde35..ea487a2a6 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,9 @@ Python Koans ============ +.. image:: https://travis-ci.org/gregmalcolm/python_koans.png?branch=master + :target: http://travis-ci.org/gregmalcolm/python_koans + Python Koans is a port of Edgecase's "Ruby Koans" which can be found at http://rubykoans.com/. From a772bed42bdd9b59f976fefc44130ff2542f26f6 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 28 Apr 2013 23:18:23 -0400 Subject: [PATCH 084/237] You know what? I think I do want an email when the tests fail --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7c7401e8e..0184d0ec5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ script: # lines above! # notifications: - email: false + email: true # Some other koans (see runner/sensei.py or "ls koans" to see the light): # From f4da7949649b01f31fdb9bd1f77fb406184c8f00 Mon Sep 17 00:00:00 2001 From: Dominique Plante Date: Sun, 28 Apr 2013 22:35:53 -0700 Subject: [PATCH 085/237] fix some typos (similar to those from Python 2 folder) --- python3/contemplate_koans.py | 2 +- python3/runner/sensei.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python3/contemplate_koans.py b/python3/contemplate_koans.py index a4c50518a..8777a46e5 100644 --- a/python3/contemplate_koans.py +++ b/python3/contemplate_koans.py @@ -7,7 +7,7 @@ # 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! +# So thanks guys! # import unittest diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index 3c6692be4..c324c4bc9 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -167,12 +167,12 @@ def report_progress(self): "reaching enlightenment.".format(koans_remaining, lessons_remaining) return sent1+sent2 - # Hat's tip to Tim Peters for the zen statements from The Zen - # of Python (http://www.python.org/dev/peps/pep-0020/) + # 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 permatation in the Ruby Koans + # Edgecase's later permutation in the Ruby Koans def say_something_zenlike(self): if self.failures: turn = self.pass_count % 37 @@ -230,7 +230,7 @@ def say_something_zenlike(self): .format(Fore.CYAN) # Hopefully this will never ever happen! - return "The temple in collapsing! Run!!!" + return "The temple is collapsing! Run!!!" def total_lessons(self): all_lessons = self.filter_all_lessons() From dd4afa6ee83e276d01831b4d9822acee2267484b Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 5 May 2013 14:27:30 -0400 Subject: [PATCH 086/237] Missing an 'import sys'. Thanks Padraic Harley for pointing this out --- python3/runner/sensei.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index cc20c4e0b..a98d1598e 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -3,6 +3,7 @@ import unittest import re +import sys import os import glob From c3a808db0430131b16f16cd6871c1f2e684166b4 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 5 May 2013 14:32:54 -0400 Subject: [PATCH 087/237] Missing an 'import sys'. Thanks Padraic Harley for pointing this out --- python3/runner/sensei.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index b49c2765d..df9915460 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -3,6 +3,7 @@ import unittest import re +import sys import os import glob From d11989be587214e057b9650158a18882cd3ca633 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Tue, 7 May 2013 11:08:34 +0100 Subject: [PATCH 088/237] py2: Split up about_strings. Removed __name__ tests in favor of educating on __class__ in a wiki page. Added an extra __class__ koan in about_asserts as a primer --- python2/koans/about_asserts.py | 25 ++++++- python2/koans/about_attribute_access.py | 4 +- python2/koans/about_classes.py | 2 +- python2/koans/about_method_bindings.py | 4 +- python2/koans/about_methods.py | 4 +- python2/koans/about_new_style_classes.py | 9 ++- python2/koans/about_none.py | 6 +- python2/koans/about_string_manipulation.py | 76 ++++++++++++++++++++++ python2/koans/about_strings.py | 69 -------------------- python2/koans/about_tuples.py | 4 +- python2/runner/path_to_enlightenment.py | 6 +- 11 files changed, 122 insertions(+), 87 deletions(-) create mode 100644 python2/koans/about_string_manipulation.py diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index 1af8b4e8e..766c5c642 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -44,8 +44,31 @@ def test_a_better_way_of_asserting_equality(self): def test_that_unittest_asserts_work_the_same_way_as_python_asserts(self): """ - Knowing how things really work is half the battle + 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 "naval". What is it's 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 + # is just what it displays. The answer is simply str. + # + # See for yourself: + + self.assertEqual(__, "naval".__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 index 72b1aa94f..fcd66a79d 100644 --- a/python2/koans/about_attribute_access.py +++ b/python2/koans/about_attribute_access.py @@ -19,7 +19,7 @@ def test_calling_undefined_functions_normally_results_in_errors(self): try: typical.foobar() except Exception as exception: - self.assertEqual(__, type(exception).__name__) + self.assertEqual(__, exception.__class__) self.assertMatch(__, exception[0]) def test_calling_getattribute_causes_an_attribute_error(self): @@ -160,7 +160,7 @@ def test_getattr_only_catches_unknown_attributes(self): catcher.free_pie() self.assertEqual(__, - type(catcher.give_me_duff_or_give_me_death()).__name__) + catcher.give_me_duff_or_give_me_death().__class__) self.assertEqual(__, catcher.no_of_getattr_calls) diff --git a/python2/koans/about_classes.py b/python2/koans/about_classes.py index 564554bba..570b03cb0 100644 --- a/python2/koans/about_classes.py +++ b/python2/koans/about_classes.py @@ -10,7 +10,7 @@ class Dog(object): def test_instances_of_classes_can_be_created_adding_parentheses(self): fido = self.Dog() - self.assertEqual(__, type(fido).__name__) + self.assertEqual(__, fido.__class__) def test_classes_have_docstrings(self): self.assertMatch(__, self.Dog.__doc__) diff --git a/python2/koans/about_method_bindings.py b/python2/koans/about_method_bindings.py index 129465c92..d41263dab 100644 --- a/python2/koans/about_method_bindings.py +++ b/python2/koans/about_method_bindings.py @@ -77,8 +77,8 @@ def test_get_descriptor_resolves_attribute_binding(self): # binding_owner = obj # owner_type = cls - self.assertEqual(__, type(bound_obj).__name__) - self.assertEqual(__, type(binding_owner).__name__) + self.assertEqual(__, bound_obj.__class__) + self.assertEqual(__, binding_owner.__class__) self.assertEqual(AboutMethodBindings, owner_type) # ------------------------------------------------------------------ diff --git a/python2/koans/about_methods.py b/python2/koans/about_methods.py index d11255829..9584e33e3 100644 --- a/python2/koans/about_methods.py +++ b/python2/koans/about_methods.py @@ -22,7 +22,7 @@ def test_calling_functions_with_wrong_number_of_arguments(self): try: my_global_function() except Exception as exception: - self.assertEqual(__, type(exception).__name__) + self.assertEqual(__, exception.__class__) self.assertMatch( r'my_global_function\(\) takes exactly 2 arguments \(0 given\)', exception[0]) @@ -158,7 +158,7 @@ def test_double_underscore_attribute_prefixes_cause_name_mangling(self): #This may not be possible... password = rover.__password() except Exception as ex: - self.assertEqual(__, type(ex).__name__) + self.assertEqual(__, ex.__class__) # But this still is! self.assertEqual(__, rover._Dog__password()) diff --git a/python2/koans/about_new_style_classes.py b/python2/koans/about_new_style_classes.py index a14d8b041..34b3957b9 100644 --- a/python2/koans/about_new_style_classes.py +++ b/python2/koans/about_new_style_classes.py @@ -34,7 +34,7 @@ def test_new_style_classes_have_more_attributes(self): # ------------------------------------------------------------------ def test_old_style_classes_have_type_but_no_class_attribute(self): - self.assertEqual(__, type(self.OldStyleClass).__name__) + self.assertEqual(__, self.OldStyleClass.__class__) try: cls = self.OldStyleClass.__class__ @@ -45,7 +45,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(__, type(self.NewStyleClass).__name__) + self.assertEqual(__, self.NewStyleClass.__class__) self.assertEqual( __, type(self.NewStyleClass) == self.NewStyleClass.__class__) @@ -54,10 +54,9 @@ def test_new_style_classes_have_same_class_as_type(self): def test_in_old_style_instances_class_is_different_to_type(self): old_style = self.OldStyleClass() - self.assertEqual(__, type(old_style).__name__) - self.assertEqual(__, old_style.__class__.__name__) + self.assertEqual(__, old_style.__class__) def test_new_style_instances_have_same_class_as_type(self): new_style = self.NewStyleClass() - self.assertEqual(__, type(new_style).__name__) + self.assertEqual(__, new_style.__class__) self.assertEqual(__, type(new_style) == new_style.__class__) diff --git a/python2/koans/about_none.py b/python2/koans/about_none.py index 556360eed..e64164dbd 100644 --- a/python2/koans/about_none.py +++ b/python2/koans/about_none.py @@ -33,7 +33,11 @@ def test_what_exception_do_you_get_when_calling_nonexistent_methods(self): None.some_method_none_does_not_know_about() except Exception as ex: # What exception has been caught? - self.assertEqual(__, ex.__class__.__name__) + # + # 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.) diff --git a/python2/koans/about_string_manipulation.py b/python2/koans/about_string_manipulation.py new file mode 100644 index 000000000..c395309cc --- /dev/null +++ b/python2/koans/about_string_manipulation.py @@ -0,0 +1,76 @@ +#!/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 index 9a1c37cd3..241e4ec67 100644 --- a/python2/koans/about_strings.py +++ b/python2/koans/about_strings.py @@ -92,72 +92,3 @@ def test_most_strings_interpret_escape_characters(self): self.assertEqual('\n', string) self.assertEqual("""\n""", string) self.assertEqual(__, len(string)) - - 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_tuples.py b/python2/koans/about_tuples.py index ea132f1a7..84ba5d552 100644 --- a/python2/koans/about_tuples.py +++ b/python2/koans/about_tuples.py @@ -39,8 +39,8 @@ def test_tuples_can_only_be_changed_through_replacement(self): self.assertEqual(__, count_of_three) def test_tuples_of_one_look_peculiar(self): - self.assertEqual(__, (1).__class__.__name__) - self.assertEqual(__, (1,).__class__.__name__) + self.assertEqual(__, (1).__class__) + self.assertEqual(__, (1,).__class__) self.assertEqual(__, ("Hello comma!", )) def test_tuple_constructor_can_be_surprising(self): diff --git a/python2/runner/path_to_enlightenment.py b/python2/runner/path_to_enlightenment.py index 61e3c2e05..f288e4a44 100644 --- a/python2/runner/path_to_enlightenment.py +++ b/python2/runner/path_to_enlightenment.py @@ -6,11 +6,12 @@ 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_string_manipulation import AboutStringManipulation from koans.about_dictionaries import AboutDictionaries -from koans.about_strings import AboutStrings from koans.about_tuples import AboutTuples from koans.about_methods import AboutMethods from koans.about_control_statements import AboutControlStatements @@ -48,11 +49,12 @@ def koans(): suite = unittest.TestSuite() 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(AboutStringManipulation)) suite.addTests(loader.loadTestsFromTestCase(AboutDictionaries)) - suite.addTests(loader.loadTestsFromTestCase(AboutStrings)) suite.addTests(loader.loadTestsFromTestCase(AboutTuples)) suite.addTests(loader.loadTestsFromTestCase(AboutMethods)) suite.addTests(loader.loadTestsFromTestCase(AboutControlStatements)) From 120957892bb062f9ef61b7d845fd16db2ea72ed1 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Tue, 7 May 2013 12:18:36 +0100 Subject: [PATCH 089/237] Updated python 3 side of the house. Added link to @hebbertja's about_asserts video --- python2/koans/about_asserts.py | 7 +- python2/runner/path_to_enlightenment.py | 4 +- python3/koans/about_asserts.py | 30 ++++++++- python3/koans/about_classes.py | 2 +- python3/koans/about_iteration.py | 6 +- python3/koans/about_method_bindings.py | 4 +- python3/koans/about_none.py | 11 ++-- python3/koans/about_sets.py | 6 +- python3/koans/about_string_manipulation.py | 74 ++++++++++++++++++++++ python3/koans/about_strings.py | 68 -------------------- python3/koans/about_tuples.py | 4 +- python3/runner/path_to_enlightenment.py | 6 +- 12 files changed, 133 insertions(+), 89 deletions(-) create mode 100644 python3/koans/about_string_manipulation.py diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index 766c5c642..61b53ada1 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -10,6 +10,11 @@ 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): @@ -71,4 +76,4 @@ def test_that_sometimes_we_need_to_know_the_class_type(self): # Need an illustration? More reading can be found here: # - # https://github.com/gregmalcolm/python_koans/wiki/Class-Attribute + # http://bit.ly/__class__ diff --git a/python2/runner/path_to_enlightenment.py b/python2/runner/path_to_enlightenment.py index f288e4a44..a93a5bd40 100644 --- a/python2/runner/path_to_enlightenment.py +++ b/python2/runner/path_to_enlightenment.py @@ -10,8 +10,8 @@ from koans.about_none import AboutNone from koans.about_lists import AboutLists from koans.about_list_assignments import AboutListAssignments -from koans.about_string_manipulation import AboutStringManipulation 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 @@ -53,8 +53,8 @@ def koans(): suite.addTests(loader.loadTestsFromTestCase(AboutNone)) suite.addTests(loader.loadTestsFromTestCase(AboutLists)) suite.addTests(loader.loadTestsFromTestCase(AboutListAssignments)) - suite.addTests(loader.loadTestsFromTestCase(AboutStringManipulation)) 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)) diff --git a/python3/koans/about_asserts.py b/python3/koans/about_asserts.py index fe4f81949..a3d7ce047 100644 --- a/python3/koans/about_asserts.py +++ b/python3/koans/about_asserts.py @@ -9,6 +9,11 @@ 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): @@ -42,9 +47,32 @@ def test_a_better_way_of_asserting_equality(self): def test_that_unittest_asserts_work_the_same_way_as_python_asserts(self): """ - Knowing how things really work is half the battle + 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 "naval". What is it's 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 + # is just what it displays. The answer is simply str. + # + # See for yourself: + + self.assertEqual(__, "naval".__class__) # It's str, not + + # Need an illustration? More reading can be found here: + # + # http://bit.ly/__class__ + diff --git a/python3/koans/about_classes.py b/python3/koans/about_classes.py index 2adbd5801..0e027d3c8 100644 --- a/python3/koans/about_classes.py +++ b/python3/koans/about_classes.py @@ -10,7 +10,7 @@ class Dog: def test_instances_of_classes_can_be_created_adding_parentheses(self): fido = self.Dog() - self.assertEqual(__, type(fido).__name__) + self.assertEqual(__, fido.__class__) def test_classes_have_docstrings(self): self.assertRegexpMatches(self.Dog.__doc__, __) diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index fdb80295b..385c18a42 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -39,8 +39,8 @@ def test_map_transforms_elements_of_a_list(self): mapping = map(self.add_ten, seq) - self.assertNotEqual(list, type(mapping).__name__) - self.assertEqual(__, type(mapping).__name__) + self.assertNotEqual(list, mapping.__class__) + self.assertEqual(__, mapping.__class__) # In Python 3 built in iterator funcs return iteratable view objects # instead of lists @@ -94,7 +94,7 @@ def test_reduce_will_blow_your_mind(self): # to the functools module. result = functools.reduce(self.add, [2, 3, 4]) - self.assertEqual(__, type(result).__name__) + self.assertEqual(__, result.__class__) # Reduce() syntax is same as Python 2 self.assertEqual(__, result) diff --git a/python3/koans/about_method_bindings.py b/python3/koans/about_method_bindings.py index f45058113..a29197365 100644 --- a/python3/koans/about_method_bindings.py +++ b/python3/koans/about_method_bindings.py @@ -68,8 +68,8 @@ def test_get_descriptor_resolves_attribute_binding(self): # binding_owner = obj # owner_type = cls - self.assertEqual(__, type(bound_obj).__name__) - self.assertEqual(__, type(binding_owner).__name__) + self.assertEqual(__, bound_obj.__class__) + self.assertEqual(__, binding_owner.__class__) self.assertEqual(AboutMethodBindings, owner_type) # ------------------------------------------------------------------ diff --git a/python3/koans/about_none.py b/python3/koans/about_none.py index a0ada8b3e..680cb1007 100644 --- a/python3/koans/about_none.py +++ b/python3/koans/about_none.py @@ -17,7 +17,7 @@ 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_on_None(self): + 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? @@ -32,7 +32,12 @@ def test_what_exception_do_you_get_when_calling_nonexistent_methods_on_None(self ex2 = ex # What exception has been caught? - self.assertEqual(__, ex2.__class__.__name__) + # + # Need a recap on how to evaluate __class__ attributes? + # + # http://bit.ly/__class__ + + self.assertEqual(__, ex2.__class__) # What message was attached to the exception? # (HINT: replace __ with part of the error message.) @@ -44,5 +49,3 @@ def test_none_is_distinct(self): """ self.assertEqual(__, None is not 0) self.assertEqual(__, None is not False) - - diff --git a/python3/koans/about_sets.py b/python3/koans/about_sets.py index 337097c24..50e20099d 100644 --- a/python3/koans/about_sets.py +++ b/python3/koans/about_sets.py @@ -18,10 +18,10 @@ def test_empty_sets_have_different_syntax_to_populated_sets(self): def test_dictionaries_and_sets_use_same_curly_braces(self): # Note: Sets have only started using braces since Python 3 - self.assertEqual(__, type({1, 2, 3}).__name__) - self.assertEqual(__, type({'one': 1, 'two': 2}).__name__) + self.assertEqual(__, {1, 2, 3}.__class__) + self.assertEqual(__, {'one': 1, 'two': 2}.__class__) - self.assertEqual(__, type({}).__name__) + self.assertEqual(__, {}.__class__) def test_creating_sets_using_strings(self): self.assertEqual(__, {'12345'}) diff --git a/python3/koans/about_string_manipulation.py b/python3/koans/about_string_manipulation.py new file mode 100644 index 000000000..bc365689f --- /dev/null +++ b/python3/koans/about_string_manipulation.py @@ -0,0 +1,74 @@ +#!/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_con_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.assertListEqual([__, __, __], 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.assertListEqual([__, __, __, __], 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/python3/koans/about_strings.py b/python3/koans/about_strings.py index 8cd1a885c..e722d29e8 100644 --- a/python3/koans/about_strings.py +++ b/python3/koans/about_strings.py @@ -91,71 +91,3 @@ def test_most_strings_interpret_escape_characters(self): self.assertEqual('\n', string) self.assertEqual("""\n""", string) self.assertEqual(__, len(string)) - - 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_con_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.assertListEqual([__, __, __], 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.assertListEqual([__, __, __, __], 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/python3/koans/about_tuples.py b/python3/koans/about_tuples.py index cd6034427..9833c40c6 100644 --- a/python3/koans/about_tuples.py +++ b/python3/koans/about_tuples.py @@ -36,8 +36,8 @@ def test_tuples_can_only_be_changed_through_replacement(self): self.assertEqual(__, count_of_three) def test_tuples_of_one_look_peculiar(self): - self.assertEqual(__, (1).__class__.__name__) - self.assertEqual(__, (1,).__class__.__name__) + self.assertEqual(__, (1).__class__) + self.assertEqual(__, (1,).__class__) self.assertEqual(__, ("Hello comma!", )) def test_tuple_constructor_can_be_surprising(self): diff --git a/python3/runner/path_to_enlightenment.py b/python3/runner/path_to_enlightenment.py index 67cd00d3e..a72ea5eda 100644 --- a/python3/runner/path_to_enlightenment.py +++ b/python3/runner/path_to_enlightenment.py @@ -6,11 +6,12 @@ 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_strings import AboutStrings +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 @@ -47,11 +48,12 @@ def koans(): suite = unittest.TestSuite() 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(AboutStrings)) + suite.addTests(loader.loadTestsFromTestCase(AboutStringManipulation)) suite.addTests(loader.loadTestsFromTestCase(AboutTuples)) suite.addTests(loader.loadTestsFromTestCase(AboutMethods)) suite.addTests(loader.loadTestsFromTestCase(AboutControlStatements)) From 0305da74a8f64c640486e335db49316e6c2e18e5 Mon Sep 17 00:00:00 2001 From: Frederico Cadete Date: Sun, 19 May 2013 23:07:05 +0200 Subject: [PATCH 090/237] Corrected typo in comment The comment was explaining module naming so the typo could be confusing. --- python2/koans/about_scope.py | 2 +- python3/koans/about_scope.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_scope.py b/python2/koans/about_scope.py index 0e7666124..aca08058f 100644 --- a/python2/koans/about_scope.py +++ b/python2/koans/about_scope.py @@ -24,7 +24,7 @@ def test_dog_is_not_available_in_the_current_scope(self): def test_you_can_reference_nested_classes_using_the_scope_operator(self): fido = jims.Dog() - # name 'jims' module name is taken from jim.py filename + # name 'jims' module name is taken from jims.py filename rover = joes.Dog() self.assertEqual(__, fido.identify()) diff --git a/python3/koans/about_scope.py b/python3/koans/about_scope.py index 9118a98d5..a9cf2a168 100644 --- a/python3/koans/about_scope.py +++ b/python3/koans/about_scope.py @@ -20,7 +20,7 @@ def test_dog_is_not_available_in_the_current_scope(self): def test_you_can_reference_nested_classes_using_the_scope_operator(self): fido = jims.Dog() - # name 'jims' module name is taken from jim.py filename + # name 'jims' module name is taken from jims.py filename rover = joes.Dog() self.assertEqual(__, fido.identify()) From 90b783d9aba217869eb24fb9c5349c89e7477215 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 17 Jul 2013 22:27:45 -0400 Subject: [PATCH 091/237] Corrected a koan to account for python3 language changes --- python3/koans/about_methods.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python3/koans/about_methods.py b/python3/koans/about_methods.py index e069bbb63..39f0682d9 100644 --- a/python3/koans/about_methods.py +++ b/python3/koans/about_methods.py @@ -23,8 +23,7 @@ def test_calling_functions_with_wrong_number_of_arguments(self): msg = exception.args[0] self.assertRegexpMatches(msg, - r'my_global_function\(\) takes exactly 2 ' + - r'arguments \(0 given\)') + r'my_global_function\(\) missing 2 required positional arguments') try: my_global_function(1, 2, 3) From 6c96767acb8a95c7a6c1eb604aa48eeb5a5b2447 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 17 Jul 2013 22:37:33 -0400 Subject: [PATCH 092/237] Make this koan a little clearer --- python2/koans/about_new_style_classes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python2/koans/about_new_style_classes.py b/python2/koans/about_new_style_classes.py index 34b3957b9..cce2c6388 100644 --- a/python2/koans/about_new_style_classes.py +++ b/python2/koans/about_new_style_classes.py @@ -41,6 +41,10 @@ def test_old_style_classes_have_type_but_no_class_attribute(self): except Exception as ex: pass + # + # Let's look at the error message we get when trying to invoke + # __class__ on an old style class object + # self.assertMatch(__, ex[0]) def test_new_style_classes_have_same_class_as_type(self): From 92d996777eb3973ef5a4dd3f26d185d518778b72 Mon Sep 17 00:00:00 2001 From: Shishir Kakaraddi Date: Sat, 3 Aug 2013 18:26:12 -0700 Subject: [PATCH 093/237] Replace a simple method in the test suite with a new test to test escaping quotes in a triple quoted string --- python2/koans/about_strings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python2/koans/about_strings.py b/python2/koans/about_strings.py index 241e4ec67..abfcf5981 100644 --- a/python2/koans/about_strings.py +++ b/python2/koans/about_strings.py @@ -56,8 +56,9 @@ def test_triple_quoted_strings_need_less_escaping(self): b = """Hello "world".""" self.assertEqual(__, (a == b)) - def but_quotes_at_the_end_of_a_triple_quoted_string_are_still_tricky(self): + 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" From dce689cbef0e8385b7937cb65f3938550db900eb Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 7 Aug 2013 12:29:06 -0400 Subject: [PATCH 094/237] Reinstated __class__.__name in a number of AboutNewStyleClasses tests --- python2/koans/about_new_style_classes.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/python2/koans/about_new_style_classes.py b/python2/koans/about_new_style_classes.py index cce2c6388..6ea34780d 100644 --- a/python2/koans/about_new_style_classes.py +++ b/python2/koans/about_new_style_classes.py @@ -34,17 +34,16 @@ def test_new_style_classes_have_more_attributes(self): # ------------------------------------------------------------------ def test_old_style_classes_have_type_but_no_class_attribute(self): - self.assertEqual(__, self.OldStyleClass.__class__) + # Note: The .__name__ attribute will convert the type into a string + # value. + #self.assertEqual(__, type(self.OldStyleClass).__name__) try: - cls = self.OldStyleClass.__class__ + cls = self.OldStyleClass.__class__.__name__ except Exception as ex: pass - # - # Let's look at the error message we get when trying to invoke - # __class__ on an old style class object - # + # What was that error message from the exception? self.assertMatch(__, ex[0]) def test_new_style_classes_have_same_class_as_type(self): @@ -58,9 +57,10 @@ def test_new_style_classes_have_same_class_as_type(self): def test_in_old_style_instances_class_is_different_to_type(self): old_style = self.OldStyleClass() - self.assertEqual(__, old_style.__class__) + 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__) + self.assertEqual(__, new_style.__class__.__name__) self.assertEqual(__, type(new_style) == new_style.__class__) From 9ae9cc7c3bf6b9369a6bfc348f5a30a38d55e8a9 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 7 Aug 2013 21:43:15 -0400 Subject: [PATCH 095/237] changed back a few __class__ tests to __class__.__name__ to avoid having to deal with those pesky namespaces --- python2/koans/about_attribute_access.py | 4 ++-- python2/koans/about_classes.py | 2 +- python2/koans/about_method_bindings.py | 4 ++-- python2/koans/about_methods.py | 6 ++++-- python2/koans/about_new_style_classes.py | 4 +--- python3/koans/about_classes.py | 4 +++- python3/koans/about_method_bindings.py | 4 ++-- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/python2/koans/about_attribute_access.py b/python2/koans/about_attribute_access.py index fcd66a79d..ac9e16f20 100644 --- a/python2/koans/about_attribute_access.py +++ b/python2/koans/about_attribute_access.py @@ -19,7 +19,7 @@ def test_calling_undefined_functions_normally_results_in_errors(self): try: typical.foobar() except Exception as exception: - self.assertEqual(__, exception.__class__) + self.assertEqual(__, exception.__class__.__name__) self.assertMatch(__, exception[0]) def test_calling_getattribute_causes_an_attribute_error(self): @@ -160,7 +160,7 @@ def test_getattr_only_catches_unknown_attributes(self): catcher.free_pie() self.assertEqual(__, - catcher.give_me_duff_or_give_me_death().__class__) + catcher.give_me_duff_or_give_me_death().__class__.__name__) self.assertEqual(__, catcher.no_of_getattr_calls) diff --git a/python2/koans/about_classes.py b/python2/koans/about_classes.py index 570b03cb0..761a5e5d8 100644 --- a/python2/koans/about_classes.py +++ b/python2/koans/about_classes.py @@ -10,7 +10,7 @@ class Dog(object): def test_instances_of_classes_can_be_created_adding_parentheses(self): fido = self.Dog() - self.assertEqual(__, fido.__class__) + self.assertEqual(__, fido.__class__.__name__) def test_classes_have_docstrings(self): self.assertMatch(__, self.Dog.__doc__) diff --git a/python2/koans/about_method_bindings.py b/python2/koans/about_method_bindings.py index d41263dab..dfa87894f 100644 --- a/python2/koans/about_method_bindings.py +++ b/python2/koans/about_method_bindings.py @@ -77,8 +77,8 @@ def test_get_descriptor_resolves_attribute_binding(self): # binding_owner = obj # owner_type = cls - self.assertEqual(__, bound_obj.__class__) - self.assertEqual(__, binding_owner.__class__) + self.assertEqual(__, bound_obj.__class__.__name__) + self.assertEqual(__, binding_owner.__class__.__name__) self.assertEqual(AboutMethodBindings, owner_type) # ------------------------------------------------------------------ diff --git a/python2/koans/about_methods.py b/python2/koans/about_methods.py index 9584e33e3..fd924f9c9 100644 --- a/python2/koans/about_methods.py +++ b/python2/koans/about_methods.py @@ -22,7 +22,9 @@ def test_calling_functions_with_wrong_number_of_arguments(self): try: my_global_function() except Exception as exception: - self.assertEqual(__, exception.__class__) + # 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]) @@ -158,7 +160,7 @@ def test_double_underscore_attribute_prefixes_cause_name_mangling(self): #This may not be possible... password = rover.__password() except Exception as ex: - self.assertEqual(__, ex.__class__) + self.assertEqual(__, ex.__class__.__name__) # But this still is! self.assertEqual(__, rover._Dog__password()) diff --git a/python2/koans/about_new_style_classes.py b/python2/koans/about_new_style_classes.py index 6ea34780d..6a2077580 100644 --- a/python2/koans/about_new_style_classes.py +++ b/python2/koans/about_new_style_classes.py @@ -34,9 +34,7 @@ def test_new_style_classes_have_more_attributes(self): # ------------------------------------------------------------------ def test_old_style_classes_have_type_but_no_class_attribute(self): - # Note: The .__name__ attribute will convert the type into a string - # value. - #self.assertEqual(__, type(self.OldStyleClass).__name__) + self.assertEqual(__, type(self.OldStyleClass).__name__) try: cls = self.OldStyleClass.__class__.__name__ diff --git a/python3/koans/about_classes.py b/python3/koans/about_classes.py index 0e027d3c8..72671ac39 100644 --- a/python3/koans/about_classes.py +++ b/python3/koans/about_classes.py @@ -9,8 +9,10 @@ class Dog: "Dogs need regular walkies. Never, ever let them drive." def test_instances_of_classes_can_be_created_adding_parentheses(self): + # NOTE: The .__name__ attribute will convert the class + # into a string value. fido = self.Dog() - self.assertEqual(__, fido.__class__) + self.assertEqual(__, fido.__class__.__name__) def test_classes_have_docstrings(self): self.assertRegexpMatches(self.Dog.__doc__, __) diff --git a/python3/koans/about_method_bindings.py b/python3/koans/about_method_bindings.py index a29197365..5fa83204c 100644 --- a/python3/koans/about_method_bindings.py +++ b/python3/koans/about_method_bindings.py @@ -68,8 +68,8 @@ def test_get_descriptor_resolves_attribute_binding(self): # binding_owner = obj # owner_type = cls - self.assertEqual(__, bound_obj.__class__) - self.assertEqual(__, binding_owner.__class__) + self.assertEqual(__, bound_obj.__class__.__name__) + self.assertEqual(__, binding_owner.__class__.__name__) self.assertEqual(AboutMethodBindings, owner_type) # ------------------------------------------------------------------ From 058d8ffa7791c3b5509fdf51f0f59ab29763f0bc Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 7 Aug 2013 21:51:09 -0400 Subject: [PATCH 096/237] Making it more obvious that __str__ needs to be implemented by the student --- python2/koans/about_classes.py | 3 +++ python3/koans/about_classes.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/python2/koans/about_classes.py b/python2/koans/about_classes.py index 761a5e5d8..3c89b0561 100644 --- a/python2/koans/about_classes.py +++ b/python2/koans/about_classes.py @@ -125,6 +125,9 @@ def get_self(self): return self def __str__(self): + # + # Implement this! + # return __ def __repr__(self): diff --git a/python3/koans/about_classes.py b/python3/koans/about_classes.py index 72671ac39..c2f6867a5 100644 --- a/python3/koans/about_classes.py +++ b/python3/koans/about_classes.py @@ -131,6 +131,9 @@ def get_self(self): return self def __str__(self): + # + # Implement this! + # return __ def __repr__(self): From 681855808d9c2f971056fd0ff68aa8f173c279d5 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 7 Aug 2013 22:00:21 -0400 Subject: [PATCH 097/237] Python3 version of @shishirmk's triple quote test --- python3/koans/about_strings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python3/koans/about_strings.py b/python3/koans/about_strings.py index e722d29e8..25f5f59df 100644 --- a/python3/koans/about_strings.py +++ b/python3/koans/about_strings.py @@ -55,8 +55,9 @@ def test_triple_quoted_strings_need_less_escaping(self): b = """Hello "world".""" self.assertEqual(__, (a == b)) - def but_you_still_have_to_be_careful_at_the_end_of_a_triple_quoted_string(self): + 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" From 09010a68b68a5e6a18da737b88b8124adbe90a22 Mon Sep 17 00:00:00 2001 From: jofusa Date: Thu, 15 Aug 2013 15:29:48 -0600 Subject: [PATCH 098/237] New comprehention koans, moved one example from about_iteration --- python2/koans/about_iteration.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/python2/koans/about_iteration.py b/python2/koans/about_iteration.py index 2bf446f41..3b7bfed79 100644 --- a/python2/koans/about_iteration.py +++ b/python2/koans/about_iteration.py @@ -85,15 +85,6 @@ def test_reduce_will_blow_your_mind(self): # ------------------------------------------------------------------ - 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_use_pass_for_iterations_with_no_body(self): for num in range(1, 5): pass From de522b5fbceede1e788f07d60dc6e94f4bc83456 Mon Sep 17 00:00:00 2001 From: jofusa Date: Thu, 15 Aug 2013 15:30:45 -0600 Subject: [PATCH 099/237] New comprehention koans, moved one example from about_iteration --- python2/koans/about_comprehension.py | 60 ++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 python2/koans/about_comprehension.py diff --git a/python2/koans/about_comprehension.py b/python2/koans/about_comprehension.py new file mode 100644 index 000000000..227b842c5 --- /dev/null +++ b/python2/koans/about_comprehension.py @@ -0,0 +1,60 @@ +#!/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_comprehention(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_comprehention(self): + comprehension = { x for x in 'aabbbcccc'} + + self.assertequal(__, len(comprehension)) # remeber that set members are unique + + def test_creating_a_dictionary_with_dictionary_comprehention(self): + dict_of_weapons = {'first': 'fear', 'second': 'surprise', + 'third':'ruthless efficiency', 'forth':'fanatical devotion', 'fifth': None} + + dict_comprehention = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} + + self.assertEqual(__, 'first' in dict_comprehention) + self.assertEqual(__, 'FIRST' in dict_comprehention) + self.assertEqual(__, len(dict_of_weapons)) + self.assertEqual(__, len(dict_comprehention)) From a4bb78daf46fedfbdb733ee13a76fb98d692ab75 Mon Sep 17 00:00:00 2001 From: jofusa Date: Thu, 15 Aug 2013 15:30:57 -0600 Subject: [PATCH 100/237] New comprehention koans, moved one example from about_iteration --- python3/koans/about_iteration.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index 385c18a42..037bb2d54 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -107,14 +107,6 @@ def test_reduce_will_blow_your_mind(self): # ------------------------------------------------------------------ - 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_use_pass_for_iterations_with_no_body(self): for num in range(1,5): pass From aa2fc207c406a969fb30505a41f4f19201038279 Mon Sep 17 00:00:00 2001 From: jofusa Date: Thu, 15 Aug 2013 15:34:47 -0600 Subject: [PATCH 101/237] New comprehention koans, moved one example from about_iteration --- python3/koans/about_comprehension.py | 60 ++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 python3/koans/about_comprehension.py diff --git a/python3/koans/about_comprehension.py b/python3/koans/about_comprehension.py new file mode 100644 index 000000000..227b842c5 --- /dev/null +++ b/python3/koans/about_comprehension.py @@ -0,0 +1,60 @@ +#!/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_comprehention(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_comprehention(self): + comprehension = { x for x in 'aabbbcccc'} + + self.assertequal(__, len(comprehension)) # remeber that set members are unique + + def test_creating_a_dictionary_with_dictionary_comprehention(self): + dict_of_weapons = {'first': 'fear', 'second': 'surprise', + 'third':'ruthless efficiency', 'forth':'fanatical devotion', 'fifth': None} + + dict_comprehention = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} + + self.assertEqual(__, 'first' in dict_comprehention) + self.assertEqual(__, 'FIRST' in dict_comprehention) + self.assertEqual(__, len(dict_of_weapons)) + self.assertEqual(__, len(dict_comprehention)) From 04e90b69ac3196b71927f2cc42fbffa8151844f9 Mon Sep 17 00:00:00 2001 From: jofusa Date: Thu, 15 Aug 2013 15:39:27 -0600 Subject: [PATCH 102/237] Added new comprehention test to main runner --- python3/runner/path_to_enlightenment.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python3/runner/path_to_enlightenment.py b/python3/runner/path_to_enlightenment.py index a72ea5eda..0ae312183 100644 --- a/python3/runner/path_to_enlightenment.py +++ b/python3/runner/path_to_enlightenment.py @@ -21,6 +21,7 @@ from koans.about_exceptions import AboutExceptions from koans.about_triangle_project2 import AboutTriangleProject2 from koans.about_iteration import AboutIteration +from koans.about_comprehention import AboutComprehention from koans.about_generators import AboutGenerators from koans.about_lambdas import AboutLambdas from koans.about_scoring_project import AboutScoringProject @@ -63,6 +64,7 @@ def koans(): suite.addTests(loader.loadTestsFromTestCase(AboutExceptions)) suite.addTests(loader.loadTestsFromTestCase(AboutTriangleProject2)) suite.addTests(loader.loadTestsFromTestCase(AboutIteration)) + suite.addTests(loader.loadTestsFromTestCase(AboutComprehention)) suite.addTests(loader.loadTestsFromTestCase(AboutGenerators)) suite.addTests(loader.loadTestsFromTestCase(AboutLambdas)) suite.addTests(loader.loadTestsFromTestCase(AboutScoringProject)) From f521f17ed37afdaa67830cdbe177ee81ca6c7df6 Mon Sep 17 00:00:00 2001 From: jofusa Date: Thu, 15 Aug 2013 15:39:36 -0600 Subject: [PATCH 103/237] Added new comprehention test to main runner --- python2/runner/path_to_enlightenment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python2/runner/path_to_enlightenment.py b/python2/runner/path_to_enlightenment.py index a93a5bd40..fd0ca2419 100644 --- a/python2/runner/path_to_enlightenment.py +++ b/python2/runner/path_to_enlightenment.py @@ -21,6 +21,7 @@ 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 c431810365d7cbe05882006f69ce94263b3fc3f1 Mon Sep 17 00:00:00 2001 From: jofusa Date: Thu, 15 Aug 2013 15:40:12 -0600 Subject: [PATCH 104/237] Added new comprehention test to main runner --- python2/runner/path_to_enlightenment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python2/runner/path_to_enlightenment.py b/python2/runner/path_to_enlightenment.py index fd0ca2419..a81faa4d4 100644 --- a/python2/runner/path_to_enlightenment.py +++ b/python2/runner/path_to_enlightenment.py @@ -65,6 +65,7 @@ def koans(): 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)) From 06dffea7b642d568516993bec37448f2db02e5eb Mon Sep 17 00:00:00 2001 From: jofusa Date: Fri, 16 Aug 2013 09:37:58 -0600 Subject: [PATCH 105/237] Fixed typo --- python3/runner/path_to_enlightenment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/runner/path_to_enlightenment.py b/python3/runner/path_to_enlightenment.py index 0ae312183..f1bcb4261 100644 --- a/python3/runner/path_to_enlightenment.py +++ b/python3/runner/path_to_enlightenment.py @@ -21,7 +21,7 @@ from koans.about_exceptions import AboutExceptions from koans.about_triangle_project2 import AboutTriangleProject2 from koans.about_iteration import AboutIteration -from koans.about_comprehention import AboutComprehention +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 @@ -64,7 +64,7 @@ def koans(): suite.addTests(loader.loadTestsFromTestCase(AboutExceptions)) suite.addTests(loader.loadTestsFromTestCase(AboutTriangleProject2)) suite.addTests(loader.loadTestsFromTestCase(AboutIteration)) - suite.addTests(loader.loadTestsFromTestCase(AboutComprehention)) + suite.addTests(loader.loadTestsFromTestCase(AboutComprehension)) suite.addTests(loader.loadTestsFromTestCase(AboutGenerators)) suite.addTests(loader.loadTestsFromTestCase(AboutLambdas)) suite.addTests(loader.loadTestsFromTestCase(AboutScoringProject)) From a622eee7450ff494e5499c110609f3ce8f0da73b Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 21 Aug 2013 12:22:00 -0400 Subject: [PATCH 106/237] Made a couple of minor tweaks to new comprehension koans --- python2/koans/about_comprehension.py | 23 ++++++++++++----------- python3/koans/about_comprehension.py | 27 ++++++++++++++------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/python2/koans/about_comprehension.py b/python2/koans/about_comprehension.py index 227b842c5..4b372732a 100644 --- a/python2/koans/about_comprehension.py +++ b/python2/koans/about_comprehension.py @@ -13,8 +13,8 @@ def test_creating_lists_with_list_comprehensions(self): comprehension = [delicacy.capitalize() for delicacy in feast] - #self.assertEqual(__, comprehension[0]) - #self.assertEqual(__, comprehension[2]) + self.assertEqual(__, comprehension[0]) + self.assertEqual(__, comprehension[2]) def test_filtering_lists_with_list_comprehensions(self): feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals', @@ -32,7 +32,7 @@ def test_unpacking_tuples_in_list_comprehensions(self): self.assertEqual(__, comprehension[0]) self.assertEqual(__, len(comprehension[2])) - def test_double_list_comprehention(self): + def test_double_list_comprehension(self): list_of_eggs = ['poached egg', 'fried egg'] list_of_meats = ['lite spam', 'ham spam', 'fried spam'] @@ -43,18 +43,19 @@ def test_double_list_comprehention(self): self.assertEqual(__, len(comprehension)) self.assertEqual(__, comprehension[0]) - def test_creating_a_set_with_set_comprehention(self): + def test_creating_a_set_with_set_comprehension(self): comprehension = { x for x in 'aabbbcccc'} - self.assertequal(__, len(comprehension)) # remeber that set members are unique + self.assertEqual(__, comprehension) # rememeber that set members are unique - def test_creating_a_dictionary_with_dictionary_comprehention(self): + def test_creating_a_dictionary_with_dictionary_comprehension(self): dict_of_weapons = {'first': 'fear', 'second': 'surprise', - 'third':'ruthless efficiency', 'forth':'fanatical devotion', 'fifth': None} + 'third':'ruthless efficiency', 'forth':'fanatical devotion', + 'fifth': None} - dict_comprehention = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} + dict_comprehension = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} - self.assertEqual(__, 'first' in dict_comprehention) - self.assertEqual(__, 'FIRST' in dict_comprehention) + self.assertEqual(__, 'first' in dict_comprehension) + self.assertEqual(__, 'FIRST' in dict_comprehension) self.assertEqual(__, len(dict_of_weapons)) - self.assertEqual(__, len(dict_comprehention)) + self.assertEqual(__, len(dict_comprehension)) diff --git a/python3/koans/about_comprehension.py b/python3/koans/about_comprehension.py index 227b842c5..a9762c480 100644 --- a/python3/koans/about_comprehension.py +++ b/python3/koans/about_comprehension.py @@ -13,8 +13,8 @@ def test_creating_lists_with_list_comprehensions(self): comprehension = [delicacy.capitalize() for delicacy in feast] - #self.assertEqual(__, comprehension[0]) - #self.assertEqual(__, comprehension[2]) + self.assertEqual(__, comprehension[0]) + self.assertEqual(__, comprehension[2]) def test_filtering_lists_with_list_comprehensions(self): feast = ['spam', 'sloths', 'orangutans', 'breakfast cereals', @@ -30,9 +30,9 @@ def test_unpacking_tuples_in_list_comprehensions(self): comprehension = [ skit * number for number, skit in list_of_tuples ] self.assertEqual(__, comprehension[0]) - self.assertEqual(__, len(comprehension[2])) + self.assertEqual(__, comprehension[2]) - def test_double_list_comprehention(self): + def test_double_list_comprehension(self): list_of_eggs = ['poached egg', 'fried egg'] list_of_meats = ['lite spam', 'ham spam', 'fried spam'] @@ -40,21 +40,22 @@ def test_double_list_comprehention(self): 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]) + self.assertEqual(__, len(comprehension)) - def test_creating_a_set_with_set_comprehention(self): + def test_creating_a_set_with_set_comprehension(self): comprehension = { x for x in 'aabbbcccc'} - self.assertequal(__, len(comprehension)) # remeber that set members are unique + self.assertEqual(__, comprehension) # remeber that set members are unique - def test_creating_a_dictionary_with_dictionary_comprehention(self): + def test_creating_a_dictionary_with_dictionary_comprehension(self): dict_of_weapons = {'first': 'fear', 'second': 'surprise', - 'third':'ruthless efficiency', 'forth':'fanatical devotion', 'fifth': None} + 'third':'ruthless efficiency', 'forth':'fanatical devotion', + 'fifth': None} - dict_comprehention = { k.upper(): weapon for k, weapon in dict_of_weapons.iteritems() if weapon} + dict_comprehension = { k.upper(): weapon for k, weapon in dict_of_weapons.items() if weapon} - self.assertEqual(__, 'first' in dict_comprehention) - self.assertEqual(__, 'FIRST' in dict_comprehention) + self.assertEqual(__, 'first' in dict_comprehension) + self.assertEqual(__, 'FIRST' in dict_comprehension) self.assertEqual(__, len(dict_of_weapons)) - self.assertEqual(__, len(dict_comprehention)) + self.assertEqual(__, len(dict_comprehension)) From 075392cb33baa574e02ba3d416c68132d8e96fa5 Mon Sep 17 00:00:00 2001 From: jofusa Date: Wed, 21 Aug 2013 10:22:56 -0600 Subject: [PATCH 107/237] new requirments --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index ea487a2a6..93bd4c2c1 100644 --- a/README.rst +++ b/README.rst @@ -52,8 +52,8 @@ 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.6 (it also works with Python 2.7) -* one for Python 3.1. +* one for use with Python 2.7 (earlier versions are no longer supported) +* one for Python 3.1+. You should be able to work with newer Python versions, but older ones will likely give you problems. From 02297dc14475d79bcf098409e5560483d895d4d6 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Wed, 21 Aug 2013 12:26:47 -0400 Subject: [PATCH 108/237] Dropping python 2.6 support --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0184d0ec5..0ef668f20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: python python: - - 2.6 - 2.7 - 3.2 - 3.3 From f739d2624451506072718f0cc5ed255a282e198c Mon Sep 17 00:00:00 2001 From: Santosh Kumar Date: Sat, 24 Aug 2013 09:31:56 +0530 Subject: [PATCH 109/237] insert missing brace --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 93bd4c2c1..2aa25bb31 100644 --- a/README.rst +++ b/README.rst @@ -133,7 +133,7 @@ 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 (green), then refactor it (that is look at the code and see if you - can make it any better. In this case you will need to run the koan + can make it any better). In this case you will need to run the koan and see it fail (red), make the test pass (green), then take a moment and reflect upon the test to see what it is teaching you and improve the code to better communicate its intent (refactor)." From 8da016cfc0685115c5a3582d694e9f09a567599e Mon Sep 17 00:00:00 2001 From: Santosh Kumar Date: Sat, 24 Aug 2013 09:36:34 +0530 Subject: [PATCH 110/237] escaped characters to prevent rendering problem --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 2aa25bb31..63027871c 100644 --- a/README.rst +++ b/README.rst @@ -87,8 +87,8 @@ 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 go to the python +koans\\python_VERSION folder and run:: python contemplate_koans.py @@ -106,7 +106,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 -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 From 82ee47ae911ed74f9124e1c6a158d2394c17a5ca Mon Sep 17 00:00:00 2001 From: Santosh Kumar Date: Sat, 24 Aug 2013 09:42:19 +0530 Subject: [PATCH 111/237] Fixed English grammar mistake --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 63027871c..a28fa23ff 100644 --- a/README.rst +++ b/README.rst @@ -119,7 +119,7 @@ expected value should be. For example:: fido = self.Dog() self.assertEqual(__, isinstance(fido, object)) -This is where the Python Command Line can come in handy. in this case I can +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 From a6f55dea2dee93faef5db644a962a26dbfa6c156 Mon Sep 17 00:00:00 2001 From: Santosh Kumar Date: Sat, 24 Aug 2013 09:51:39 +0530 Subject: [PATCH 112/237] formatted for visual improvements --- README.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.rst b/README.rst index a28fa23ff..1c7ef631d 100644 --- a/README.rst +++ b/README.rst @@ -13,7 +13,7 @@ at http://rubykoans.com/. Python Koans is an interactive tutorial for learning the Python programming language by making tests pass. -Most tests are 'fixed' by filling the missing parts of assert functions. Eg: +Most tests are *fixed* by filling the missing parts of assert functions. Eg: self.assertEqual(__, 1+2) @@ -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.1+ You should be able to work with newer Python versions, but older ones will likely give you problems. @@ -64,16 +64,16 @@ You can download Python from here: 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 -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'. +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`. If you have problems, this may help: http://www.python.org/about/gettingstarted -Windows users may also want to update the line in the batch file run.bat to -set the python path: +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 From 9b45103418eb4b3f66f6410bfb2221b3e4b0ea15 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sat, 24 Aug 2013 21:38:58 -0400 Subject: [PATCH 113/237] Updated startup scripts to look for python 2.7 or 3.2 --- python2/contemplate_koans.py | 8 ++++---- python2/run.bat | 4 +--- python3/contemplate_koans.py | 13 ++++++++++++- python3/run.bat | 4 +--- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/python2/contemplate_koans.py b/python2/contemplate_koans.py index 025ba9a08..d49c6c214 100644 --- a/python2/contemplate_koans.py +++ b/python2/contemplate_koans.py @@ -21,14 +21,14 @@ "Did you accidentally use the wrong python script? \nTry:\n\n" + " python contemplate_koans.py\n") else: - if sys.version_info < (2, 6): + if sys.version_info < (2, 7): print("\n" + "********************************************************\n" + "WARNING:\n" + "This version of Python Koans was designed for " + - "Python 2.6 or greater.\n" + - "Your version of Python is older, so this is unlikely " + - "to work!\n\n" + + "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") diff --git a/python2/run.bat b/python2/run.bat index 7bfc5d8b0..b1f704261 100644 --- a/python2/run.bat +++ b/python2/run.bat @@ -5,9 +5,7 @@ REM You don't actually need this script! SET RUN_KOANS=python.exe contemplate_koans.py REM Set this to your python folder: -SET PYTHON_PATH=C:\Python26 - - +SET PYTHON_PATH=C:\Python27 set SCRIPT= REM Hunt around for python diff --git a/python3/contemplate_koans.py b/python3/contemplate_koans.py index 8777a46e5..81c1502bc 100644 --- a/python3/contemplate_koans.py +++ b/python3/contemplate_koans.py @@ -16,10 +16,21 @@ if __name__ == '__main__': if sys.version_info < (3, 0): print("\nThis is the Python 3 version of Python Koans, but you are " + - "running it with Python 2 or older!\n\n" + "running it with Python 2!\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): + print("\n" + + "********************************************************\n" + + "WARNING:\n" + + "This version of Python Koans was designed for " + + "Python 3.3 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/python3/run.bat b/python3/run.bat index 0496c5f2e..e5c86c361 100644 --- a/python3/run.bat +++ b/python3/run.bat @@ -5,9 +5,7 @@ REM You don't actually need this script! SET RUN_KOANS=python.exe contemplate_koans.py REM Set this to your python folder: -SET PYTHON_PATH=C:\Python31 - - +SET PYTHON_PATH=C:\Python33 set SCRIPT= REM Hunt around for python From d5899a0fd3ca8024e38225ddea4555595bd0f34a Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sat, 24 Aug 2013 21:45:16 -0400 Subject: [PATCH 114/237] Made some updates to account for Python 3 language changes --- python3/koans/a_normal_folder/a_module.py | 7 ------- python3/koans/about_methods.py | 2 ++ python3/koans/about_packages.py | 4 ---- python3/koans/about_regex.py | 0 4 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 python3/koans/a_normal_folder/a_module.py mode change 100755 => 100644 python3/koans/about_regex.py diff --git a/python3/koans/a_normal_folder/a_module.py b/python3/koans/a_normal_folder/a_module.py deleted file mode 100644 index f8b4231a4..000000000 --- a/python3/koans/a_normal_folder/a_module.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -class Duck: - @property - def name(self): - return "Howard" \ No newline at end of file diff --git a/python3/koans/about_methods.py b/python3/koans/about_methods.py index 39f0682d9..c9572ad25 100644 --- a/python3/koans/about_methods.py +++ b/python3/koans/about_methods.py @@ -22,6 +22,8 @@ def test_calling_functions_with_wrong_number_of_arguments(self): except TypeError as exception: msg = exception.args[0] + # Note, the text comparison works for Python 3.2 + # It has changed in the past and may change in the future self.assertRegexpMatches(msg, r'my_global_function\(\) missing 2 required positional arguments') diff --git a/python3/koans/about_packages.py b/python3/koans/about_packages.py index d33d8fa38..678de0006 100644 --- a/python3/koans/about_packages.py +++ b/python3/koans/about_packages.py @@ -37,10 +37,6 @@ def test_subfolders_become_modules_if_they_have_an_init_module(self): self.assertEqual(__, an_attribute) - def test_subfolders_without_an_init_module_are_not_part_of_the_package(self): - # Import ./a_normal_folder/ - with self.assertRaises(___): from a_normal_folder import Duck - # ------------------------------------------------------------------ def test_use_absolute_imports_to_import_upper_level_modules(self): diff --git a/python3/koans/about_regex.py b/python3/koans/about_regex.py old mode 100755 new mode 100644 From afdc39fe1473600e1471797fd8bd9a342a9f94fc Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sat, 24 Aug 2013 22:53:19 -0400 Subject: [PATCH 115/237] Fixed a bug with showing negative number of koans to complete when all koans are completed. Added a little highlighing for which file and line number to edit. Removed some brittle tests --- python2/runner/runner_tests/test_sensei.py | 24 ----------- python2/runner/sensei.py | 46 ++++++++++++++-------- python3/runner/runner_tests/test_sensei.py | 26 +----------- python3/runner/sensei.py | 46 ++++++++++++++-------- 4 files changed, 59 insertions(+), 83 deletions(-) diff --git a/python2/runner/runner_tests/test_sensei.py b/python2/runner/runner_tests/test_sensei.py index 5aa1d7815..8149a7fac 100644 --- a/python2/runner/runner_tests/test_sensei.py +++ b/python2/runner/runner_tests/test_sensei.py @@ -225,30 +225,6 @@ def test_that_scraping_the_assertion_error_with_list_error(self): def test_that_scraping_a_non_existent_stack_dump_gives_you_nothing(self): self.assertEqual("", self.sensei.scrapeInterestingStackDump(None)) - def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_messaged_assert(self): - expected = """ 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...")""" - self.assertEqual(expected, - self.sensei.scrapeInterestingStackDump(error_assertion_with_message)) - - def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_assert_equals(self): - expected = """ File "/Users/Greg/hg/python_koans/koans/about_exploding_trousers.py", line 49, in test_math - self.assertEqual(4,99)""" - self.assertEqual(expected, - self.sensei.scrapeInterestingStackDump(error_assertion_equals)) - - def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_assert_true(self): - expected = """ File "/Users/Greg/hg/python_koans/koans/about_armories.py", line 25, in test_weoponary - self.assertTrue("Pen" > "Sword")""" - self.assertEqual(expected, - self.sensei.scrapeInterestingStackDump(error_assertion_true)) - - def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_syntax_error(self): - expected = """ File "/Users/Greg/hg/python_koans/koans/about_asserts.py", line 20 - self.assertTrue(eoe"Pen" > "Sword", "nhnth")""" - self.assertEqual(expected, - self.sensei.scrapeInterestingStackDump(error_mess)) - def test_that_if_there_are_no_failures_say_the_final_zenlike_remark(self): self.sensei.failures = None words = self.sensei.say_something_zenlike() diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index fb93e817b..4e8165334 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -87,6 +87,8 @@ def learn(self): 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()) @@ -138,36 +140,46 @@ def scrapeInterestingStackDump(self, err): sep = '@@@@@SEP@@@@@' - scrape = "" + stack_text = "" for line in lines: m = re.search("^ File .*$",line) if m and m.group(0): - scrape += '\n' + line + stack_text += '\n' + line m = re.search("^ \w(\w)+.*$",line) if m and m.group(0): - scrape += sep + line + stack_text += sep + line - lines = scrape.splitlines() + lines = stack_text.splitlines() - scrape = "" + stack_text = "" for line in lines: m = re.search("^.*[/\\\\]koans[/\\\\].*$",line) if m and m.group(0): - scrape += line + '\n' - return scrape.replace(sep, '\n').strip('\n') + 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): - koans_complete = self.pass_count - lessons_complete = self.lesson_pass_count - koans_remaining = self.total_koans() - koans_complete - lessons_remaining = self.total_lessons() - lessons_complete - - sent1 = "You have completed {0} koans and " \ - "{1} lessons.\n".format(koans_complete, lessons_complete) - sent2 = "You are now {0} koans and {1} lessons away from " \ - "reaching enlightenment.".format(koans_remaining, lessons_remaining) - return sent1+sent2 + return "You have completed {0} koans and " \ + "{1} lessons.".format( + self.pass_count, + self.lesson_pass_count) + + def report_remaining(self): + koans_remaining = self.total_koans() - self.pass_count + lessons_remaining = self.total_lessons() - self.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/) diff --git a/python3/runner/runner_tests/test_sensei.py b/python3/runner/runner_tests/test_sensei.py index 018d4ca22..416c7ce2f 100644 --- a/python3/runner/runner_tests/test_sensei.py +++ b/python3/runner/runner_tests/test_sensei.py @@ -32,7 +32,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...""" @@ -205,30 +205,6 @@ def test_that_scraping_the_assertion_error_with_list_error(self): def test_that_scraping_a_non_existent_stack_dump_gives_you_nothing(self): self.assertEqual("", self.sensei.scrapeInterestingStackDump(None)) - def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_messaged_assert(self): - expected = """ 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...")""" - self.assertEqual(expected, - self.sensei.scrapeInterestingStackDump(error_assertion_with_message)) - - def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_assert_equals(self): - expected = """ File "/Users/Greg/hg/python_koans/koans/about_exploding_trousers.py", line 49, in test_math - self.assertEqual(4,99)""" - self.assertEqual(expected, - self.sensei.scrapeInterestingStackDump(error_assertion_equals)) - - def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_assert_true(self): - expected = """ File "/Users/Greg/hg/python_koans/koans/about_armories.py", line 25, in test_weoponary - self.assertTrue("Pen" > "Sword")""" - self.assertEqual(expected, - self.sensei.scrapeInterestingStackDump(error_assertion_true)) - - def test_that_scraping_the_stack_dump_only_shows_interesting_lines_for_syntax_error(self): - expected = """ File "/Users/Greg/hg/python_koans/koans/about_asserts.py", line 20 - self.assertTrue(eoe"Pen" > "Sword", "nhnth")""" - self.assertEqual(expected, - self.sensei.scrapeInterestingStackDump(error_mess)) - def test_that_if_there_are_no_failures_say_the_final_zenlike_remark(self): self.sensei.failures = None words = self.sensei.say_something_zenlike() diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index df9915460..434e4e9a0 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -86,6 +86,8 @@ def learn(self): 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()) @@ -138,36 +140,46 @@ def scrapeInterestingStackDump(self, err): sep = '@@@@@SEP@@@@@' - scrape = "" + stack_text = "" for line in lines: m = re.search("^ File .*$",line) if m and m.group(0): - scrape += '\n' + line + stack_text += '\n' + line m = re.search("^ \w(\w)+.*$",line) if m and m.group(0): - scrape += sep + line + stack_text += sep + line - lines = scrape.splitlines() + lines = stack_text.splitlines() - scrape = "" + stack_text = "" for line in lines: m = re.search("^.*[/\\\\]koans[/\\\\].*$",line) if m and m.group(0): - scrape += line + '\n' - return scrape.replace(sep, '\n').strip('\n') + 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): - koans_complete = self.pass_count - lessons_complete = self.lesson_pass_count - koans_remaining = self.total_koans() - koans_complete - lessons_remaining = self.total_lessons() - lessons_complete - - sent1 = "You have completed {0} koans and " \ - "{1} lessons.\n".format(koans_complete, lessons_complete) - sent2 = "You are now {0} koans and {1} lessons away from " \ - "reaching enlightenment.".format(koans_remaining, lessons_remaining) - return sent1+sent2 + return "You have completed {0} koans and " \ + "{1} lessons.".format( + self.pass_count, + self.lesson_pass_count) + + def report_remaining(self): + koans_remaining = self.total_koans() - self.pass_count + lessons_remaining = self.total_lessons() - self.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/) From ddd5823d3bb32ad6402a4969f9692b46ecdf4099 Mon Sep 17 00:00:00 2001 From: Ben Nuttall Date: Wed, 28 Aug 2013 01:16:16 +0100 Subject: [PATCH 116/237] Fixed a bug with showing negative number of lessons to complete --- 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 4e8165334..5b5cd937d 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -174,7 +174,7 @@ def report_progress(self): def report_remaining(self): koans_remaining = self.total_koans() - self.pass_count - lessons_remaining = self.total_lessons() - 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( diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index 434e4e9a0..44eecd7cc 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -174,7 +174,7 @@ def report_progress(self): def report_remaining(self): koans_remaining = self.total_koans() - self.pass_count - lessons_remaining = self.total_lessons() - 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( From 9f86dd1c8bc9f9111b15cbd4c814bcc055a0c9fc Mon Sep 17 00:00:00 2001 From: Alex Kesling Date: Mon, 2 Sep 2013 19:17:00 -0400 Subject: [PATCH 117/237] Typo in about_string_manipulation.py Python3 --- python3/koans/about_string_manipulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_string_manipulation.py b/python3/koans/about_string_manipulation.py index bc365689f..02a799000 100644 --- a/python3/koans/about_string_manipulation.py +++ b/python3/koans/about_string_manipulation.py @@ -11,7 +11,7 @@ def test_use_format_to_interpolate_variables(self): string = "The values are {0} and {1}".format(value1, value2) self.assertEqual(__, string) - def test_formatted_values_con_be_shown_in_any_order_or_be_repeated(self): + 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) From 434d673c37bfec6e279e63257bb30cd698ff422b Mon Sep 17 00:00:00 2001 From: Alex Kesling Date: Sat, 7 Sep 2013 12:54:54 -0400 Subject: [PATCH 118/237] Removed unnecessary line continuation --- python3/koans/about_string_manipulation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_string_manipulation.py b/python3/koans/about_string_manipulation.py index 02a799000..5204f29ba 100644 --- a/python3/koans/about_string_manipulation.py +++ b/python3/koans/about_string_manipulation.py @@ -21,7 +21,7 @@ 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), \ + string = "The square root of 5 is {0:.{1}f}".format(math.sqrt(5), decimal_places) self.assertEqual(__, string) From 065e221804e55289431e5859b71d4d15398ddc8a Mon Sep 17 00:00:00 2001 From: Rob Prouse Date: Sun, 24 Nov 2013 16:44:51 -0500 Subject: [PATCH 119/237] Fixes issue #72 - Update to Colorama 0.2.7 This fixes random crashes on Windows. See the issue for more details. --- python2/libs/colorama/__init__.py | 5 +- python2/libs/colorama/ansi.py | 1 + python2/libs/colorama/ansitowin32.py | 17 ++- python2/libs/colorama/initialise.py | 24 +++- python2/libs/colorama/win32.py | 159 +++++++++++++++++---------- python2/libs/colorama/winterm.py | 57 +++++++++- python3/libs/colorama/__init__.py | 5 +- python3/libs/colorama/ansi.py | 1 + python3/libs/colorama/ansitowin32.py | 17 ++- python3/libs/colorama/initialise.py | 24 +++- python3/libs/colorama/win32.py | 159 +++++++++++++++++---------- python3/libs/colorama/winterm.py | 57 +++++++++- 12 files changed, 386 insertions(+), 140 deletions(-) diff --git a/python2/libs/colorama/__init__.py b/python2/libs/colorama/__init__.py index 331174e57..2d127fa8e 100644 --- a/python2/libs/colorama/__init__.py +++ b/python2/libs/colorama/__init__.py @@ -1,6 +1,7 @@ -from .initialise import init +# 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.1.18' +VERSION = '0.2.7' diff --git a/python2/libs/colorama/ansi.py b/python2/libs/colorama/ansi.py index 7b818e19e..5dfe374ce 100644 --- a/python2/libs/colorama/ansi.py +++ b/python2/libs/colorama/ansi.py @@ -1,3 +1,4 @@ +# 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 diff --git a/python2/libs/colorama/ansitowin32.py b/python2/libs/colorama/ansitowin32.py index 5c39a480e..ea0a6c15f 100644 --- a/python2/libs/colorama/ansitowin32.py +++ b/python2/libs/colorama/ansitowin32.py @@ -1,4 +1,4 @@ - +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. import re import sys @@ -123,7 +123,7 @@ def write(self, text): def reset_all(self): if self.convert: self.call_win32('m', (0,)) - else: + elif is_a_tty(self.wrapped): self.wrapped.write(Style.RESET_ALL) @@ -173,4 +173,17 @@ def call_win32(self, command, params): 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 index eca2bea40..cba3676dd 100644 --- a/python2/libs/colorama/initialise.py +++ b/python2/libs/colorama/initialise.py @@ -1,3 +1,4 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. import atexit import sys @@ -7,6 +8,9 @@ orig_stdout = sys.stdout orig_stderr = sys.stderr +wrapped_stdout = sys.stdout +wrapped_stderr = sys.stderr + atexit_done = False @@ -16,11 +20,14 @@ def reset_all(): def init(autoreset=False, convert=None, strip=None, wrap=True): - if wrap==False and (autoreset==True or convert==True or strip==True): + if not wrap and any([autoreset, convert, strip]): raise ValueError('wrap=False conflicts with any other arg=True') - sys.stdout = wrap_stream(orig_stdout, convert, strip, autoreset, wrap) - sys.stderr = wrap_stream(orig_stderr, convert, strip, autoreset, wrap) + 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: @@ -28,6 +35,16 @@ def init(autoreset=False, convert=None, strip=None, wrap=True): 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, @@ -36,3 +53,4 @@ def wrap_stream(stream, convert, strip, autoreset, wrap): stream = wrapper.stream return stream + diff --git a/python2/libs/colorama/win32.py b/python2/libs/colorama/win32.py index 5f49e6cba..f4024f95e 100644 --- a/python2/libs/colorama/win32.py +++ b/python2/libs/colorama/win32.py @@ -1,3 +1,4 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. # from winbase.h STDOUT = -11 @@ -5,91 +6,129 @@ 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 + byref, Structure, c_char, c_short, c_uint32, c_ushort, POINTER ) - handles = { - STDOUT: windll.kernel32.GetStdHandle(STDOUT), - STDERR: windll.kernel32.GetStdHandle(STDERR), - } - - SHORT = c_short - WORD = c_ushort - DWORD = c_uint32 - TCHAR = c_char - - class COORD(Structure): - """struct in wincon.h""" - _fields_ = [ - ('X', SHORT), - ('Y', SHORT), - ] - - class SMALL_RECT(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("Left", SHORT), - ("Top", SHORT), - ("Right", SHORT), - ("Bottom", SHORT), - ] - class CONSOLE_SCREEN_BUFFER_INFO(Structure): """struct in wincon.h.""" _fields_ = [ - ("dwSize", COORD), - ("dwCursorPosition", COORD), - ("wAttributes", WORD), - ("srWindow", SMALL_RECT), - ("dwMaximumWindowSize", COORD), + ("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 - def GetConsoleScreenBufferInfo(stream_id): + _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 = windll.kernel32.GetConsoleScreenBufferInfo( + success = _GetConsoleScreenBufferInfo( handle, byref(csbi)) - # This fails when imported via setup.py when installing using 'pip' - # presumably the fix is that running setup.py should not trigger all - # this activity. - # assert success return csbi def SetConsoleTextAttribute(stream_id, attrs): handle = handles[stream_id] - success = windll.kernel32.SetConsoleTextAttribute(handle, attrs) - assert success + 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] - position = COORD(*position) - success = windll.kernel32.SetConsoleCursorPosition(handle, position) - assert success + return _SetConsoleCursorPosition(handle, adjusted_position) def FillConsoleOutputCharacter(stream_id, char, length, start): handle = handles[stream_id] - char = TCHAR(char) - length = DWORD(length) - start = COORD(*start) - num_written = DWORD(0) - # AttributeError: function 'FillConsoleOutputCharacter' not found - # could it just be that my types are wrong? - success = windll.kernel32.FillConsoleOutputCharacter( + 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)) - assert success return num_written.value - -if __name__=='__main__': - x = GetConsoleScreenBufferInfo(STDOUT) - print(x.dwSize) - print(x.dwCursorPosition) - print(x.wAttributes) - print(x.srWindow) - print(x.dwMaximumWindowSize) - + 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 index 63f4469cc..270881154 100644 --- a/python2/libs/colorama/winterm.py +++ b/python2/libs/colorama/winterm.py @@ -1,4 +1,4 @@ - +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. from . import win32 @@ -22,8 +22,7 @@ class WinStyle(object): class WinTerm(object): def __init__(self): - self._default = \ - win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes + self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes self.set_attrs(self._default) self._default_fore = self._fore self._default_back = self._back @@ -67,3 +66,55 @@ def set_console(self, attrs=None, on_stderr=False): 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/python3/libs/colorama/__init__.py b/python3/libs/colorama/__init__.py index 331174e57..2d127fa8e 100644 --- a/python3/libs/colorama/__init__.py +++ b/python3/libs/colorama/__init__.py @@ -1,6 +1,7 @@ -from .initialise import init +# 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.1.18' +VERSION = '0.2.7' diff --git a/python3/libs/colorama/ansi.py b/python3/libs/colorama/ansi.py index 7b818e19e..5dfe374ce 100644 --- a/python3/libs/colorama/ansi.py +++ b/python3/libs/colorama/ansi.py @@ -1,3 +1,4 @@ +# 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 diff --git a/python3/libs/colorama/ansitowin32.py b/python3/libs/colorama/ansitowin32.py index 5c39a480e..ea0a6c15f 100644 --- a/python3/libs/colorama/ansitowin32.py +++ b/python3/libs/colorama/ansitowin32.py @@ -1,4 +1,4 @@ - +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. import re import sys @@ -123,7 +123,7 @@ def write(self, text): def reset_all(self): if self.convert: self.call_win32('m', (0,)) - else: + elif is_a_tty(self.wrapped): self.wrapped.write(Style.RESET_ALL) @@ -173,4 +173,17 @@ def call_win32(self, command, params): 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/python3/libs/colorama/initialise.py b/python3/libs/colorama/initialise.py index eca2bea40..cba3676dd 100644 --- a/python3/libs/colorama/initialise.py +++ b/python3/libs/colorama/initialise.py @@ -1,3 +1,4 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. import atexit import sys @@ -7,6 +8,9 @@ orig_stdout = sys.stdout orig_stderr = sys.stderr +wrapped_stdout = sys.stdout +wrapped_stderr = sys.stderr + atexit_done = False @@ -16,11 +20,14 @@ def reset_all(): def init(autoreset=False, convert=None, strip=None, wrap=True): - if wrap==False and (autoreset==True or convert==True or strip==True): + if not wrap and any([autoreset, convert, strip]): raise ValueError('wrap=False conflicts with any other arg=True') - sys.stdout = wrap_stream(orig_stdout, convert, strip, autoreset, wrap) - sys.stderr = wrap_stream(orig_stderr, convert, strip, autoreset, wrap) + 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: @@ -28,6 +35,16 @@ def init(autoreset=False, convert=None, strip=None, wrap=True): 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, @@ -36,3 +53,4 @@ def wrap_stream(stream, convert, strip, autoreset, wrap): stream = wrapper.stream return stream + diff --git a/python3/libs/colorama/win32.py b/python3/libs/colorama/win32.py index 5f49e6cba..f4024f95e 100644 --- a/python3/libs/colorama/win32.py +++ b/python3/libs/colorama/win32.py @@ -1,3 +1,4 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. # from winbase.h STDOUT = -11 @@ -5,91 +6,129 @@ 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 + byref, Structure, c_char, c_short, c_uint32, c_ushort, POINTER ) - handles = { - STDOUT: windll.kernel32.GetStdHandle(STDOUT), - STDERR: windll.kernel32.GetStdHandle(STDERR), - } - - SHORT = c_short - WORD = c_ushort - DWORD = c_uint32 - TCHAR = c_char - - class COORD(Structure): - """struct in wincon.h""" - _fields_ = [ - ('X', SHORT), - ('Y', SHORT), - ] - - class SMALL_RECT(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("Left", SHORT), - ("Top", SHORT), - ("Right", SHORT), - ("Bottom", SHORT), - ] - class CONSOLE_SCREEN_BUFFER_INFO(Structure): """struct in wincon.h.""" _fields_ = [ - ("dwSize", COORD), - ("dwCursorPosition", COORD), - ("wAttributes", WORD), - ("srWindow", SMALL_RECT), - ("dwMaximumWindowSize", COORD), + ("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 - def GetConsoleScreenBufferInfo(stream_id): + _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 = windll.kernel32.GetConsoleScreenBufferInfo( + success = _GetConsoleScreenBufferInfo( handle, byref(csbi)) - # This fails when imported via setup.py when installing using 'pip' - # presumably the fix is that running setup.py should not trigger all - # this activity. - # assert success return csbi def SetConsoleTextAttribute(stream_id, attrs): handle = handles[stream_id] - success = windll.kernel32.SetConsoleTextAttribute(handle, attrs) - assert success + 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] - position = COORD(*position) - success = windll.kernel32.SetConsoleCursorPosition(handle, position) - assert success + return _SetConsoleCursorPosition(handle, adjusted_position) def FillConsoleOutputCharacter(stream_id, char, length, start): handle = handles[stream_id] - char = TCHAR(char) - length = DWORD(length) - start = COORD(*start) - num_written = DWORD(0) - # AttributeError: function 'FillConsoleOutputCharacter' not found - # could it just be that my types are wrong? - success = windll.kernel32.FillConsoleOutputCharacter( + 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)) - assert success return num_written.value - -if __name__=='__main__': - x = GetConsoleScreenBufferInfo(STDOUT) - print(x.dwSize) - print(x.dwCursorPosition) - print(x.wAttributes) - print(x.srWindow) - print(x.dwMaximumWindowSize) - + 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/python3/libs/colorama/winterm.py b/python3/libs/colorama/winterm.py index 63f4469cc..270881154 100644 --- a/python3/libs/colorama/winterm.py +++ b/python3/libs/colorama/winterm.py @@ -1,4 +1,4 @@ - +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. from . import win32 @@ -22,8 +22,7 @@ class WinStyle(object): class WinTerm(object): def __init__(self): - self._default = \ - win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes + self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes self.set_attrs(self._default) self._default_fore = self._fore self._default_back = self._back @@ -67,3 +66,55 @@ def set_console(self, attrs=None, on_stderr=False): 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)) From ea9d251bd876485c77bc027fbb99c5d12c0db29e Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Sat, 18 Jan 2014 03:05:23 -0700 Subject: [PATCH 120/237] Update about_classes.py --- python2/koans/about_classes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_classes.py b/python2/koans/about_classes.py index 3c89b0561..7b82e60d1 100644 --- a/python2/koans/about_classes.py +++ b/python2/koans/about_classes.py @@ -109,7 +109,7 @@ def test_args_must_match_init(self): # THINK ABOUT IT: # Why is this so? - def test_different_objects_have_difference_instance_variables(self): + def test_different_objects_have_different_instance_variables(self): fido = self.Dog5("Fido") rover = self.Dog5("Rover") From a6668126d3f033ac86a1bbc52a808c5aad54e94c Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Sun, 19 Jan 2014 11:57:56 -0700 Subject: [PATCH 121/237] Update about_classes.py --- python3/koans/about_classes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_classes.py b/python3/koans/about_classes.py index c2f6867a5..f3ed7eeb1 100644 --- a/python3/koans/about_classes.py +++ b/python3/koans/about_classes.py @@ -115,7 +115,7 @@ def test_args_must_match_init(self): # THINK ABOUT IT: # Why is this so? - def test_different_objects_have_difference_instance_variables(self): + def test_different_objects_have_different_instance_variables(self): fido = self.Dog5("Fido") rover = self.Dog5("Rover") From add4d0f58de299ceffb5058ae85489ba93278731 Mon Sep 17 00:00:00 2001 From: YCFlame Date: Tue, 28 Jan 2014 16:19:57 +0800 Subject: [PATCH 122/237] remove useless import and change indentation according to pep8 --- python2/contemplate_koans.py | 23 +++++++++++------------ python3/contemplate_koans.py | 23 +++++++++++------------ 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/python2/contemplate_koans.py b/python2/contemplate_koans.py index d49c6c214..34e06d7bb 100644 --- a/python2/contemplate_koans.py +++ b/python2/contemplate_koans.py @@ -10,27 +10,26 @@ # So thank guys! # -import unittest 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") + "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") + "********************************************************\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 diff --git a/python3/contemplate_koans.py b/python3/contemplate_koans.py index 81c1502bc..b7d35d4b3 100644 --- a/python3/contemplate_koans.py +++ b/python3/contemplate_koans.py @@ -10,26 +10,25 @@ # So thanks guys! # -import unittest import sys if __name__ == '__main__': 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" + - " python3 contemplate_koans.py\n") + "running it with Python 2!\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): print("\n" + - "********************************************************\n" + - "WARNING:\n" + - "This version of Python Koans was designed for " + - "Python 3.3 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") + "********************************************************\n" + + "WARNING:\n" + + "This version of Python Koans was designed for " + + "Python 3.3 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 From fc9154953a9ec003c46aefc3bc1730f82db5565d Mon Sep 17 00:00:00 2001 From: Munkhbaatar Date: Tue, 4 Feb 2014 12:31:32 +0800 Subject: [PATCH 123/237] extra whitespace trimmed --- python2/koans/about_deleting_objects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_deleting_objects.py b/python2/koans/about_deleting_objects.py index d2ee8be05..e8a556dc1 100644 --- a/python2/koans/about_deleting_objects.py +++ b/python2/koans/about_deleting_objects.py @@ -1,4 +1,4 @@ - #!/usr/bin/env python +#!/usr/bin/env python # -*- coding: utf-8 -*- from runner.koan import * From 421c28b44ef32b59ae7749044d01f5fc10298efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kiss=20Gy=C3=B6rgy?= Date: Sat, 8 Feb 2014 01:04:34 +0100 Subject: [PATCH 124/237] AboutRegex missing from collector Fixes #81 --- python2/runner/path_to_enlightenment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python2/runner/path_to_enlightenment.py b/python2/runner/path_to_enlightenment.py index a81faa4d4..21758bcec 100644 --- a/python2/runner/path_to_enlightenment.py +++ b/python2/runner/path_to_enlightenment.py @@ -88,5 +88,6 @@ def koans(): suite.addTests(loader.loadTestsFromTestCase(AboutProxyObjectProject)) suite.addTests(loader.loadTestsFromTestCase(TelevisionTest)) suite.addTests(loader.loadTestsFromTestCase(AboutExtraCredit)) + suite.addTests(loader.loadTestsFromTestCase(AboutRegex)) return suite From 7894c4f16673b12a0a0c36ac66f69cd038608d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kiss=20Gy=C3=B6rgy?= Date: Sat, 8 Feb 2014 01:28:57 +0100 Subject: [PATCH 125/237] Makes regex example self explanatory. 20 == `re.DOTALL | re.LOCALE` doesn't makes much sense here and can be confusing for a beginner. also 10 == `re.IGNORECASE | re.MULTILINE` why overcomplicate it when the `string` doesn't even have a newline? --- python2/koans/about_regex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_regex.py b/python2/koans/about_regex.py index 95678d2eb..3a0a57092 100755 --- a/python2/koans/about_regex.py +++ b/python2/koans/about_regex.py @@ -63,8 +63,8 @@ def test_matching_literal_text_not_case_sensitivity(self): 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, 20), __) - self.assertEqual(re.findall("felix", string, 10), __) + self.assertEqual(re.findall("felix", string), __) + self.assertEqual(re.findall("felix", string, re.IGNORECASE), __) def test_matching_any_character(self): """ From c40491c67cfef1c6b74ddacf7c85fe2ff52ae572 Mon Sep 17 00:00:00 2001 From: Daniel Karp Date: Sat, 8 Feb 2014 15:19:27 -0500 Subject: [PATCH 126/237] Fix tuple creation koan --- python3/koans/about_tuples.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_tuples.py b/python3/koans/about_tuples.py index 9833c40c6..76c193395 100644 --- a/python3/koans/about_tuples.py +++ b/python3/koans/about_tuples.py @@ -6,7 +6,7 @@ class AboutTuples(Koan): def test_creating_a_tuple(self): count_of_three = (1, 2, 5) - self.assertEqual(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) From e061bc4fb01c6c072690734957c6b8e29a93d503 Mon Sep 17 00:00:00 2001 From: Daniel Karp Date: Sat, 8 Feb 2014 16:16:05 -0500 Subject: [PATCH 127/237] add example with zero in a string to true_and_false koans --- python2/koans/about_true_and_false.py | 1 + python3/koans/about_true_and_false.py | 1 + 2 files changed, 2 insertions(+) diff --git a/python2/koans/about_true_and_false.py b/python2/koans/about_true_and_false.py index 89250353c..51a6b537f 100644 --- a/python2/koans/about_true_and_false.py +++ b/python2/koans/about_true_and_false.py @@ -39,3 +39,4 @@ def test_everything_else_is_treated_as_true(self): __, self.truth_value("Python is named after Monty Python")) self.assertEqual(__, self.truth_value(' ')) + self.assertEqual(__, self.truth_value('0')) diff --git a/python3/koans/about_true_and_false.py b/python3/koans/about_true_and_false.py index c6585567f..4aa021a4c 100644 --- a/python3/koans/about_true_and_false.py +++ b/python3/koans/about_true_and_false.py @@ -36,3 +36,4 @@ def test_everything_else_is_treated_as_true(self): self.assertEqual(__, self.truth_value(1,)) self.assertEqual(__, self.truth_value("Python is named after Monty Python")) self.assertEqual(__, self.truth_value(' ')) + self.assertEqual(__, self.truth_value('0')) From 287be68d738bf66d17402c4a8f200e2697155ec8 Mon Sep 17 00:00:00 2001 From: gregmalcolm Date: Sun, 9 Feb 2014 20:58:36 -0500 Subject: [PATCH 128/237] Python3 version of suit also needs AboutRegEx in the suite --- python3/runner/path_to_enlightenment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python3/runner/path_to_enlightenment.py b/python3/runner/path_to_enlightenment.py index f1bcb4261..e8a23fa32 100644 --- a/python3/runner/path_to_enlightenment.py +++ b/python3/runner/path_to_enlightenment.py @@ -86,5 +86,6 @@ def koans(): suite.addTests(loader.loadTestsFromTestCase(AboutProxyObjectProject)) suite.addTests(loader.loadTestsFromTestCase(TelevisionTest)) suite.addTests(loader.loadTestsFromTestCase(AboutExtraCredit)) + suite.addTests(loader.loadTestsFromTestCase(AboutRegex)) return suite From 0e90ef724da948fdc2b78239a51fdbff1784cfa3 Mon Sep 17 00:00:00 2001 From: ChuntaoLu Date: Mon, 3 Mar 2014 01:21:33 -0500 Subject: [PATCH 129/237] Fix typo --- python2/koans/about_proxy_object_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_proxy_object_project.py b/python2/koans/about_proxy_object_project.py index 50a949496..4e391bc40 100644 --- a/python2/koans/about_proxy_object_project.py +++ b/python2/koans/about_proxy_object_project.py @@ -13,7 +13,7 @@ # 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 that its Ruby Koans counterpart, but you +# Note: This is a bit trickier than its Ruby Koans counterpart, but you # can do it! from runner.koan import * From 5701789ee8626e968becdb3e915bb5db2df35c06 Mon Sep 17 00:00:00 2001 From: ChuntaoLu Date: Tue, 4 Mar 2014 11:16:42 -0500 Subject: [PATCH 130/237] Fix typo --- python3/koans/about_proxy_object_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_proxy_object_project.py b/python3/koans/about_proxy_object_project.py index 165585849..663a4f633 100644 --- a/python3/koans/about_proxy_object_project.py +++ b/python3/koans/about_proxy_object_project.py @@ -13,7 +13,7 @@ # 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 that its Ruby Koans counterpart, but you +# Note: This is a bit trickier than its Ruby Koans counterpart, but you # can do it! from runner.koan import * From aeae3fd0283b7445063c744c77e88e78796f9804 Mon Sep 17 00:00:00 2001 From: Adam Chainz Date: Thu, 27 Mar 2014 16:26:05 +0000 Subject: [PATCH 131/237] Fix some spelling mistakes --- python2/koans/about_iteration.py | 2 +- python2/koans/about_regex.py | 2 +- python3/koans/about_comprehension.py | 2 +- python3/koans/about_iteration.py | 4 ++-- python3/koans/about_regex.py | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/python2/koans/about_iteration.py b/python2/koans/about_iteration.py index 3b7bfed79..73adc58e9 100644 --- a/python2/koans/about_iteration.py +++ b/python2/koans/about_iteration.py @@ -94,7 +94,7 @@ def test_use_pass_for_iterations_with_no_body(self): # ------------------------------------------------------------------ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): - # Ranges are an iteratable sequence + # Ranges are an iterable sequence result = map(self.add_ten, range(1, 4)) self.assertEqual(__, list(result)) diff --git a/python2/koans/about_regex.py b/python2/koans/about_regex.py index 3a0a57092..f562594e5 100755 --- a/python2/koans/about_regex.py +++ b/python2/koans/about_regex.py @@ -30,7 +30,7 @@ def test_matching_literal_text_how_many(self): """ Lesson 1 -- How many matches? - The default behaviour of most regular extression engines is + The default behaviour of most regular expression engines is to return just the first match. In python you have the following options: diff --git a/python3/koans/about_comprehension.py b/python3/koans/about_comprehension.py index a9762c480..05cb58ec2 100644 --- a/python3/koans/about_comprehension.py +++ b/python3/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) # remeber 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', diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index 037bb2d54..bfed6e028 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -41,7 +41,7 @@ def test_map_transforms_elements_of_a_list(self): self.assertNotEqual(list, mapping.__class__) self.assertEqual(__, mapping.__class__) - # In Python 3 built in iterator funcs return iteratable view objects + # In Python 3 built in iterator funcs return iterable view objects # instead of lists for item in mapping: @@ -116,7 +116,7 @@ def test_use_pass_for_iterations_with_no_body(self): # ------------------------------------------------------------------ def test_all_iteration_methods_work_on_any_sequence_not_just_lists(self): - # Ranges are an iteratable sequence + # Ranges are an iterable sequence result = map(self.add_ten, range(1,4)) self.assertEqual(__, list(result)) diff --git a/python3/koans/about_regex.py b/python3/koans/about_regex.py index eb930644d..a4eb5a162 100644 --- a/python3/koans/about_regex.py +++ b/python3/koans/about_regex.py @@ -22,7 +22,7 @@ def test_matching_literal_text_how_many(self): """ Lesson 1 How many matches? - The default behaviour of most regular extression engines is to return just the first match. + 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. @@ -92,7 +92,7 @@ def test_matching_set_character(self): def test_anything_but_matching(self): """ Lesson 2 Using character set ranges - Occsionally, you'll want a list of characters that you don't want to match. + Occasionally, you'll want a list of characters that you don't want to match. Character sets can be negated using the ^ metacharacter. """ From 3b638dfc7bed3c51b4062e94def8680d1c40b369 Mon Sep 17 00:00:00 2001 From: Adam Chainz Date: Fri, 4 Apr 2014 10:49:27 +0100 Subject: [PATCH 132/237] Python 3 about_regex use the IGNORECASE flag explicitly, not magic numbers --- python3/koans/about_regex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python3/koans/about_regex.py b/python3/koans/about_regex.py index a4eb5a162..ad52e2946 100644 --- a/python3/koans/about_regex.py +++ b/python3/koans/about_regex.py @@ -47,8 +47,8 @@ def test_matching_literal_text_not_case_sensitivity(self): """ string = "Hello, my name is Felix or felix and this koans is based on the Ben's book: Regular Expressions in 10 minutes." - self.assertEqual(re.findall("felix", string, 20), __) - self.assertEqual(re.findall("felix", string, 10), __) + self.assertEqual(re.findall("felix", string), __) + self.assertEqual(re.findall("felix", string, re.IGNORECASE), __) def test_matching_any_character(self): """ From cceafc98d4c1757be4a4292c2a6346e086fc6d4a Mon Sep 17 00:00:00 2001 From: Konstantinos Servis Date: Fri, 2 May 2014 11:45:25 +0200 Subject: [PATCH 133/237] Simplify line counting --- python2/koans/about_with_statements.py | 15 +++------------ python3/koans/about_with_statements.py | 15 +++------------ 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/python2/koans/about_with_statements.py b/python2/koans/about_with_statements.py index 15cfbaf69..08515428b 100644 --- a/python2/koans/about_with_statements.py +++ b/python2/koans/about_with_statements.py @@ -15,10 +15,7 @@ def count_lines(self, file_name): try: f = open(file_name) try: - count = 0 - for line in f.readlines(): - count += 1 - return count + return len(f.readlines()) finally: f.close() except IOError: @@ -86,10 +83,7 @@ def __exit__(self, cls, value, tb): def count_lines2(self, file_name): with self.FileContextManager(file_name) as f: - count = 0 - for line in f.readlines(): - count += 1 - return count + return len(f.readlines()) def test_counting_lines2(self): self.assertEqual(__, self.count_lines2("example_file.txt")) @@ -108,10 +102,7 @@ def test_finding_lines2(self): def count_lines3(self, file_name): with open(file_name) as f: - count = 0 - for line in f.readlines(): - count += 1 - return count + 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/python3/koans/about_with_statements.py b/python3/koans/about_with_statements.py index a224e8264..9d126dd33 100644 --- a/python3/koans/about_with_statements.py +++ b/python3/koans/about_with_statements.py @@ -14,10 +14,7 @@ def count_lines(self, file_name): try: file = open(file_name) try: - count = 0 - for line in file.readlines(): - count += 1 - return count + return len(file.readlines()) finally: file.close() except IOError: @@ -85,10 +82,7 @@ def __exit__(self, cls, value, tb): def count_lines2(self, file_name): with self.FileContextManager(file_name) as file: - count = 0 - for line in file.readlines(): - count += 1 - return count + return len(file.readlines()) def test_counting_lines2(self): self.assertEqual(__, self.count_lines2("example_file.txt")) @@ -107,10 +101,7 @@ def test_finding_lines2(self): def count_lines3(self, file_name): with open(file_name) as file: - count = 0 - for line in file.readlines(): - count += 1 - return count + return len(file.readlines()) def test_open_already_has_its_own_built_in_context_manager(self): self.assertEqual(__, self.count_lines3("example_file.txt")) From 1821699a84858c6f7dc7e1c0f4d8d487cbb57a23 Mon Sep 17 00:00:00 2001 From: Konstantinos Servis Date: Fri, 2 May 2014 11:51:46 +0200 Subject: [PATCH 134/237] Fixed comment --- python3/koans/about_modules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_modules.py b/python3/koans/about_modules.py index cf3af2fe5..721ba2a45 100644 --- a/python3/koans/about_modules.py +++ b/python3/koans/about_modules.py @@ -34,7 +34,7 @@ def test_we_can_import_multiple_items_at_once(self): def test_importing_all_module_attributes_at_once(self): # NOTE Using this module level import declared at the top of this script: - # from .other_local_module import * + # from .another_local_module import * # # Import wildcard cannot be used from within classes or functions From cf8727757580d16acebea2010932bf83f8166895 Mon Sep 17 00:00:00 2001 From: Konstantinos Servis Date: Sat, 3 May 2014 10:56:15 +0200 Subject: [PATCH 135/237] Changed to accommodate implementations that account for degenerate triangles also --- python2/koans/about_triangle_project2.py | 2 +- python3/koans/about_triangle_project2.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python2/koans/about_triangle_project2.py b/python2/koans/about_triangle_project2.py index 6b6184657..ad637f602 100644 --- a/python2/koans/about_triangle_project2.py +++ b/python2/koans/about_triangle_project2.py @@ -16,4 +16,4 @@ def test_illegal_triangles_throw_exceptions(self): self.assertRaises(TriangleError, triangle, 3, 4, -5) self.assertRaises(TriangleError, triangle, 1, 1, 3) - self.assertRaises(TriangleError, triangle, 2, 4, 2) + self.assertRaises(TriangleError, triangle, 2, 5, 2) diff --git a/python3/koans/about_triangle_project2.py b/python3/koans/about_triangle_project2.py index d31dd60a5..83267d082 100644 --- a/python3/koans/about_triangle_project2.py +++ b/python3/koans/about_triangle_project2.py @@ -20,6 +20,6 @@ def test_illegal_triangles_throw_exceptions(self): triangle(1, 1, 3) with self.assertRaises(TriangleError): - triangle(2, 4, 2) + triangle(2, 5, 2) From cef768d1f834816606def66ed9afef42de5345f5 Mon Sep 17 00:00:00 2001 From: Ryan Wiedemann Date: Sun, 18 May 2014 10:13:11 -0600 Subject: [PATCH 136/237] Added test_if_then_elif_else_statements --- python2/koans/about_control_statements.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/python2/koans/about_control_statements.py b/python2/koans/about_control_statements.py index 921f0bf7f..35e6f6a07 100644 --- a/python2/koans/about_control_statements.py +++ b/python2/koans/about_control_statements.py @@ -18,6 +18,16 @@ def test_if_then_statements(self): if True: result = 'true value' self.assertEqual(__, result) + + def test_if_then_elif_else_statements(self): + result = 'default value' + if False: + result = 'first value' + elif True: + result = 'true value' + else: + result = 'default value' + self.assertEqual(__, result) def test_while_statement(self): i = 1 From fc65b52aea3b2448e159942cbcbbee96feed0055 Mon Sep 17 00:00:00 2001 From: Ryan Wiedemann Date: Sun, 18 May 2014 10:17:32 -0600 Subject: [PATCH 137/237] Added test_if_then_elif_else_statements --- python2/koans/about_control_statements.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python2/koans/about_control_statements.py b/python2/koans/about_control_statements.py index 35e6f6a07..38665cb15 100644 --- a/python2/koans/about_control_statements.py +++ b/python2/koans/about_control_statements.py @@ -20,7 +20,6 @@ def test_if_then_statements(self): self.assertEqual(__, result) def test_if_then_elif_else_statements(self): - result = 'default value' if False: result = 'first value' elif True: From d41bd786da4ce006ad872c0dca12f5a1c8e9cfe8 Mon Sep 17 00:00:00 2001 From: Ryan Wiedemann Date: Sun, 18 May 2014 10:24:53 -0600 Subject: [PATCH 138/237] Added test_if_then_elif_else_statements --- python3/koans/about_control_statements.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/python3/koans/about_control_statements.py b/python3/koans/about_control_statements.py index ade8ce22c..3ead55fff 100644 --- a/python3/koans/about_control_statements.py +++ b/python3/koans/about_control_statements.py @@ -17,6 +17,15 @@ 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: + result = 'true value' + else: + result = 'default value' + self.assertEqual(__, result) def test_while_statement(self): i = 1 From 46044593858fc9d5bf8540a73600d7d79e097dc8 Mon Sep 17 00:00:00 2001 From: Nathan Houle Date: Tue, 17 Jun 2014 11:02:33 -0700 Subject: [PATCH 139/237] Fix a few filename/spelling errors --- python2/koans/about_class_attributes.py | 2 +- python2/koans/about_packages.py | 2 +- python3/koans/about_packages.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python2/koans/about_class_attributes.py b/python2/koans/about_class_attributes.py index d48211054..e94b1ae8c 100644 --- a/python2/koans/about_class_attributes.py +++ b/python2/koans/about_class_attributes.py @@ -14,7 +14,7 @@ class Dog(object): def test_new_style_class_objects_are_objects(self): # Note: Old style class instances are not objects but they are being - # phased out it Python 3. + # phased out in Python 3. fido = self.Dog() self.assertEqual(__, isinstance(fido, object)) diff --git a/python2/koans/about_packages.py b/python2/koans/about_packages.py index 99293ebd7..5eeab5945 100644 --- a/python2/koans/about_packages.py +++ b/python2/koans/about_packages.py @@ -56,7 +56,7 @@ def test_use_absolute_imports_to_import_upper_level_modules(self): # contemplate_koans.py is the root module in this package because its # the first python module called in koans. # - # If contemplate_koan.py was based in a_package_folder that would be + # 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. diff --git a/python3/koans/about_packages.py b/python3/koans/about_packages.py index 678de0006..afc6976fb 100644 --- a/python3/koans/about_packages.py +++ b/python3/koans/about_packages.py @@ -48,7 +48,7 @@ def test_use_absolute_imports_to_import_upper_level_modules(self): # contemplate_koans.py is the root module in this package because its # the first python module called in koans. # - # If contemplate_koan.py was based in a_package_folder that would be + # 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. From f44242ec395cfbe2f447497c85c318d17ad43fe4 Mon Sep 17 00:00:00 2001 From: irheart Date: Wed, 9 Jul 2014 00:12:58 +0400 Subject: [PATCH 140/237] about_lists: pop(0) vs popleft() in 2vs3 I've looked for information on this note and haven't been able to find anything of the sort. A brief test in Py3.4.1 also indicates that list.pop(0) vs deque.popleft() performance in Py3 is consistent with Py2. >>> import timeit >>> timeit.timeit('''x = list(range(100000)) while x: x.pop(0) ''', number = 100) 385.9676046228002 >>> timeit.timeit('''x = deque(range(1000000)) while x: x.popleft() ''', setup = 'from collections import deque', number = 100) 17.6067819813139 --- python3/koans/about_lists.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python3/koans/about_lists.py b/python3/koans/about_lists.py index 493953345..d2ae9fd6d 100644 --- a/python3/koans/about_lists.py +++ b/python3/koans/about_lists.py @@ -103,8 +103,6 @@ def test_making_queues(self): self.assertEqual(__, popped_value) self.assertEqual(__, queue) - # Note, for Python 2 popping from the left hand side of a list is + # Note, popping from the left hand side of a list is # inefficient. Use collections.deque instead. - # This is not an issue for Python 3 though - From fccde38d5b6c9865646cf0e8ac2bb3b1bc859ab2 Mon Sep 17 00:00:00 2001 From: Sumana Harihareswara Date: Mon, 27 Oct 2014 13:40:25 -0400 Subject: [PATCH 141/237] grammar fix in about_asserts.py --- python3/koans/about_asserts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_asserts.py b/python3/koans/about_asserts.py index a3d7ce047..ea10ccab5 100644 --- a/python3/koans/about_asserts.py +++ b/python3/koans/about_asserts.py @@ -60,7 +60,7 @@ 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 it's class type? + # For example, contemplate the text string "naval". What is its class type? # The koans runner will include this feedback for this koan: # # AssertionError: '-=> FILL ME IN! <=-' != From f629a2ca62886c4bf7d564e4b7b5fa09e5d5756b Mon Sep 17 00:00:00 2001 From: Sumana Harihareswara Date: Fri, 31 Oct 2014 17:49:44 -0400 Subject: [PATCH 142/237] grammar fix in Python 2's about_asserts.py --- python2/koans/about_asserts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/koans/about_asserts.py b/python2/koans/about_asserts.py index 61b53ada1..476458337 100644 --- a/python2/koans/about_asserts.py +++ b/python2/koans/about_asserts.py @@ -62,7 +62,7 @@ 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 it's class type? + # For example, contemplate the text string "naval". What is its class type? # The koans runner will include this feedback for this koan: # # AssertionError: '-=> FILL ME IN! <=-' != From 76944479ce29a011e7148c9d180248f426c40cf8 Mon Sep 17 00:00:00 2001 From: Haoming Zhu Date: Tue, 25 Nov 2014 10:40:22 +0800 Subject: [PATCH 143/237] fix run.bat/run.sh, don't write .py[co] files on import. --- python2/run.bat | 4 ++-- python2/run.sh | 4 ++-- python3/run.bat | 4 ++-- python3/run.sh | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) mode change 100644 => 100755 python2/run.bat mode change 100644 => 100755 python3/run.bat diff --git a/python2/run.bat b/python2/run.bat old mode 100644 new mode 100755 index b1f704261..e8d1b0f57 --- a/python2/run.bat +++ b/python2/run.bat @@ -2,7 +2,7 @@ REM This is how you run it from the command line. REM You don't actually need this script! -SET RUN_KOANS=python.exe contemplate_koans.py +SET RUN_KOANS=python.exe -B contemplate_koans.py REM Set this to your python folder: SET PYTHON_PATH=C:\Python27 @@ -32,4 +32,4 @@ IF NOT "" == "%SCRIPT%" ( echo python.exe contemplate_koans.py pause ) -:end \ No newline at end of file +:end diff --git a/python2/run.sh b/python2/run.sh index fda73be7d..1fdcb7a99 100755 --- a/python2/run.sh +++ b/python2/run.sh @@ -1,7 +1,7 @@ #!/bin/sh if [ -x /usr/bin/python2 ]; then - python2 contemplate_koans.py + python2 -B contemplate_koans.py else - python contemplate_koans.py + python -B contemplate_koans.py fi diff --git a/python3/run.bat b/python3/run.bat old mode 100644 new mode 100755 index e5c86c361..68d7b9b8e --- a/python3/run.bat +++ b/python3/run.bat @@ -2,10 +2,10 @@ REM This is how you run it from the command line. REM You don't actually need this script! -SET RUN_KOANS=python.exe contemplate_koans.py +SET RUN_KOANS=python.exe -B contemplate_koans.py REM Set this to your python folder: -SET PYTHON_PATH=C:\Python33 +SET PYTHON_PATH=C:\Python34 set SCRIPT= REM Hunt around for python diff --git a/python3/run.sh b/python3/run.sh index 987b4cdd3..eb978ce78 100755 --- a/python3/run.sh +++ b/python3/run.sh @@ -1,4 +1,4 @@ #!/bin/sh -python3 contemplate_koans.py +python3 -B contemplate_koans.py From d72940cd22f33750664d25de125a74514cd1644d Mon Sep 17 00:00:00 2001 From: Thibaud Colas Date: Thu, 11 Dec 2014 15:09:45 +1300 Subject: [PATCH 144/237] Fix #98. Exclude extra credit from lesson_pass_count. --- python2/runner/sensei.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python2/runner/sensei.py b/python2/runner/sensei.py index 5b5cd937d..ecb450600 100644 --- a/python2/runner/sensei.py +++ b/python2/runner/sensei.py @@ -33,7 +33,7 @@ def startTest(self, test): self.stream.writeln() self.stream.writeln("{0}{1}Thinking {2}".format( Fore.RESET, Style.NORMAL, helper.cls_name(test))) - if helper.cls_name(test) != 'AboutAsserts': + if helper.cls_name(test) not in ['AboutAsserts', 'AboutExtraCredit']: self.lesson_pass_count += 1 def addSuccess(self, test): From 6aee95a3449b275763322d404738e978108c84ea Mon Sep 17 00:00:00 2001 From: Thibaud Colas Date: Thu, 11 Dec 2014 15:20:26 +1300 Subject: [PATCH 145/237] Exclude extra credit from lesson pass count in python3 version --- python3/runner/sensei.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/runner/sensei.py b/python3/runner/sensei.py index 44eecd7cc..6aeb49608 100644 --- a/python3/runner/sensei.py +++ b/python3/runner/sensei.py @@ -33,7 +33,7 @@ def startTest(self, test): self.stream.writeln() self.stream.writeln("{0}{1}Thinking {2}".format( Fore.RESET, Style.NORMAL, helper.cls_name(test))) - if helper.cls_name(test) != 'AboutAsserts': + if helper.cls_name(test) not in ['AboutAsserts', 'AboutExtraCredit']: self.lesson_pass_count += 1 def addSuccess(self, test): From 0aa5410f91499d8482d944d405519597f195706e Mon Sep 17 00:00:00 2001 From: Charlotte Spencer Date: Sun, 25 Jan 2015 17:23:55 +0000 Subject: [PATCH 146/237] Minor spelling change for about_iteration.py --- python3/koans/about_iteration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python3/koans/about_iteration.py b/python3/koans/about_iteration.py index bfed6e028..c7810545b 100644 --- a/python3/koans/about_iteration.py +++ b/python3/koans/about_iteration.py @@ -49,7 +49,7 @@ def test_map_transforms_elements_of_a_list(self): self.assertEqual(__, mapped_seq) - # None, iterator methods actually return objects of iter type in + # Note, iterator methods actually return objects of iter type in # python 3. In python 2 map() would give you a list. def test_filter_selects_certain_items_from_a_list(self): From 3663c8629a16d2791bfd6eaabbd9461d9d731ee2 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sun, 19 Apr 2015 17:49:56 -0700 Subject: [PATCH 147/237] 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 148/237] 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 149/237] 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 150/237] 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 151/237] 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 152/237] 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 153/237] 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 154/237] 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 155/237] 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 156/237] 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 157/237] 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 158/237] 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 159/237] 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 160/237] 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 161/237] 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 162/237] 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 163/237] 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 164/237] 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 165/237] 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 166/237] 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 167/237] 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 168/237] 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 169/237] 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 170/237] 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 171/237] 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 172/237] 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 173/237] 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 174/237] 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 175/237] 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 176/237] 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 177/237] 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 178/237] 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 179/237] 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 180/237] 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 181/237] 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 182/237] 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 183/237] 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 184/237] 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 185/237] 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 186/237] 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 187/237] 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 188/237] 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 189/237] 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 190/237] 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 191/237] 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 192/237] 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 193/237] 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 194/237] 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 195/237] 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 196/237] 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 197/237] 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 198/237] 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 199/237] 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 200/237] 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 201/237] 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 202/237] 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 203/237] 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 204/237] 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 205/237] 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 206/237] 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 207/237] 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 208/237] 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 209/237] 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 210/237] 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 211/237] 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 212/237] 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 213/237] 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 214/237] 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 215/237] 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 216/237] 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 217/237] 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 218/237] 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 219/237] 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 220/237] 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 221/237] 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 222/237] 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 223/237] 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 224/237] 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 225/237] 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 226/237] 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 227/237] 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 228/237] 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 229/237] 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 230/237] 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 231/237] 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 232/237] 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 233/237] 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 234/237] 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 235/237] 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 236/237] 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 237/237] 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')