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/.travis.yml b/.travis.yml index 1f94c3610..e8f7d64ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,9 @@ language: python python: - - 2.7 - - 3.2 - - 3.3 - - 3.4 - - 3.5 + - 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 diff --git a/Contributor Notes.txt b/Contributor Notes.txt index b97fc6aea..c14bb947a 100644 --- a/Contributor Notes.txt +++ b/Contributor Notes.txt @@ -1,4 +1,3 @@ - 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 e3b0a3575..5e57f89fd 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,22 +1,19 @@ -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 ef018c4f6..e2f303fe9 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,23 @@ Python Koans .. image:: https://travis-ci.org/gregmalcolm/python_koans.png?branch=master :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 + +.. image:: https://www.eclipse.org/che/contribute.svg + :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://gitpod.io/#https://github.com/gregmalcolm/python_koans +| or +.. image:: https://gitpod.io/button/open-in-gitpod.svg + :target: https://gitpod.io/#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/. @@ -15,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. @@ -33,15 +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 -It is also mirrored on bitbucket for Mercurial users: - - http://bitbucket.org/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 @@ -50,32 +67,28 @@ 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.1+ +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 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. 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: - 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:\Python27 + SET PYTHON_PATH=C:\Python39 Getting Started @@ -83,20 +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 go to the python -koans\\python_VERSION folder and 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 @@ -106,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 @@ -130,41 +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: - $ pip install pyinotify +.. code-block:: sh -On Windows:: + python3 -m pip install pyinotify - $ pip install pywin32 - -(If that failed, try:: - - $ pip install pypiwin32 -) +On Windows: + +.. code-block:: sh + + python3 -m pip install pywin32 + + Also available here: + + https://github.com/mhammond/pywin32/releases + +On macOS: + +.. code-block:: sh -On Mac OS X:: + 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 @@ -175,33 +203,28 @@ 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: 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 --------------- @@ -213,4 +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 diff --git a/python2/_runner_tests.py b/_runner_tests.py similarity index 100% rename from python2/_runner_tests.py rename to _runner_tests.py diff --git a/python3/contemplate_koans.py b/contemplate_koans.py similarity index 82% rename from python3/contemplate_koans.py rename to contemplate_koans.py index b7d35d4b3..ddf992388 100644 --- a/python3/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/python2/example_file.txt b/example_file.txt similarity index 100% rename from python2/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/python2/koans/GREEDS_RULES.txt b/koans/GREEDS_RULES.txt similarity index 100% rename from python2/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/python2/koans/a_package_folder/__init__.py b/koans/a_package_folder/__init__.py similarity index 100% rename from python2/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 80% rename from python3/koans/about_iteration.py rename to koans/about_iteration.py index d232d07b8..1faca8e33 100644 --- a/python3/koans/about_iteration.py +++ b/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 test_filter_returns_all_items_matching_criterion(self): def is_big_name(item): - return len(item) > 4 - - names = ["Jim", "Bill", "Clarence", "Doug", "Eli"] - name = None + 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() 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 83% rename from python3/koans/about_list_assignments.py rename to koans/about_list_assignments.py index d32d89911..8a8d48090 100644 --- a/python3/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) 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/python2/koans/about_regex.py b/koans/about_regex.py old mode 100755 new mode 100644 similarity index 100% rename from python2/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 94% rename from python3/koans/about_scoring_project.py rename to koans/about_scoring_project.py index 2bd06c418..0fd055de2 100644 --- a/python3/koans/about_scoring_project.py +++ b/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])) 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/python2/koans/about_true_and_false.py b/koans/about_true_and_false.py similarity index 100% rename from python2/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 96% rename from python3/koans/about_tuples.py rename to koans/about_tuples.py index 2d65ea8f1..1b38c8f7f 100644 --- a/python3/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') 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/python2/libs/__init__.py b/libs/__init__.py similarity index 100% rename from python2/libs/__init__.py rename to libs/__init__.py diff --git a/python2/libs/colorama/LICENSE-colorama b/libs/colorama/LICENSE-colorama similarity index 100% rename from python2/libs/colorama/LICENSE-colorama rename to libs/colorama/LICENSE-colorama diff --git a/python2/libs/colorama/__init__.py b/libs/colorama/__init__.py similarity index 100% rename from python2/libs/colorama/__init__.py rename to libs/colorama/__init__.py diff --git a/python2/libs/colorama/ansi.py b/libs/colorama/ansi.py similarity index 100% rename from python2/libs/colorama/ansi.py rename to libs/colorama/ansi.py diff --git a/python2/libs/colorama/ansitowin32.py b/libs/colorama/ansitowin32.py similarity index 100% rename from python2/libs/colorama/ansitowin32.py rename to libs/colorama/ansitowin32.py diff --git a/python2/libs/colorama/initialise.py b/libs/colorama/initialise.py similarity index 100% rename from python2/libs/colorama/initialise.py rename to libs/colorama/initialise.py diff --git a/python2/libs/colorama/win32.py b/libs/colorama/win32.py similarity index 100% rename from python2/libs/colorama/win32.py rename to libs/colorama/win32.py diff --git a/python2/libs/colorama/winterm.py b/libs/colorama/winterm.py similarity index 100% rename from python2/libs/colorama/winterm.py rename to libs/colorama/winterm.py diff --git a/python2/libs/mock.py b/libs/mock.py similarity index 100% rename from python2/libs/mock.py rename to libs/mock.py 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/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/__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/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. - - # --