From 282e3dabb0e4ce20decd2efa47bd41e3f254604e Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Mon, 12 Nov 2018 18:18:07 +0300 Subject: [PATCH 01/26] Initial commit --- expression.py | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ expression1.py | 90 ++++++++++++++++++++++++++++++++++++++ test.py | 15 +++++++ 3 files changed, 220 insertions(+) create mode 100644 expression.py create mode 100644 expression1.py create mode 100644 test.py diff --git a/expression.py b/expression.py new file mode 100644 index 0000000..3dca715 --- /dev/null +++ b/expression.py @@ -0,0 +1,115 @@ +#!/usr/bin/python3 + + +class BaseExpressionException(Exception): + pass + + +class NoExpressionException(BaseExpressionException): + pass + + +class BracketsAreNotBalanced(BaseExpressionException): + pass + + +class Element: + + def __init__(self, expression): + if not expression: + raise NoExpressionException("The expression was not passed") + + self._expression = [] + + bracket_level = 0 + item = [] + + for i in expression: + if i == "(": + bracket_level += 1 + if bracket_level == 1: + continue + + elif i == ")": + bracket_level -= 1 + if bracket_level == 0: + if item: + self._expression.append(Element("".join(item))) + item.clear() + continue + + if bracket_level > 0: + item.append(i) + else: + if i in ["+", "-", "*", "/", "%", "^"]: + if item: + self._expression.append(float("".join(item))) + item.clear() + self._expression.append(i) + else: + item.append(i) + + if item: + self._expression.append(float("".join(item))) + + if bracket_level != 0: + raise BracketsAreNotBalanced() + + def __str__(self): + result = [] + for i in self._expression: + result.append(str(i)) + return "{cls_name}{{{data}}}".format( + cls_name=self.__class__.__name__, + data=", ".join(result) + ) + + def value(self): + new_expression = [] + operation = None + + # Calculate high priority math operations + for i in self._expression: + if i in ("*", "/", "%", "//",): + operation = i + elif operation: + if operation == "*": + new_expression[-1] *= i + elif operation == "/": + new_expression[-1] /= i + elif operation == "%": + new_expression[-1] %= i + elif operation == "//": + new_expression[-1] //= i + operation = None + else: + new_expression.append(i) + + self._expression = new_expression + + # Calculate low priority math operations + + value = 0 + action = None + + for i in self._expression: + if i in ("+", "-",): + action = i + elif action: + if action == "+": + value += i + elif action == "-": + value -= i + action = None + else: + value = i + return value + + +if __name__ == '__main__': + expr = Element("-9/2+5*2") + + print(str(expr)) + print(expr.value()) + print(str(expr)) + print(expr.value()) diff --git a/expression1.py b/expression1.py new file mode 100644 index 0000000..772d258 --- /dev/null +++ b/expression1.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 + + +class BaseExpressionException(Exception): + pass + + +class NoExpressionException(BaseExpressionException): + pass + + +class BracketsAreNotBalanced(BaseExpressionException): + pass + + +class Element: + + def __init__(self, expression): + if not expression: + raise NoExpressionException("The expression was not passed") + + self._expression = [] + + bracket_level = 0 + item = [] + + for i in expression: + if i == "(": + bracket_level += 1 + if bracket_level == 1: + continue + + elif i == ")": + bracket_level -= 1 + if bracket_level == 0: + if item: + self._expression.append(Element("".join(item))) + item.clear() + continue + + if bracket_level > 0: + item.append(i) + else: + if i in ["+", "-", "*", "/", "%", "^"]: + if item: + self._expression.append(float("".join(item))) + item.clear() + self._expression.append(i) + + else: + item.append(i) + + if item: + self._expression.append(float("".join(item))) + + if bracket_level != 0: + raise BracketsAreNotBalanced() + + def __str__(self): + result = [] + for i in self._expression: + result.append(str(i)) + return "{cls_name}{{{data}}}".format( + cls_name=self.__class__.__name__, + data=", ".join(result) + ) + + def in_total(self): + new_expression = [] + for i in range(len(self._expression)): + + new_expression.append(i) + if self._expression[i] == "*": + new_expression[-1] = self._expression[i-1]*self._expression[i+1] + i=i+1 + if i == "/": + new_expression[-1] = new_expression[-1]/self._expression[i+1] + + + + + return self._in_total + + +if __name__ == '__main__': + expr = Element("4*2+10/5") + + print(str(expr)) + print(expr.in_total()) + # print(y) \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..0fb875f --- /dev/null +++ b/test.py @@ -0,0 +1,15 @@ +#!/usr/bin/python3 + + +# def in_total(self): +Element = "4/2+10*5" +new_expression = [] +for i in Element: + while i != "*": + new_expression.append(i) + if i == "*": + new_expression[-1] = new_expression[-1] * Element[ 1] + print(Element[i+1]) + print((new_expression)) + + From 3e737b4e6dcec41104e9443b83f08ce4f3aea745 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Mon, 12 Nov 2018 18:45:51 +0300 Subject: [PATCH 02/26] [BUGFIX] Fix issue with first minus sign Signed-off-by: Elena Volkova --- expression.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/expression.py b/expression.py index 3dca715..8909773 100644 --- a/expression.py +++ b/expression.py @@ -13,6 +13,10 @@ class BracketsAreNotBalanced(BaseExpressionException): pass +class DoubleOperationException(BaseExpressionException): + pass + + class Element: def __init__(self, expression): @@ -67,6 +71,11 @@ def __str__(self): def value(self): new_expression = [] operation = None + first_negative = False + + if self._expression[0] == "-": + first_negative = True + del self._expression[0] # Calculate high priority math operations for i in self._expression: @@ -83,6 +92,9 @@ def value(self): new_expression[-1] //= i operation = None else: + if first_negative: + i = -i + first_negative = False new_expression.append(i) self._expression = new_expression @@ -94,6 +106,11 @@ def value(self): for i in self._expression: if i in ("+", "-",): + if action: + raise DoubleOperationException("'{so}' operation follows '{fo}'".format( + so=i, + fo=action + )) action = i elif action: if action == "+": @@ -107,9 +124,9 @@ def value(self): if __name__ == '__main__': - expr = Element("-9/2+5*2") + expr = Element("-9+2") print(str(expr)) print(expr.value()) - print(str(expr)) - print(expr.value()) + # print(str(expr)) + # print(expr.value()) From 0048435376f38c9bc542d3d04977dae367e340dc Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Tue, 13 Nov 2018 14:29:17 +0300 Subject: [PATCH 03/26] [DIVISION AND CONSTRACTION IN THE DEGREE] Realization construction in the degree and division --- expression.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/expression.py b/expression.py index 8909773..f9b5497 100644 --- a/expression.py +++ b/expression.py @@ -27,6 +27,7 @@ def __init__(self, expression): bracket_level = 0 item = [] + act = None for i in expression: if i == "(": @@ -46,13 +47,17 @@ def __init__(self, expression): item.append(i) else: if i in ["+", "-", "*", "/", "%", "^"]: + if i in ("/", "*",): + if act == i: + del self._expression[-1] + i = i * 2 + act = i if item: self._expression.append(float("".join(item))) item.clear() self._expression.append(i) else: item.append(i) - if item: self._expression.append(float("".join(item))) @@ -79,9 +84,16 @@ def value(self): # Calculate high priority math operations for i in self._expression: - if i in ("*", "/", "%", "//",): + if i in ("*", "/", "%", "//", "**",): + if operation: + raise DoubleOperationException("'{so}' operation follows '{fo}'".format( + so=i, + fo=operation + )) operation = i elif operation: + if isinstance(i, Element): + i = i.value() if operation == "*": new_expression[-1] *= i elif operation == "/": @@ -90,6 +102,8 @@ def value(self): new_expression[-1] %= i elif operation == "//": new_expression[-1] //= i + elif operation == "**": + new_expression[-1] **= i operation = None else: if first_negative: @@ -124,7 +138,7 @@ def value(self): if __name__ == '__main__': - expr = Element("-9+2") + expr = Element("-2//3+7") print(str(expr)) print(expr.value()) From 3f957d4e2ddeab096bc6a6bd4eebc5bd35f5cb59 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Thu, 15 Nov 2018 12:40:27 +0300 Subject: [PATCH 04/26] [Fix division and multiplication] Modify functionalit;y --- expression.py | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/expression.py b/expression.py index f9b5497..96edbfb 100644 --- a/expression.py +++ b/expression.py @@ -1,5 +1,7 @@ #!/usr/bin/python3 +import pdb + class BaseExpressionException(Exception): pass @@ -42,7 +44,6 @@ def __init__(self, expression): self._expression.append(Element("".join(item))) item.clear() continue - if bracket_level > 0: item.append(i) else: @@ -51,19 +52,19 @@ def __init__(self, expression): if act == i: del self._expression[-1] i = i * 2 - act = i + act = i if item: self._expression.append(float("".join(item))) item.clear() self._expression.append(i) else: item.append(i) - if item: - self._expression.append(float("".join(item))) - if bracket_level != 0: raise BracketsAreNotBalanced() + if item: + self._expression.append(float("".join(item))) + def __str__(self): result = [] for i in self._expression: @@ -84,6 +85,9 @@ def value(self): # Calculate high priority math operations for i in self._expression: + if isinstance(i, Element): + i = i.value() + print(i) if i in ("*", "/", "%", "//", "**",): if operation: raise DoubleOperationException("'{so}' operation follows '{fo}'".format( @@ -92,8 +96,6 @@ def value(self): )) operation = i elif operation: - if isinstance(i, Element): - i = i.value() if operation == "*": new_expression[-1] *= i elif operation == "/": @@ -119,6 +121,8 @@ def value(self): action = None for i in self._expression: + if isinstance(i, Element): + i = i.value() if i in ("+", "-",): if action: raise DoubleOperationException("'{so}' operation follows '{fo}'".format( @@ -138,9 +142,9 @@ def value(self): if __name__ == '__main__': - expr = Element("-2//3+7") - + expr = Element("((14/7)+2)*(3+5)") + # expr = Element() + print(str(expr)) + print(expr.value()) print(str(expr)) print(expr.value()) - # print(str(expr)) - # print(expr.value()) From 3e341d3a185e03ceedcf1e42e421302480a7f136 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Thu, 15 Nov 2018 17:47:52 +0300 Subject: [PATCH 05/26] [tests] Started unittests implementation --- .gitignore | 5 ++ expression1.py | 90 -------------------------------- libs/__init__.py | 0 expression.py => libs/element.py | 28 +++++----- solve.py | 9 ++++ test.py | 15 ------ tests/__init__.py | 0 tests/test_bracket.py | 10 ++++ tests/test_negatives.py | 11 ++++ tests/test_simple.py | 22 ++++++++ 10 files changed, 72 insertions(+), 118 deletions(-) delete mode 100644 expression1.py create mode 100644 libs/__init__.py rename expression.py => libs/element.py (87%) create mode 100644 solve.py delete mode 100644 test.py create mode 100644 tests/__init__.py create mode 100644 tests/test_bracket.py create mode 100644 tests/test_negatives.py create mode 100644 tests/test_simple.py diff --git a/.gitignore b/.gitignore index d7dc40d..4c1b077 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,15 @@ __pycache__/ # PyCharm files .idea/ +htmlcov/ +__pycache__/ # C extensions *.so +.coverage + +*.pyc # Distribution / packaging .Python build/ diff --git a/expression1.py b/expression1.py deleted file mode 100644 index 772d258..0000000 --- a/expression1.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/python3 - - -class BaseExpressionException(Exception): - pass - - -class NoExpressionException(BaseExpressionException): - pass - - -class BracketsAreNotBalanced(BaseExpressionException): - pass - - -class Element: - - def __init__(self, expression): - if not expression: - raise NoExpressionException("The expression was not passed") - - self._expression = [] - - bracket_level = 0 - item = [] - - for i in expression: - if i == "(": - bracket_level += 1 - if bracket_level == 1: - continue - - elif i == ")": - bracket_level -= 1 - if bracket_level == 0: - if item: - self._expression.append(Element("".join(item))) - item.clear() - continue - - if bracket_level > 0: - item.append(i) - else: - if i in ["+", "-", "*", "/", "%", "^"]: - if item: - self._expression.append(float("".join(item))) - item.clear() - self._expression.append(i) - - else: - item.append(i) - - if item: - self._expression.append(float("".join(item))) - - if bracket_level != 0: - raise BracketsAreNotBalanced() - - def __str__(self): - result = [] - for i in self._expression: - result.append(str(i)) - return "{cls_name}{{{data}}}".format( - cls_name=self.__class__.__name__, - data=", ".join(result) - ) - - def in_total(self): - new_expression = [] - for i in range(len(self._expression)): - - new_expression.append(i) - if self._expression[i] == "*": - new_expression[-1] = self._expression[i-1]*self._expression[i+1] - i=i+1 - if i == "/": - new_expression[-1] = new_expression[-1]/self._expression[i+1] - - - - - return self._in_total - - -if __name__ == '__main__': - expr = Element("4*2+10/5") - - print(str(expr)) - print(expr.in_total()) - # print(y) \ No newline at end of file diff --git a/libs/__init__.py b/libs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/expression.py b/libs/element.py similarity index 87% rename from expression.py rename to libs/element.py index 96edbfb..45053bd 100644 --- a/expression.py +++ b/libs/element.py @@ -1,7 +1,5 @@ #!/usr/bin/python3 -import pdb - class BaseExpressionException(Exception): pass @@ -19,7 +17,12 @@ class DoubleOperationException(BaseExpressionException): pass +class ExpressionFormatException(BaseExpressionException): + pass + + class Element: + MATH_ACTIONS = ("+", "-", "*", "/", "%", "^",) def __init__(self, expression): if not expression: @@ -30,8 +33,15 @@ def __init__(self, expression): bracket_level = 0 item = [] act = None + bracket_closed = False for i in expression: + if bracket_closed: + if i not in self.MATH_ACTIONS and i != ")": + raise ExpressionFormatException("After bracket closed 'math sign' or " + "another bracket close are expected") + bracket_closed = False + if i == "(": bracket_level += 1 if bracket_level == 1: @@ -39,6 +49,7 @@ def __init__(self, expression): elif i == ")": bracket_level -= 1 + bracket_closed = True if bracket_level == 0: if item: self._expression.append(Element("".join(item))) @@ -47,7 +58,7 @@ def __init__(self, expression): if bracket_level > 0: item.append(i) else: - if i in ["+", "-", "*", "/", "%", "^"]: + if i in self.MATH_ACTIONS: if i in ("/", "*",): if act == i: del self._expression[-1] @@ -87,7 +98,6 @@ def value(self): for i in self._expression: if isinstance(i, Element): i = i.value() - print(i) if i in ("*", "/", "%", "//", "**",): if operation: raise DoubleOperationException("'{so}' operation follows '{fo}'".format( @@ -138,13 +148,5 @@ def value(self): action = None else: value = i - return value - -if __name__ == '__main__': - expr = Element("((14/7)+2)*(3+5)") - # expr = Element() - print(str(expr)) - print(expr.value()) - print(str(expr)) - print(expr.value()) + return value diff --git a/solve.py b/solve.py new file mode 100644 index 0000000..3ca6dc0 --- /dev/null +++ b/solve.py @@ -0,0 +1,9 @@ +from libs.element import Element + +if __name__ == '__main__': + expr = Element("(14/7)+(-5)-(15//5)") + # expr = Element() + # print(str(expr)) + # print(expr.value()) + print(str(expr)) + print(expr.value()) diff --git a/test.py b/test.py deleted file mode 100644 index 0fb875f..0000000 --- a/test.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/python3 - - -# def in_total(self): -Element = "4/2+10*5" -new_expression = [] -for i in Element: - while i != "*": - new_expression.append(i) - if i == "*": - new_expression[-1] = new_expression[-1] * Element[ 1] - print(Element[i+1]) - print((new_expression)) - - diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_bracket.py b/tests/test_bracket.py new file mode 100644 index 0000000..e6ea2d3 --- /dev/null +++ b/tests/test_bracket.py @@ -0,0 +1,10 @@ +from unittest import TestCase + +from libs.element import Element + + +class TestBracketsElementSimple(TestCase): + + def test_bracket_calculation(self): + expression = Element(expression="(2+4)/2") + self.assertEqual(expression.value(), 3) diff --git a/tests/test_negatives.py b/tests/test_negatives.py new file mode 100644 index 0000000..444ae3d --- /dev/null +++ b/tests/test_negatives.py @@ -0,0 +1,11 @@ +from unittest import TestCase + +from libs.element import Element, NoExpressionException + + +class TestNegativesElementSimple(TestCase): + + def test_no_expression(self): + with self.assertRaises(NoExpressionException): + expression = Element(expression="") + expression.value() diff --git a/tests/test_simple.py b/tests/test_simple.py new file mode 100644 index 0000000..a0aa1b5 --- /dev/null +++ b/tests/test_simple.py @@ -0,0 +1,22 @@ +from unittest import TestCase + +from libs.element import Element + + +class TestElementSimple(TestCase): + + def test_sum(self): + expression = Element(expression="5+3") + self.assertEqual(expression.value(), 8) + + def test_div(self): + expression = Element(expression="5/2") + self.assertEqual(expression.value(), 2.5) + + def test_double_mod(self): + expression = Element(expression="9//3//3") + self.assertEqual(expression.value(), 1) + + def test_math_operator_priority(self): + expression = Element(expression="5/2+0.1*5") + self.assertEqual(expression.value(), 3) From bfc8d1cf54e455e8b88c33bbb9b9be72e0f77cde Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Sun, 18 Nov 2018 10:28:38 +0300 Subject: [PATCH 06/26] [fixes] Fixed 2 issues Issues: * Double operations of different priorities were ignored * Ignored redundunt closed brackets --- libs/element.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/libs/element.py b/libs/element.py index 45053bd..ac0f0b2 100644 --- a/libs/element.py +++ b/libs/element.py @@ -50,6 +50,8 @@ def __init__(self, expression): elif i == ")": bracket_level -= 1 bracket_closed = True + if bracket_level < 0: + raise BracketsAreNotBalanced("Closed non-opened bracket.") if bracket_level == 0: if item: self._expression.append(Element("".join(item))) @@ -70,6 +72,7 @@ def __init__(self, expression): self._expression.append(i) else: item.append(i) + act = None if bracket_level != 0: raise BracketsAreNotBalanced() @@ -94,16 +97,22 @@ def value(self): first_negative = True del self._expression[0] + # Validate mathematical operations + last_operation = None + for i in self._expression: + if last_operation and i in self.MATH_ACTIONS: + raise DoubleOperationException("'{so}' operation follows '{fo}'".format( + so=last_operation, + fo=i + )) + if i in self.MATH_ACTIONS: + last_operation = i + # Calculate high priority math operations for i in self._expression: if isinstance(i, Element): i = i.value() if i in ("*", "/", "%", "//", "**",): - if operation: - raise DoubleOperationException("'{so}' operation follows '{fo}'".format( - so=i, - fo=operation - )) operation = i elif operation: if operation == "*": @@ -126,26 +135,20 @@ def value(self): self._expression = new_expression # Calculate low priority math operations - value = 0 - action = None + operation = None for i in self._expression: if isinstance(i, Element): i = i.value() if i in ("+", "-",): - if action: - raise DoubleOperationException("'{so}' operation follows '{fo}'".format( - so=i, - fo=action - )) - action = i - elif action: - if action == "+": + operation = i + elif operation: + if operation == "+": value += i - elif action == "-": + elif operation == "-": value -= i - action = None + operation = None else: value = i From 034bae59e0ec61bf706b7c851eb28362ae193b42 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Sun, 18 Nov 2018 11:10:06 +0300 Subject: [PATCH 07/26] [changes] Changed double math operation logic --- libs/element.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/libs/element.py b/libs/element.py index ac0f0b2..51b130c 100644 --- a/libs/element.py +++ b/libs/element.py @@ -32,8 +32,9 @@ def __init__(self, expression): bracket_level = 0 item = [] - act = None + last_mathematical_action = None bracket_closed = False + bracket_content = [] for i in expression: if bracket_closed: @@ -53,26 +54,29 @@ def __init__(self, expression): if bracket_level < 0: raise BracketsAreNotBalanced("Closed non-opened bracket.") if bracket_level == 0: - if item: - self._expression.append(Element("".join(item))) - item.clear() + if bracket_content: + self._expression.append(Element("".join(bracket_content))) + bracket_content.clear() + else: + raise ExpressionFormatException("Empty brackets.") continue if bracket_level > 0: - item.append(i) + bracket_content.append(i) else: if i in self.MATH_ACTIONS: - if i in ("/", "*",): - if act == i: - del self._expression[-1] - i = i * 2 - act = i if item: self._expression.append(float("".join(item))) item.clear() - self._expression.append(i) + + # Handle double mathematical operation + if last_mathematical_action == i: + self._expression[-1] += i + else: + self._expression.append(i) + last_mathematical_action = i else: item.append(i) - act = None + last_mathematical_action = None if bracket_level != 0: raise BracketsAreNotBalanced() From 884e152e6debf31b50dfab9db146c3db6c6fa159 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Sun, 18 Nov 2018 11:14:26 +0300 Subject: [PATCH 08/26] [fix] Fixed mathiematical operations validation --- libs/element.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/element.py b/libs/element.py index 51b130c..1749eef 100644 --- a/libs/element.py +++ b/libs/element.py @@ -111,6 +111,8 @@ def value(self): )) if i in self.MATH_ACTIONS: last_operation = i + else: + last_operation = None # Calculate high priority math operations for i in self._expression: From c820f15ffb6f3fe61f6a3b05e9b0a0b74c24583e Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Sun, 18 Nov 2018 11:15:12 +0300 Subject: [PATCH 09/26] [ut] Added UT's --- solve.py | 11 +++++------ tests/test_negatives.py | 23 ++++++++++++++++++++++- tests/test_simple.py | 12 ++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) mode change 100644 => 100755 solve.py diff --git a/solve.py b/solve.py old mode 100644 new mode 100755 index 3ca6dc0..cbc4910 --- a/solve.py +++ b/solve.py @@ -1,9 +1,8 @@ +#!/usr/bin/env python3 + from libs.element import Element if __name__ == '__main__': - expr = Element("(14/7)+(-5)-(15//5)") - # expr = Element() - # print(str(expr)) - # print(expr.value()) - print(str(expr)) - print(expr.value()) + expression = Element(expression="(-2**4)-5*2*3") + print(str(expression)) + print(expression.value()) diff --git a/tests/test_negatives.py b/tests/test_negatives.py index 444ae3d..0626026 100644 --- a/tests/test_negatives.py +++ b/tests/test_negatives.py @@ -1,6 +1,7 @@ from unittest import TestCase -from libs.element import Element, NoExpressionException +from libs.element import Element, NoExpressionException, ExpressionFormatException, BracketsAreNotBalanced, \ + DoubleOperationException class TestNegativesElementSimple(TestCase): @@ -9,3 +10,23 @@ def test_no_expression(self): with self.assertRaises(NoExpressionException): expression = Element(expression="") expression.value() + + def test_format_expression(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="(5+2)4*5") + expression.value() + + def test_brackets_are_not_balanced(self): + with self.assertRaises(BracketsAreNotBalanced): + expression = Element(expression="((8-3)//5*2") + expression.value() + + def test_double_operation(self): + with self.assertRaises(DoubleOperationException): + expression = Element(expression="(3*2)-/6+2") + expression.value() + + def test_first_negative_value(self): + with self.assertRaises(BracketsAreNotBalanced): + expression = Element(expression="(-2)**4)-5*2") + self.assertEqual(expression.value(), -26) diff --git a/tests/test_simple.py b/tests/test_simple.py index a0aa1b5..8910682 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -20,3 +20,15 @@ def test_double_mod(self): def test_math_operator_priority(self): expression = Element(expression="5/2+0.1*5") self.assertEqual(expression.value(), 3) + + def test_mul(self): + expression = Element(expression="5*5-10") + self.assertEqual(expression.value(), 15) + + def test_double_mul(self): + expression = Element(expression="5*5*4") + self.assertEqual(expression.value(), 100) + + def test_modulo(self): + expression = Element(expression="5%3**4") + self.assertEqual(expression.value(), 16) \ No newline at end of file From f6c9ff2be3dfc4d6ef170f2b721129fca674f905 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Sun, 18 Nov 2018 11:25:37 +0300 Subject: [PATCH 10/26] [feature] Added exception handlig for simple mathematical operations --- libs/element.py | 11 +++++++++-- solve.py | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libs/element.py b/libs/element.py index 1749eef..cf8799f 100644 --- a/libs/element.py +++ b/libs/element.py @@ -21,6 +21,10 @@ class ExpressionFormatException(BaseExpressionException): pass +class UnsupportedMathematicalOperationException(ExpressionFormatException): + pass + + class Element: MATH_ACTIONS = ("+", "-", "*", "/", "%", "^",) @@ -147,8 +151,11 @@ def value(self): for i in self._expression: if isinstance(i, Element): i = i.value() - if i in ("+", "-",): - operation = i + if isinstance(i, str): + if i in ("+", "-",): + operation = i + else: + raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(i)) elif operation: if operation == "+": value += i diff --git a/solve.py b/solve.py index cbc4910..86d62eb 100755 --- a/solve.py +++ b/solve.py @@ -3,6 +3,6 @@ from libs.element import Element if __name__ == '__main__': - expression = Element(expression="(-2**4)-5*2*3") + expression = Element(expression="3--2") print(str(expression)) print(expression.value()) From c233d4063dc1d4dd0b687ed5ccec53eba691436f Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Sun, 18 Nov 2018 11:47:52 +0300 Subject: [PATCH 11/26] [CI] Configuring GitLab CI --- gitlab-ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 gitlab-ci.yml diff --git a/gitlab-ci.yml b/gitlab-ci.yml new file mode 100644 index 0000000..abf7d61 --- /dev/null +++ b/gitlab-ci.yml @@ -0,0 +1,8 @@ +image: python:3.6-alpine + +test: + stage: test + script: + - pip install coverage + - coverage run --source=libs -m unittest discover + - coverage report From 4b3fb3a362e7767aa9405249a2470d9ccc7c39ad Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Mon, 19 Nov 2018 15:51:04 +0300 Subject: [PATCH 12/26] [UT] Wreite unit tests with coverage more 95% --- libs/element.py | 4 +++- solve.py | 2 +- tests/test_bracket.py | 2 ++ tests/test_negatives.py | 18 ++++++++++++++---- tests/test_simple.py | 22 ++++++++++++++++++++-- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/libs/element.py b/libs/element.py index cf8799f..9b15448 100644 --- a/libs/element.py +++ b/libs/element.py @@ -123,7 +123,7 @@ def value(self): if isinstance(i, Element): i = i.value() if i in ("*", "/", "%", "//", "**",): - operation = i + operation = i elif operation: if operation == "*": new_expression[-1] *= i @@ -166,3 +166,5 @@ def value(self): value = i return value + + diff --git a/solve.py b/solve.py index 86d62eb..90f1ce0 100755 --- a/solve.py +++ b/solve.py @@ -3,6 +3,6 @@ from libs.element import Element if __name__ == '__main__': - expression = Element(expression="3--2") + expression = Element(expression="2+3*((5-1)-(-2))") print(str(expression)) print(expression.value()) diff --git a/tests/test_bracket.py b/tests/test_bracket.py index e6ea2d3..e475b25 100644 --- a/tests/test_bracket.py +++ b/tests/test_bracket.py @@ -8,3 +8,5 @@ class TestBracketsElementSimple(TestCase): def test_bracket_calculation(self): expression = Element(expression="(2+4)/2") self.assertEqual(expression.value(), 3) + + diff --git a/tests/test_negatives.py b/tests/test_negatives.py index 0626026..a1a0988 100644 --- a/tests/test_negatives.py +++ b/tests/test_negatives.py @@ -1,7 +1,7 @@ from unittest import TestCase from libs.element import Element, NoExpressionException, ExpressionFormatException, BracketsAreNotBalanced, \ - DoubleOperationException + DoubleOperationException, ExpressionFormatException, UnsupportedMathematicalOperationException class TestNegativesElementSimple(TestCase): @@ -26,7 +26,17 @@ def test_double_operation(self): expression = Element(expression="(3*2)-/6+2") expression.value() - def test_first_negative_value(self): + def test_empty_bracket(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="(2+4)/()") + expression.value() + + def test_unsupported_operation(self): + with self.assertRaises(UnsupportedMathematicalOperationException): + expression = Element(expression="10--4*3") + expression.value() + + def test_brackets_are_not_balanced_second(self): with self.assertRaises(BracketsAreNotBalanced): - expression = Element(expression="(-2)**4)-5*2") - self.assertEqual(expression.value(), -26) + expression = Element(expression="8-3)//5*2") + expression.value() diff --git a/tests/test_simple.py b/tests/test_simple.py index 8910682..e773853 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -30,5 +30,23 @@ def test_double_mul(self): self.assertEqual(expression.value(), 100) def test_modulo(self): - expression = Element(expression="5%3**4") - self.assertEqual(expression.value(), 16) \ No newline at end of file + expression = Element(expression="5%3") + self.assertEqual(expression.value(), 2) + + def test_first_negative_value(self): + expression = Element(expression="-2*4-6/2") + self.assertEqual(expression.value(), -11) + + def test_exponentiation(self): + expression = Element(expression="2**3//4") + self.assertEqual(expression.value(), 2) + + def test_nesting_of_elements(self): + expression = Element(expression="2+(3*((5-1)-2))") + self.assertEqual(expression.value(), 8) + + def test_str(self): + expression = Element(expression="2+3*((5-1)-2)") + self.assertTrue(str(expression), 8) + + From 723aa0f19cefb1b6b138c488d7224ae68a5b6f67 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Tue, 20 Nov 2018 09:42:24 +0300 Subject: [PATCH 13/26] [ut] Finished coverage with UT's --- libs/element.py | 52 +++++++++++++++++++++++++++++-------------- tests/test_bracket.py | 4 ++-- tests/test_simple.py | 2 +- 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/libs/element.py b/libs/element.py index 9b15448..3a3f92b 100644 --- a/libs/element.py +++ b/libs/element.py @@ -26,9 +26,17 @@ class UnsupportedMathematicalOperationException(ExpressionFormatException): class Element: + """ + Base class for parsing and calculation the mathematical expression. + """ + MATH_ACTIONS = ("+", "-", "*", "/", "%", "^",) def __init__(self, expression): + """ + Class constructor + :param expression: mathematical expression as string + """ if not expression: raise NoExpressionException("The expression was not passed") @@ -40,6 +48,11 @@ def __init__(self, expression): bracket_closed = False bracket_content = [] + """ + Check the expression for the number of brackets. Perform the transformation of the expression, + depending on the number of brackets. If brackets an odd number raise exception. Parse the expression into + the components, separate mathematical operations and numbers. And create new expression. + """ for i in expression: if bracket_closed: if i not in self.MATH_ACTIONS and i != ")": @@ -64,6 +77,7 @@ def __init__(self, expression): else: raise ExpressionFormatException("Empty brackets.") continue + if bracket_level > 0: bracket_content.append(i) else: @@ -88,6 +102,10 @@ def __init__(self, expression): self._expression.append(float("".join(item))) def __str__(self): + """ + String representation of the class + :return: string representation of the class + """ result = [] for i in self._expression: result.append(str(i)) @@ -97,33 +115,37 @@ def __str__(self): ) def value(self): + """ + Method for expression calculation + :return: + """ new_expression = [] operation = None first_negative = False - if self._expression[0] == "-": - first_negative = True - del self._expression[0] - - # Validate mathematical operations + # Validate mathematical operations and calculate nested expressions last_operation = None - for i in self._expression: - if last_operation and i in self.MATH_ACTIONS: + for i, v in enumerate(self._expression): + if isinstance(v, Element): + self._expression[i] = v.value() + if last_operation and v in self.MATH_ACTIONS: raise DoubleOperationException("'{so}' operation follows '{fo}'".format( so=last_operation, - fo=i + fo=v )) - if i in self.MATH_ACTIONS: - last_operation = i + if v in self.MATH_ACTIONS: + last_operation = v else: last_operation = None + if self._expression[0] == "-": + first_negative = True + del self._expression[0] + # Calculate high priority math operations for i in self._expression: - if isinstance(i, Element): - i = i.value() if i in ("*", "/", "%", "//", "**",): - operation = i + operation = i elif operation: if operation == "*": new_expression[-1] *= i @@ -149,8 +171,6 @@ def value(self): operation = None for i in self._expression: - if isinstance(i, Element): - i = i.value() if isinstance(i, str): if i in ("+", "-",): operation = i @@ -166,5 +186,3 @@ def value(self): value = i return value - - diff --git a/tests/test_bracket.py b/tests/test_bracket.py index e475b25..a182979 100644 --- a/tests/test_bracket.py +++ b/tests/test_bracket.py @@ -6,7 +6,7 @@ class TestBracketsElementSimple(TestCase): def test_bracket_calculation(self): - expression = Element(expression="(2+4)/2") - self.assertEqual(expression.value(), 3) + expression = Element(expression="(2+8)//2+(6-3)") + self.assertEqual(expression.value(), 8) diff --git a/tests/test_simple.py b/tests/test_simple.py index e773853..2971f1d 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -49,4 +49,4 @@ def test_str(self): expression = Element(expression="2+3*((5-1)-2)") self.assertTrue(str(expression), 8) - + From ca7bf09c5084f323febc9f75348511850e032167 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Wed, 21 Nov 2018 11:11:49 +0300 Subject: [PATCH 14/26] [Documentation] Wreite documentation and coments for class Element --- libs/element.py | 26 +++++++++++++++++++------- solve.py | 2 +- tests/test_bracket.py | 4 +++- tests/test_negatives.py | 5 +++++ tests/test_simple.py | 4 +--- tests/test_sin.py | 10 ++++++++++ 6 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 tests/test_sin.py diff --git a/libs/element.py b/libs/element.py index 3a3f92b..b4e5b6e 100644 --- a/libs/element.py +++ b/libs/element.py @@ -2,32 +2,43 @@ class BaseExpressionException(Exception): + """ Common base class for all exceptions """ pass class NoExpressionException(BaseExpressionException): + """ Class exception for no expression. """ pass class BracketsAreNotBalanced(BaseExpressionException): + """ Class exception for expression when brackets are not balanced. """ pass class DoubleOperationException(BaseExpressionException): + """ Class exception for expression with double operation. """ pass class ExpressionFormatException(BaseExpressionException): + """ Class exception for expression with not correct format. """ pass class UnsupportedMathematicalOperationException(ExpressionFormatException): + """ Class exception for expression with not correct mathematical operations. """ pass class Element: """ - Base class for parsing and calculation the mathematical expression. + Base class for parsing and calculation the mathematical expression. Check the expression for the number of brackets. + Perform the transformation of the expression, depending on the number of brackets. If brackets an odd number raise + exception. Parse the expression into the components, separate mathematical operations and numbers. And create new + expression. Validate format expression. Validate first negative numbers in expression. Validate mathematical + operations and calculate nested expressions. Calculate high priority math operations.Calculate low priority math + operations. """ MATH_ACTIONS = ("+", "-", "*", "/", "%", "^",) @@ -37,6 +48,7 @@ def __init__(self, expression): Class constructor :param expression: mathematical expression as string """ + # Validate on expression and raise exception if not true if not expression: raise NoExpressionException("The expression was not passed") @@ -48,11 +60,7 @@ def __init__(self, expression): bracket_closed = False bracket_content = [] - """ - Check the expression for the number of brackets. Perform the transformation of the expression, - depending on the number of brackets. If brackets an odd number raise exception. Parse the expression into - the components, separate mathematical operations and numbers. And create new expression. - """ + # Validate format expression and raise exception if it is not valid for i in expression: if bracket_closed: if i not in self.MATH_ACTIONS and i != ")": @@ -60,6 +68,7 @@ def __init__(self, expression): "another bracket close are expected") bracket_closed = False + # Validate and count brackets if i == "(": bracket_level += 1 if bracket_level == 1: @@ -78,6 +87,7 @@ def __init__(self, expression): raise ExpressionFormatException("Empty brackets.") continue + # Check number brackets and add value, if bracket_level above zero we are inside brackets if bracket_level > 0: bracket_content.append(i) else: @@ -98,6 +108,7 @@ def __init__(self, expression): if bracket_level != 0: raise BracketsAreNotBalanced() + # Add item after parsing if item: self._expression.append(float("".join(item))) @@ -117,7 +128,7 @@ def __str__(self): def value(self): """ Method for expression calculation - :return: + :return: calculate value """ new_expression = [] operation = None @@ -138,6 +149,7 @@ def value(self): else: last_operation = None + # Validate first negative numbers in expression if self._expression[0] == "-": first_negative = True del self._expression[0] diff --git a/solve.py b/solve.py index 90f1ce0..b27b153 100755 --- a/solve.py +++ b/solve.py @@ -3,6 +3,6 @@ from libs.element import Element if __name__ == '__main__': - expression = Element(expression="2+3*((5-1)-(-2))") + expression = Element(expression="sin(5-1)") print(str(expression)) print(expression.value()) diff --git a/tests/test_bracket.py b/tests/test_bracket.py index a182979..6132738 100644 --- a/tests/test_bracket.py +++ b/tests/test_bracket.py @@ -9,4 +9,6 @@ def test_bracket_calculation(self): expression = Element(expression="(2+8)//2+(6-3)") self.assertEqual(expression.value(), 8) - + def test_nesting_of_elements_in_brackets(self): + expression = Element(expression="2+(3*((5-1)-2))") + self.assertEqual(expression.value(), 8) diff --git a/tests/test_negatives.py b/tests/test_negatives.py index a1a0988..97b75a7 100644 --- a/tests/test_negatives.py +++ b/tests/test_negatives.py @@ -40,3 +40,8 @@ def test_brackets_are_not_balanced_second(self): with self.assertRaises(BracketsAreNotBalanced): expression = Element(expression="8-3)//5*2") expression.value() + + def test_first_negative_value_bad_format(self): + with self.assertRaises(UnsupportedMathematicalOperationException): + expression = Element(expression="--2*4-6/2") + expression.value() diff --git a/tests/test_simple.py b/tests/test_simple.py index 2971f1d..8a7d848 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -41,9 +41,7 @@ def test_exponentiation(self): expression = Element(expression="2**3//4") self.assertEqual(expression.value(), 2) - def test_nesting_of_elements(self): - expression = Element(expression="2+(3*((5-1)-2))") - self.assertEqual(expression.value(), 8) + def test_str(self): expression = Element(expression="2+3*((5-1)-2)") diff --git a/tests/test_sin.py b/tests/test_sin.py new file mode 100644 index 0000000..b6a3057 --- /dev/null +++ b/tests/test_sin.py @@ -0,0 +1,10 @@ +from unittest import TestCase + +from libs.element import Element + + +# class TestSinElement(TestCase): +# +# def test_sin(self): +# expression = Element(expression="sin(30)") +# self.assertEqual(expression.value(), 8) From 8796cfed637dcee0ae365bd48702bfac35258ddf Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Fri, 23 Nov 2018 17:51:49 +0300 Subject: [PATCH 15/26] [func] Add calculation of the math functions --- libs/element.py | 33 ++++++++++++++++++++++++++++++--- solve.py | 2 +- tests/test_sin.py | 11 ++++++----- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/libs/element.py b/libs/element.py index b4e5b6e..0e41bde 100644 --- a/libs/element.py +++ b/libs/element.py @@ -1,5 +1,7 @@ #!/usr/bin/python3 +import math + class BaseExpressionException(Exception): """ Common base class for all exceptions """ @@ -31,6 +33,11 @@ class UnsupportedMathematicalOperationException(ExpressionFormatException): pass +class UnsupportedMathematicalFunctionException(ExpressionFormatException): + """ Class exception for expression with unsupported mathematical function. """ + pass + + class Element: """ Base class for parsing and calculation the mathematical expression. Check the expression for the number of brackets. @@ -42,8 +49,11 @@ class Element: """ MATH_ACTIONS = ("+", "-", "*", "/", "%", "^",) + MATHEMATICAL_FUNCTIONS = { + "sin": math.sin + } - def __init__(self, expression): + def __init__(self, expression, func=None): """ Class constructor :param expression: mathematical expression as string @@ -52,6 +62,8 @@ def __init__(self, expression): if not expression: raise NoExpressionException("The expression was not passed") + self._func = func + self._expression = [] bracket_level = 0 @@ -81,13 +93,16 @@ def __init__(self, expression): raise BracketsAreNotBalanced("Closed non-opened bracket.") if bracket_level == 0: if bracket_content: - self._expression.append(Element("".join(bracket_content))) + if item: + self._expression.append(Element(expression="".join(bracket_content), func="".join(item))) + item.clear() + else: + self._expression.append(Element("".join(bracket_content))) bracket_content.clear() else: raise ExpressionFormatException("Empty brackets.") continue - # Check number brackets and add value, if bracket_level above zero we are inside brackets if bracket_level > 0: bracket_content.append(i) else: @@ -102,6 +117,7 @@ def __init__(self, expression): else: self._expression.append(i) last_mathematical_action = i + else: item.append(i) last_mathematical_action = None @@ -193,8 +209,19 @@ def value(self): value += i elif operation == "-": value -= i + else: + raise UnsupportedMathematicalOperationException( + "We do not support '{}' operation".format(operation) + ) operation = None else: value = i + if self._func: + math_func = self.MATHEMATICAL_FUNCTIONS.get(self._func) + if math_func: + value = math_func(value) + else: + raise UnsupportedMathematicalFunctionException("We do not support '{}' function".format(self._func)) + return value diff --git a/solve.py b/solve.py index b27b153..0174251 100755 --- a/solve.py +++ b/solve.py @@ -3,6 +3,6 @@ from libs.element import Element if __name__ == '__main__': - expression = Element(expression="sin(5-1)") + expression = Element(expression="sin(3.14/2)") print(str(expression)) print(expression.value()) diff --git a/tests/test_sin.py b/tests/test_sin.py index b6a3057..93b0daf 100644 --- a/tests/test_sin.py +++ b/tests/test_sin.py @@ -1,10 +1,11 @@ +import math from unittest import TestCase from libs.element import Element -# class TestSinElement(TestCase): -# -# def test_sin(self): -# expression = Element(expression="sin(30)") -# self.assertEqual(expression.value(), 8) +class TestSinElement(TestCase): + + def test_sin(self): + expression = Element(expression="sin({})".format(math.pi/2)) + self.assertEqual(expression.value(), 1.0) From 9953fb7489f0a1a06b5ea2f6642a1756a452e099 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Mon, 26 Nov 2018 11:24:29 +0300 Subject: [PATCH 16/26] [TRIGONOMETRIC FUNCTION] Check on trigonometric function --- libs/element.py | 9 ++++++++- tests/test_sin.py | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/libs/element.py b/libs/element.py index 0e41bde..4eebb74 100644 --- a/libs/element.py +++ b/libs/element.py @@ -50,7 +50,14 @@ class Element: MATH_ACTIONS = ("+", "-", "*", "/", "%", "^",) MATHEMATICAL_FUNCTIONS = { - "sin": math.sin + "sin": math.sin, + "cos": math.cos, + "tan": math.tan, + "log": math.log, + "log10": math.log10, + "log2": math.log2, + "abs": math.fabs + } def __init__(self, expression, func=None): diff --git a/tests/test_sin.py b/tests/test_sin.py index 93b0daf..df57e52 100644 --- a/tests/test_sin.py +++ b/tests/test_sin.py @@ -4,8 +4,37 @@ from libs.element import Element -class TestSinElement(TestCase): +class TestTrigonometricFunctionElement(TestCase): def test_sin(self): - expression = Element(expression="sin({})".format(math.pi/2)) + expression = Element(expression="sin({})".format(math.pi / 2)) self.assertEqual(expression.value(), 1.0) + + def test_cos(self): + expression = Element(expression="cos({})".format(math.pi * 2)) + self.assertEqual(expression.value(), 1.0) + + def test_tan(self): + # expression = Element(expression="tan({})".format(math.pi * 3)) + expression = Element(expression="tan(0)") + self.assertEqual(expression.value(), 0) + + def test_log10(self): + # expression = Element(expression="cos({})".format(math.pi / 2)) + expression = Element(expression="log10(1)") + self.assertEqual(expression.value(), 0.0) + + def test_log2(self): + # expression = Element(expression="cos({})".format(math.pi / 2)) + expression = Element(expression="log2(2)") + self.assertEqual(expression.value(), 1.0) + + def test_log(self): + # expression = Element(expression="cos({})".format(math.pi / 2)) + expression = Element(expression="log(1)") + self.assertEqual(expression.value(), 0.0) + + def test_abs(self): + # expression = Element(expression="cos({})".format(math.pi / 2)) + expression = Element(expression="abs(10)") + self.assertEqual(expression.value(), 10.0) From 142d66bc26d7c9c435b5d642877632c088cd6d9d Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Fri, 30 Nov 2018 17:30:49 +0300 Subject: [PATCH 17/26] [base] Implement comparison operations. --- libs/element.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ solve.py | 2 +- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/libs/element.py b/libs/element.py index 4eebb74..df6119b 100644 --- a/libs/element.py +++ b/libs/element.py @@ -49,6 +49,7 @@ class Element: """ MATH_ACTIONS = ("+", "-", "*", "/", "%", "^",) + COMPARISON_OPERATIONS = (">", "<", "=", "!",) MATHEMATICAL_FUNCTIONS = { "sin": math.sin, "cos": math.cos, @@ -78,6 +79,35 @@ def __init__(self, expression, func=None): last_mathematical_action = None bracket_closed = False bracket_content = [] + self._comparison_operation = False + + # Validate expression on comparison operation and raise exception if it is not valid format + previous_is_comparison = False + for i, v in enumerate(expression): + if v in self.COMPARISON_OPERATIONS: + self._comparison_operation = True + if item: + self._expression.append(Element("".join(item))) + item.clear() + + if previous_is_comparison: + self._expression[-1] += v + else: + self._expression.append(v) + + previous_is_comparison = True + else: + previous_is_comparison = False + item.append(v) + + if self._comparison_operation: + if item: + self._expression.append(Element("".join(item))) + return + else: + raise ExpressionFormatException("After comparison operation expression or number are expected") + + item = [] # Validate format expression and raise exception if it is not valid for i in expression: @@ -172,6 +202,36 @@ def value(self): else: last_operation = None + boolean_value = True + if self._comparison_operation: + for i, v in enumerate(self._expression): + if isinstance(v, str): + if v == ">=": + if not self._expression[i - 1] >= self._expression[i + 1]: + boolean_value = False + elif v == "<=": + if not self._expression[i - 1] <= self._expression[i + 1]: + boolean_value = False + elif v == "==": + if not self._expression[i - 1] == self._expression[i + 1]: + boolean_value = False + elif v == "<": + if not self._expression[i - 1] < self._expression[i + 1]: + boolean_value = False + elif v == ">": + if not self._expression[i - 1] > self._expression[i + 1]: + boolean_value = False + elif v in ("!=", "<>",): + if not self._expression[i - 1] != self._expression[i + 1]: + boolean_value = False + else: + raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(v)) + + if not boolean_value: + return boolean_value + + return boolean_value + # Validate first negative numbers in expression if self._expression[0] == "-": first_negative = True diff --git a/solve.py b/solve.py index 0174251..cfd7751 100755 --- a/solve.py +++ b/solve.py @@ -3,6 +3,6 @@ from libs.element import Element if __name__ == '__main__': - expression = Element(expression="sin(3.14/2)") + expression = Element(expression="3+14>=2-1<5+4") print(str(expression)) print(expression.value()) From 647b235c618d2783fbf6559090218f4729656305 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Tue, 4 Dec 2018 18:36:53 +0300 Subject: [PATCH 18/26] Fixed some cases --- libs/element.py | 64 ++++++++++++------- pycalc | 15 +++++ solve.py | 8 --- tests/test_comparison_operation.py | 55 ++++++++++++++++ tests/test_negatives.py | 19 +++++- ...sin.py => test_trigonometric_operation.py} | 5 -- 6 files changed, 127 insertions(+), 39 deletions(-) create mode 100755 pycalc delete mode 100755 solve.py create mode 100644 tests/test_comparison_operation.py rename tests/{test_sin.py => test_trigonometric_operation.py} (74%) diff --git a/libs/element.py b/libs/element.py index df6119b..ac89b4a 100644 --- a/libs/element.py +++ b/libs/element.py @@ -2,6 +2,8 @@ import math +from inspect import getmembers + class BaseExpressionException(Exception): """ Common base class for all exceptions """ @@ -50,16 +52,6 @@ class Element: MATH_ACTIONS = ("+", "-", "*", "/", "%", "^",) COMPARISON_OPERATIONS = (">", "<", "=", "!",) - MATHEMATICAL_FUNCTIONS = { - "sin": math.sin, - "cos": math.cos, - "tan": math.tan, - "log": math.log, - "log10": math.log10, - "log2": math.log2, - "abs": math.fabs - - } def __init__(self, expression, func=None): """ @@ -70,8 +62,17 @@ def __init__(self, expression, func=None): if not expression: raise NoExpressionException("The expression was not passed") - self._func = func + self._mathematical_functions = { + name: val for name, val in getmembers(math) if type(val).__name__ == "builtin_function_or_method" + } + self._mathematical_functions["abs"] = abs + self._mathematical_functions["round"] = round + + self._mathematical_constants = { + name: val for name, val in getmembers(math) if type(val).__name__ == "float" + } + self._func = func self._expression = [] bracket_level = 0 @@ -123,6 +124,7 @@ def __init__(self, expression, func=None): if bracket_level == 1: continue + # Validate and sorted data in brackets elif i == ")": bracket_level -= 1 bracket_closed = True @@ -145,8 +147,11 @@ def __init__(self, expression, func=None): else: if i in self.MATH_ACTIONS: if item: - self._expression.append(float("".join(item))) - item.clear() + item = "".join(item) + if item in self._mathematical_constants: + item = self._mathematical_constants[item] + self._expression.append(float(item)) + item = [] # Handle double mathematical operation if last_mathematical_action == i: @@ -163,7 +168,10 @@ def __init__(self, expression, func=None): # Add item after parsing if item: - self._expression.append(float("".join(item))) + item = "".join(item) + if item in self._mathematical_constants: + item = self._mathematical_constants[item] + self._expression.append(float(item)) def __str__(self): """ @@ -183,7 +191,6 @@ def value(self): Method for expression calculation :return: calculate value """ - new_expression = [] operation = None first_negative = False @@ -202,6 +209,7 @@ def value(self): else: last_operation = None + # Validate on comparison operation boolean_value = True if self._comparison_operation: for i, v in enumerate(self._expression): @@ -237,9 +245,22 @@ def value(self): first_negative = True del self._expression[0] - # Calculate high priority math operations + # Calculate power mathematical operation + self._expression.reverse() + while True: + try: + index = self._expression.index("^") + self._expression.pop(index) + power = self._expression.pop(index - 1) + self._expression[index - 1] **= power + except ValueError: + break + self._expression.reverse() + + # Calculate high priority mathematical operations + new_expression = [] for i in self._expression: - if i in ("*", "/", "%", "//", "**",): + if i in ("*", "/", "%", "//",): operation = i elif operation: if operation == "*": @@ -250,8 +271,6 @@ def value(self): new_expression[-1] %= i elif operation == "//": new_expression[-1] //= i - elif operation == "**": - new_expression[-1] **= i operation = None else: if first_negative: @@ -276,16 +295,13 @@ def value(self): value += i elif operation == "-": value -= i - else: - raise UnsupportedMathematicalOperationException( - "We do not support '{}' operation".format(operation) - ) operation = None else: value = i + # Validate on mathematical function if self._func: - math_func = self.MATHEMATICAL_FUNCTIONS.get(self._func) + math_func = self._mathematical_functions.get(self._func) if math_func: value = math_func(value) else: diff --git a/pycalc b/pycalc new file mode 100755 index 0000000..0e4f105 --- /dev/null +++ b/pycalc @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 + +import argparse +from libs.element import Element + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="") + parser.add_argument("-m MODULE ", "--use-modules", metavar="MODULE...", nargs="?", help="additional modules to use") + parser.add_argument("EXPRESSION", help="expression string to evaluate") + + args = parser.parse_args() + + expression = Element(expression=args.EXPRESSION) + # print(str(expression)) + print(expression.value()) diff --git a/solve.py b/solve.py deleted file mode 100755 index cfd7751..0000000 --- a/solve.py +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env python3 - -from libs.element import Element - -if __name__ == '__main__': - expression = Element(expression="3+14>=2-1<5+4") - print(str(expression)) - print(expression.value()) diff --git a/tests/test_comparison_operation.py b/tests/test_comparison_operation.py new file mode 100644 index 0000000..0b7815e --- /dev/null +++ b/tests/test_comparison_operation.py @@ -0,0 +1,55 @@ + +from unittest import TestCase + +from libs.element import Element + + +class TestComparisonFunctionElement(TestCase): + + def test_more_or_equal(self): + expression = Element(expression="3+14>=2-1") + self.assertEqual(expression.value(), True) + + def test_less_or_equal(self): + expression = Element(expression="2-1<=5+4") + self.assertEqual(expression.value(), True) + + def test_less(self): + expression = Element(expression="2<4") + self.assertEqual(expression.value(), True) + + def test_equal(self): + expression = Element(expression="9==5+4") + self.assertEqual(expression.value(), True) + + def test_more(self): + expression = Element(expression="10>5+4") + self.assertEqual(expression.value(), True) + + def test_not_equal(self): + expression = Element(expression="1!=5") + self.assertEqual(expression.value(), True) + + def test_negative_more_or_equal(self): + expression = Element(expression="3+14>=20-1") + self.assertEqual(expression.value(), False) + + def test_negative_less_or_equal(self): + expression = Element(expression="12-1<=5+4") + self.assertEqual(expression.value(), False) + + def test_negative_less(self): + expression = Element(expression="8<4") + self.assertEqual(expression.value(), False) + + def test_negative_equal(self): + expression = Element(expression="9==5-4") + self.assertEqual(expression.value(), False) + + def test_negative_more(self): + expression = Element(expression="10>5+14") + self.assertEqual(expression.value(), False) + + def test_negative_not_equal(self): + expression = Element(expression="15<>15") + self.assertEqual(expression.value(), False) diff --git a/tests/test_negatives.py b/tests/test_negatives.py index 97b75a7..1d59d11 100644 --- a/tests/test_negatives.py +++ b/tests/test_negatives.py @@ -41,7 +41,22 @@ def test_brackets_are_not_balanced_second(self): expression = Element(expression="8-3)//5*2") expression.value() - def test_first_negative_value_bad_format(self): + def test_comparison_format_exception(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="2*4>") + expression.value() + + def test_unsupported_comparison_operation(self): + with self.assertRaises(UnsupportedMathematicalOperationException): + expression = Element(expression="10<<=4*3") + expression.value() + + def test_unsupported_operation(self): with self.assertRaises(UnsupportedMathematicalOperationException): - expression = Element(expression="--2*4-6/2") + expression = Element(expression="1++5*3") expression.value() + + # def test_unsupported_trigonometric_operation(self): + # with self.assertRaises(UnsupportedMathematicalOperationException): + # expression = Element(expression="erf(10)") + # expression.value() diff --git a/tests/test_sin.py b/tests/test_trigonometric_operation.py similarity index 74% rename from tests/test_sin.py rename to tests/test_trigonometric_operation.py index df57e52..9a34c4c 100644 --- a/tests/test_sin.py +++ b/tests/test_trigonometric_operation.py @@ -15,26 +15,21 @@ def test_cos(self): self.assertEqual(expression.value(), 1.0) def test_tan(self): - # expression = Element(expression="tan({})".format(math.pi * 3)) expression = Element(expression="tan(0)") self.assertEqual(expression.value(), 0) def test_log10(self): - # expression = Element(expression="cos({})".format(math.pi / 2)) expression = Element(expression="log10(1)") self.assertEqual(expression.value(), 0.0) def test_log2(self): - # expression = Element(expression="cos({})".format(math.pi / 2)) expression = Element(expression="log2(2)") self.assertEqual(expression.value(), 1.0) def test_log(self): - # expression = Element(expression="cos({})".format(math.pi / 2)) expression = Element(expression="log(1)") self.assertEqual(expression.value(), 0.0) def test_abs(self): - # expression = Element(expression="cos({})".format(math.pi / 2)) expression = Element(expression="abs(10)") self.assertEqual(expression.value(), 10.0) From 1e35d2b0d7aaa3cb155947deff177f484422248c Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Tue, 4 Dec 2018 19:37:03 +0300 Subject: [PATCH 19/26] [UT] Fixed multivalue function call --- libs/element.py | 139 ++++++++++++++++++++++++++++-------------------- pycalc | 10 ++-- 2 files changed, 86 insertions(+), 63 deletions(-) diff --git a/libs/element.py b/libs/element.py index ac89b4a..46b669a 100644 --- a/libs/element.py +++ b/libs/element.py @@ -59,9 +59,11 @@ def __init__(self, expression, func=None): :param expression: mathematical expression as string """ # Validate on expression and raise exception if not true + expression = expression.replace(" ", "") if not expression: raise NoExpressionException("The expression was not passed") + # TODO: comment self._mathematical_functions = { name: val for name, val in getmembers(math) if type(val).__name__ == "builtin_function_or_method" } @@ -72,7 +74,12 @@ def __init__(self, expression, func=None): name: val for name, val in getmembers(math) if type(val).__name__ == "float" } - self._func = func + self._func = None + if func: + if func not in self._mathematical_functions: + raise UnsupportedMathematicalFunctionException("We do not support '{}' function".format(self._func)) + self._func = self._mathematical_functions.get(func) + self._expression = [] bracket_level = 0 @@ -81,8 +88,9 @@ def __init__(self, expression, func=None): bracket_closed = False bracket_content = [] self._comparison_operation = False + self._multivalue = False - # Validate expression on comparison operation and raise exception if it is not valid format + # Validate expression on comparison operation and raise exception if it has not valid format previous_is_comparison = False for i, v in enumerate(expression): if v in self.COMPARISON_OPERATIONS: @@ -108,9 +116,17 @@ def __init__(self, expression, func=None): else: raise ExpressionFormatException("After comparison operation expression or number are expected") - item = [] + # Look for multivalue expression + if "(" not in expression and ")" not in expression and "," in expression: + if not self._func: + raise ExpressionFormatException("Commas allowed only in function calls.") + parts = expression.split(",") + self._expression = [Element(i) for i in parts] + self._multivalue = True + return # Validate format expression and raise exception if it is not valid + item = [] for i in expression: if bracket_closed: if i not in self.MATH_ACTIONS and i != ")": @@ -186,60 +202,38 @@ def __str__(self): data=", ".join(result) ) - def value(self): - """ - Method for expression calculation - :return: calculate value - """ - operation = None - first_negative = False - - # Validate mathematical operations and calculate nested expressions - last_operation = None - for i, v in enumerate(self._expression): - if isinstance(v, Element): - self._expression[i] = v.value() - if last_operation and v in self.MATH_ACTIONS: - raise DoubleOperationException("'{so}' operation follows '{fo}'".format( - so=last_operation, - fo=v - )) - if v in self.MATH_ACTIONS: - last_operation = v - else: - last_operation = None - - # Validate on comparison operation + def _calculate_boolean_expression(self): boolean_value = True - if self._comparison_operation: - for i, v in enumerate(self._expression): - if isinstance(v, str): - if v == ">=": - if not self._expression[i - 1] >= self._expression[i + 1]: - boolean_value = False - elif v == "<=": - if not self._expression[i - 1] <= self._expression[i + 1]: - boolean_value = False - elif v == "==": - if not self._expression[i - 1] == self._expression[i + 1]: - boolean_value = False - elif v == "<": - if not self._expression[i - 1] < self._expression[i + 1]: - boolean_value = False - elif v == ">": - if not self._expression[i - 1] > self._expression[i + 1]: - boolean_value = False - elif v in ("!=", "<>",): - if not self._expression[i - 1] != self._expression[i + 1]: - boolean_value = False - else: - raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(v)) - - if not boolean_value: - return boolean_value + for i, v in enumerate(self._expression): + if isinstance(v, str): + if v == ">=": + if not self._expression[i - 1] >= self._expression[i + 1]: + boolean_value = False + elif v == "<=": + if not self._expression[i - 1] <= self._expression[i + 1]: + boolean_value = False + elif v == "==": + if not self._expression[i - 1] == self._expression[i + 1]: + boolean_value = False + elif v == "<": + if not self._expression[i - 1] < self._expression[i + 1]: + boolean_value = False + elif v == ">": + if not self._expression[i - 1] > self._expression[i + 1]: + boolean_value = False + elif v in ("!=", "<>",): + if not self._expression[i - 1] != self._expression[i + 1]: + boolean_value = False + else: + raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(v)) - return boolean_value + if not boolean_value: + return boolean_value + return boolean_value + def _calculate_mathematical_expression(self): + operation = None + first_negative = False # Validate first negative numbers in expression if self._expression[0] == "-": first_negative = True @@ -301,10 +295,37 @@ def value(self): # Validate on mathematical function if self._func: - math_func = self._mathematical_functions.get(self._func) - if math_func: - value = math_func(value) - else: - raise UnsupportedMathematicalFunctionException("We do not support '{}' function".format(self._func)) + value = self._func(value) return value + + def value(self): + """ + Method for expression calculation + :return: calculate value + """ + + # Validate mathematical operations and calculate nested expressions + last_operation = None + for i, v in enumerate(self._expression): + if isinstance(v, Element): + self._expression[i] = v.value() + if last_operation and v in self.MATH_ACTIONS: + raise DoubleOperationException("'{so}' operation follows '{fo}'".format( + so=last_operation, + fo=v + )) + if v in self.MATH_ACTIONS: + last_operation = v + else: + last_operation = None + + # Evaluate comparison expression + if self._comparison_operation: + return self._calculate_boolean_expression() + + # Evaluate multi-value expression + if self._multivalue: + return self._func(*self._expression) + + return self._calculate_mathematical_expression() diff --git a/pycalc b/pycalc index 0e4f105..a432ea0 100755 --- a/pycalc +++ b/pycalc @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import argparse -from libs.element import Element +from libs.element import Element, BaseExpressionException if __name__ == '__main__': parser = argparse.ArgumentParser(description="") @@ -10,6 +10,8 @@ if __name__ == '__main__': args = parser.parse_args() - expression = Element(expression=args.EXPRESSION) - # print(str(expression)) - print(expression.value()) + try: + expression = Element(expression=args.EXPRESSION) + print(expression.value()) + except BaseExpressionException as exc: + print("ERROR: {}".format(str(exc))) From c5a9ce7cd1a75ef2e392cb6e798c6127b2dbc8eb Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Wed, 5 Dec 2018 17:57:35 +0300 Subject: [PATCH 20/26] [fix and add logic to pycalc] unary operation and ERRORs --- libs/element.py | 40 ++++++++++++++++++++++++++++++++++------ pycalc | 9 ++++++++- pycalc_checker.py | 2 +- 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/libs/element.py b/libs/element.py index 46b669a..fb6d557 100644 --- a/libs/element.py +++ b/libs/element.py @@ -187,7 +187,10 @@ def __init__(self, expression, func=None): item = "".join(item) if item in self._mathematical_constants: item = self._mathematical_constants[item] - self._expression.append(float(item)) + try: + self._expression.append(float(item)) + except ValueError: + raise ExpressionFormatException("Could not convert string to float: '{}'".format(item)) def __str__(self): """ @@ -234,6 +237,7 @@ def _calculate_boolean_expression(self): def _calculate_mathematical_expression(self): operation = None first_negative = False + # Validate first negative numbers in expression if self._expression[0] == "-": first_negative = True @@ -254,7 +258,7 @@ def _calculate_mathematical_expression(self): # Calculate high priority mathematical operations new_expression = [] for i in self._expression: - if i in ("*", "/", "%", "//",): + if i in ("*", "/", "%", "//", "**"): operation = i elif operation: if operation == "*": @@ -265,6 +269,8 @@ def _calculate_mathematical_expression(self): new_expression[-1] %= i elif operation == "//": new_expression[-1] //= i + elif operation == "**": + raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(i)) operation = None else: if first_negative: @@ -310,11 +316,27 @@ def value(self): for i, v in enumerate(self._expression): if isinstance(v, Element): self._expression[i] = v.value() - if last_operation and v in self.MATH_ACTIONS: + if isinstance(v, str): + if v not in ("<=", ">=", "==", '!=', "**", "//"): + if len(v) > 1: + if len(v) % 2 == 0: + self._expression[i] = "+" + else: + self._expression[i] = "-" + + if last_operation and v in ("+", "-",): + if last_operation == "+" and v == "-": + self._expression[i] = "-" + del self._expression[i - 1] + elif last_operation == "-" and v == "+": + self._expression[i] = "-" + del self._expression[i] + elif last_operation and v in self.MATH_ACTIONS: raise DoubleOperationException("'{so}' operation follows '{fo}'".format( so=last_operation, fo=v )) + if v in self.MATH_ACTIONS: last_operation = v else: @@ -326,6 +348,12 @@ def value(self): # Evaluate multi-value expression if self._multivalue: - return self._func(*self._expression) - - return self._calculate_mathematical_expression() + try: + return self._func(*self._expression) + except TypeError: + raise ExpressionFormatException("Expected 2 arguments, got 3: '{}'".format(self._func)) + + try: + return self._calculate_mathematical_expression() + except TypeError: + raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(i)) diff --git a/pycalc b/pycalc index a432ea0..c75c1d9 100755 --- a/pycalc +++ b/pycalc @@ -6,7 +6,7 @@ from libs.element import Element, BaseExpressionException if __name__ == '__main__': parser = argparse.ArgumentParser(description="") parser.add_argument("-m MODULE ", "--use-modules", metavar="MODULE...", nargs="?", help="additional modules to use") - parser.add_argument("EXPRESSION", help="expression string to evaluate") + parser.add_argument("EXPRESSION", help="expression string to evaluate", type=str) args = parser.parse_args() @@ -15,3 +15,10 @@ if __name__ == '__main__': print(expression.value()) except BaseExpressionException as exc: print("ERROR: {}".format(str(exc))) + # except ValueError as exc: + # print("ERROR: {}".format(str(exc))) + # except TypeError as exc: + # print("ERROR: {}".format(str(exc))) + # expression = Element(expression=args.EXPRESSION) + # print(expression.value()) + # print(expression.booleen_value()) diff --git a/pycalc_checker.py b/pycalc_checker.py index 0b48a2b..c410e0f 100644 --- a/pycalc_checker.py +++ b/pycalc_checker.py @@ -5,7 +5,7 @@ from termcolor import colored -PYCALC_UTIL_NAME = "pycalc" +PYCALC_UTIL_NAME = "./pycalc" RETURN_CODE = 0 From 58547915b29ff863c4c9ee11ac4ce0a61ad788fe Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Wed, 5 Dec 2018 18:30:18 +0300 Subject: [PATCH 21/26] [FIX unittests] fix unittests for comparison operation --- libs/element.py | 2 +- pycalc_checker.py | 2 +- tests/test_negatives.py | 4 ++-- tests/test_simple.py | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/element.py b/libs/element.py index fb6d557..4047654 100644 --- a/libs/element.py +++ b/libs/element.py @@ -317,7 +317,7 @@ def value(self): if isinstance(v, Element): self._expression[i] = v.value() if isinstance(v, str): - if v not in ("<=", ">=", "==", '!=', "**", "//"): + if v not in ("<=", ">=", "==", "!=", "<>", "**", "//"): if len(v) > 1: if len(v) % 2 == 0: self._expression[i] = "+" diff --git a/pycalc_checker.py b/pycalc_checker.py index c410e0f..0b48a2b 100644 --- a/pycalc_checker.py +++ b/pycalc_checker.py @@ -5,7 +5,7 @@ from termcolor import colored -PYCALC_UTIL_NAME = "./pycalc" +PYCALC_UTIL_NAME = "pycalc" RETURN_CODE = 0 diff --git a/tests/test_negatives.py b/tests/test_negatives.py index 1d59d11..3763edc 100644 --- a/tests/test_negatives.py +++ b/tests/test_negatives.py @@ -52,8 +52,8 @@ def test_unsupported_comparison_operation(self): expression.value() def test_unsupported_operation(self): - with self.assertRaises(UnsupportedMathematicalOperationException): - expression = Element(expression="1++5*3") + with self.assertRaises(DoubleOperationException): + expression = Element(expression="1*/5*3") expression.value() # def test_unsupported_trigonometric_operation(self): diff --git a/tests/test_simple.py b/tests/test_simple.py index 8a7d848..7ed6876 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -38,8 +38,8 @@ def test_first_negative_value(self): self.assertEqual(expression.value(), -11) def test_exponentiation(self): - expression = Element(expression="2**3//4") - self.assertEqual(expression.value(), 2) + expression = Element(expression="2*3//2") + self.assertEqual(expression.value(), 3) From c35a88ca9be10e12a5255bee8994bd2294a83937 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Thu, 6 Dec 2018 22:55:53 +0300 Subject: [PATCH 22/26] [fixes] Fixed last crucial cases --- libs/element.py | 184 +++++++++++++++++++++++++++++----------- pycalc | 9 +- pycalc_checker.py | 2 +- tests/test_negatives.py | 52 ++++++++++-- tests/test_simple.py | 20 ++++- 5 files changed, 202 insertions(+), 65 deletions(-) diff --git a/libs/element.py b/libs/element.py index 4047654..091ab07 100644 --- a/libs/element.py +++ b/libs/element.py @@ -59,10 +59,20 @@ def __init__(self, expression, func=None): :param expression: mathematical expression as string """ # Validate on expression and raise exception if not true - expression = expression.replace(" ", "") + + # if " " in expression: + # raise ExpressionFormatException("Expression should not de with spaces") + + # expression = expression.replace(" ", "") + if not expression: raise NoExpressionException("The expression was not passed") + # if expression.startswith("--") or expression.startswith("=") or expression.startswith("+"): + # raise ExpressionFormatException("The expression bad format") + # if expression.endswith("-"): + # raise ExpressionFormatException("The expression bad format") + # TODO: comment self._mathematical_functions = { name: val for name, val in getmembers(math) if type(val).__name__ == "builtin_function_or_method" @@ -76,8 +86,9 @@ def __init__(self, expression, func=None): self._func = None if func: + func = func.strip() if func not in self._mathematical_functions: - raise UnsupportedMathematicalFunctionException("We do not support '{}' function".format(self._func)) + raise UnsupportedMathematicalFunctionException("We do not support '{}' function".format(func)) self._func = self._mathematical_functions.get(func) self._expression = [] @@ -85,7 +96,6 @@ def __init__(self, expression, func=None): bracket_level = 0 item = [] last_mathematical_action = None - bracket_closed = False bracket_content = [] self._comparison_operation = False self._multivalue = False @@ -116,19 +126,32 @@ def __init__(self, expression, func=None): else: raise ExpressionFormatException("After comparison operation expression or number are expected") - # Look for multivalue expression - if "(" not in expression and ")" not in expression and "," in expression: - if not self._func: - raise ExpressionFormatException("Commas allowed only in function calls.") - parts = expression.split(",") - self._expression = [Element(i) for i in parts] - self._multivalue = True + # Look for commas in expression + start_index = 0 + multivalue_items = [] + for i, c in enumerate(expression): + # increase bracket level + if c == "(": + bracket_level += 1 + # decrease bracket level + elif c == ")": + bracket_level -= 1 + elif c == "," and bracket_level == 0: + self._multivalue = True + multivalue_items.append(Element(expression[start_index:i])) + start_index = i + 1 + if self._multivalue: + self._expression = multivalue_items + self._expression.append(Element(expression[start_index:])) return # Validate format expression and raise exception if it is not valid item = [] + bracket_closed = False for i in expression: - if bracket_closed: + if bracket_closed and bracket_level == 0: + if i == " ": + continue if i not in self.MATH_ACTIONS and i != ")": raise ExpressionFormatException("After bracket closed 'math sign' or " "another bracket close are expected") @@ -163,10 +186,11 @@ def __init__(self, expression, func=None): else: if i in self.MATH_ACTIONS: if item: - item = "".join(item) - if item in self._mathematical_constants: - item = self._mathematical_constants[item] - self._expression.append(float(item)) + item = "".join(item).strip() + if item: + if item in self._mathematical_constants: + item = self._mathematical_constants[item] + self._expression.append(float(item)) item = [] # Handle double mathematical operation @@ -209,6 +233,8 @@ def _calculate_boolean_expression(self): boolean_value = True for i, v in enumerate(self._expression): if isinstance(v, str): + if i <= 0: + raise ExpressionFormatException("Comparison could be at the first position") if v == ">=": if not self._expression[i - 1] >= self._expression[i + 1]: boolean_value = False @@ -243,17 +269,16 @@ def _calculate_mathematical_expression(self): first_negative = True del self._expression[0] - # Calculate power mathematical operation - self._expression.reverse() - while True: - try: - index = self._expression.index("^") - self._expression.pop(index) - power = self._expression.pop(index - 1) - self._expression[index - 1] **= power - except ValueError: - break - self._expression.reverse() + i = len(self._expression) - 1 + while i >= 0: + el = self._expression[i] + if el == "^": + self._expression.pop(i) + power = self._expression.pop(i) + if power == "-": + power = -self._expression.pop(i) + self._expression[i - 1] **= power + i -= 1 # Calculate high priority mathematical operations new_expression = [] @@ -288,8 +313,8 @@ def _calculate_mathematical_expression(self): if isinstance(i, str): if i in ("+", "-",): operation = i - else: - raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(i)) + # else: + # raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(i)) elif operation: if operation == "+": value += i @@ -312,35 +337,94 @@ def value(self): """ # Validate mathematical operations and calculate nested expressions - last_operation = None + # i = len(self._expression) - 1 + # last_operation = None + # print(">>", self._expression) + # while i >= 0: + # el = self._expression[i] + # if isinstance(el, Element): + # self._expression[i] = el.value() + # last_operation = None + # elif isinstance(el, str): + for i, v in enumerate(self._expression): if isinstance(v, Element): self._expression[i] = v.value() if isinstance(v, str): - if v not in ("<=", ">=", "==", "!=", "<>", "**", "//"): + if v.startswith("-"): if len(v) > 1: if len(v) % 2 == 0: self._expression[i] = "+" else: self._expression[i] = "-" + if v.startswith("+"): + self._expression[i] = "+" - if last_operation and v in ("+", "-",): - if last_operation == "+" and v == "-": - self._expression[i] = "-" - del self._expression[i - 1] - elif last_operation == "-" and v == "+": - self._expression[i] = "-" - del self._expression[i] - elif last_operation and v in self.MATH_ACTIONS: - raise DoubleOperationException("'{so}' operation follows '{fo}'".format( - so=last_operation, - fo=v - )) - - if v in self.MATH_ACTIONS: - last_operation = v - else: + expression = [] + last_operation = None + sign = None + for i, v in enumerate(self._expression): + if isinstance(v, str): + if last_operation: + if last_operation in ("+", "-",): + if v in ("+", "-"): + if last_operation == v: + last_operation = "+" + else: + last_operation = "-" + else: + raise DoubleOperationException("'{so}' operation follows '{fo}'".format( + so=last_operation, + fo=v + )) + else: + if v not in ("+", "-"): + raise DoubleOperationException("'{so}' operation follows '{fo}'".format( + so=last_operation, + fo=v + )) + if sign: + if sign == v: + sign = "+" + else: + sign = "-" + else: + sign = v + else: + last_operation = v + continue + + if last_operation: + expression.append(last_operation) last_operation = None + if sign == "-": + v = -v + sign = None + expression.append(v) + + if last_operation or sign: + raise ExpressionFormatException("Expression finishes with mathematical operation.") + + self._expression = expression + + # for i, v in enumerate(self._expression): + # if isinstance(v, str): + # if last_operation and v in ("+", "-",): + # if last_operation == "+" and v == "-": + # self._expression[i] = "-" + # elif last_operation == "-" and v == "+": + # self._expression[i] = "-" + # del self._expression[i - 1] + # elif last_operation and v in self.MATH_ACTIONS: + # raise DoubleOperationException("'{so}' operation follows '{fo}'".format( + # so=last_operation, + # fo=v + # )) + + # if v in self.MATH_ACTIONS: + # last_operation = v + # else: + # last_operation = None # Evaluate comparison expression if self._comparison_operation: @@ -351,9 +435,7 @@ def value(self): try: return self._func(*self._expression) except TypeError: - raise ExpressionFormatException("Expected 2 arguments, got 3: '{}'".format(self._func)) + raise ExpressionFormatException("Expected 2 arguments: '{}'".format(self._func)) - try: - return self._calculate_mathematical_expression() - except TypeError: - raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(i)) + # print(self._expression) + return self._calculate_mathematical_expression() diff --git a/pycalc b/pycalc index c75c1d9..fa86465 100755 --- a/pycalc +++ b/pycalc @@ -15,10 +15,9 @@ if __name__ == '__main__': print(expression.value()) except BaseExpressionException as exc: print("ERROR: {}".format(str(exc))) - # except ValueError as exc: - # print("ERROR: {}".format(str(exc))) - # except TypeError as exc: - # print("ERROR: {}".format(str(exc))) + except ValueError as exc: + print("ERROR: {}".format(str(exc))) + except TypeError as exc: + print("ERROR: {}".format(str(exc))) # expression = Element(expression=args.EXPRESSION) # print(expression.value()) - # print(expression.booleen_value()) diff --git a/pycalc_checker.py b/pycalc_checker.py index 0b48a2b..c410e0f 100644 --- a/pycalc_checker.py +++ b/pycalc_checker.py @@ -5,7 +5,7 @@ from termcolor import colored -PYCALC_UTIL_NAME = "pycalc" +PYCALC_UTIL_NAME = "./pycalc" RETURN_CODE = 0 diff --git a/tests/test_negatives.py b/tests/test_negatives.py index 3763edc..5133bf9 100644 --- a/tests/test_negatives.py +++ b/tests/test_negatives.py @@ -1,7 +1,8 @@ from unittest import TestCase from libs.element import Element, NoExpressionException, ExpressionFormatException, BracketsAreNotBalanced, \ - DoubleOperationException, ExpressionFormatException, UnsupportedMathematicalOperationException + DoubleOperationException, ExpressionFormatException, UnsupportedMathematicalOperationException, \ + UnsupportedMathematicalFunctionException class TestNegativesElementSimple(TestCase): @@ -53,10 +54,49 @@ def test_unsupported_comparison_operation(self): def test_unsupported_operation(self): with self.assertRaises(DoubleOperationException): - expression = Element(expression="1*/5*3") + expression = Element(expression="1+/5*3") expression.value() - # def test_unsupported_trigonometric_operation(self): - # with self.assertRaises(UnsupportedMathematicalOperationException): - # expression = Element(expression="erf(10)") - # expression.value() + def test_unsupported_trigonometric_operation(self): + with self.assertRaises(UnsupportedMathematicalFunctionException): + expression = Element(expression="iii(10)") + expression.value() + + def test_not_mathematical_constant(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="li") + expression.value() + + def test_exponentiation(self): + with self.assertRaises(UnsupportedMathematicalOperationException): + expression = Element(expression="2**6") + expression.value() + + def test_expected_arguments(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="pow(2,5,6)") + expression.value() + + def test_comma_without_func(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="2+3,4") + expression.value() + + # def test_calculate_mathematical_expression(self): + # # with self.assertRaises(UnsupportedMathematicalOperationException): + # expression = Element(expression="") + # expression.value() + def test_bad_expression(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="--+1-") + expression.value() + + def test_expression_bad(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="2-") + expression.value() + + def test_expression_with_space(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="2- 3+") + expression.value() \ No newline at end of file diff --git a/tests/test_simple.py b/tests/test_simple.py index 7ed6876..ac0e753 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -41,10 +41,26 @@ def test_exponentiation(self): expression = Element(expression="2*3//2") self.assertEqual(expression.value(), 3) - - def test_str(self): expression = Element(expression="2+3*((5-1)-2)") self.assertTrue(str(expression), 8) + def test_mathematical_constant(self): + expression = Element(expression="pi") + self.assertEqual(expression.value(), 3.141592653589793) + + def test_mathematical_power(self): + expression = Element(expression="2^3") + self.assertEqual(expression.value(), 8) + def test_two_mathematical_constant(self): + expression = Element(expression="pi*e") + self.assertEqual(expression.value(), 8.539734222673566) + + def test_unary_operation(self): + expression = Element(expression="2*4-----3+++4--3") + self.assertEqual(expression.value(), 12) + + def test_various_unary_operation(self): + expression = Element(expression="2*4++4-+++4---3++2----1") + self.assertEqual(expression.value(), 8) From 721016d87faf7debb0d5a12636c96d9ffdcc37ce Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Fri, 7 Dec 2018 14:03:12 +0300 Subject: [PATCH 23/26] [finished hometask] code checking unittests --- libs/element.py | 69 +++++++++++------------------------------ pycalc | 4 --- tests/test_negatives.py | 20 +++++++----- tests/test_simple.py | 12 +++---- 4 files changed, 37 insertions(+), 68 deletions(-) diff --git a/libs/element.py b/libs/element.py index 091ab07..577b367 100644 --- a/libs/element.py +++ b/libs/element.py @@ -59,31 +59,22 @@ def __init__(self, expression, func=None): :param expression: mathematical expression as string """ # Validate on expression and raise exception if not true - - # if " " in expression: - # raise ExpressionFormatException("Expression should not de with spaces") - - # expression = expression.replace(" ", "") - if not expression: raise NoExpressionException("The expression was not passed") - # if expression.startswith("--") or expression.startswith("=") or expression.startswith("+"): - # raise ExpressionFormatException("The expression bad format") - # if expression.endswith("-"): - # raise ExpressionFormatException("The expression bad format") - - # TODO: comment + # Validate function and constant function in expression self._mathematical_functions = { name: val for name, val in getmembers(math) if type(val).__name__ == "builtin_function_or_method" } self._mathematical_functions["abs"] = abs self._mathematical_functions["round"] = round + # Validate mathematical constants in expression self._mathematical_constants = { name: val for name, val in getmembers(math) if type(val).__name__ == "float" } + # Check function in expression self._func = None if func: func = func.strip() @@ -158,12 +149,14 @@ def __init__(self, expression, func=None): bracket_closed = False # Validate and count brackets + if i == "(": bracket_level += 1 if bracket_level == 1: continue # Validate and sorted data in brackets + elif i == ")": bracket_level -= 1 bracket_closed = True @@ -190,7 +183,10 @@ def __init__(self, expression, func=None): if item: if item in self._mathematical_constants: item = self._mathematical_constants[item] - self._expression.append(float(item)) + try: + self._expression.append(float(item)) + except ValueError: + raise ExpressionFormatException("Could not convert string to float: '{}'".format(item)) item = [] # Handle double mathematical operation @@ -216,6 +212,7 @@ def __init__(self, expression, func=None): except ValueError: raise ExpressionFormatException("Could not convert string to float: '{}'".format(item)) + # Conversation to string expression def __str__(self): """ String representation of the class @@ -229,6 +226,7 @@ def __str__(self): data=", ".join(result) ) + # Calculate comparison expression def _calculate_boolean_expression(self): boolean_value = True for i, v in enumerate(self._expression): @@ -260,6 +258,7 @@ def _calculate_boolean_expression(self): return boolean_value return boolean_value + # Calculate mathematical expression def _calculate_mathematical_expression(self): operation = None first_negative = False @@ -275,8 +274,6 @@ def _calculate_mathematical_expression(self): if el == "^": self._expression.pop(i) power = self._expression.pop(i) - if power == "-": - power = -self._expression.pop(i) self._expression[i - 1] **= power i -= 1 @@ -313,8 +310,6 @@ def _calculate_mathematical_expression(self): if isinstance(i, str): if i in ("+", "-",): operation = i - # else: - # raise UnsupportedMathematicalOperationException("We do not support '{}' operation".format(i)) elif operation: if operation == "+": value += i @@ -330,23 +325,13 @@ def _calculate_mathematical_expression(self): return value + # Calculate value expression def value(self): """ Method for expression calculation :return: calculate value """ - - # Validate mathematical operations and calculate nested expressions - # i = len(self._expression) - 1 - # last_operation = None - # print(">>", self._expression) - # while i >= 0: - # el = self._expression[i] - # if isinstance(el, Element): - # self._expression[i] = el.value() - # last_operation = None - # elif isinstance(el, str): - + # Validate unary operation for i, v in enumerate(self._expression): if isinstance(v, Element): self._expression[i] = v.value() @@ -360,9 +345,11 @@ def value(self): if v.startswith("+"): self._expression[i] = "+" + # Validate negative item in expression expression = [] last_operation = None sign = None + for i, v in enumerate(self._expression): if isinstance(v, str): if last_operation: @@ -399,7 +386,7 @@ def value(self): last_operation = None if sign == "-": v = -v - sign = None + sign = None expression.append(v) if last_operation or sign: @@ -407,25 +394,6 @@ def value(self): self._expression = expression - # for i, v in enumerate(self._expression): - # if isinstance(v, str): - # if last_operation and v in ("+", "-",): - # if last_operation == "+" and v == "-": - # self._expression[i] = "-" - # elif last_operation == "-" and v == "+": - # self._expression[i] = "-" - # del self._expression[i - 1] - # elif last_operation and v in self.MATH_ACTIONS: - # raise DoubleOperationException("'{so}' operation follows '{fo}'".format( - # so=last_operation, - # fo=v - # )) - - # if v in self.MATH_ACTIONS: - # last_operation = v - # else: - # last_operation = None - # Evaluate comparison expression if self._comparison_operation: return self._calculate_boolean_expression() @@ -436,6 +404,5 @@ def value(self): return self._func(*self._expression) except TypeError: raise ExpressionFormatException("Expected 2 arguments: '{}'".format(self._func)) - - # print(self._expression) + # Value mathematical expression return self._calculate_mathematical_expression() diff --git a/pycalc b/pycalc index fa86465..ea8341d 100755 --- a/pycalc +++ b/pycalc @@ -15,9 +15,5 @@ if __name__ == '__main__': print(expression.value()) except BaseExpressionException as exc: print("ERROR: {}".format(str(exc))) - except ValueError as exc: - print("ERROR: {}".format(str(exc))) - except TypeError as exc: - print("ERROR: {}".format(str(exc))) # expression = Element(expression=args.EXPRESSION) # print(expression.value()) diff --git a/tests/test_negatives.py b/tests/test_negatives.py index 5133bf9..8d922aa 100644 --- a/tests/test_negatives.py +++ b/tests/test_negatives.py @@ -82,10 +82,6 @@ def test_comma_without_func(self): expression = Element(expression="2+3,4") expression.value() - # def test_calculate_mathematical_expression(self): - # # with self.assertRaises(UnsupportedMathematicalOperationException): - # expression = Element(expression="") - # expression.value() def test_bad_expression(self): with self.assertRaises(ExpressionFormatException): expression = Element(expression="--+1-") @@ -96,7 +92,17 @@ def test_expression_bad(self): expression = Element(expression="2-") expression.value() - def test_expression_with_space(self): + def test_convert_string_to_float(self): with self.assertRaises(ExpressionFormatException): - expression = Element(expression="2- 3+") - expression.value() \ No newline at end of file + expression = Element(expression="21 + 2(3 * 4))") + expression.value() + + def test_first_comparison(self): + with self.assertRaises(ExpressionFormatException): + expression = Element(expression="<=4+6") + expression.value() + + def test_unsupported_operation(self): + with self.assertRaises(DoubleOperationException): + expression = Element(expression="4/*5-3") + expression.value() diff --git a/tests/test_simple.py b/tests/test_simple.py index ac0e753..5c03d6c 100644 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -42,7 +42,7 @@ def test_exponentiation(self): self.assertEqual(expression.value(), 3) def test_str(self): - expression = Element(expression="2+3*((5-1)-2)") + expression = Element(expression="2+3*((5-1)-2) ") self.assertTrue(str(expression), 8) def test_mathematical_constant(self): @@ -58,9 +58,9 @@ def test_two_mathematical_constant(self): self.assertEqual(expression.value(), 8.539734222673566) def test_unary_operation(self): - expression = Element(expression="2*4-----3+++4--3") - self.assertEqual(expression.value(), 12) + expression = Element(expression="2*4-----3+++-4*-+-+-3") + self.assertEqual(expression.value(), 17) - def test_various_unary_operation(self): - expression = Element(expression="2*4++4-+++4---3++2----1") - self.assertEqual(expression.value(), 8) + def test_negative_exponentiation(self): + expression = Element(expression="2^-8") + self.assertEqual(expression.value(), 0.00390625) From 63c74e2ffc58a7b0e66b22c26f1e89d74c612666 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Fri, 7 Dec 2018 17:40:20 +0300 Subject: [PATCH 24/26] [integration] Move code to the final_task folder --- {libs => final_task/libs}/__init__.py | 0 {libs => final_task/libs}/element.py | 0 pycalc => final_task/pycalc | 2 -- {tests => final_task/tests}/__init__.py | 0 {tests => final_task/tests}/test_bracket.py | 0 {tests => final_task/tests}/test_comparison_operation.py | 0 {tests => final_task/tests}/test_negatives.py | 2 +- {tests => final_task/tests}/test_simple.py | 0 {tests => final_task/tests}/test_trigonometric_operation.py | 0 gitlab-ci.yml | 3 +++ pycalc_checker.py | 2 +- 11 files changed, 5 insertions(+), 4 deletions(-) rename {libs => final_task/libs}/__init__.py (100%) rename {libs => final_task/libs}/element.py (100%) rename pycalc => final_task/pycalc (87%) rename {tests => final_task/tests}/__init__.py (100%) rename {tests => final_task/tests}/test_bracket.py (100%) rename {tests => final_task/tests}/test_comparison_operation.py (100%) rename {tests => final_task/tests}/test_negatives.py (97%) rename {tests => final_task/tests}/test_simple.py (100%) rename {tests => final_task/tests}/test_trigonometric_operation.py (100%) diff --git a/libs/__init__.py b/final_task/libs/__init__.py similarity index 100% rename from libs/__init__.py rename to final_task/libs/__init__.py diff --git a/libs/element.py b/final_task/libs/element.py similarity index 100% rename from libs/element.py rename to final_task/libs/element.py diff --git a/pycalc b/final_task/pycalc similarity index 87% rename from pycalc rename to final_task/pycalc index ea8341d..d133a30 100755 --- a/pycalc +++ b/final_task/pycalc @@ -15,5 +15,3 @@ if __name__ == '__main__': print(expression.value()) except BaseExpressionException as exc: print("ERROR: {}".format(str(exc))) - # expression = Element(expression=args.EXPRESSION) - # print(expression.value()) diff --git a/tests/__init__.py b/final_task/tests/__init__.py similarity index 100% rename from tests/__init__.py rename to final_task/tests/__init__.py diff --git a/tests/test_bracket.py b/final_task/tests/test_bracket.py similarity index 100% rename from tests/test_bracket.py rename to final_task/tests/test_bracket.py diff --git a/tests/test_comparison_operation.py b/final_task/tests/test_comparison_operation.py similarity index 100% rename from tests/test_comparison_operation.py rename to final_task/tests/test_comparison_operation.py diff --git a/tests/test_negatives.py b/final_task/tests/test_negatives.py similarity index 97% rename from tests/test_negatives.py rename to final_task/tests/test_negatives.py index 8d922aa..6cddd30 100644 --- a/tests/test_negatives.py +++ b/final_task/tests/test_negatives.py @@ -1,6 +1,6 @@ from unittest import TestCase -from libs.element import Element, NoExpressionException, ExpressionFormatException, BracketsAreNotBalanced, \ +from libs.element import Element, NoExpressionException, BracketsAreNotBalanced, \ DoubleOperationException, ExpressionFormatException, UnsupportedMathematicalOperationException, \ UnsupportedMathematicalFunctionException diff --git a/tests/test_simple.py b/final_task/tests/test_simple.py similarity index 100% rename from tests/test_simple.py rename to final_task/tests/test_simple.py diff --git a/tests/test_trigonometric_operation.py b/final_task/tests/test_trigonometric_operation.py similarity index 100% rename from tests/test_trigonometric_operation.py rename to final_task/tests/test_trigonometric_operation.py diff --git a/gitlab-ci.yml b/gitlab-ci.yml index abf7d61..69a48b6 100644 --- a/gitlab-ci.yml +++ b/gitlab-ci.yml @@ -1,5 +1,8 @@ image: python:3.6-alpine +before_script: + - cd final_task + test: stage: test script: diff --git a/pycalc_checker.py b/pycalc_checker.py index c410e0f..0b48a2b 100644 --- a/pycalc_checker.py +++ b/pycalc_checker.py @@ -5,7 +5,7 @@ from termcolor import colored -PYCALC_UTIL_NAME = "./pycalc" +PYCALC_UTIL_NAME = "pycalc" RETURN_CODE = 0 From d4b90109cf323c9543cb55afba237b6943cddec6 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Fri, 7 Dec 2018 18:00:43 +0300 Subject: [PATCH 25/26] [ci] fix --- .travis.yml | 3 +-- pycalc_checker.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index baca138..b1c38b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,7 @@ install: - pip install -r requirements.txt script: - cd final_task - - pip install . - - nosetests --cover-branches --with-coverage . + - coverage run -m unittest discover - pycodestyle --max-line-length=120 . - python ./../pycalc_checker.py - cd - \ No newline at end of file diff --git a/pycalc_checker.py b/pycalc_checker.py index 0b48a2b..c410e0f 100644 --- a/pycalc_checker.py +++ b/pycalc_checker.py @@ -5,7 +5,7 @@ from termcolor import colored -PYCALC_UTIL_NAME = "pycalc" +PYCALC_UTIL_NAME = "./pycalc" RETURN_CODE = 0 From cabe3c55c18c86e5679a6cfe40b10567961a7849 Mon Sep 17 00:00:00 2001 From: Elena Volkova Date: Sat, 29 Dec 2018 14:19:20 +0300 Subject: [PATCH 26/26] [core] Add setup.py --- .travis.yml | 1 + final_task/setup.py | 11 +++++++++++ pycalc_checker.py | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b1c38b4..21dd972 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ install: - pip install -r requirements.txt script: - cd final_task + - pip install . - coverage run -m unittest discover - pycodestyle --max-line-length=120 . - python ./../pycalc_checker.py diff --git a/final_task/setup.py b/final_task/setup.py index e69de29..923231b 100644 --- a/final_task/setup.py +++ b/final_task/setup.py @@ -0,0 +1,11 @@ +from setuptools import setup, find_packages + +setup( + name='pycalc', + version='0.1', + author='Elena Volkova', + author_email='volkovaelen87@gmail.com', + description='Python command-line calculator', + packages=find_packages(), + scripts=['pycalc'] +) diff --git a/pycalc_checker.py b/pycalc_checker.py index c410e0f..0b48a2b 100644 --- a/pycalc_checker.py +++ b/pycalc_checker.py @@ -5,7 +5,7 @@ from termcolor import colored -PYCALC_UTIL_NAME = "./pycalc" +PYCALC_UTIL_NAME = "pycalc" RETURN_CODE = 0