From 37c7ee1d941b32868d554895b7cf79d844066924 Mon Sep 17 00:00:00 2001 From: "Kevin J. Chase" Date: Fri, 21 Jul 2017 19:01:31 -0400 Subject: [PATCH 01/54] 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 02/54] 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 03/54] 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 04/54] 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 05/54] 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 06/54] 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 07/54] 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 08/54] 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 09/54] 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 10/54] 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 11/54] 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 12/54] 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 13/54] 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 14/54] 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 15/54] 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 16/54] 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 17/54] 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 18/54] 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 19/54] 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 20/54] 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 21/54] 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 -#