From f9765ef19034d39ed0bf8e49656be9ebc003273d Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 13 Oct 2017 10:55:31 -0500 Subject: [PATCH 01/14] (WIP) error-handling: implement exercise From 04f385b78a076220ac2cd2bb130e6b7682c9a3e8 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 13 Oct 2017 11:02:34 -0500 Subject: [PATCH 02/14] error-handling: update config.json --- config.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config.json b/config.json index 83c94e441e..348ae504d6 100644 --- a/config.json +++ b/config.json @@ -854,6 +854,16 @@ "conditionals" ] }, + { + "uuid": "3a2a947a-01b3-1e80-e32b-de1756fd88365adf12e", + "slug": "error-handling", + "core": false, + "unlocked_by": null, + "difficulty": 3, + "topics": [ + "exception handling" + ] + }, { "uuid": "e7351e8e-d3ff-4621-b818-cd55cf05bffd", "slug": "accumulate", From b1c2967cee8306d94b106fb6f67bdb6c44d6464f Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 13 Oct 2017 11:03:44 -0500 Subject: [PATCH 03/14] error-handling: add README --- exercises/error-handling/README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 exercises/error-handling/README.md diff --git a/exercises/error-handling/README.md b/exercises/error-handling/README.md new file mode 100644 index 0000000000..9039642454 --- /dev/null +++ b/exercises/error-handling/README.md @@ -0,0 +1,27 @@ +# Error Handling + +Implement various kinds of error handling and resource management. + +An important point of programming is how to handle errors and close +resources even if errors occur. + +This exercise requires you to handle various errors. Because error handling +is rather programming language specific you'll have to refer to the tests +for your track to see what's exactly required. + +### Submitting Exercises + +Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/` directory. + +For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit /python/bob/bob.py`. + + +For more detailed information about running tests, code style and linting, +please see the [help page](http://exercism.io/languages/python). + +## Source + +Problem 6 at Project Euler [http://projecteuler.net/problem=6](http://projecteuler.net/problem=6) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. From 135cdb7f16372978774acf06d4da556d0a7a7db7 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 13 Oct 2017 11:18:33 -0500 Subject: [PATCH 04/14] error-handling: add solution template --- exercises/error-handling/error_handling.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 exercises/error-handling/error_handling.py diff --git a/exercises/error-handling/error_handling.py b/exercises/error-handling/error_handling.py new file mode 100644 index 0000000000..f34ccee1cf --- /dev/null +++ b/exercises/error-handling/error_handling.py @@ -0,0 +1,14 @@ +def handle_error_by_throwing_exception(): + pass + + +def handle_error_by_returning_none(input_data): + pass + + +def handle_error_by_returning_tuple(input_data): + pass + + +def filelike_objects_are_closed_on_exception(filelike_object): + pass From e8e0ae1968e82468c7d590c37bd5b2ce0b767057 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 13 Oct 2017 11:18:51 -0500 Subject: [PATCH 05/14] error-handling: write test cases --- .../error-handling/error_handling_test.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 exercises/error-handling/error_handling_test.py diff --git a/exercises/error-handling/error_handling_test.py b/exercises/error-handling/error_handling_test.py new file mode 100644 index 0000000000..1436b2f35f --- /dev/null +++ b/exercises/error-handling/error_handling_test.py @@ -0,0 +1,46 @@ +import unittest + +import error_handling as er + + +class FileLike(object): + def __init__(self): + self.is_open = False + + def open(self): + self.is_open = True + + def close(self): + self.is_open = False + + +class ErrorHandlingTest(unittest.TestCase): + def test_throw_exception(self): + with self.assertRaises(Exception): + er.handle_error_by_throwing_exception() + + def test_return_none(self): + self.assertEqual(1, er.handle_error_by_returning_none('1'), + 'Result of valid input should not be None') + self.assertNone(er.handle_error_by_returning_none('a'), + 'Result of invalid input should be None') + + def test_return_tuple(self): + successful_result, result = er.handle_error_by_returning_tuple('1') + self.assertTrue(successful_result, 'Valid input should be successful') + self.assertEqual(1, result, 'Result of valid input should not be None') + + failure_result, result = er.handle_error_by_returning_tuple('a') + self.assertFalse(failure_result, + 'Invalid input should not be successful') + + def test_filelike_objects_are_closed_on_exception(self): + filelike_object = FileLike() + filelike_object.open() + with self.assertRaises(BaseException): + er.filelike_objects_are_closed_on_exception(filelike_object) + self.assertFalse(filelike_object.is_open) + + +if __name__ == '__main__': + unittest.main() From 2a75c7949da2cc34189140c4829f4b06d70b42b3 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 13 Oct 2017 11:31:52 -0500 Subject: [PATCH 06/14] write example solution --- .../error-handling/error_handling_test.py | 10 +++++++-- exercises/error-handling/example.py | 22 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 exercises/error-handling/example.py diff --git a/exercises/error-handling/error_handling_test.py b/exercises/error-handling/error_handling_test.py index 1436b2f35f..0103431531 100644 --- a/exercises/error-handling/error_handling_test.py +++ b/exercises/error-handling/error_handling_test.py @@ -10,9 +10,15 @@ def __init__(self): def open(self): self.is_open = True + def __enter__(self): + self.is_open = True + def close(self): self.is_open = False + def __exit__(self): + self.is_open = False + class ErrorHandlingTest(unittest.TestCase): def test_throw_exception(self): @@ -22,7 +28,7 @@ def test_throw_exception(self): def test_return_none(self): self.assertEqual(1, er.handle_error_by_returning_none('1'), 'Result of valid input should not be None') - self.assertNone(er.handle_error_by_returning_none('a'), + self.assertIsNone(er.handle_error_by_returning_none('a'), 'Result of invalid input should be None') def test_return_tuple(self): @@ -37,7 +43,7 @@ def test_return_tuple(self): def test_filelike_objects_are_closed_on_exception(self): filelike_object = FileLike() filelike_object.open() - with self.assertRaises(BaseException): + with self.assertRaises(Exception): er.filelike_objects_are_closed_on_exception(filelike_object) self.assertFalse(filelike_object.is_open) diff --git a/exercises/error-handling/example.py b/exercises/error-handling/example.py new file mode 100644 index 0000000000..837f678380 --- /dev/null +++ b/exercises/error-handling/example.py @@ -0,0 +1,22 @@ +def handle_error_by_throwing_exception(): + raise Exception() + + +def handle_error_by_returning_none(input_data): + try: + return int(input_data) + except ValueError: + return None + + +def handle_error_by_returning_tuple(input_data): + try: + return (True, int(input_data)) + except ValueError: + return (False, None) + + +def filelike_objects_are_closed_on_exception(filelike_object): + with filelike_object: + filelike_object.close() + raise Exception() From 2c9575a74575b2174de6c455747c016931f4aa7f Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Fri, 13 Oct 2017 11:34:30 -0500 Subject: [PATCH 07/14] error-handling: fixes for flake8 compliance --- exercises/error-handling/error_handling_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/error-handling/error_handling_test.py b/exercises/error-handling/error_handling_test.py index 0103431531..d80b06a0b0 100644 --- a/exercises/error-handling/error_handling_test.py +++ b/exercises/error-handling/error_handling_test.py @@ -29,7 +29,7 @@ def test_return_none(self): self.assertEqual(1, er.handle_error_by_returning_none('1'), 'Result of valid input should not be None') self.assertIsNone(er.handle_error_by_returning_none('a'), - 'Result of invalid input should be None') + 'Result of invalid input should be None') def test_return_tuple(self): successful_result, result = er.handle_error_by_returning_tuple('1') From 6543fcd05bf91af74842fcb918076c45450cd3fc Mon Sep 17 00:00:00 2001 From: cmccandless Date: Sat, 21 Oct 2017 10:35:13 -0500 Subject: [PATCH 08/14] error-handling: change topics to snake_case --- config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json b/config.json index 348ae504d6..577c95bfd2 100644 --- a/config.json +++ b/config.json @@ -861,7 +861,7 @@ "unlocked_by": null, "difficulty": 3, "topics": [ - "exception handling" + "exception_handling" ] }, { From 6adccdea1905fcc6a8d83037d54482cb8ff4b0e9 Mon Sep 17 00:00:00 2001 From: cmccandless Date: Sat, 21 Oct 2017 10:55:09 -0500 Subject: [PATCH 09/14] error-handling: remove incorrect Source section --- exercises/error-handling/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/exercises/error-handling/README.md b/exercises/error-handling/README.md index 9039642454..94adb62aea 100644 --- a/exercises/error-handling/README.md +++ b/exercises/error-handling/README.md @@ -19,9 +19,5 @@ For example, if you're submitting `bob.py` for the Bob exercise, the submit comm For more detailed information about running tests, code style and linting, please see the [help page](http://exercism.io/languages/python). -## Source - -Problem 6 at Project Euler [http://projecteuler.net/problem=6](http://projecteuler.net/problem=6) - ## Submitting Incomplete Solutions It's possible to submit an incomplete solution so you can see how others have completed the exercise. From 68b8f22c75fbbd5a83c8a426eb4fdf99d41e5e0a Mon Sep 17 00:00:00 2001 From: cmccandless Date: Sat, 21 Oct 2017 11:08:01 -0500 Subject: [PATCH 10/14] error-handling: improve use of context manager --- .../error-handling/error_handling_test.py | 23 +++++++++++++++---- exercises/error-handling/example.py | 7 ++++-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/exercises/error-handling/error_handling_test.py b/exercises/error-handling/error_handling_test.py index d80b06a0b0..dff2baf391 100644 --- a/exercises/error-handling/error_handling_test.py +++ b/exercises/error-handling/error_handling_test.py @@ -6,18 +6,26 @@ class FileLike(object): def __init__(self): self.is_open = False + self.was_open = False + self.did_something = False def open(self): - self.is_open = True - - def __enter__(self): + self.was_open = False self.is_open = True def close(self): self.is_open = False + self.was_open = True + + def __enter__(self): + self.open() def __exit__(self): - self.is_open = False + self.close() + + def do_something(self): + self.did_something = True + raise Exception() class ErrorHandlingTest(unittest.TestCase): @@ -45,7 +53,12 @@ def test_filelike_objects_are_closed_on_exception(self): filelike_object.open() with self.assertRaises(Exception): er.filelike_objects_are_closed_on_exception(filelike_object) - self.assertFalse(filelike_object.is_open) + self.assertFalse(filelike_object.is_open, + 'filelike_object should be closed') + self.assertTrue(filelike_object.was_open, + 'filelike_object should have been opened') + self.assertTrue(filelike_object.did_something, + 'filelike_object should call did_something()') if __name__ == '__main__': diff --git a/exercises/error-handling/example.py b/exercises/error-handling/example.py index 837f678380..ba146f1306 100644 --- a/exercises/error-handling/example.py +++ b/exercises/error-handling/example.py @@ -18,5 +18,8 @@ def handle_error_by_returning_tuple(input_data): def filelike_objects_are_closed_on_exception(filelike_object): with filelike_object: - filelike_object.close() - raise Exception() + try: + filelike_object.do_something() + except Exception: + filelike_object.close() + raise From 24c7f7947905443ecce2203f509ef5e1d981b377 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Mon, 23 Oct 2017 12:00:06 -0500 Subject: [PATCH 11/14] error-handling: further improve context manager implementation --- exercises/error-handling/error_handling_test.py | 6 +++--- exercises/error-handling/example.py | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/exercises/error-handling/error_handling_test.py b/exercises/error-handling/error_handling_test.py index dff2baf391..f44525c4ef 100644 --- a/exercises/error-handling/error_handling_test.py +++ b/exercises/error-handling/error_handling_test.py @@ -19,8 +19,9 @@ def close(self): def __enter__(self): self.open() + return self - def __exit__(self): + def __exit__(self, *args): self.close() def do_something(self): @@ -50,7 +51,6 @@ def test_return_tuple(self): def test_filelike_objects_are_closed_on_exception(self): filelike_object = FileLike() - filelike_object.open() with self.assertRaises(Exception): er.filelike_objects_are_closed_on_exception(filelike_object) self.assertFalse(filelike_object.is_open, @@ -58,7 +58,7 @@ def test_filelike_objects_are_closed_on_exception(self): self.assertTrue(filelike_object.was_open, 'filelike_object should have been opened') self.assertTrue(filelike_object.did_something, - 'filelike_object should call did_something()') + 'filelike_object should call do_something()') if __name__ == '__main__': diff --git a/exercises/error-handling/example.py b/exercises/error-handling/example.py index ba146f1306..b882423e39 100644 --- a/exercises/error-handling/example.py +++ b/exercises/error-handling/example.py @@ -17,9 +17,8 @@ def handle_error_by_returning_tuple(input_data): def filelike_objects_are_closed_on_exception(filelike_object): - with filelike_object: + with filelike_object as fobj: try: - filelike_object.do_something() - except Exception: - filelike_object.close() - raise + fobj.do_something() + finally: + fobj.close() From bc7eb8889f6a1f402d2429c4aa364216ef485efc Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Mon, 23 Oct 2017 14:00:09 -0500 Subject: [PATCH 12/14] error-handling: remove redundant error handling inside "with" --- exercises/error-handling/example.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/exercises/error-handling/example.py b/exercises/error-handling/example.py index b882423e39..8544114809 100644 --- a/exercises/error-handling/example.py +++ b/exercises/error-handling/example.py @@ -18,7 +18,4 @@ def handle_error_by_returning_tuple(input_data): def filelike_objects_are_closed_on_exception(filelike_object): with filelike_object as fobj: - try: - fobj.do_something() - finally: - fobj.close() + fobj.do_something() From d01e63ea322f918cac6108e941619f2e3ec456e6 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Tue, 24 Oct 2017 11:16:47 -0500 Subject: [PATCH 13/14] error-handling: replace assertTrue and assertFalse with assertIs --- .../error-handling/error_handling_test.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/exercises/error-handling/error_handling_test.py b/exercises/error-handling/error_handling_test.py index f44525c4ef..de4ab41a4d 100644 --- a/exercises/error-handling/error_handling_test.py +++ b/exercises/error-handling/error_handling_test.py @@ -42,23 +42,24 @@ def test_return_none(self): def test_return_tuple(self): successful_result, result = er.handle_error_by_returning_tuple('1') - self.assertTrue(successful_result, 'Valid input should be successful') + self.assertIs(True, successful_result, + 'Valid input should be successful') self.assertEqual(1, result, 'Result of valid input should not be None') failure_result, result = er.handle_error_by_returning_tuple('a') - self.assertFalse(failure_result, - 'Invalid input should not be successful') + self.assertIs(False, failure_result, + 'Invalid input should not be successful') def test_filelike_objects_are_closed_on_exception(self): filelike_object = FileLike() with self.assertRaises(Exception): er.filelike_objects_are_closed_on_exception(filelike_object) - self.assertFalse(filelike_object.is_open, - 'filelike_object should be closed') - self.assertTrue(filelike_object.was_open, - 'filelike_object should have been opened') - self.assertTrue(filelike_object.did_something, - 'filelike_object should call do_something()') + self.assertIs(False, filelike_object.is_open, + 'filelike_object should be closed') + self.assertIs(True, filelike_object.was_open, + 'filelike_object should have been opened') + self.assertIs(True, filelike_object.did_something, + 'filelike_object should call do_something()') if __name__ == '__main__': From 55b13a2d22d50cf4c12051b6150351c1ec55b0b6 Mon Sep 17 00:00:00 2001 From: Corey McCandless Date: Tue, 24 Oct 2017 11:56:52 -0500 Subject: [PATCH 14/14] error-handling: conform to parameter order convention --- exercises/error-handling/error_handling_test.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/exercises/error-handling/error_handling_test.py b/exercises/error-handling/error_handling_test.py index de4ab41a4d..b29bbfa050 100644 --- a/exercises/error-handling/error_handling_test.py +++ b/exercises/error-handling/error_handling_test.py @@ -35,30 +35,30 @@ def test_throw_exception(self): er.handle_error_by_throwing_exception() def test_return_none(self): - self.assertEqual(1, er.handle_error_by_returning_none('1'), + self.assertEqual(er.handle_error_by_returning_none('1'), 1, 'Result of valid input should not be None') self.assertIsNone(er.handle_error_by_returning_none('a'), 'Result of invalid input should be None') def test_return_tuple(self): successful_result, result = er.handle_error_by_returning_tuple('1') - self.assertIs(True, successful_result, + self.assertIs(successful_result, True, 'Valid input should be successful') - self.assertEqual(1, result, 'Result of valid input should not be None') + self.assertEqual(result, 1, 'Result of valid input should not be None') failure_result, result = er.handle_error_by_returning_tuple('a') - self.assertIs(False, failure_result, + self.assertIs(failure_result, False, 'Invalid input should not be successful') def test_filelike_objects_are_closed_on_exception(self): filelike_object = FileLike() with self.assertRaises(Exception): er.filelike_objects_are_closed_on_exception(filelike_object) - self.assertIs(False, filelike_object.is_open, + self.assertIs(filelike_object.is_open, False, 'filelike_object should be closed') - self.assertIs(True, filelike_object.was_open, + self.assertIs(filelike_object.was_open, True, 'filelike_object should have been opened') - self.assertIs(True, filelike_object.did_something, + self.assertIs(filelike_object.did_something, True, 'filelike_object should call do_something()')