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

@ -1,646 +0,0 @@
#!/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(str):
"""The operator class, is a string (representation of the operator) with its arity"""
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
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:
#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 __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 == op.sub1.name:
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 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
"""
Fake = type('fake_'+str(type(obj)), (type(obj),), {'mainOp': 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
* "l_parenthesis": mechanism to add parenthesis for left operande
* "r_parenthesis": mechanism to add parenthesis for rigth operande
"""
@wraps(fun)
def mod_fun(self, *args):
ans = fun(self, *args)
def _eq(op1, op2):
""" op1 == op2 """
return op1.name == op2.name == name and op1.arity == op2.arity
ans["__eq__"] = _eq
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",\
}
@ClassProperty
@operatorize
def add(cls):
""" The operator +
For doctest see test/test_operator.py
"""
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
caract = {
"operator" : "+", \
"name" : "add",\
"priority" : 1, \
"arity" : 2, \
"actions" : ("__add__","__radd__"), \
"txt" : "{op1} + {op2}",\
"tex" : "{op1} + {op2}",\
"_render": _render,\
}
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)'
>>> sub.__tex__('-1','2')
'-1 - 2'
"""
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
caract = {
"operator" : "-", \
"name" : "sub",\
"priority" : 2, \
"arity" : 2, \
"actions" : ("__sub__","__rsub__"), \
"txt" : "{op1} - {op2}",\
"tex" : "{op1} - {op2}",\
"l_parenthesis": l_parenthesis,\
"r_parenthesis": r_parenthesis,\
}
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 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
caract = {
"operator" : "-", \
"name" : "sub1",\
"priority" : 3, \
"arity" : 1, \
"actions" : "__neg__",\
"txt" : "- {op1}",\
"tex" : "- {op1}",\
"l_parenthesis": l_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.__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)'
"""
# * can not be display in some cases
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
caract = {
"operator" : "*", \
"name" : "mul",\
"priority" : 4, \
"arity" : 2, \
"actions" : ("__mul__","__rmul__"), \
"txt" : "{op1} * {op2}",\
"tex" : "{op1} \\times {op2}",\
"visibility": 1,\
"_render": _render,\
"is_visible": is_visible,\
}
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" : 5, \
"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)
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
caract = {
"operator" : "^", \
"name" : "pw",\
"priority" : 6, \
"arity" : 2, \
"actions" : ("__pow__",""), \
"txt" : "{op1} ^ {op2}",\
"tex" : "{op1}^{{ {op2} }}",\
"l_parenthesis": l_parenthesis,\
"_call":_call,\
}
return caract
@ClassProperty
@operatorize
def par(self):
""" The operator ( """
caract = {
"operator" : "(", \
"name" : "par",\
"priority" : 0, \
"arity" : 0, \
}
return caract
@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 """
if type(symbole) == str:
return symbole in [i[0] for i in cls._operators]
else:
return False
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,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