diff --git a/MANIFEST b/MANIFEST index 5ce56e9..c5c233b 100644 --- a/MANIFEST +++ b/MANIFEST @@ -5,5 +5,16 @@ pymath/arithmetic.py pymath/expression.py pymath/fraction.py pymath/generic.py +pymath/operator.py +pymath/polynom.py pymath/random_expression.py pymath/render.py +pymath/str2tokens.py +test/test_arithmetic.py +test/test_expression.py +test/test_fraction.py +test/test_generic.py +test/test_polynom.py +test/test_random_expression.py +test/test_render.py +test/test_str2tokens.py diff --git a/pymath/expression.py b/pymath/expression.py index eae21fe..1a5dc10 100644 --- a/pymath/expression.py +++ b/pymath/expression.py @@ -98,7 +98,7 @@ class Expression(object): op1 = tokenList[0] op2 = tokenList[1] operator = tokenList[2] - + res = operator(op1, op2) tmpTokenList.append(res) diff --git a/pymath/operator.py b/pymath/operator.py index d5dbf5d..975772a 100644 --- a/pymath/operator.py +++ b/pymath/operator.py @@ -3,71 +3,57 @@ from .generic import flatten_list, isNumber +import types class Operator(str): """The operator class, is a string (representation of the operator) with its arity""" - PRIORITY = {"^": [0, 5], "/": [0, 4], "*" : [0,3], ":": [0,3], "+": [0,1], "-":[2,1], "(":[0,0]} - OPERATIONS = { \ - "+": ["", ("__add__","__radd__")],\ - "-": ["__neg__", ("__sub__", "__rsub__")], \ - "*": ["", ("__mul__", "__rmul__")], \ - "/": ["", ("__div__","__rdiv__")], \ - "^": ["", ("__pow__", "")], \ - "(": ["",""],\ - } - TXT = { \ - "+": ["", "{op1} + {op2}"] ,\ - "-": ["- {op1}", "{op1} - {op2}"] ,\ - "*": ["", "{op1} * {op2}"] ,\ - "/": ["", "{op1} / {op2}"] ,\ - "^": ["", "{op1} ^ {op2}"] ,\ - "(": ["",""],\ - } - TEX = { \ - "+": ["", "{op1} + {op2}"] ,\ - "-": ["- {op1}", "{op1} - {op2}"] ,\ - "*": ["", "{op1} \\times {op2}"] ,\ - "/": ["", "\\frac{{ {op1} }}{{ {op2} }}"] ,\ - "^": ["", "{op1}^{{ {op2} }}"] ,\ - "(": ["",""],\ - } - - - def __new__(cls, operator, arity = 2): + def __new__(cls, operator = "", name = "", priority = 0, actions = ("",""), txt = "", tex = "", arity = 2): + """ Create an Operator """ + #def __new__(cls, operator, arity = 2): op = str.__new__(cls, operator) + op.operator = operator + op.name = name op.arity = arity - - # TODO: Add op.visibility |sam. nov. 8 17:00:08 CET 2014 - - op.priority = cls.PRIORITY[operator][arity - 1] - op.actions = cls.OPERATIONS[operator][arity-1] - op._txt = cls.TXT[operator][arity-1] - op._tex = cls.TEX[operator][arity-1] + op.priority = priority + op.actions = actions + op.txt = txt + op.tex = tex op.isOperator = 1 - + # TODO: Add self.visibility |sam. nov. 8 17:00:08 CET 2014 return op def __call__(self, *args): """ Calling this operator performs the rigth calculus """ + return self._call(*args) + + + def _call(self, *args): + """Trick to avoid overloading __call__ """ 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) == "/": - # TODO: faudra changer ça c'est pas beau! |ven. nov. 14 16:13:49 CET 2014 - from .fraction import Fraction - ans = [Fraction(args[0], args[1])] - ans += ans[0].simplify() - return ans + if type(args[1]) == int: + return getattr(args[0], self.actions[0])(args[1]) 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]) + return getattr(args[1], self.actions[1])(args[0]) + + def _render(self, link, *args): + """Global step for __txt__ and __tex__ + + :param link: the link between operators + :param *args: the operands + :returns: the string with operator and operands + + """ + replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)} + + ans = link.format(**replacement) + ans = save_mainOp(ans, self) + return ans def __txt__(self, *args): """Txt rendering for the operator @@ -91,11 +77,7 @@ class Operator(str): >>> op.sub1.__txt__(f) '- ( 2 + 3 )' """ - replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)} - - ans = self._txt.format(**replacement) - ans = save_mainOp(ans, self) - return ans + return self._render(self.txt, *args) def __tex__(self, *args): """Tex rendering for the operator @@ -119,11 +101,7 @@ class Operator(str): >>> op.sub1.__tex__(f) '- ( 2 + 3 )' """ - replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)} - - ans = self._tex.format(**replacement) - ans = save_mainOp(ans, self) - return ans + return self._render(self.tex, *args) def __p2i__(self, *args): """Fix list transformation for the operator @@ -166,6 +144,7 @@ class Operator(str): if op.mainOp.priority < self.priority: op = flatten_list(["("] + [op] + [")"]) except AttributeError: + # op has not the attribute priority try: if int(op) < 0: op = ['(', op, ')'] @@ -173,18 +152,6 @@ class Operator(str): pass return flatten_list([op]) - -class op(object): - """ List of admited operations """ - # TODO: On pourrait peut être le faire plus proprement avec des décorateurs? |mar. nov. 11 20:24:54 CET 2014 - add = Operator("+") - sub = Operator("-") - mul = Operator("*") - div = Operator("/") - pw = Operator("^") - sub1 = Operator("-", 1) - par = Operator("(") - def save_mainOp(obj, mainOp): """Create a temporary class build over built-in type to stock the main operation of a calculus @@ -201,27 +168,339 @@ def save_mainOp(obj, mainOp): return Fake(obj) +def operatorize(fun): + """Transform the answer of the function into an operator + + The returned value of the function has to be a dictionnary with those keys + * "operator": the name (Needed!) + * "priority": the priority level + * "actions": mathematics actions of the operator (list of 1 element if the arity is 1, 2 elements if arity is 2) + * "txt": string ready to be formated in txt for with {op1} and/or {op2} + * "tex": string ready to be formated in tex for with {op1} and/or {op2} + * "arity": arity ie number of operands needed + * "_call": action to perform when call the operator + * "_render": action use in __txt__ and __tex__ + * "__txt__": txt rendering + * "__tex__": tex rendering + * "add_parenthesis": mechanism to add parenthesis + """ + def mod_fun(self, *args): + ans = fun(self, *args) + + new_op = Operator(ans["operator"]) + for (attr, value) in ans.items(): + if hasattr(value, '__call__'): + setattr(new_op, attr, types.MethodType(value, new_op)) + else: + setattr(new_op, attr, value) + + return new_op + return mod_fun + +class ClassProperty(object): + + def __init__(self, fget): + self.fget = fget + + def __get__(self, owner_self, owner_cls): + return self.fget(owner_cls) + +class op(object): + """ List of admited operations """ + + _operators = {("+",2): "add",\ + ("-", 2): "sub",\ + ("-", 1): "sub1",\ + ("*", 2): "mul",\ + ("/", 2): "div",\ + ("^", 2): "pw",\ + ("(", 2): "par",\ + } + + @classmethod + def get_op(cls, op, arity = 2): + """Return the corresponding operator + + :op: symbole of the op + :arity: the arity + + >>> op.get_op('+') + '+' + >>> mul = op.get_op('*') + >>> mul.tex + '{op1} \\\\times {op2}' + >>> mul.txt + '{op1} * {op2}' + """ + try: + return getattr(cls, cls._operators[(op, arity)]) + except KeyError: + raise KeyError("{theOp} (arity: {arity}) is not available".format(theOp = op, arity = arity)) + + @classmethod + def can_be_operator(cls, symbole): + """ Tell if the symbole can be an operator """ + return symbole in [i[0] for i in cls._operators] + + + @ClassProperty + @operatorize + def add(cls): + """ The operator + + + >>> add = op.add + >>> add + '+' + >>> add(1, 2) + 3 + >>> add.__tex__('1','2') + '1 + 2' + >>> add.__txt__('1','2') + '1 + 2' + >>> add.__tex__('1','-2') + '1 + (-2)' + """ + caract = { + "operator" : "+", \ + "name" : "add",\ + "priority" : 1, \ + "arity" : 2, \ + "actions" : ("__add__","__radd__"), \ + "txt" : "{op1} + {op2}",\ + "tex" : "{op1} + {op2}",\ + } + + return caract + + @ClassProperty + @operatorize + def sub(self): + """ The operator - + + >>> sub = op.sub + >>> sub + '-' + >>> sub(1, 2) + -1 + >>> sub.__tex__('1','2') + '1 - 2' + >>> sub.__txt__('1','2') + '1 - 2' + >>> sub.__tex__('1','-2') + '1 - (-2)' + """ + caract = { + "operator" : "-", \ + "name" : "sub",\ + "priority" : 1, \ + "arity" : 2, \ + "actions" : ("__sub__","__rsub__"), \ + "txt" : "{op1} - {op2}",\ + "tex" : "{op1} - {op2}",\ + } + + return caract + + @ClassProperty + @operatorize + def sub1(self): + """ The operator - + + >>> sub1 = op.sub1 + >>> sub1 + '-' + >>> sub1(1) + -1 + >>> sub1.__tex__('1') + '- 1' + >>> sub1.__txt__('1') + '- 1' + >>> sub1.__tex__('-1') + '- (-1)' + """ + def add_parenthesis(self, op): + """ Add parenthesis if necessary """ + try: + if op.mainOp.priority <= self.priority: + op = flatten_list(["("] + [op] + [")"]) + except AttributeError: + # op has not the attribute priority + try: + if int(op) < 0: + op = ['(', op, ')'] + except ValueError: + pass + return flatten_list([op]) + + caract = { + "operator" : "-", \ + "name" : "sub1",\ + "priority" : 2, \ + "arity" : 1, \ + "actions" : "__neg__",\ + "txt" : "- {op1}",\ + "tex" : "- {op1}",\ + "add_parenthesis": add_parenthesis,\ + } + + return caract + + @ClassProperty + @operatorize + def mul(self): + """ The operator * + + >>> mul = op.mul + >>> mul + '*' + >>> mul(1, 2) + 2 + >>> mul.__tex__('1','2') + '1 \\times 2' + >>> mul.__txt__('1','2') + '1 * 2' + >>> mul.__tex__('1','-2') + '1 \\times (-2)' + """ + # * can not be display in some cases + def _render(self, link, *args): + + replacement = {"op"+str(i+1): ' '.join(self.add_parenthesis(op)) for (i,op) in enumerate(args)} + + if not self.visibility or args[1][0] == "(" or \ + (type(args[1][0]) == str and args[1][0].isalpha()): + ans = "{op1} {op2}".format(**replacement) + ans = save_mainOp(ans, self) + return ans + else: + ans = link.format(**replacement) + ans = save_mainOp(ans, self) + return ans + + caract = { + "operator" : "*", \ + "name" : "mul",\ + "priority" : 4, \ + "arity" : 2, \ + "actions" : ("__mul__","__rmul__"), \ + "txt" : "{op1} * {op2}",\ + "tex" : "{op1} \\times {op2}",\ + "visibility": 1,\ + "_render": _render + } + + return caract + + @ClassProperty + @operatorize + def div(self): + """ The operator / + + >>> div = op.div + >>> div + '/' + >>> div(1, 2) + < Fraction 1 / 2> + >>> div.__tex__('1','2') + '\\frac{ 1 }{ 2 }' + >>> div.__tex__('1','2') + '\\frac{ -1 }{ 2 }' + >>> div.__txt__('1','2') + '1 / 2' + """ + from .fraction import Fraction + def _call(self, op1, op2): + if op2 == 1: + return op1 + else: + return Fraction(op1,op2) + + def __tex__(self, *args): + # Pas besoin de parenthèses en plus pour \frac + replacement = {"op"+str(i+1): op for (i,op) in enumerate(args)} + + ans = self.tex.format(**replacement) + ans = save_mainOp(ans, self) + return ans + + caract = { + "operator" : "/", \ + "name" : "div",\ + "priority" : 4, \ + "arity" : 2, \ + "txt" : "{op1} / {op2}",\ + "tex" : "\\frac{{ {op1} }}{{ {op2} }}",\ + "_call": _call,\ + "__tex__":__tex__,\ + } + + return caract + + @ClassProperty + @operatorize + def pw(self): + """ The operator ^ + + >>> pw = op.pw + >>> pw + '^' + >>> pw(2, 3) + 8 + >>> pw.__tex__('2','3') + '2^{ 3 }' + >>> pw.__txt__('2','3') + '2 ^ 3' + >>> pw.__txt__('-2','3') + '( -2 ) ^ 3' + """ + def _call(self, op1, op2): + """ Calling this operator performs the rigth calculus """ + return getattr(op1, "__pow__")(op2) + + caract = { + "operator" : "^", \ + "name" : "pw",\ + "priority" : 5, \ + "arity" : 2, \ + "actions" : ("__pow__",""), \ + "txt" : "{op1} ^ {op2}",\ + "tex" : "{op1}^{{ {op2} }}",\ + "_call":_call,\ + } + + return caract + + @ClassProperty + @operatorize + def par(self): + """ The operator ( """ + caract = { + "operator" : "(", \ + "name" : "par",\ + "priority" : 0, \ + "arity" : 0, \ + } + return caract + if __name__ == '__main__': - op = Operator("+", 2) - print(op.__txt__('1','2')) - mul = Operator("*", 2) - add = Operator("+", 2) - sub1 = Operator("-", 1) - div = Operator("/", 1) - print(mul.__txt__('1','2')) - print(add.__txt__('1','2')) - f = save_mainOp('2 + 3',add) - print(mul.__txt__(f, '4')) - f = save_mainOp('-3',sub1) - print(sub1.__txt__(f)) - print(sub1.__txt__('-3')) - f = save_mainOp('2 + 3',add) - print(sub1.__txt__(f)) + print(op.add.__tex__('1','2')) + print(op.mul.__tex__('1','2')) + print(op.sub.__tex__('1','2')) + f = save_mainOp('2 + 3',op.add) + print(op.mul.__txt__(f, '4')) + f = save_mainOp('-3',op.sub1) + print(op.sub1.__txt__(f)) + print(op.sub1.__txt__('-3')) + f = save_mainOp('2 + 3',op.add) + print(op.sub1.__txt__(f)) from .fraction import Fraction f = Fraction(1, 2) - print(add.__txt__(f.__txt__(),'2')) - print(add.__tex__(f.__tex__(),'2')) + print(op.add.__txt__(f.__txt__(),'2')) + print(op.add.__tex__(f.__tex__(),'2')) + + print("\t op.can_be_operator('+') :" + str(op.can_be_operator('+'))) + print("\t op.can_be_operator('t') :" + str(op.can_be_operator('t'))) import doctest diff --git a/pymath/random_expression.py b/pymath/random_expression.py index 32935a6..a638744 100644 --- a/pymath/random_expression.py +++ b/pymath/random_expression.py @@ -31,6 +31,19 @@ class RdExpression(object): @classmethod def set_form(cls, form): + """ Define whether RdExpression create expression with Expression (nice render) or if it only replace inside {} not taking care or render + + >>> form = "{a}*{b}" + >>> exp = RdExpression(form)() + >>> print(type(exp)) + + >>> RdExpression.set_form("raw") + >>> form = "{a}*{b}" + >>> exp = RdExpression(form)() + >>> print(type(exp)) + + """ + cls.FORM = form @classmethod @@ -189,12 +202,13 @@ if __name__ == '__main__': rdExp3 = RdExpression(form, cond) desc_rdExp(rdExp3) - form = "{a + a*10}*4 + {a} + 2*{b}" + form = "{a+a*10}*4 + {a} + 2*{b}" cond = ["{a-b} + {b} in list(range(20))", "abs({a}) not in [1]", "{b} not in [1]", "gcd({a},{b}) == 1"] rdExp3 = RdExpression(form, cond) desc_rdExp(rdExp3) - + import doctest + doctest.testmod() diff --git a/pymath/str2tokens.py b/pymath/str2tokens.py index 69042b7..124b698 100644 --- a/pymath/str2tokens.py +++ b/pymath/str2tokens.py @@ -1,8 +1,8 @@ #!/usr/bin/env python # encoding: utf-8 -from .operator import Operator from .generic import Stack, isOperator, isNumber +from pymath.operator import op def str2tokens(exp): """ Parse the string into tokens then turn it into postfix form @@ -51,7 +51,7 @@ def str2in_tokens(exp): tokens.append(int(character)) elif character in "+-*/:^": - tokens.append(Operator(character)) + tokens.append(character) elif character == ")": tokens.append(character) @@ -60,9 +60,8 @@ def str2in_tokens(exp): # If "3(", ")(" if isNumber(tokens[-1]) \ or tokens[-1] == ")" : - #tokens.append(Operator("*")) - tokens.append(Operator("*")) - tokens.append(Operator(character)) + tokens.append("*") + tokens.append(character) elif character == ".": raise ValueError("No float number please") @@ -80,15 +79,11 @@ def in2post_fix(infix_tokens): @param infix_tokens: the infix list of tokens to transform into postfix form. @return: the corresponding postfix list of tokens. - >>> a, s, m, d, p = Operator("+"), Operator("-"), Operator("*"), Operator("/"), Operator("^") - >>> s1 = Operator("-", 1) - >>> par = Operator("(") - - >>> in2post_fix([par, 2, a, 5, s, 1, ')', d, par, 3, m, 4, ')']) + >>> in2post_fix([op.par, 2, op.add, 5, op.sub, 1, ')', op.div, op.par, 3, op.mul, 4, ')']) [2, 5, '+', 1, '-', 3, 4, '*', '/'] - >>> in2post_fix([s1, par, s1, 2, ')']) + >>> in2post_fix([op.sub1, op.par, op.sub1, 2, ')']) [2, '-', '-'] - >>> in2post_fix([s1, par, s1, 2, a, 3, m, 4, ')']) + >>> in2post_fix([op.sub1, op.par, op.sub1, 2, op.add, 3, op.mul, 4, ')']) [2, '-', 3, 4, '*', '+', '-'] """ # Stack where operator will be stocked @@ -101,13 +96,13 @@ def in2post_fix(infix_tokens): for (pos_token,token) in enumerate(infix_tokens): - ## Pour voir ce qu'il se passe dans cette procédure + # 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 == ")": - op = opStack.pop() - while op != "(": - postfix_tokens.append(op) - op = opStack.pop() + next_op = opStack.pop() + while next_op != "(": + postfix_tokens.append(next_op) + next_op = opStack.pop() # Go back to old arity arity_Stack.pop() @@ -115,23 +110,22 @@ def in2post_fix(infix_tokens): arity = arity_Stack.pop() arity_Stack.push(arity + 1) - elif isOperator(token): + elif op.can_be_operator(token): if token == "(": - opStack.push(token) + opStack.push(op.get_op(token)) # Set next arity counter arity_Stack.push(0) else: - while (not opStack.isEmpty()) and opStack.peek().priority >= token.priority: - op = opStack.pop() - postfix_tokens.append(op) - arity = arity_Stack.pop() - - token.arity = arity + 1 - opStack.push(token) - # print("--", token, " -> ", str(arity + 1)) + token_op = op.get_op(token, arity + 1) # Reset arity to 0 in case there is other operators (the real operation would be "-op.arity + 1") arity_Stack.push(0) + while (not opStack.isEmpty()) and opStack.peek().priority >= token_op.priority: + next_op = opStack.pop() + postfix_tokens.append(next_op) + + opStack.push(token_op) + #print("--", token, " -> ", str(arity + 1)) else: postfix_tokens.append(token) arity = arity_Stack.pop() @@ -141,8 +135,8 @@ def in2post_fix(infix_tokens): #print(str(postfix_tokens), " | ", str(opStack), " | ", str(infix_tokens[(pos_token+1):]), " | ", str(arity_Stack)) while not opStack.isEmpty(): - op = opStack.pop() - postfix_tokens.append(op) + next_op = opStack.pop() + postfix_tokens.append(next_op) ## 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)) @@ -161,7 +155,6 @@ if __name__ == '__main__': # #print(in2post_fix(in_tokens)) - from .operator import op print(in2post_fix([op.par, 2, op.add, 5, op.sub, 1, ')', op.div, op.par, 3, op.mul, 4, ')'])) print(in2post_fix([op.sub1, op.par, op.sub1, 2, ')'])) print(in2post_fix([op.sub1, op.par, op.sub1, 2, op.add, 3, op.mul, 4, ')'])) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a4ced4f --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pyparsing==2.0.3 diff --git a/test/test_fraction.py b/test/test_fraction.py index 78c4cdf..3ed27f9 100644 --- a/test/test_fraction.py +++ b/test/test_fraction.py @@ -121,6 +121,17 @@ class TestFraction(unittest.TestCase): def test_le(self): pass + def test_tex(self): + f = Fraction(2, 3) + ans = "\\frac{ 2 }{ 3 }" + self.assertEqual(f.__tex__(), ans) + + def test_txt(self): + f = Fraction(2, 3) + ans = "2 / 3" + self.assertEqual(f.__txt__(), ans) + + if __name__ == '__main__': unittest.main() diff --git a/test/test_random_expression.py b/test/test_random_expression.py index bed6114..8dc11e1 100644 --- a/test/test_random_expression.py +++ b/test/test_random_expression.py @@ -22,15 +22,15 @@ class TestRandomExpression(unittest.TestCase): self.assertEqual(set(rdExp._gene_2replaced.keys()), {'a'}) def test_only_form_calc(self): - form = "{a + b} + 2" + form = "{a+b} + 2" rdExp = RdExpression(form) self.assertEqual(rdExp._letters, {'a', 'b'}) - self.assertEqual(rdExp._2replaced, {'a + b'}) + self.assertEqual(rdExp._2replaced, {'a+b'}) rdExp() self.assertEqual(set(rdExp._gene_varia.keys()), {'a', 'b'}) - self.assertEqual(set(rdExp._gene_2replaced.keys()), {'a + b'}) + self.assertEqual(set(rdExp._gene_2replaced.keys()), {'a+b'}) def test_only_form_cond(self): form = "{a} + 2" @@ -78,15 +78,15 @@ class TestRandomExpression(unittest.TestCase): def test_only_form_calc_cond_calc(self): form = "{a*3} * {b}" - cond = ["{a + b} == 3"] + cond = ["{a+b} == 3"] rdExp = RdExpression(form, cond) self.assertEqual(rdExp._letters, {'a', 'b'}) - self.assertEqual(rdExp._2replaced, {'b', 'a*3', 'a + b'}) + self.assertEqual(rdExp._2replaced, {'b', 'a*3', 'a+b'}) rdExp() self.assertEqual(set(rdExp._gene_varia.keys()), {'a', 'b'}) - self.assertEqual(set(rdExp._gene_2replaced.keys()), {'b', 'a*3', 'a + b'}) + self.assertEqual(set(rdExp._gene_2replaced.keys()), {'b', 'a*3', 'a+b'}) self.assertEqual((rdExp._gene_varia['a'] + rdExp._gene_varia['b']), 3) diff --git a/test/test_render.py b/test/test_render.py index aa22126..0dee1dd 100644 --- a/test/test_render.py +++ b/test/test_render.py @@ -6,7 +6,7 @@ import unittest from pymath.render import tex, txt,p2i from pymath.fraction import Fraction -from pymath.operator import Operator +from pymath.operator import op @@ -23,29 +23,29 @@ class TestTexRender(unittest.TestCase): self.assertEqual(tex([Fraction(1,2)]), "\\frac{ 1 }{ 2 }") def test_mult_interger(self): - exps = [ [2, 3, Operator("*", 2)], [2, -3, Operator("*", 2)], [-2, 3, Operator("*", 2)]] + exps = [ [2, 3, op.get_op("*", 2)], [2, -3, op.get_op("*", 2)], [-2, 3, op.get_op("*", 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", Operator("*", 2)], ["a", 3, Operator("*", 2)], [-2, "a", Operator("*", 2)], ["a", -2, Operator("*", 2)]] + exps = [ [2, "a", op.get_op("*", 2)], ["a", 3, op.get_op("*", 2)], [-2, "a", op.get_op("*", 2)], ["a", -2, op.get_op("*", 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), Operator("*", 2)], [Fraction(1,2), 3, Operator("*", 2)]] + exps = [ [2, Fraction(1,2), op.get_op("*", 2)], [Fraction(1,2), 3, op.get_op("*", 2)]] wanted_render = [ "2 \\times \\frac{ 1 }{ 2 }", "\\frac{ 1 }{ 2 } \\times 3"] for (i,e) in enumerate(exps): rend = tex(e) self.assertEqual(rend, wanted_render[i]) def test_parentheses(self): - mul = Operator("*", 2) - add = Operator("+", 2) + mul = op.get_op("*", 2) + add = op.get_op("+", 2) exps = [\ [ 2, 3, add, 4, mul],\ [ 2, 3, mul, 4, add],\ @@ -81,35 +81,35 @@ class TesttxtRender(unittest.TestCase): self.assertEqual(txt([Fraction(1,2)]), "1 / 2") def test_mult_interger(self): - exps = [ [2, 3, Operator("*", 2)], \ - [2, -3, Operator("*", 2)], \ - [-2, 3, Operator("*", 2)]] + exps = [ [2, 3, op.get_op("*", 2)], \ + [2, -3, op.get_op("*", 2)], \ + [-2, 3, op.get_op("*", 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", Operator("*", 2)], \ - ["a", 3, Operator("*", 2)], \ - [-2, "a", Operator("*", 2)], \ - ["a", -2, Operator("*", 2)]] + exps = [ [2, "a", op.get_op("*", 2)], \ + ["a", 3, op.get_op("*", 2)], \ + [-2, "a", op.get_op("*", 2)], \ + ["a", -2, op.get_op("*", 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), Operator("*", 2)], \ - [Fraction(1,2), 3, Operator("*", 2)]] + exps = [ [2, Fraction(1,2), op.get_op("*", 2)], \ + [Fraction(1,2), 3, op.get_op("*", 2)]] wanted_render = [ "2 * 1 / 2", "1 / 2 * 3"] for (i,e) in enumerate(exps): rend = txt(e) self.assertEqual(rend, wanted_render[i]) def test_parentheses(self): - mul = Operator("*", 2) - add = Operator("+", 2) + mul = op.get_op("*", 2) + add = op.get_op("+", 2) exps = [\ [ 2, 3, add, 4, mul],\ [ 2, 3, mul, 4, add],\