From 62549d2e10ebb4d8424acc8c80c12f7eca2396f3 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sat, 18 Oct 2014 19:04:40 +0200 Subject: [PATCH 1/6] new class for operator and include it into expression.in2post_fix --- pymath/expression.py | 33 +++++++++++++++++++++++++-------- pymath/generic.py | 10 ++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index 1be503d..eff4a77 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # encoding: utf-8 -from .generic import Stack, flatten_list, expand_list +from .generic import Stack, flatten_list, expand_list, Operator from .fraction import Fraction from .renders import txt, post2in_fix, tex @@ -248,24 +248,41 @@ class Expression(object): >>> Expression.in2post_fix(['(', 2, '+', 5, '-', 1, ')', '/', '(', 3, '*', 4, ')']) [2, 5, '+', 1, '-', 3, 4, '*', '/'] """ + # Stack where operator will be stocked opStack = Stack() + # final postfix list of tokens postfixList = [] + # Nbr of tokens to compute in postfixList + nbr_token_in_postfix = 0 - for token in infix_tokens: + for (pos_token,token) in enumerate(infix_tokens): if token == "(": opStack.push(token) + nbr_token_in_postfix -= 1 elif token == ")": - topToken = opStack.pop() - while topToken != "(": - postfixList.append(topToken) - topToken = opStack.pop() + op = opStack.pop() + while op != "(": + postfixList.append(op) + nbr_token_in_postfix -= (op.arrity - 1) + op = opStack.pop() + + nbr_token_in_postfix += 1 + elif cls.isOperator(token): # On doit ajouter la condition == str sinon python ne veut pas tester l'appartenance à la chaine de caractère. while (not opStack.isEmpty()) and (cls.PRIORITY[opStack.peek()] >= cls.PRIORITY[token]): - postfixList.append(opStack.pop()) - opStack.push(token) + op = opStack.pop() + postfixList.append(op) + nbr_token_in_postfix -= (op.arrity - 1) + + # la max est là dans le cas où l'expression commence par "(" + opStack.push(Operator(token, max(1,nbr_token_in_postfix + 1))) else: postfixList.append(token) + nbr_token_in_postfix += 1 + + ## Pour voir ce qu'il se passe dans cette procédure + #print(str(postfixList), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(nbr_token_in_postfix)) while not opStack.isEmpty(): postfixList.append(opStack.pop()) diff --git a/pymath/generic.py b/pymath/generic.py index f1a43ef..df70345 100644 --- a/pymath/generic.py +++ b/pymath/generic.py @@ -57,6 +57,16 @@ class Stack(object): def __add__(self, addList): return self.items + addList +class Operator(str): + + """The operator class, is a string (representation of the operator) with its arrity (?!? - arrite)""" + + def __new__(cls, operator, arrity = 2): + op = str.__new__(cls, operator) + op.arrity = arrity + return op + + def flatten_list(a, result=None): """Flattens a nested list. From cdf5a552b2abe3dbc647296ba5a6e230760b82b5 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Oct 2014 12:59:21 +0200 Subject: [PATCH 2/6] arity is fine now! --- pymath/expression.py | 69 ++++++++++++++++++++++++++++++++------------ pymath/generic.py | 6 ++-- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index eff4a77..a1ae1f0 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -247,47 +247,80 @@ class Expression(object): >>> Expression.in2post_fix(['(', 2, '+', 5, '-', 1, ')', '/', '(', 3, '*', 4, ')']) [2, 5, '+', 1, '-', 3, 4, '*', '/'] + >>> Expression.in2post_fix(['-', '(', '-', 2, ')']) + [2, 5, '+', 1, '-', 3, 4, '*', '/'] + >>> Expression.in2post_fix(['-', '(', '-', 2, '+', 3, "*", 4, ')']) + [2, 5, '+', 1, '-', 3, 4, '*', '/'] """ # Stack where operator will be stocked opStack = Stack() # final postfix list of tokens - postfixList = [] - # Nbr of tokens to compute in postfixList - nbr_token_in_postfix = 0 + postfix_tokens = [] + # stack with the nbr of tokens still to compute in postfix_tokens + arity_Stack = Stack() + arity_Stack.push(0) for (pos_token,token) in enumerate(infix_tokens): + + # Pour voir ce qu'il se passe dans cette procédure + print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack)) if token == "(": opStack.push(token) - nbr_token_in_postfix -= 1 + # Set next arity counter + arity_Stack.push(0) elif token == ")": op = opStack.pop() while op != "(": - postfixList.append(op) - nbr_token_in_postfix -= (op.arrity - 1) + #print(str(op), " -> ", op.arity) + postfix_tokens.append(op) + #arity = arity_Stack.pop() + #arity_Stack.push(arity - (op.arity + 1)) op = opStack.pop() - nbr_token_in_postfix += 1 + # Go back to old arity + arity_Stack.pop() + # Raise the arity + arity = arity_Stack.pop() + arity_Stack.push(arity + 1) elif cls.isOperator(token): # On doit ajouter la condition == str sinon python ne veut pas tester l'appartenance à la chaine de caractère. while (not opStack.isEmpty()) and (cls.PRIORITY[opStack.peek()] >= cls.PRIORITY[token]): op = opStack.pop() - postfixList.append(op) - nbr_token_in_postfix -= (op.arrity - 1) + postfix_tokens.append(op) - # la max est là dans le cas où l'expression commence par "(" - opStack.push(Operator(token, max(1,nbr_token_in_postfix + 1))) + ## decrease arity + #arity = arity_Stack.pop() + #arity_Stack.push(arity - (op.arity - 1)) + + #print(str(op), " -> ", op.arity) + + arity = arity_Stack.pop() + opStack.push(Operator(token, arity + 1)) + print("--", token, " -> ", str(arity + 1)) + # Reset arity to 0 in case there is other operators (the real operation would be "-op.arity + 1") + arity_Stack.push(0) else: - postfixList.append(token) - nbr_token_in_postfix += 1 - - ## Pour voir ce qu'il se passe dans cette procédure - #print(str(postfixList), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(nbr_token_in_postfix)) + postfix_tokens.append(token) + arity = arity_Stack.pop() + arity_Stack.push(arity + 1) while not opStack.isEmpty(): - postfixList.append(opStack.pop()) + op = opStack.pop() + postfix_tokens.append(op) - return postfixList + # decrease arity + arity = arity_Stack.pop() + arity_Stack.push(arity - (op.arity - 1)) + + #print(str(op), " -> ", op.arity) + + print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack)) + + #if arity_Stack != 1: + # raise ValueError("No float number please") + + return postfix_tokens ## --------------------- ## Computing the expression diff --git a/pymath/generic.py b/pymath/generic.py index df70345..f5ee9ba 100644 --- a/pymath/generic.py +++ b/pymath/generic.py @@ -59,11 +59,11 @@ class Stack(object): class Operator(str): - """The operator class, is a string (representation of the operator) with its arrity (?!? - arrite)""" + """The operator class, is a string (representation of the operator) with its arity (?!? - arrite)""" - def __new__(cls, operator, arrity = 2): + def __new__(cls, operator, arity = 2): op = str.__new__(cls, operator) - op.arrity = arrity + op.arity = arity return op From 4630d0de748cf6db8424416894fcc10aec2bc0d0 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Thu, 23 Oct 2014 13:13:28 +0200 Subject: [PATCH 3/6] Definively finished arity setup --- pymath/expression.py | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index a1ae1f0..ca1fae4 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -248,9 +248,9 @@ class Expression(object): >>> Expression.in2post_fix(['(', 2, '+', 5, '-', 1, ')', '/', '(', 3, '*', 4, ')']) [2, 5, '+', 1, '-', 3, 4, '*', '/'] >>> Expression.in2post_fix(['-', '(', '-', 2, ')']) - [2, 5, '+', 1, '-', 3, 4, '*', '/'] + [2, '-', '-'] >>> Expression.in2post_fix(['-', '(', '-', 2, '+', 3, "*", 4, ')']) - [2, 5, '+', 1, '-', 3, 4, '*', '/'] + [2, '-', 3, 4, '*', '+', '-'] """ # Stack where operator will be stocked opStack = Stack() @@ -262,8 +262,8 @@ class Expression(object): for (pos_token,token) in enumerate(infix_tokens): - # Pour voir ce qu'il se passe dans cette procédure - print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack)) + # # Pour voir ce qu'il se passe dans cette procédure + # print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack)) if token == "(": opStack.push(token) # Set next arity counter @@ -271,10 +271,7 @@ class Expression(object): elif token == ")": op = opStack.pop() while op != "(": - #print(str(op), " -> ", op.arity) postfix_tokens.append(op) - #arity = arity_Stack.pop() - #arity_Stack.push(arity - (op.arity + 1)) op = opStack.pop() # Go back to old arity @@ -289,15 +286,9 @@ class Expression(object): op = opStack.pop() postfix_tokens.append(op) - ## decrease arity - #arity = arity_Stack.pop() - #arity_Stack.push(arity - (op.arity - 1)) - - #print(str(op), " -> ", op.arity) - arity = arity_Stack.pop() opStack.push(Operator(token, arity + 1)) - print("--", token, " -> ", str(arity + 1)) + # print("--", token, " -> ", str(arity + 1)) # Reset arity to 0 in case there is other operators (the real operation would be "-op.arity + 1") arity_Stack.push(0) else: @@ -309,16 +300,11 @@ class Expression(object): op = opStack.pop() postfix_tokens.append(op) - # decrease arity - arity = arity_Stack.pop() - arity_Stack.push(arity - (op.arity - 1)) + # # Pour voir ce qu'il se passe dans cette procédure + # print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack)) - #print(str(op), " -> ", op.arity) - - print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack)) - - #if arity_Stack != 1: - # raise ValueError("No float number please") + if arity_Stack.peek() != 1: + raise ValueError("Unvalid expression. The arity Stack is ", str(arity_Stack)) return postfix_tokens From 6e99dadd395dc3f783bdfa7799f47584e17f8bb0 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sun, 2 Nov 2014 08:19:31 +0100 Subject: [PATCH 4/6] Create real class Operator and include it into expression (need to fix render now) --- pymath/expression.py | 67 ++++++++++++++++++++------------------------ pymath/generic.py | 11 -------- pymath/operator.py | 50 +++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 48 deletions(-) create mode 100644 pymath/operator.py diff --git a/pymath/expression.py b/pymath/expression.py index ca1fae4..e24359c 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -1,7 +1,8 @@ #!/usr/bin/env python # encoding: utf-8 -from .generic import Stack, flatten_list, expand_list, Operator +from .generic import Stack, flatten_list, expand_list +from .operator import Operator from .fraction import Fraction from .renders import txt, post2in_fix, tex @@ -81,20 +82,36 @@ class Expression(object): tmpTokenList = [] while len(tokenList) > 2: - # on va chercher les motifs du genre A B + pour les calculer - if self.isNumber(tokenList[0]) and self.isNumber(tokenList[1]) and self.isOperator(tokenList[2]): + # on va chercher les motifs du genre A B +, quad l'operateur est d'arité 2, pour les calculer + if self.isNumber(tokenList[0]) and self.isNumber(tokenList[1]) \ + and type(tokenList[2]) == Operator and tokenList[2].arity == 2 : # S'il y a une opération à faire op1 = tokenList[0] op2 = tokenList[1] - token = tokenList[2] + operator = tokenList[2] - res = self.doMath(token, op1, op2) + res = operator(op1, op2) tmpTokenList.append(res) # Comme on vient de faire le calcul, on peut détruire aussi les deux prochains termes del tokenList[0:3] + + elif self.isNumber(tokenList[0]) \ + and type(tokenList[1]) == Operator and tokenList[1].arity == 1 : + + # S'il y a une opération à faire + op1 = tokenList[0] + operator = tokenList[1] + + res = operator(op1) + + tmpTokenList.append(res) + + # Comme on vient de faire le calcul, on peut détruire aussi les deux prochains termes + del tokenList[0:2] + else: tmpTokenList.append(tokenList[0]) @@ -106,7 +123,9 @@ class Expression(object): if len(steps[:-1]) > 0: self.steps += [flatten_list(s) for s in steps[:-1]] + print("self.steps -> ", self.steps) self.child = Expression(steps[-1]) + print("self.child -> ", self.child) ## --------------------- ## String parsing @@ -281,7 +300,6 @@ class Expression(object): arity_Stack.push(arity + 1) elif cls.isOperator(token): - # On doit ajouter la condition == str sinon python ne veut pas tester l'appartenance à la chaine de caractère. while (not opStack.isEmpty()) and (cls.PRIORITY[opStack.peek()] >= cls.PRIORITY[token]): op = opStack.pop() postfix_tokens.append(op) @@ -308,32 +326,6 @@ class Expression(object): return postfix_tokens - ## --------------------- - ## Computing the expression - - @staticmethod - def doMath(op, op1, op2): - """Compute "op1 op op2" or create a fraction - - :param op: operator - :param op1: first operande - :param op2: second operande - :returns: string representing the result - - """ - if op == "/": - ans = [Fraction(op1, op2)] - ans += ans[0].simplify() - return ans - else: - if type(op2) != int: - operations = {"+": "__radd__", "-": "__rsub__", "*": "__rmul__"} - return getattr(op2,operations[op])(op1) - else: - operations = {"+": "__add__", "-": "__sub__", "*": "__mul__", "^": "__pow__"} - return getattr(op1,operations[op])(op2) - - ## --------------------- ## Recognize numbers and operators @@ -367,12 +359,13 @@ def test(exp): print("\n") if __name__ == '__main__': - Expression.STR_RENDER = txt - #exp = "2 ^ 3 * 5" - #test(exp) + #Expression.STR_RENDER = txt + Expression.STR_RENDER = lambda x: str(x) + exp = "2 ^ 3 * 5" + test(exp) - #exp = "1 + 3 * 5" - #test(exp) + exp = "1 + 3 * 5" + test(exp) #exp = "2 * 3 * 3 * 5" #test(exp) diff --git a/pymath/generic.py b/pymath/generic.py index f5ee9ba..959c66a 100644 --- a/pymath/generic.py +++ b/pymath/generic.py @@ -57,17 +57,6 @@ class Stack(object): def __add__(self, addList): return self.items + addList -class Operator(str): - - """The operator class, is a string (representation of the operator) with its arity (?!? - arrite)""" - - def __new__(cls, operator, arity = 2): - op = str.__new__(cls, operator) - op.arity = arity - return op - - - def flatten_list(a, result=None): """Flattens a nested list. diff --git a/pymath/operator.py b/pymath/operator.py new file mode 100644 index 0000000..138ea65 --- /dev/null +++ b/pymath/operator.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +class Operator(str): + + """The operator class, is a string (representation of the operator) with its arity""" + + OPERATORS = { \ + "+": ["", "", ("__add__","__radd__")],\ + "-": ["", "__neg__", ("__sub__", "__rsub__")], \ + "*": ["", "", ("__mul__", "__rmul__")], \ + "/": ["", "", ("__div__","__rdiv__")], \ + "^": ["", "", ("__pow__", "")] \ + } + + def __new__(cls, operator, arity = 2): + op = str.__new__(cls, operator) + op.arity = arity + + op.actions = cls.OPERATORS[operator][arity] + + return op + + def __call__(self, *args): + """ Calling this operator performs the rigth calculus """ + if self.arity == 1: + return getattr(args[0], self.actions)() + + elif self.arity == 2: + # C'est moche mais je veux que ça marche... + if str(self) == "/": + ans = [Fraction(op1, op2)] + ans += ans[0].simplify() + return ans + else: + if type(args[1]) == int: + return getattr(args[0], self.actions[0])(args[1]) + else: + return getattr(args[1], self.actions[1])(args[0]) + + + + + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del From 9b1ad5c14aec414db96328e076c75f01d57c4f65 Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sun, 2 Nov 2014 11:12:47 +0100 Subject: [PATCH 5/6] Adapt unit test to Operator. Still have to includ fractions --- pymath/expression.py | 5 +---- pymath/render.py | 3 ++- test/test_renders.py | 19 +++++++++++++------ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/pymath/expression.py b/pymath/expression.py index e24359c..fa32f0a 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -123,9 +123,7 @@ class Expression(object): if len(steps[:-1]) > 0: self.steps += [flatten_list(s) for s in steps[:-1]] - print("self.steps -> ", self.steps) self.child = Expression(steps[-1]) - print("self.child -> ", self.child) ## --------------------- ## String parsing @@ -359,8 +357,7 @@ def test(exp): print("\n") if __name__ == '__main__': - #Expression.STR_RENDER = txt - Expression.STR_RENDER = lambda x: str(x) + Expression.STR_RENDER = txt exp = "2 ^ 3 * 5" test(exp) diff --git a/pymath/render.py b/pymath/render.py index 24c36e8..05fa577 100644 --- a/pymath/render.py +++ b/pymath/render.py @@ -3,6 +3,7 @@ from .generic import Stack,flatten_list from .fraction import Fraction +from .operator import Operator __all__ = ['Render'] @@ -195,7 +196,7 @@ class Render(object): :returns: boolean """ - return (type(exp) == str and exp in self.operators) + return (type(exp) == Operator and str(exp) in self.operators) class flist(list): """Fake list- they are used to stock the main operation of an rendered expression""" diff --git a/test/test_renders.py b/test/test_renders.py index 8f0bec4..6453dff 100644 --- a/test/test_renders.py +++ b/test/test_renders.py @@ -6,6 +6,7 @@ import unittest from pymath.renders import tex, txt from pymath.fraction import Fraction +from pymath.operator import Operator @@ -22,21 +23,21 @@ class TestTexRender(unittest.TestCase): self.assertEqual(tex([Fraction(1,2)]), "\\frac{ 1 }{ 2 }") def test_mult_interger(self): - exps = [ [2, 3, "*"], [2, -3, "*"], [-2, 3, "*"]] + exps = [ [2, 3, Operator("*", 2)], [2, -3, Operator("*", 2)], [-2, 3, Operator("*", 2)]] wanted_render = [ "2 \\times 3", "2 \\times ( -3 )", "-2 \\times 3"] for (i,e) in enumerate(exps): rend = tex(e) self.assertEqual(rend, wanted_render[i]) def test_mult_letter(self): - exps = [ [2, "a", "*"], ["a", 3, "*"], [-2, "a", "*"], ["a", -2, "*"]] + exps = [ [2, "a", Operator("*", 2)], ["a", 3, Operator("*", 2)], [-2, "a", Operator("*", 2)], ["a", -2, Operator("*", 2)]] wanted_render = [ "2 a", "a \\times 3", "-2 a", "a \\times ( -2 )"] for (i,e) in enumerate(exps): rend = tex(e) self.assertEqual(rend, wanted_render[i]) def test_mult_fraction(self): - exps = [ [2, Fraction(1,2), "*"], [Fraction(1,2), 3, "*"]] + exps = [ [2, Fraction(1,2), Operator("*", 2)], [Fraction(1,2), 3, Operator("*", 2)]] wanted_render = [ "2 \\times \\frac{ 1 }{ 2 }", "\\frac{ 1 }{ 2 } \\times 3"] for (i,e) in enumerate(exps): rend = tex(e) @@ -64,21 +65,27 @@ class TesttxtRender(unittest.TestCase): self.assertEqual(txt([Fraction(1,2)]), "1 / 2") def test_mult_interger(self): - exps = [ [2, 3, "*"], [2, -3, "*"], [-2, 3, "*"]] + exps = [ [2, 3, Operator("*", 2)], \ + [2, -3, Operator("*", 2)], \ + [-2, 3, Operator("*", 2)]] wanted_render = [ "2 * 3", "2 * ( -3 )", "-2 * 3"] for (i,e) in enumerate(exps): rend = txt(e) self.assertEqual(rend, wanted_render[i]) def test_mult_letter(self): - exps = [ [2, "a", "*"], ["a", 3, "*"], [-2, "a", "*"], ["a", -2, "*"]] + exps = [ [2, "a", Operator("*", 2)], \ + ["a", 3, Operator("*", 2)], \ + [-2, "a", Operator("*", 2)], \ + ["a", -2, Operator("*", 2)]] wanted_render = [ "2 a", "a * 3", "-2 a", "a * ( -2 )"] for (i,e) in enumerate(exps): rend = txt(e) self.assertEqual(rend, wanted_render[i]) def test_mult_fraction(self): - exps = [ [2, Fraction(1,2), "*"], [Fraction(1,2), 3, "*"]] + exps = [ [2, Fraction(1,2), Operator("*", 2)], \ + [Fraction(1,2), 3, Operator("*", 2)]] wanted_render = [ "2 * 1 / 2", "1 / 2 * 3"] for (i,e) in enumerate(exps): rend = txt(e) From a3c84d6eabf54185dbc8feb6fce34c72b71aacde Mon Sep 17 00:00:00 2001 From: Lafrite Date: Sun, 2 Nov 2014 11:17:12 +0100 Subject: [PATCH 6/6] ok Operator well included need to use them correctly now! --- pymath/operator.py | 4 +++- test/test_expression.py | 12 ------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/pymath/operator.py b/pymath/operator.py index 138ea65..3deba4a 100644 --- a/pymath/operator.py +++ b/pymath/operator.py @@ -2,6 +2,8 @@ # encoding: utf-8 +from .fraction import Fraction + class Operator(str): """The operator class, is a string (representation of the operator) with its arity""" @@ -30,7 +32,7 @@ class Operator(str): elif self.arity == 2: # C'est moche mais je veux que ça marche... if str(self) == "/": - ans = [Fraction(op1, op2)] + ans = [Fraction(args[0], args[1])] ans += ans[0].simplify() return ans else: diff --git a/test/test_expression.py b/test/test_expression.py index c4126bb..03716d0 100644 --- a/test/test_expression.py +++ b/test/test_expression.py @@ -56,18 +56,6 @@ class TestExpression(unittest.TestCase): exp = "1 + $" self.assertRaises(ValueError, Expression.str2tokens, exp) - def test_doMath(self): - ops = [\ - {"op": ("+", 1 , 2), "res" : 3}, \ - {"op": ("-", 1 , 2), "res" : -1}, \ - {"op": ("*", 1 , 2), "res" : 2}, \ - {"op": ("/", 1 , 2), "res" : Fraction(1,2)}, \ - {"op": ("^", 1 , 2), "res" : 1}, \ - ] - for op in ops: - res = first_elem(Expression.doMath(*op["op"])) - self.assertAlmostEqual(res, op["res"]) - def test_isNumber(self): pass