refactoring op but tests are not passed yet

This commit is contained in:
Benjamin Bertrand
2016-02-23 13:53:13 +03:00
parent fa393ef65e
commit 8ed382bbe2
13 changed files with 772 additions and 646 deletions

View File

@@ -0,0 +1,12 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator_set import op
from .operator import save_mainOp
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator import Operator, save_mainOp
class Add(Operator):
_CARACT = {
"operator" : "+", \
"name" : "add",\
"priority" : 1, \
"arity" : 2, \
"actions" : ("__add__","__radd__"), \
"txt" : "{op1} + {op2}",\
"tex" : "{op1} + {op2}",\
}
def __init__(self):
""" Initiate Add Operator """
super(Add, self).__init__(**self._CARACT)
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
"""
if args[1][0] == "-":
op1 = self.l_parenthesis(args[0], True)
op2 = self.r_parenthesis(args[1][1:], True)
ans = link.replace('+','-').format(op1 = op1, op2 = op2)
ans = save_mainOp(ans, self)
return ans
else:
op1 = self.l_parenthesis(args[0], True)
op2 = self.r_parenthesis(args[1], True)
ans = link.format(op1 = op1, op2 = op2)
ans = save_mainOp(ans, self)
return ans
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator import Operator, save_mainOp
class Div(Operator):
""" 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'
"""
_CARACT = {
"operator" : "/", \
"name" : "div",\
"priority" : 5, \
"arity" : 2, \
"txt" : "{op1} / {op2}",\
"tex" : "\\frac{{ {op1} }}{{ {op2} }}",\
}
def __init__(self):
""" Initiate Div Operator """
super(Div, self).__init__(**self._CARACT)
def __call__(self, op1, op2):
if op2 == 1:
return op1
else:
from ..fraction import Fraction
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
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator import Operator, save_mainOp
class Mul(Operator):
""" The operator *
>>> mul = op.mul
>>> mul
'*'
>>> mul(1, 2)
2
>>> mul.__tex__('1','2')
'1 \\times 2'
>>> mul.__tex__('2','a')
'2 a'
>>> mul.__txt__('1','2')
'1 * 2'
>>> mul.__txt__('2','a')
'2 a'
>>> mul.__txt__('a','2')
'a * 2'
>>> mul.__tex__('1','-2')
'1 \\times (-2)'
"""
_CARACT = {
"operator" : "*", \
"name" : "mul",\
"priority" : 4, \
"arity" : 2, \
"actions" : ("__mul__","__rmul__"), \
"txt" : "{op1} * {op2}",\
"tex" : "{op1} \\times {op2}",\
}
def __init__(self):
""" Initiate Mul Operator """
super(Mul, self).__init__(**self._CARACT)
# TODO: Add self.visibility |sam. nov. 8 17:00:08 CET 2014
self.visibility = 1
def is_visible(self, op1, op2):
""" Tells whether self has to be visible or not
:param op1: left operande
:param op2: rigth operande
"""
# TODO: À finir!!! |lun. mars 9 00:03:40 CET 2015
if type(op2) == int:
# op2 est maintenant une chaine de caractères
return True
elif op2.isdecimal():
return True
elif op2.isalpha():
return False
elif op2[0].isdecimal():
return True
elif op2[0] == "(" and not ("+" in op2 or "-" in op2[3:]):
return True
# Giga bricolage...
elif "frac" in op2:
return True
else:
return False
def _render(self, link, *args):
op1 = self.l_parenthesis(args[0], True)
op2 = self.r_parenthesis(args[1], True)
if not self.is_visible(op1, op2):
ans = "{op1} {op2}".format(op1 = op1, op2 = op2)
else:
ans = link.format(op1 = op1, op2 = op2)
ans = save_mainOp(ans, self)
return ans
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,236 @@
#!/usr/bin/env python
# encoding: utf-8
#from debug.tools import report
from ..generic import flatten_list, isNumber
from functools import wraps
import types
class Operator():
"""The operator class, is a string (representation of the operator) with its arity"""
def __init__(self, operator = "", name = "", priority = 0, actions = ("",""), txt = "", tex = "", arity = 2, **kwrds):
""" Create an Operator """
self.operator = operator
self.name = name
self.arity = arity
self.priority = priority
self.actions = actions
self.txt = txt
self.tex = tex
self.isOperator = 1
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:
#if type(args[1]) == int:
if issubclass(type(args[1]),int):
return getattr(args[0], self.actions[0])(args[1])
else:
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
"""
if self.arity == 1:
op1 = self.l_parenthesis(args[0], True)
ans = link.format(op1 = op1)
elif self.arity == 2:
op1 = self.l_parenthesis(args[0], True)
op2 = self.r_parenthesis(args[1], True)
ans = link.format(op1 = op1, op2 = op2)
ans = save_mainOp(ans, self)
return ans
def __repr__(self):
return self.operator
def __str__(self):
return str(self.operator)
def __txt__(self, *args):
"""Txt rendering for the operator
:*args: Operands for this operation
:returns: String with operator and his operands
>>> op.mul.__txt__('1','2')
'1 * 2'
>>> op.add.__txt__('1','2')
'1 + 2'
>>> f = save_mainOp('2 + 3',op.add)
>>> op.mul.__txt__(f, '4')
'( 2 + 3 ) * 4'
>>> f = save_mainOp('-3',op.sub1)
>>> op.sub1.__txt__(f)
'- ( -3 )'
>>> op.sub1.__txt__('-3')
'- ( -3 )'
>>> f = save_mainOp('2 + 3',op.add)
>>> op.sub1.__txt__(f)
'- ( 2 + 3 )'
"""
return self._render(self.txt, *args)
def __tex__(self, *args):
"""Tex rendering for the operator
:*args: Operands for this operation
:returns: String with operator and his operands
>>> op.mul.__tex__('1','2')
'1 \\\\times 2'
>>> op.add.__tex__('1','2')
'1 + 2'
>>> f = save_mainOp('2 + 3',op.add)
>>> op.mul.__tex__(f, '4')
'( 2 + 3 ) \\\\times 4'
>>> f = save_mainOp('-3',op.sub1)
>>> op.sub1.__tex__(f)
'- ( -3 )'
>>> op.sub1.__tex__('-3')
'- ( -3 )'
>>> f = save_mainOp('2 + 3',op.add)
>>> op.sub1.__tex__(f)
'- ( 2 + 3 )'
"""
return self._render(self.tex, *args)
def __p2i__(self, *args):
"""Fix list transformation for the operator
:*args: Operands for this operation
:returns: list with the operator surrounded by operands
>>> op.mul.__p2i__(1,2)
[1, '*', 2]
>>> f = save_mainOp([2, op.add, 3],op.add)
>>> op.mul.__p2i__(f, 4)
['(', 2, '+', 3, ')', '*', 4]
>>> f = save_mainOp([op.sub1, 3],op.sub1)
>>> op.sub1.__p2i__(f)
['-', '(', '-', 3, ')']
>>> op.sub1.__p2i__(-3)
['-', '(', -3, ')']
>>> f = save_mainOp([2, op.add, 3],op.add)
>>> op.sub1.__p2i__(f)
['-', '(', 2, '+', 3, ')']
"""
if self.arity == 1:
op1 = self.l_parenthesis(args[0])
ans = flatten_list([self, op1])
elif self.arity == 2:
op1 = self.l_parenthesis(args[0])
op2 = self.r_parenthesis(args[1])
ans = flatten_list([op1, self, op2])
ans = save_mainOp(ans, self)
return ans
def l_parenthesis(self, opl, str_join=False):
""" Add parenthesis for left operand if necessary """
ans = opl
try:
# TODO: Je pige pas pourquoi quand on enlève .name ça marche plus... |lun. avril 27 19:07:24 CEST 2015
if opl.mainOp.name == "sub1":
ans = opl
elif opl.mainOp.priority < self.priority:
ans = flatten_list(["(", opl, ")"])
except AttributeError as e:
# op has not the attribute priority
pass
ans = flatten_list([ans])
if str_join:
ans = ' '.join([str(i) for i in ans])
return ans
def r_parenthesis(self, op, str_join=False):
""" Add parenthesis for rigth operand 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
ans = flatten_list([op])
if str_join:
ans = ' '.join([str(i) for i in ans])
return ans
def uniq_desc(self):
""" Return the uniq description of the operator
:returns: (self.name, self.arity)
"""
return (self.operator, self.arity)
def __eq__(self, op2):
""" op1 == op2 """
return self.name == op2.name and self.arity == op2.arity
def save_mainOp(obj, mainOp):
"""Create a temporary class build over built-in type to stock the main operation of a calculus
:obj: the object to add the attribute
:mainOp: the main operator
:returns: the same object with the main operation attribute
"""
# TODO: À mettre avec render? |mar. févr. 23 09:45:22 EAT 2016
# TODO: On pourrait mettre un try avant de créer une nouvelle classe |mar. févr. 23 09:44:45 EAT 2016
Fake = type('fake_'+str(type(obj)), (type(obj),), {'mainOp': mainOp})
return Fake(obj)
if __name__ == '__main__':
#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(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')))
print("op.sub.__dict__ -> ", op.sub.__dict__)
print(op.sub == op.sub1)
#import doctest
#doctest.testmod()
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python
# encoding: utf-8
import types
from .add import Add
from .div import Div
from .mul import Mul
from .par import Par
from .pw import Pw
from .sub import Sub
from .sub1 import Sub1
class Operator_set(object):
""" Class for sets of operators"""
def __init__(self):
""" Initiate the operator_set """
self._operators = {}
def get_op(self, op, arity = 2):
"""Return the corresponding operator
:op: symbole of the op
:arity: the arity
>>> op = Operator_set()
>>> op.get_op('+')
'+'
>>> mul = op.get_op('*')
>>> mul.tex
'{op1} \\\\times {op2}'
>>> mul.txt
'{op1} * {op2}'
"""
try:
return getattr(self, self._operators[(op, arity)])
except KeyError:
raise KeyError("{theOp} (arity: {arity}) is not available".format(theOp = op, arity = arity))
def can_be_operator(cls, symbole):
""" Tell if the symbole can be an operator """
if type(symbole) == str:
return symbole in [i[0] for i in cls._operators]
else:
return False
def store_operator(self, operator):
""" Save the operator as a method and
:param operator: the operator (the class) (it will be accessible through .name method name.
"""
# TODO: faire une vérif si on peut utiliser operator_name |mar. févr. 23 09:09:44 EAT 2016
self._operators[operator.uniq_desc()] = operator.name
setattr(self, operator.name, operator)
op = Operator_set()
op.store_operator(Add())
op.store_operator(Div())
op.store_operator(Mul())
op.store_operator(Par())
op.store_operator(Pw())
op.store_operator(Sub())
op.store_operator(Sub1())
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator import Operator
class Par(Operator):
""" The operator ( """
_CARACT = {
"operator" : "(", \
"name" : "par",\
"priority" : 0, \
"arity" : 0, \
}
def __init__(self):
""" Initiate Par Operator """
super(Par, self).__init__(**self._CARACT)
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,67 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator import Operator
from ..generic import flatten_list
class Pw(Operator):
""" 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'
"""
_CARACT = {
"operator" : "^", \
"name" : "pw",\
"priority" : 6, \
"arity" : 2, \
"actions" : ("__pow__",""), \
"txt" : "{op1} ^ {op2}",\
"tex" : "{op1}^{{ {op2} }}",\
}
def __init__(self):
""" Initiate Pw Operator """
super(Pw, self).__init__(**self._CARACT)
def __call__(self, op1, op2):
""" Calling this operator performs the rigth calculus """
return getattr(op1, "__pow__")(op2)
def l_parenthesis(self, opl, str_join=False):
""" Add parenthesis for left operand if necessary """
ans = opl
try:
if opl.mainOp.priority < self.priority:
ans = flatten_list(["(", opl, ")"])
except AttributeError as e:
# op has not the attribute priority
pass
try:
if int(opl) < 0:
ans = ["(", opl, ")"]
except ValueError:
pass
ans = flatten_list([ans])
if str_join:
ans = ' '.join([str(i) for i in ans])
return ans
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator import Operator
from ..generic import flatten_list
class Sub(Operator):
""" 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)'
>>> sub.__tex__('-1','2')
'-1 - 2'
"""
_CARACT = {
"operator" : "-", \
"name" : "sub",\
"priority" : 2, \
"arity" : 2, \
"actions" : ("__sub__","__rsub__"), \
"txt" : "{op1} - {op2}",\
"tex" : "{op1} - {op2}",\
}
def __init__(self):
""" Initiate Sub Operator """
super(Sub, self).__init__(**self._CARACT)
def l_parenthesis(self, op, str_join=False):
return op
def r_parenthesis(self, op, str_join=False):
try:
if op.mainOp.priority <= self.priority:
op = flatten_list(["(", op, ")"])
elif op[0] == '-':
op = flatten_list(["(", op, ")"])
except AttributeError:
# op has not the attribute priority
try:
if int(op) < 0:
op = ['(', op, ')']
except ValueError:
pass
ans = flatten_list([op])
if str_join:
ans = ' '.join([str(i) for i in ans])
return ans
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env python
# encoding: utf-8
from .operator import Operator
from ..generic import flatten_list
class Sub1(Operator):
""" The operator -
>>> sub1 = op.sub1
>>> sub1
'-'
>>> sub1(1)
-1
>>> sub1.__tex__('1')
'- 1'
>>> sub1.__txt__('1')
'- 1'
>>> sub1.__tex__('-1')
'- (-1)'
"""
_CARACT = {
"operator" : "-", \
"name" : "sub1",\
"priority" : 3, \
"arity" : 1, \
"actions" : "__neg__",\
"txt" : "- {op1}",\
"tex" : "- {op1}",\
}
def __init__(self):
""" Initiate Sub1 Operator """
super(Sub1, self).__init__(**self._CARACT)
def l_parenthesis(self, op, str_join=False):
""" 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
ans = flatten_list([op])
if str_join:
ans = ' '.join([str(i) for i in ans])
return ans
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env python
# encoding: utf-8
from pymath.calculus.operator.add import Add
def test_add_render_tex():
assert Add().__tex__('1', '2') == '1 + 2'
assert Add().__tex__('1', '-2') == '1 - 2'
def test_add_render_txt():
assert Add().__txt__('1', '2') == '1 + 2'
assert Add().__txt__('1', '-2') == '1 - 2'
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python
# encoding: utf-8
from pymath.calculus.operator import op
# Test de op.add
def test_add_render_tex():
assert op.add.__tex__('1', '2') == '1 + 2'
assert op.add.__tex__('1', '-2') == '1 - 2'
def test_add_render_txt():
assert op.add.__txt__('1', '2') == '1 + 2'
assert op.add.__txt__('1', '-2') == '1 - 2'
# Test de op.sub
def test_sub_render_tex():
assert op.sub.__tex__('1', '2') == '1 - 2'
assert op.sub.__tex__('1', '-2') == '1 - ( -2 )'
def test_sub_render_txt():
assert op.sub.__txt__('1', '2') == '1 - 2'
assert op.sub.__txt__('1', '-2') == '1 - ( -2 )'
# Test de op.sub1
def test_sub1_render():
assert op.sub1.__tex__('1') == '- 1'
assert op.sub1.__tex__('-1') == '- ( -1 )'
assert op.sub1.__txt__('1') == '- 1'
assert op.sub1.__txt__('-1') == '- ( -1 )'
# Test de op.mul
def test_mul_render_tex():
assert op.mul.__tex__('1', '2') == '1 \\times 2'
assert op.mul.__tex__('1', '-2') == '1 \\times ( -2 )'
def test_mul_render_txt():
assert op.mul.__txt__('1', '2') == '1 * 2'
assert op.mul.__txt__('1', '-2') == '1 * ( -2 )'
def test_mul_is_visible():
assert op.mul.is_visible(2, 3)
assert op.mul.is_visible(2, -3)
assert op.mul.is_visible(-2, 3)
assert op.mul.is_visible('a', 2)
assert op.mul.is_visible('(2a + 1)', 2)
assert op.mul.is_visible(2, '(-2)')
assert op.mul.is_visible(2, '2a')
assert op.mul.is_visible(2, '(-2a)')
assert op.mul.is_visible(2, '(-2abc)')
assert op.mul.is_visible(2, 'a') == False
assert op.mul.is_visible(2, '(2a + 1)') == False
assert op.mul.is_visible('(3x - 1)', '(2a + 1)') == False
assert op.mul.is_visible(2, '(-2x + 1)(3x + 2)') == False
# Test de op.div
def test_div_render_tex():
assert op.div.__tex__('1', '2') == '\\frac{ 1 }{ 2 }'
assert op.div.__tex__('1', '-2') == '\\frac{ 1 }{ -2 }'
def test_div_render_txt():
assert op.div.__txt__('1', '2') == '1 / 2'
assert op.div.__txt__('1', '-2') == '1 / ( -2 )'
# Test de op.pw
def test_pw_render_tex():
assert op.pw.__tex__('1', '2') == '1^{ 2 }'
#assert op.pw.__tex__('1','-2') == '1^{-2}'
#assert op.pw.__tex__('-1','2') == '( -1 )^{ 2 }'
def test_pw_render_txt():
assert op.pw.__txt__('1', '2') == '1 ^ 2'
assert op.pw.__txt__('1', '-2') == '1 ^ ( -2 )'
#assert op.pw.__txt__('-1','2') == '( -1 ) ^ 2 '
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del