From 65a78c502c3954b3e4aeb474733d104d14d5da46 Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 15:20:42 -0700 Subject: [PATCH 1/9] Tests mostly written; helper generator finished. Now on function itself. --- parenthetic/README.md | 0 parenthetic/parenthetics.py | 31 +++++++++++++ parenthetic/test_parenthetics.py | 76 ++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 parenthetic/README.md create mode 100644 parenthetic/parenthetics.py create mode 100644 parenthetic/test_parenthetics.py diff --git a/parenthetic/README.md b/parenthetic/README.md new file mode 100644 index 0000000..e69de29 diff --git a/parenthetic/parenthetics.py b/parenthetic/parenthetics.py new file mode 100644 index 0000000..800206b --- /dev/null +++ b/parenthetic/parenthetics.py @@ -0,0 +1,31 @@ +from __future__ import unicode_literals +from random import choice as choice + +def generate_parenthetical_iterable(string): + """ + Take a string and return an ordered iterable with only the "(" and ")" + characters remaining + """ + set_to_find = ["(", ")"] #Defining a filter + characters = tuple(string) #Turning characters into an iterable + + for character in characters: + if character in set_to_find: + yield character + + + +# def parenthetical(string): +# """ +# Examine a string for closed, open, and well-formed parentheses; +# return a -1, 1, and 0 respectively. + +# It might be helpful to recall that parenthesis is of greek etymology; +# parenthesis is singular, parentheses plural. +# """ + +# parentheses = generate_parenthetical_iterable(string) + + +# for parenthesis in parentheses: + diff --git a/parenthetic/test_parenthetics.py b/parenthetic/test_parenthetics.py new file mode 100644 index 0000000..8f28d6d --- /dev/null +++ b/parenthetic/test_parenthetics.py @@ -0,0 +1,76 @@ +from __future__ import unicode_literals +import pytest +from parenthetics import parenthetical + + +#Case that should return -1 +broken_case = [ + ")))(((" + ")()", + ")))", + "()()()()(()))", + ")", + "()()(()()()()", + "()()()()()))(()))()(((()"] + + +#Case that should return 1 +open_case = [ + "()(", + "()()()(", + "((()()", + "()()(", + "()()()((", + "()()(((()()()" +] + + +#Case that should return 0 +okay_case = [ + "()()()()", + "(())", + "((()())()()())" +] + + +#Types that should fail with TypeError +bad_types = [ + 0, + None, + 5.32324, + {1: 123123, "a": 45243}, + [1, 2, 3, 4, 5] +] + +def test_broken_case_via_assert(broken_case=broken_case): + """ + Testing a set of arguments that should return -1 + """ + for case in broken_case: + assert parenthetical(case) == -1 + + +def test_open_case_via_assert(open_case=open_case): + """ + Testing a set of arguments that should return 1 + """ + for case in open_case: + assert parenthetical(case) == 1 + + +def test_okay_case_via_assert(okay_case=okay_case): + """ + Testing a set of arguments that should return 1 + """ + for case in okay_case: + assert parenthetical(case) == 1 + + +def test_bad_types(bad_types=bad_types): + """ + Testing types that are not currently supported by parenthetical; + these will raise TypeError + """ + + #TODO: Increase robustness of above cases by interposing random unicode + #characters exclusive of "(" and ")" using a random generator \ No newline at end of file From bb15d80c4067b42ed7f8b00c71c648ca7dd100aa Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 15:38:32 -0700 Subject: [PATCH 2/9] Functions filled out; still reshaping to pass tests --- parenthetic/parenthetics.py | 30 +++++++++++++++++++++--------- parenthetic/test_parenthetics.py | 6 ++++-- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/parenthetic/parenthetics.py b/parenthetic/parenthetics.py index 800206b..f3d4db9 100644 --- a/parenthetic/parenthetics.py +++ b/parenthetic/parenthetics.py @@ -15,17 +15,29 @@ def generate_parenthetical_iterable(string): -# def parenthetical(string): -# """ -# Examine a string for closed, open, and well-formed parentheses; -# return a -1, 1, and 0 respectively. +def parenthetical(string): + """ + Examine a string for closed, open, and well-formed parentheses; + return a -1, 1, and 0 respectively. -# It might be helpful to recall that parenthesis is of greek etymology; -# parenthesis is singular, parentheses plural. -# """ + It might be helpful to recall that parenthesis is of greek etymology; + parenthesis is singular, parentheses plural. + """ -# parentheses = generate_parenthetical_iterable(string) + parentheses = generate_parenthetical_iterable(string) + # Score will help us keep track of parentheses state as we iterate; + # also will allow us to short-circuit out of for loop for open parenthesis + score = 0 -# for parenthesis in parentheses: + for parenthesis in parentheses: + if parenthesis is ")": + score -= 1 + if score < 0: + # An open parenthesis exists. No need to check further. + return -1 + else: + # Parenthesis is "(" here + score += 1 + return score diff --git a/parenthetic/test_parenthetics.py b/parenthetic/test_parenthetics.py index 8f28d6d..fbd5f9f 100644 --- a/parenthetic/test_parenthetics.py +++ b/parenthetic/test_parenthetics.py @@ -63,7 +63,7 @@ def test_okay_case_via_assert(okay_case=okay_case): Testing a set of arguments that should return 1 """ for case in okay_case: - assert parenthetical(case) == 1 + assert parenthetical(case) == 0 def test_bad_types(bad_types=bad_types): @@ -71,6 +71,8 @@ def test_bad_types(bad_types=bad_types): Testing types that are not currently supported by parenthetical; these will raise TypeError """ - + for bad_type in bad_types: + with pytest.raises(TypeError): + parenthetical(bad_type) #TODO: Increase robustness of above cases by interposing random unicode #characters exclusive of "(" and ")" using a random generator \ No newline at end of file From 024a7f4acf6e97bd312f51426c192f9e34113deb Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 16:08:03 -0700 Subject: [PATCH 3/9] All tests pass; tis' good. Will soon add readme. Tests could be bolstered --- parenthetic/parenthetics.py | 19 ++++++++++++++++--- parenthetic/test_parenthetics.py | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/parenthetic/parenthetics.py b/parenthetic/parenthetics.py index f3d4db9..84a1f3d 100644 --- a/parenthetic/parenthetics.py +++ b/parenthetic/parenthetics.py @@ -1,11 +1,18 @@ from __future__ import unicode_literals from random import choice as choice +from abc import types +import math def generate_parenthetical_iterable(string): """ Take a string and return an ordered iterable with only the "(" and ")" characters remaining """ + # Using an abstract base class to "goose-type" check; + # this is an intentional part of the Python language. See README.md + if not isinstance(string, types.StringTypes): + raise TypeError + set_to_find = ["(", ")"] #Defining a filter characters = tuple(string) #Turning characters into an iterable @@ -31,13 +38,19 @@ def parenthetical(string): score = 0 for parenthesis in parentheses: - if parenthesis is ")": + if parenthesis == ")": score -= 1 if score < 0: # An open parenthesis exists. No need to check further. - return -1 + break else: # Parenthesis is "(" here score += 1 - return score + if score in set([1, 0, -1]): + # Score can be directly returned in some cases + return score + + else: + # Else use copysign to transfer sign of score to 1 + return math.copysign(1, score) diff --git a/parenthetic/test_parenthetics.py b/parenthetic/test_parenthetics.py index fbd5f9f..9e163fc 100644 --- a/parenthetic/test_parenthetics.py +++ b/parenthetic/test_parenthetics.py @@ -10,7 +10,7 @@ ")))", "()()()()(()))", ")", - "()()(()()()()", + "()()())()()()()", "()()()()()))(()))()(((()"] From 0208fd54391ab3209c22904bba18cf50e169013e Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 16:12:00 -0700 Subject: [PATCH 4/9] Better tests: added random symbols to test cases to double check robustness --- parenthetic/test_parenthetics.py | 34 +++++++++++++++----------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/parenthetic/test_parenthetics.py b/parenthetic/test_parenthetics.py index 9e163fc..3dbe63d 100644 --- a/parenthetic/test_parenthetics.py +++ b/parenthetic/test_parenthetics.py @@ -5,31 +5,31 @@ #Case that should return -1 broken_case = [ - ")))(((" - ")()", - ")))", - "()()()()(()))", - ")", - "()()())()()()()", - "()()()()()))(()))()(((()"] + "))sdf)as((43215(" + ")tqw()3", + "345a)))", + "eq()()q()hq()(hqre[][][]{()))", + ")dfh", + "ehu{()()())()()()()", + "({})()()()()))asdg(())asgwq)()321t5(((()12fds"] #Case that should return 1 open_case = [ - "()(", - "()()()(", - "((()()", - "()()(", - "()()()((", - "()()(((()()()" + "!@#^$#&(324643)(", + "()asdgw()(@!#&^$#&)(", + "13246((()asd()oigo", + "$@*-=()()(", + "(qy1235)()(qwet)((", + "()()((3461(()25()153()145" ] #Case that should return 0 okay_case = [ - "()()()()", - "(())", - "((()())()()())" + "(1266)()32164()!$#^%@&()|||", + "((qwet)qwet)", + "(52135(()1231())()q143265123()())" ] @@ -74,5 +74,3 @@ def test_bad_types(bad_types=bad_types): for bad_type in bad_types: with pytest.raises(TypeError): parenthetical(bad_type) - #TODO: Increase robustness of above cases by interposing random unicode - #characters exclusive of "(" and ")" using a random generator \ No newline at end of file From bb02fd2bd007ff8f0a222ba6868e8cfd5edf64b5 Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 16:24:58 -0700 Subject: [PATCH 5/9] README should be done now --- parenthetic/README.md | 29 +++++++++++++++++++++++++++++ parenthetic/test_parenthetics.py | 12 +++++------- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/parenthetic/README.md b/parenthetic/README.md index e69de29..dc76565 100644 --- a/parenthetic/README.md +++ b/parenthetic/README.md @@ -0,0 +1,29 @@ +#Parenthetics +Parenthetics includes an eponymous function which takes a string +argument and determines whether or not it has bron + +##Illustrative +###Case One: Broken Parentheses + +All of the following will return -1 +''' +)))((( +) +()()()()()))(()))()(((() +''' +###Case Two: Open Parentheses + +All of the following will return 1 +''' +()( +()()()( +()()(((()()() +''' + +###Case Three: Okay Parentheses +''' +All of the following will return 0 +()()()() +(()) +((()())()()()) +''' \ No newline at end of file diff --git a/parenthetic/test_parenthetics.py b/parenthetic/test_parenthetics.py index 3dbe63d..5e9b696 100644 --- a/parenthetic/test_parenthetics.py +++ b/parenthetic/test_parenthetics.py @@ -3,7 +3,7 @@ from parenthetics import parenthetical -#Case that should return -1 +# Case that should return -1 broken_case = [ "))sdf)as((43215(" ")tqw()3", @@ -13,8 +13,7 @@ "ehu{()()())()()()()", "({})()()()()))asdg(())asgwq)()321t5(((()12fds"] - -#Case that should return 1 +# Case that should return 1 open_case = [ "!@#^$#&(324643)(", "()asdgw()(@!#&^$#&)(", @@ -24,16 +23,14 @@ "()()((3461(()25()153()145" ] - -#Case that should return 0 +# Case that should return 0 okay_case = [ "(1266)()32164()!$#^%@&()|||", "((qwet)qwet)", "(52135(()1231())()q143265123()())" ] - -#Types that should fail with TypeError +# Types that should fail with TypeError bad_types = [ 0, None, @@ -42,6 +39,7 @@ [1, 2, 3, 4, 5] ] + def test_broken_case_via_assert(broken_case=broken_case): """ Testing a set of arguments that should return -1 From 26860d98caea294743c2e970d8920b6ac15ece59 Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 16:27:01 -0700 Subject: [PATCH 6/9] didn't save README last time; here it is now --- parenthetic/README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/parenthetic/README.md b/parenthetic/README.md index dc76565..90097a7 100644 --- a/parenthetic/README.md +++ b/parenthetic/README.md @@ -26,4 +26,18 @@ All of the following will return 0 ()()()() (()) ((()())()()()) -''' \ No newline at end of file +''' + +##Helpful Resources +All of the following were helpful in constructing this code: +* +* [Filtering using a set constructor] +(http://stackoverflow.com/questions/3013449/list-filtering-list-comprehension-vs-lambda-filter) +* [Why isn't there a sign function in Python?] +(http://stackoverflow.com/questions/1986152/why-python-doesnt-have-a-sign-function) +* [Goose-typing is intended in Python] +(https://docs.python.org/2/glossary.html#term-abstract-base-class) + +The "goose typing" coin was termed in an amusing little article by +Alex Martelli included as part of Luciano Rahmalho's Fluent Python. +I'm tempted to do a lightining talk on it. \ No newline at end of file From cc64a2ee6e71df3ea661676057ab86a0f0dfa8a0 Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 16:32:41 -0700 Subject: [PATCH 7/9] more README changes --- parenthetic/README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/parenthetic/README.md b/parenthetic/README.md index 90097a7..e5a7dad 100644 --- a/parenthetic/README.md +++ b/parenthetic/README.md @@ -2,35 +2,37 @@ Parenthetics includes an eponymous function which takes a string argument and determines whether or not it has bron -##Illustrative +##Illustrative Examples of functionality +These are all simplified examples. Any unicode characters can be +intersperced into any of the following. + ###Case One: Broken Parentheses All of the following will return -1 -''' +``` )))((( ) ()()()()()))(()))()(((() -''' +``` ###Case Two: Open Parentheses All of the following will return 1 -''' +``` ()( ()()()( ()()(((()()() -''' +``` ###Case Three: Okay Parentheses -''' +``` All of the following will return 0 ()()()() (()) ((()())()()()) -''' +``` ##Helpful Resources All of the following were helpful in constructing this code: -* * [Filtering using a set constructor] (http://stackoverflow.com/questions/3013449/list-filtering-list-comprehension-vs-lambda-filter) * [Why isn't there a sign function in Python?] From c8d95e5087bac9b3dc41f0cdc415db5d38d2cd10 Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 16:35:59 -0700 Subject: [PATCH 8/9] more README changes, again --- parenthetic/README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/parenthetic/README.md b/parenthetic/README.md index e5a7dad..824f0e3 100644 --- a/parenthetic/README.md +++ b/parenthetic/README.md @@ -8,27 +8,27 @@ intersperced into any of the following. ###Case One: Broken Parentheses -All of the following will return -1 +All of the following arguments will return -1: ``` -)))((( -) -()()()()()))(()))()(((() +>>> parenthetical("))))(((") +>>> parenthetical(")") +>>> parenthetical("()()()()()))(()))()(((()") ``` ###Case Two: Open Parentheses -All of the following will return 1 +All of the following will return 1: ``` -()( -()()()( -()()(((()()() +>>> parenthetical("()(") +>>> parenthetical("()()()(") +>>> parenthetical("()()(((()()()") ``` ###Case Three: Okay Parentheses +All of the following will return 0: ``` -All of the following will return 0 -()()()() -(()) -((()())()()()) +>>> parenthetical("()()()()") +>>> parenthetical("(())") +>>> parenthetical("((()())()()())") ``` ##Helpful Resources From 4df0f92c656f1c0fb830eedfb581d249b7f08df9 Mon Sep 17 00:00:00 2001 From: Jason Tyler Date: Sun, 28 Jun 2015 16:37:31 -0700 Subject: [PATCH 9/9] more README changes, again --- parenthetic/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/parenthetic/README.md b/parenthetic/README.md index 824f0e3..c591c56 100644 --- a/parenthetic/README.md +++ b/parenthetic/README.md @@ -1,6 +1,7 @@ #Parenthetics Parenthetics includes an eponymous function which takes a string -argument and determines whether or not it has bron +argument and determines whether or not it has broken, open, or well-formed +parentheses. ##Illustrative Examples of functionality These are all simplified examples. Any unicode characters can be