From f69ddbe5529b3fc268eb6b8d59848d02d2296986 Mon Sep 17 00:00:00 2001 From: eficas <> Date: Mon, 23 Jan 2006 09:41:11 +0000 Subject: [PATCH] CCAR: adaptation pour validation parametres --- Accas/A_ASSD.py | 8 +- Accas/A_VALIDATOR.py | 1 + Accas/__init__.py | 1 + Editeur/appli.py | 17 ++ Editeur/composimp.py | 8 + Editeur/uniqueassdpanel.py | 2 +- Extensions/commande_comm.py | 1 + Extensions/jdc_include.py | 1 + Extensions/param2.py | 16 +- Extensions/parametre.py | 211 ++------------------- Ihm/I_ASSD.py | 25 +++ Ihm/I_ETAPE.py | 2 + Ihm/I_FONCTION.py | 2 + Ihm/I_JDC.py | 8 +- Ihm/I_MACRO_ETAPE.py | 70 ++++--- Ihm/I_MCSIMP.py | 355 +++++++++++++++++++++++++++++------- Ihm/I_VALIDATOR.py | 232 +++++++++++++++++++++-- 17 files changed, 654 insertions(+), 306 deletions(-) diff --git a/Accas/A_ASSD.py b/Accas/A_ASSD.py index e8669988..2968709f 100644 --- a/Accas/A_ASSD.py +++ b/Accas/A_ASSD.py @@ -37,7 +37,7 @@ class ASSD(N_ASSD.ASSD,I_ASSD.ASSD):pass #class LASSD(I_LASSD.LASSD,N_LASSD.LASSD):pass class LASSD(I_LASSD.LASSD):pass -class assd(N_ASSD.assd,I_ASSD.ASSD,ASSD):pass +class assd(N_ASSD.assd,I_ASSD.assd,ASSD):pass class FONCTION(N_FONCTION.FONCTION,I_FONCTION.FONCTION,ASSD): def __init__(self,etape=None,sd=None,reg='oui'): @@ -56,6 +56,6 @@ class fonction(N_FONCTION.formule,I_FONCTION.fonction,ASSD): N_FONCTION.formule.__init__(self,etape=etape,sd=sd,reg=reg) I_FONCTION.fonction.__init__(self,etape=etape,sd=sd,reg=reg) -class GEOM(N_GEOM.GEOM,I_ASSD.ASSD,ASSD):pass -class geom(N_GEOM.geom,I_ASSD.ASSD,ASSD):pass -class CO(N_CO.CO,I_ASSD.ASSD,ASSD):pass +class GEOM(N_GEOM.GEOM,I_ASSD.GEOM,ASSD):pass +class geom(N_GEOM.geom,I_ASSD.geom,ASSD):pass +class CO(N_CO.CO,I_ASSD.CO,ASSD):pass diff --git a/Accas/A_VALIDATOR.py b/Accas/A_VALIDATOR.py index c127c965..2f0d2978 100644 --- a/Accas/A_VALIDATOR.py +++ b/Accas/A_VALIDATOR.py @@ -2,6 +2,7 @@ import types from Noyau import N_VALIDATOR from Ihm import I_VALIDATOR +from Ihm.I_VALIDATOR import ValidException class FunctionVal(I_VALIDATOR.FunctionVal,N_VALIDATOR.FunctionVal):pass class OrVal(I_VALIDATOR.OrVal,N_VALIDATOR.OrVal):pass diff --git a/Accas/__init__.py b/Accas/__init__.py index 28d0e179..1eb50497 100644 --- a/Accas/__init__.py +++ b/Accas/__init__.py @@ -77,6 +77,7 @@ from Noyau.N_utils import AsType from A_VALIDATOR import OrdList,NoRepeat,LongStr,OrVal,AndVal from A_VALIDATOR import RangeVal, EnumVal, TypeVal, PairVal from A_VALIDATOR import CardVal, InstanceVal +from A_VALIDATOR import ValidException # On remplace la factory des validateurs initialement dans Noyau par celle # de A_VALIDATOR diff --git a/Editeur/appli.py b/Editeur/appli.py index 0df69855..97fdba1a 100644 --- a/Editeur/appli.py +++ b/Editeur/appli.py @@ -379,6 +379,23 @@ class STANDALONE(APPLI): rep_mat=self.CONFIGURATION.rep_mat, ) J.analyse() + txt= J.cr.get_mess_exception() + if txt:raise ValueError(txt) + return J + + def openTXT(self,text): + self.JDCName="TEXT" + CONTEXT.unset_current_step() + J=self.readercata.cata[0].JdC(procedure=text, + appli=self, + cata=self.readercata.cata, + cata_ord_dico=self.readercata.cata_ordonne_dico, + nom=self.JDCName, + rep_mat=self.CONFIGURATION.rep_mat, + ) + J.analyse() + txt= J.cr.get_mess_exception() + if txt:raise ValueError(txt) return J def create_item(self,obj): diff --git a/Editeur/composimp.py b/Editeur/composimp.py index cf8eae08..101239dc 100644 --- a/Editeur/composimp.py +++ b/Editeur/composimp.py @@ -524,6 +524,14 @@ class SIMPTreeItem(Objecttreeitem.AtomicObjectTreeItem): # traite_reel def eval_valeur(self,valeur): + """ Lance l'interprétation de 'valeur' (chaîne de caractères) comme valeur de self : + - retourne l'objet associé si on a pu interpréter (entier, réel, ASSD,...) + - retourne 'valeur' (chaîne de caractères) sinon + """ + newvaleur=self.eval_val(valeur) + return newvaleur,1 + + def eval_valeur_BAK(self,valeur): """ Lance l'interprétation de 'valeur' (chaîne de caractères) comme valeur de l'objet pointé par self : - retourne l'objet associé si on a pu interpréter (entier, réel, ASSD,...) diff --git a/Editeur/uniqueassdpanel.py b/Editeur/uniqueassdpanel.py index 6bff4bdf..b90b532a 100644 --- a/Editeur/uniqueassdpanel.py +++ b/Editeur/uniqueassdpanel.py @@ -188,7 +188,7 @@ class UNIQUE_ASSD_Panel(UNIQUE_Panel): """ valeur = self.node.item.get_valeur() if valeur == None or valeur == '' : return # pas de valeur à afficher ... - self.valeur_choisie.set(valeur.nom) + self.valeur_choisie.set(getattr(valeur,"nom","unknown")) def erase_valeur(self): pass diff --git a/Extensions/commande_comm.py b/Extensions/commande_comm.py index 2d7950c2..d54060a4 100644 --- a/Extensions/commande_comm.py +++ b/Extensions/commande_comm.py @@ -207,6 +207,7 @@ class COMMANDE_COMM(N_OBJECT.OBJECT,I_OBJECT.OBJECT) : #print "uncomment",new_etape.sd pos=self.parent.etapes.index(self) + # L'ordre d'appel est important : suppentite fait le menage des concepts dans les etapes suivantes self.parent.addentite(new_etape,pos) self.parent.suppentite(self) return new_etape,nom_sd diff --git a/Extensions/jdc_include.py b/Extensions/jdc_include.py index e02f1dcc..8a74ee42 100644 --- a/Extensions/jdc_include.py +++ b/Extensions/jdc_include.py @@ -303,6 +303,7 @@ class JDC_POURSUITE(JDC): #Regularise les etapes du jdc apres l'etape etape self.control_jdc_context_apres(etape) if self.etape_include: + #print "CONTROL_INCLUDE:",self.etape_include,self.etape_include.nom # il existe un jdc pere. On propage la regularisation self.etape_include.parent.control_context_apres(self.etape_include) diff --git a/Extensions/param2.py b/Extensions/param2.py index 61c6e3ae..2ccdac4b 100644 --- a/Extensions/param2.py +++ b/Extensions/param2.py @@ -3,15 +3,19 @@ import math import Numeric def mkf(value): - if type(value) in (type(1), type(1L), type(1.5), type(1j),type("hh")): + if type(value) in (type(1), type(1L), type(1.5), type(1j),type("hh")) : return Constant(value) elif isinstance(value, Formula): return value + elif type(value) == type([]): + return Constant(value) else: +# return Constant(value) raise TypeError, ("Can't make formula from", value) #class Formula(object): class Formula: + def __len__(self): return len(self.eval()) def __complex__(self): return complex(self.eval()) def __int__(self): return int(self.eval()) def __long__(self): return long(self.eval()) @@ -58,6 +62,8 @@ class Binop(Formula): while isinstance(result,Formula): result=result.eval() return result + def __adapt__(self,validator): + return validator(self.eval()) original_cos=math.cos original_sin=math.sin @@ -66,7 +72,7 @@ original_nsin=Numeric.sin class Unop(Formula): opmap = { '-': lambda x: -x, - 'sin': lambda x: math.sin(x), + 'sin': lambda x: original_sin(x), 'cos': lambda x: original_cos(x) , 'ncos': lambda x: original_ncos(x), 'nsin': lambda x: original_nsin(x), @@ -80,6 +86,8 @@ class Unop(Formula): return "%s(%s)" % (self._op, self._arg) def eval(self): return self.opmap[self._op](self._arg.eval()) + def __adapt__(self,validator): + return validator(self.eval()) class Unop2(Unop): def __init__(self, nom, op, arg): @@ -110,6 +118,8 @@ class Constant(Formula): def __init__(self, value): self._value = value def eval(self): return self._value def __str__(self): return str(self._value) + def __adapt__(self,validator): + return validator(self._value) class Variable(Formula): def __init__(self,name,value): @@ -118,6 +128,8 @@ class Variable(Formula): def eval(self): return self._value def __repr__(self): return "Variable('%s',%s)" % (self._name, self._value) def __str__(self): return self._name + def __adapt__(self,validator): + return validator(self._value) def cos(f): return Unop('ncos', f) def sin(f): return Unop('nsin', f) diff --git a/Extensions/parametre.py b/Extensions/parametre.py index bb525091..7ca8ca64 100644 --- a/Extensions/parametre.py +++ b/Extensions/parametre.py @@ -60,171 +60,11 @@ class PARAMETRE(N_OBJECT.OBJECT,I_OBJECT.OBJECT,Formula) : self.state='undetermined' self.register() self.dict_valeur=[] - self.valeur = self.interprete_valeur(valeur) - self.val=valeur - -# def __getitem__(self,key): -# param_item=ITEM_PARAMETRE(self,key) -# return param_item - -# def __neg__(self): -# try: -# return -1*self.valeur -# except: -# print "******* Probleme : pas de valeur négative" -# return None - -# def __add__(self,a): -# try : -# return self.valeur+a.valeur -# except : -# print "******* Probleme : a l addition" -# return None - -# def __radd__(self,a): -# try : -# return self.valeur+a.valeur -# except : -# print "******* Probleme : a l addition" -# return None - -# def __sub__(self,a): -# try : -# return self.valeur - a.valeur -# except : -# print "******* Probleme : a la soustraction" -# return None - -# def __rsub__(self,a): -# try : -# return a.valeur - self.valeur -# except : -# print "******* Probleme : a la soustraction" -# return None - - -# def __mul__(self,a): -# try : -# return self.valeur*a.valeur -# except : -# print "******* Probleme : a la multiplication" -# return None - -# def __rmul__(self,a): -# try : -# return self.valeur*a.valeur -# except : -# print "******* Probleme : a la multiplication" -# return None - -# def __add__(self,other): -# try : -# return self.valeur+other -# except : -# print "******* Probleme : a l addition" -# return None - -# def __radd__(self,other): -# try : -# return self.valeur+other -# except : -# print "******* Probleme : a l addition" -# return None - -# def __sub__(self,other): -# try : -# return self.valeur - other -# except : -# print "******* Probleme : a la soustraction" -# return None - -# def __rsub__(self,other): -# try : -# return other - self.valeur -# except : -# print "******* Probleme : a la soustraction" -# return None - -# def __mul__ (self,other): -# retour=None -# try : -# retour = eval(self.valeur) * other -# except : -# try : -# retour = self.valeur * other -# except : -# try : -# retour = eval(self.valeur) * eval(other) -# except : -# try : -# retour = self.valeur * eval(other) -# except : -# print other -# print "******* Probleme : a la multiplication _mul__" -# return retour -# -# def __rmul__ (self,other): -# retour=None -# try : -# retour = eval(self.valeur) * other -# except : -# try : -# retour = self.valeur * other -# except : -# try : -# retour = eval(self.valeur) * eval(other) -# except : -# print "******* Probleme : a la multiplication __rmul__" -# return retour -# -# -# def __div__(self,other): -# retour=None -# try: -# retour = eval(self.valeur) / other -# except : -# try : -# retour = self.valeur / other -# except : -# print "******* Probleme : a la division" -# return retour -# -# -# def cos(self): -# try : -# retour=cos(self.valeur) -# return retour -# except: -# print "pb pour cosinus" -# -# def sin(self): -# try : -# retour=sin(self.valeur) -# return retour -# except: -# print "pb pour sinus" -# -# def tan(self): -# try : -# retour=tan(self.valeur) -# return retour -# except: -# print "pb pour tangente" -# -# def log(self): -# try : -# retour=log(self.valeur) -# return retour -# except: -# print "pb pour log" -# -# def sqrt(self): -# try : -# retour=sqrt(self.valeur) -# return retour -# except: -# print "pb pour sqrt" -# + #self.valeur = self.interprete_valeur(valeur) + #self.val=valeur + self.valeur = valeur + self.val=repr(valeur) + def interprete_valeur(self,val): """ Essaie d'interpréter val (chaîne de caractères)comme : @@ -236,36 +76,19 @@ class PARAMETRE(N_OBJECT.OBJECT,I_OBJECT.OBJECT,Formula) : """ #if not val : return None valeur = None - # on vérifie si val est un entier - #try : - # valeur = string.atoi(val) # on a un entier - # print "int",valeur - # return valeur - #except : - # traceback.print_exc() - # pass - #print val,valeur - # on vérifie si val est un réel - #try: - # valeur = string.atof(val) # on a un réel - # print "float",valeur - # return valeur - #except : - # traceback.print_exc() - # pass - #print val,valeur if type(val) == types.StringType: - # on tente l'evaluation (dans quel contexte ?) + # on tente l'evaluation dans un contexte fourni par le parent s'il existe if self.parent: valeur=self.parent.eval_in_context(val,self) else: try : valeur = eval(val) except: - traceback.print_exc() + #traceback.print_exc() pass #PN je n ose pas modifier je rajoute + # refus des listes heterogenes : ne dvrait pas etre la if valeur != None : if type(valeur) == types.TupleType: l_new_val = [] @@ -282,11 +105,7 @@ class PARAMETRE(N_OBJECT.OBJECT,I_OBJECT.OBJECT,Formula) : return val l_new_val.append(v) return tuple(l_new_val) - # PN : commente le print - #else: - # on a réussi à évaluer val en autre chose qu'un tuple ... - #print "on a réussi à évaluer %s en autre chose qu'un tuple ..." %val - #print 'on trouve : ',str(valeur),' de type : ',type(valeur) + if valeur != None : if type(valeur).__name__ == 'list': self.dict_valeur=[] @@ -437,7 +256,14 @@ class PARAMETRE(N_OBJECT.OBJECT,I_OBJECT.OBJECT,Formula) : Donne un echo de self sous la forme nom = valeur """ if type(self.valeur) == types.StringType: - return self.nom+' = '+ repr(self.valeur) + if self.valeur.find('\n') == -1: + # pas de retour chariot, on utilise repr + return self.nom+' = '+ repr(self.valeur) + elif self.valeur.find('"""') == -1: + # retour chariot mais pas de triple ", on formatte + return self.nom+' = """'+self.valeur+'"""' + else: + return self.nom+' = '+ repr(self.valeur) else: return self.nom+' = '+ str(self.valeur) @@ -508,6 +334,9 @@ class PARAMETRE(N_OBJECT.OBJECT,I_OBJECT.OBJECT,Formula) : else: return self.valeur + def __adapt__(self,validator): + return validator(self.eval()) + class COMBI_PARAMETRE : def __init__(self,chainevaleur,valeur): self.chainevaleur=chainevaleur diff --git a/Ihm/I_ASSD.py b/Ihm/I_ASSD.py index f7bd493e..15b7e162 100644 --- a/Ihm/I_ASSD.py +++ b/Ihm/I_ASSD.py @@ -19,8 +19,33 @@ # # ====================================================================== +from I_VALIDATOR import ValidException + class ASSD: def __repr__(self): return "concept %s de type %s" % (self.get_name(),self.__class__.__name__) #def __del__(self): # print "__del__",self + +class assd(ASSD): + def __convert__(cls,valeur): + return valeur + __convert__=classmethod(__convert__) + +class GEOM(ASSD): + def __convert__(cls,valeur): + return valeur + __convert__=classmethod(__convert__) + +class geom(GEOM):pass + +class CO(ASSD): + def __convert__(cls,valeur): + if hasattr(valeur,'_etape') : + # valeur est un concept CO qui a ete transforme par type_sdprod + if valeur.etape == valeur._etape: + # le concept est bien produit par l'etape + return valeur + raise ValidException("Pas un concept CO") + __convert__=classmethod(__convert__) + diff --git a/Ihm/I_ETAPE.py b/Ihm/I_ETAPE.py index eb3d20bf..16752497 100644 --- a/Ihm/I_ETAPE.py +++ b/Ihm/I_ETAPE.py @@ -85,12 +85,14 @@ class ETAPE(I_MCCOMPO.MCCOMPO): """ #print "fin_modif",self,self.parent if self.nom == "DETRUIRE": + traceback.print_stack(limit=8) #Il n'est pas conseillé de mettre des traitements dans fin_modif. Ceci est une # exception qu'il faut supprimer à terme. #une commande DETRUIRE a été modifiée. Il faut verifier les commandes #suivantes #ATTENTION: aux eventuelles recursions self.parent.control_context_apres(self) + pass CONNECTOR.Emit(self,"valid") if self.parent: diff --git a/Ihm/I_FONCTION.py b/Ihm/I_FONCTION.py index 04879d4f..18f66362 100644 --- a/Ihm/I_FONCTION.py +++ b/Ihm/I_FONCTION.py @@ -46,6 +46,8 @@ class fonction(FONCTION) : pass from Extensions import param2 class formule(FONCTION) : def __call__(self,*val): + if len(val) != len(self.nompar): + raise TypeError(" %s() takes exactly %d argument (%d given)" % (self.nom,len(self.nompar),len(val))) return param2.Unop2(self.nom,self.real_call,val) def real_call(self,*val): diff --git a/Ihm/I_JDC.py b/Ihm/I_JDC.py index 17de72e2..26e13e44 100644 --- a/Ihm/I_JDC.py +++ b/Ihm/I_JDC.py @@ -702,17 +702,13 @@ class JDC(I_OBJECT.OBJECT): """ #contexte initial du jdc context=self.condition_context.copy() - #contexte courant des concepts + #contexte courant des concepts. Il contient les parametres context.update(self.get_contexte_avant(etape)) - #contexte des parametres - for e in self.etapes: - if e is etape:break - if not e.isactif():continue - e.update_context(context) try : objet = eval(valeur,context) return objet except: + #traceback.print_exc() pass return valeur diff --git a/Ihm/I_MACRO_ETAPE.py b/Ihm/I_MACRO_ETAPE.py index e351b006..6be22b12 100644 --- a/Ihm/I_MACRO_ETAPE.py +++ b/Ihm/I_MACRO_ETAPE.py @@ -28,6 +28,7 @@ import traceback,types,string import I_ETAPE import Noyau from Noyau.N_ASSD import ASSD +import convert # import rajoutés suite à l'ajout de Build_sd --> à résorber import Noyau, Validation.V_MACRO_ETAPE @@ -95,6 +96,15 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): self.jdc_aux.supprime_aux() if fichier is None:fichier="SansNom" + + # Il faut convertir le texte inclus en fonction du format + format=self.jdc.appli.format_fichier.get() + if convert.plugins.has_key(format): + # Le convertisseur existe on l'utilise + p=convert.plugins[format]() + p.text=text + text=p.convert('exec',self) + j=self.JdC_aux( procedure=text, nom=fichier, appli=self.jdc.appli, cata=self.jdc.cata, @@ -110,6 +120,7 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): self.etapes=j.etapes self.jdc_aux=j except: + traceback.print_exc() # On retablit l'etape courante step CONTEXT.unset_current_step() CONTEXT.set_current_step(step) @@ -676,6 +687,14 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): #print "update_context.fin",d.keys() #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro) + def copy(self): + etape=Noyau.N_MACRO_ETAPE.MACRO_ETAPE.copy(self) + if hasattr(etape,"etapes") :etape.etapes=[] + if hasattr(etape,"jdc_aux") : + etape.jdc_aux=None + del etape.fichier_ini + return etape + def supprime(self): #print "supprime",self if hasattr(self,"jdc_aux") and self.jdc_aux: @@ -774,30 +793,35 @@ class MACRO_ETAPE(I_ETAPE.ETAPE): # On supprime l'attribut mat qui bloque l'evaluation du source de l'INCLUDE_MATERIAU # car on ne s'appuie pas sur lui dans EFICAS mais sur l'attribut fichier_ini if hasattr(self,'mat'):del self.mat - self.fichier_ini =fichier - self.fichier_unite =fichier - self.fichier_text=text - self.fichier_err=None - self.contexte_fichier_init={} - # On specifie la classe a utiliser pour le JDC auxiliaire - try: - import Extensions.jdc_include - except: - traceback.print_exc() - raise - self.JdC_aux=Extensions.jdc_include.JdC_include - try: - self.make_contexte_include(self.fichier_ini ,self.fichier_text) - #self.parent.record_unit(self.fichier_unite,self) - except: - l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1]) - self.fichier_err = string.join(l) - #self.parent.record_unit(self.fichier_unite,self) - self.g_context={} - self.etapes=[] - self.jdc_aux=None + if not hasattr(self,'fichier_ini') or self.fichier_ini != fichier or self.fichier_mater != self.nom_mater: + # le fichier est nouveau ou change + self.fichier_ini =fichier + self.fichier_unite =fichier + self.fichier_mater=self.nom_mater + self.fichier_text=text + self.fichier_err=None self.contexte_fichier_init={} - raise + # On specifie la classe a utiliser pour le JDC auxiliaire + try: + import Extensions.jdc_include + self.JdC_aux=Extensions.jdc_include.JdC_include + except: + traceback.print_exc() + raise + try: + self.make_contexte_include(self.fichier_ini ,self.fichier_text) + except: + l=traceback.format_exception_only("Fichier invalide",sys.exc_info()[1]) + self.fichier_err = string.join(l) + self.g_context={} + self.etapes=[] + self.jdc_aux=None + self.contexte_fichier_init={} + raise + else: + # le fichier est le meme on ne le reevalue pas + # et on leve une exception si une erreur a été enregistrée + if self.fichier_err is not None: raise Exception(self.fichier_err) #ATTENTION SURCHARGE : cette methode surcharge celle de Noyau (a garder en synchro) def update_sdprod(self,cr='non'): diff --git a/Ihm/I_MCSIMP.py b/Ihm/I_MCSIMP.py index 6dedfca2..3e549ce7 100644 --- a/Ihm/I_MCSIMP.py +++ b/Ihm/I_MCSIMP.py @@ -48,6 +48,8 @@ from Extensions import param2 import I_OBJECT import CONNECTOR +from I_VALIDATOR import ValidException + class MCSIMP(I_OBJECT.OBJECT): def GetNomConcept(self): @@ -290,7 +292,7 @@ class MCSIMP(I_OBJECT.OBJECT): sd = self.jdc.get_sd_avant_etape(new_valeur,self.etape) #sd = self.jdc.get_contexte_avant(self.etape).get(new_valeur,None) #print sd - if sd : + if sd is not None: return sd,1 lsd = self.jdc.cherche_list_avant(self.etape,new_valeur) if lsd : @@ -327,11 +329,6 @@ class MCSIMP(I_OBJECT.OBJECT): return valeurretour else: valeur=self.eval_val_item(new_valeur) - if valeur == new_valeur and new_valeur.find(',') > 0: - valeurretour=[] - for item in new_valeur.split(',') : - valeurretour.append(self.eval_val_item(item)) - return valeurretour return valeur def eval_val_item(self,new_valeur): @@ -340,22 +337,17 @@ class MCSIMP(I_OBJECT.OBJECT): Si c'est impossible retourne new_valeur inchange argument new_valeur : string (nom de concept, de parametre, expression ou simple chaine) """ - # concept ? - sd = self.jdc.get_sd_avant_etape(new_valeur,self.etape) - if sd : - return sd - # expression ou item parametre ? - d={} - # On veut EVAL avec tous ses comportements. On utilise Accas. Perfs ?? - d['EVAL']=Accas.EVAL - for p in self.jdc.params: - d[p.nom]=p - try : - objet = eval(new_valeur,d) - return objet - except: - pass - return new_valeur + if self.etape and self.etape.parent: + valeur=self.etape.parent.eval_in_context(new_valeur,self.etape) + return valeur + else: + try : + valeur = eval(val) + return valeur + except: + #traceback.print_exc() + return new_valeur + pass def cherche_item_parametre (self,new_valeur): try: @@ -464,11 +456,11 @@ class MCSIMP(I_OBJECT.OBJECT): self.init_modif() self.valeur = new_objet self.val = new_objet - self.fin_modif() - step.reset_context() # On force l'enregistrement de new_objet en tant que concept produit # de la macro en appelant get_type_produit avec force=1 self.etape.get_type_produit(force=1) + self.fin_modif() + step.reset_context() #print "set_valeur_co",new_objet return 1,"Concept créé" @@ -479,21 +471,24 @@ class MCSIMP(I_OBJECT.OBJECT): """ #print "verif_existence_sd" # Attention : possible probleme avec include + # A priori il n'y a pas de raison de retirer les concepts non existants + # avant etape. En fait il s'agit uniquement eventuellement de ceux crees par une macro l_sd_avant_etape = self.jdc.get_contexte_avant(self.etape).values() if type(self.valeur) in (types.TupleType,types.ListType) : l=[] - self.init_modif() for sd in self.valeur: if isinstance(sd,ASSD) : - if sd in l_sd_avant_etape : + if sd in l_sd_avant_etape or self.etape.get_sdprods(sd.nom) is sd: l.append(sd) else: l.append(sd) - self.valeur=tuple(l) - self.fin_modif() + if len(l) < len(self.valeur): + self.init_modif() + self.valeur=tuple(l) + self.fin_modif() else: if isinstance(self.valeur,ASSD) : - if self.valeur not in l_sd_avant_etape : + if self.valeur not in l_sd_avant_etape and self.etape.get_sdprods(self.valeur.nom) is None: self.init_modif() self.valeur = None self.fin_modif() @@ -547,6 +542,262 @@ class MCSIMP(I_OBJECT.OBJECT): # Elles doivent etre reintegrees des que possible + def convert_card(self,valeur): + """ + Cette methode verifie que la cardinalite de valeur est correcte (comprise entre min et max) + Si c'est le cas elle retourne valeur eventuellement convertie + Si ce n'est pas le cas, elle leve une exception + """ + + adapt = getattr(valeur, '__adapt__', None) + if adapt is not None: + # l'objet valeur peut se verifier lui meme + return adapt(self.convert_card) + + min=self.definition.min + max=self.definition.max + + if type(valeur) == types.TupleType and valeur[0] in ('RI','MP'): + #il s'agit d'un complexe ancienne mode. La cardinalite vaut 1 + length=1 + elif valeur == None : + # pas de valeur affecte. La cardinalite vaut 0 + length=0 + elif type(valeur) == types.StringType : + #il s'agit d'une chaine. La cardinalite vaut 1 + length=1 + else: + try: + # si l'objet supporte len, on a la cardinalite + length=len(valeur) + except: + # sinon elle vaut 1 + length=1 + + if length < min or length >max: + raise ValidException("Nombre d'arguments de %s incorrect pour %s (min = %s, max = %s)" % (repr(valeur),self.nom,min,max) ) + + return valeur + + def verif_card(self,cr='non'): + """ + un mot-clé simple ne peut etre répété : + la cardinalité ici s'entend par la vérification que le nombre d'arguments de self.valeur + est bien compris entre self.min et self.max dans le cas où il s'agit d'une liste + """ + card = 1 + try: + self.convert_card(self.valeur) + except ValidException,e: + if cr == 'oui': self.cr.fatal(str(e)) + card = 0 + return card + + def convert_into(self,valeur): + """ + Cette methode verifie que valeur est dans la liste des valeurs possibles donnée + dans la definition (attribut into) ou dans un intervalle donné dans la definition (attributs + val_min, val_max) + Si c'est le cas elle retourne valeur eventuellement convertie + Si ce n'est pas le cas, elle leve une exception + """ + adapt = getattr(valeur, '__adapt__', None) + if adapt is not None: + # l'objet valeur peut se verifier lui meme + return adapt(self.convert_into) + + if type(valeur) == types.TupleType and not valeur[0] in ('RI','MP') or type(valeur) == types.ListType: + # Cas d'une liste de valeurs + # on s'arrete a la premiere erreur + for val in valeur: + self.convert_into(val) + return valeur + + # Cas d'un scalaire + if self.definition.into == None : + #on est dans le cas d'un ensemble continu de valeurs possibles (intervalle) + if type(valeur) in (types.IntType,types.FloatType,types.LongType) : + min = self.definition.val_min + max = self.definition.val_max + if min == '**': min = valeur -1 + if max == '**': max = valeur +1 + if valeur < min or valeur > max : + raise ValidException("La valeur : %s du mot-clé %s est en dehors du domaine de validité [ %s , %s ]" % (repr(valeur),self.nom,min,max) ) + return valeur + else : + # on est dans le cas d'un ensemble discret de valeurs possibles (into) + if valeur not in self.definition.into: + raise ValidException("La valeur : %s n'est pas permise pour le mot-clé : %s" % (repr(valeur),self.nom) ) + return valeur + + def verif_into(self,cr='non'): + """ + Vérifie si la valeur de self est bien dans l'ensemble discret de valeurs + donné dans le catalogue derrière l'attribut into ou vérifie que valeur est bien compris + entre val_min et val_max + """ + into = 1 + try: + self.convert_into(self.valeur) + except ValidException,e: + if cr == 'oui': self.cr.fatal(str(e)) + into = 0 + return into + + def convert_type(self,valeur): + """ + Cette methode verifie que valeur est du bon type + Si c'est le cas elle retourne valeur eventuellement convertie + Si ce n'est pas le cas, elle leve une exception + """ + if self.definition.type is None: return valeur + + if valeur == None : + raise ValidException("None n'est pas une valeur autorisée") + + adapt = getattr(valeur, '__adapt__', None) + if adapt is not None: + # l'objet valeur peut se verifier lui meme + return adapt(self.convert_type) + + if type(valeur) == types.TupleType and not valeur[0] in ('RI','MP') or type(valeur) == types.ListType: + # Cas d'une liste de valeurs + # on s'arrete a la premiere erreur + for val in valeur: + self.convert_type(val) + return valeur + + # Ici, valeur est un scalaire ...il faut tester sur tous les types ou les valeurs possibles + for type_permis in self.definition.type: + if self.check_type(valeur,type_permis) : return valeur + # si on sort de la boucle précédente par ici c'est que l'on n'a trouvé aucun type valable --> valeur refusée + raise ValidException("%s n'est pas d'un type autorisé" % repr(valeur)) + + def check_type(self,valeur,type_permis): + """ + Fonction booléenne qui retourne 1 si valeur est du type type_permis, 0 sinon + """ + if type_permis == 'R': + return self.is_reel(valeur) + elif type_permis == 'I': + return self.is_entier(valeur) + elif type_permis == 'C': + return self.is_complexe(valeur) + elif type_permis == 'TXM': + return type(valeur)==types.StringType + elif type(type_permis) == types.ClassType: + return self.is_object_from(valeur,type_permis) + elif type(type_permis) == types.InstanceType: + try: + return type_permis.__convert__(valeur) is not None + except: + return 0 + elif type_permis == 'shell': + return self.is_shell(valeur) + else: + print "Type non encore géré %s" %`type_permis` + print self.nom,self.parent.nom,self.jdc.fichier + return 0 + + def is_complexe(self,valeur): + """ Retourne 1 si valeur est un complexe, 0 sinon """ + if type(valeur) in (types.ComplexType,types.IntType,types.FloatType,types.LongType): + # Pour permettre l'utilisation de complexes Python + return 1 + elif type(valeur) != types.TupleType : + # On n'autorise pas les listes pour les complexes + return 0 + elif len(valeur) != 3:return 0 + else: + # Un complexe doit etre un tuple de longueur 3 avec 'RI' ou 'MP' comme premiere + # valeur suivie de 2 reels. + if string.strip(valeur[0]) in ('RI','MP'): + try: + v1=self.convert_reel(valeur[1]),self.convert_reel(valeur[2]) + return 1 + except: + return 0 + else: + return 0 + + def convert_reel(self,valeur): + try: + return float(valeur) + except: + adapt = getattr(valeur, '__adapt__', None) + if adapt is not None: + # l'objet valeur peut se verifier lui meme + return adapt(self.convert_reel) + raise ValidException("%s n'est pas un reel" % repr(valeur)) + + def is_reel(self,valeur): + """ + Retourne 1 si valeur est un reel, 0 sinon + """ + if type(valeur) not in (types.IntType,types.FloatType,types.LongType): + # ce n'est pas un réel + return 0 + else: + return 1 + + def is_entier(self,valeur): + """ Retourne 1 si valeur est un entier, 0 sinon """ + if type(valeur) not in (types.IntType,types.LongType): + # ce n'est pas un entier + return 0 + else: + return 1 + + def is_shell(self,valeur): + """ + Retourne 1 si valeur est un shell, 0 sinon + Pour l'instant aucune vérification n'est faite + On impose juste que valeur soit une string + """ + if type(valeur) != types.StringType: + return 0 + else: + return 1 + + def is_object_from(self,objet,classe): + """ + Retourne 1 si objet est une instance de la classe classe, 0 sinon + """ + convert = getattr(classe, '__convert__', None) + if convert is not None: + # classe verifie les valeurs + try: + v= convert(objet) + if v is None:return 0 + else:return 1 + except: + return 0 + if type(objet) != types.InstanceType : + return 0 + if isinstance(objet,classe) : + # On accepte les instances de la classe et des classes derivees + return 1 + + return 0 + + def verif_type(self,val=None,cr='non'): + """ + FONCTION : + Cette methode verifie que le type de l'argument val est en conformite avec celui + qui est declare dans la definition du mot cle simple. + Elle a plusieurs modes de fonctionnement liés à la valeur de cr. + Si cr vaut 'oui' : elle remplit le compte-rendu self.cr sinon elle ne le remplit pas. + PARAMETRE DE RETOUR : + Cette méthode retourne une valeur booléenne qui vaut 1 si le type de val est correct ou 0 sinon + + """ + try: + self.convert_type(val) + return 1 + except ValidException,e: + if cr == 'oui': self.cr.fatal(str(e)) + return 0 + def isvalid(self,cr='non'): """ Cette méthode retourne un indicateur de validité de l'objet de type MCSIMP @@ -575,49 +826,19 @@ class MCSIMP(I_OBJECT.OBJECT): self.cr.fatal("None n'est pas une valeur autorisée") else: # type,into ... - #PN ??? je n ose pas y toucher ??? - #if v.__class__.__name__ in ('PARAMETRE','EVAL', 'ITEM_PARAMETRE','PARAMETRE_EVAL'): - if ((issubclass(v.__class__,param2.Formula)) or - (v.__class__.__name__ in ('EVAL', 'ITEM_PARAMETRE','PARAMETRE_EVAL'))): - verif_type=self.verif_typeihm(v) - else: - verif_type=self.verif_type(val=v,cr=None) - # cas des tuples avec un ITEM_PARAMETRE - if verif_type == 0: - if type(v) in ( types.TupleType ,types.ListType): - new_val=[] - for i in v: - if ((issubclass(i.__class__,param2.Formula)) or - (i.__class__.__name__ in ('EVAL', 'ITEM_PARAMETRE','PARAMETRE_EVAL'))): - if self.verif_typeihm(val=i,cr=cr) == 0: - verif_type = 0 - break - else: - new_val.append(i) - if new_val != [] : - verif_type=self.verif_type(val=new_val,cr=cr) - else : - # Cas d une liste de paramétre - verif_type=self.verif_typeliste(val=v,cr=cr) - else: - verif_type=self.verif_type(val=v,cr=cr) - valid = verif_type*self.verif_into(cr=cr)*self.verif_card(cr=cr) + valid = self.verif_type(val=v,cr=cr)*self.verif_into(cr=cr)*self.verif_card(cr=cr) # # On verifie les validateurs s'il y en a et si necessaire (valid == 1) # - if valid and self.definition.validators and not self.definition.validators.verif(self.valeur): - if cr == 'oui' : - self.cr.fatal(string.join(("Mot-clé : ",self.nom,"devrait avoir ",self.definition.validators.info()))) - valid=0 + if valid and self.definition.validators: + try: + self.definition.validators.convert(self.valeur) + except ValidException,e: + if cr == 'oui' : + self.cr.fatal(string.join(("Mot-clé : ",self.nom,"devrait avoir ",self.definition.validators.info()))) + valid=0 # fin des validateurs # - # cas d un item Parametre - if self.valeur.__class__.__name__ == 'ITEM_PARAMETRE': - valid=self.valeur.isvalid() - if valid == 0: - if cr == 'oui' : - self.cr.fatal(string.join( repr (self.valeur), " a un indice incorrect")) - self.set_valid(valid) return self.valid diff --git a/Ihm/I_VALIDATOR.py b/Ihm/I_VALIDATOR.py index 3e6aa3ac..23c34f7c 100644 --- a/Ihm/I_VALIDATOR.py +++ b/Ihm/I_VALIDATOR.py @@ -9,8 +9,10 @@ Ces comportements pourront etre rapatries dans le Noyau quand leur interface sera stabilisée. """ +class ValidException(Exception):pass import types +from I_MCSIMP import ValidException class Valid: """ @@ -18,21 +20,215 @@ class Valid: que l'on trouve dans Ihm. """ -class ListVal(Valid):pass +class ListVal(Valid): + """ + Cette classe sert de classe mère pour tous les validateurs qui acceptent + des listes. + """ + def is_list(self): + return 1 + + def get_into(self,liste_courante=None,into_courant=None): + """ + Cette méthode get_into effectue un traitement général qui consiste + a filtrer la liste de choix into_courant, si elle existe, en ne + conservant que les valeurs valides (appel de la méthode valid). + """ + if into_courant is None: + return None + else: + liste_choix=[] + for e in into_courant: + if self.verif(e): + liste_choix.append(e) + return liste_choix + + def convert(self,valeur): + """ + Méthode verif pour les validateurs de listes. Cette méthode + fait appel à la méthode verif_item sur chaque élément de la + liste. Si valeur est un paramètre, on utilise sa valeur effective + valeur.valeur. + """ + if type(valeur) in (types.ListType,types.TupleType): + for val in valeur: + self.convert_item(val) + return valeur + else: + return self.convert_item(valeur) + + +class RangeVal(ListVal): + def convert_item(self,valeur): + if valeur > self.low and valeur < self.high:return valeur + raise ValidException("%s devrait etre comprise entre %s et %s" %(valeur,self.low,self.high)) + + +class CardVal(Valid): + def convert(self,valeur): + if type(valeur) in (types.ListType,types.TupleType): + l=len(valeur) + elif valeur is None: + l=0 + else: + l=1 + if self.max != '**' and l > self.max:raise ValidException("%s devrait etre de longueur inferieure a %s" %(valeur,self.max)) + if self.min != '**' and l < self.min:raise ValidException("%s devrait etre de longueur superieure a %s" %(valeur,self.min)) + return valeur -class RangeVal(ListVal):pass -class CardVal(Valid):pass +class PairVal(ListVal): + def convert(self,valeur): + if type(valeur) in (types.ListType,types.TupleType): + for val in valeur: + if val % 2 != 0:raise ValidException("%s contient des valeurs non paires" % repr(valeur)) + else: + if valeur % 2 != 0:raise ValidException("%s n'est pas pair" % repr(valeur)) + return valeur -class PairVal(ListVal):pass -class EnumVal(ListVal):pass + +class EnumVal(ListVal): + def convert_item(self,valeur): + if valeur in self.into:return valeur + raise ValidException("%s contient des valeurs hors des choix possibles: %s " %(valeur,self.into)) + -class NoRepeat(ListVal):pass +class NoRepeat(ListVal): + """ + Verification d'absence de doublons dans la liste. + """ + def __init__(self): + self.cata_info="" + + def info(self): + return ": pas de présence de doublon dans la liste" + + def info_erreur_liste(self): + return "Les doublons ne sont pas permis" -class LongStr(ListVal):pass + def verif_item(self,valeur): + return 1 + + def verif(self,valeur): + if type(valeur) in (types.ListType,types.TupleType): + liste=list(valeur) + for val in liste: + if liste.count(val)!=1 : return 0 + return 1 + else: + return 1 + + def convert_item(self,valeur): + if valeur in self.liste : raise ValidException("%s est un doublon" % valeur) + return valeur + + def convert(self,valeur): + adapt = getattr(valeur, '__adapt__', None) + if adapt is not None: + # l'objet valeur peut se verifier lui meme + return adapt(self.convert) + + if type(valeur) == types.TupleType and not valeur[0] in ('RI','MP') or type(valeur) == types.ListType: + # Cas d'une liste de valeurs + # on s'arrete a la premiere erreur + self.liste=[] + for val in valeur: + adapt = getattr(val, '__adapt__', None) + if adapt is not None: + v=adapt(self.convert_item) + else: + v=self.convert_item(val) + self.liste.append(v) + return valeur + + def get_into(self,liste_courante=None,into_courant=None): + """ + Methode get_into spécifique pour validateur NoRepeat, on retourne + une liste de choix qui ne contient aucune valeur de into_courant + déjà contenue dans liste_courante + """ + if into_courant is None: + liste_choix=None + else: + liste_choix=[] + for e in into_courant: + if e in liste_choix: continue + if liste_courante is not None and e in liste_courante: continue + liste_choix.append(e) + return liste_choix + + +class LongStr(ListVal): + """ + Verification de la longueur d une chaine + """ + def __init__(self,low,high): + self.low=low + self.high=high + self.cata_info="" + + def info(self): + return "longueur de la chaine entre %s et %s" %(self.low,self.high) + + def info_erreur_item(self): + return "Longueur de la chaine incorrecte" + + def verif_item(self,valeur): + low=self.low + high=self.high + if valeur[0]=="'" and valeur[-1]=="'" : + low=low+2 + high=high+2 + if len(valeur) < low :return 0 + if len(valeur) > high:return 0 + return 1 + + def convert(self,valeur): + adapt = getattr(valeur, '__adapt__', None) + if adapt is not None: + # l'objet valeur peut se verifier lui meme + return adapt(self.convert) + + if type(valeur) == types.TupleType and not valeur[0] in ('RI','MP') or type(valeur) == types.ListType: + # Cas d'une liste de valeurs + # on s'arrete a la premiere erreur + for val in valeur: + self.convert_item(val) + return valeur + else: + return self.convert_item(valeur) + + def convert_item(self,valeur): + low=self.low + high=self.high + if valeur[0]=="'" and valeur[-1]=="'" : + low=low+2 + high=high+2 + if len(valeur) < low or len(valeur) > high : + raise ValidException("%s n'est pas de la bonne longueur" % repr(valeur)) + return valeur + + + +class OrdList(ListVal): + def convert(self,valeur): + if type(valeur) in (types.ListType,types.TupleType): + if self.ord=='croissant': + var=valeur[0] + for val in valeur[1:]: + if valvar:raise ValidException("%s n'est pas par valeurs decroissantes" % repr(valeur)) + var=val + return valeur + else: + return valeur -class OrdList(ListVal):pass CoercableFuncs = { types.IntType: int, types.LongType: long, @@ -40,13 +236,25 @@ CoercableFuncs = { types.IntType: int, types.ComplexType: complex, types.UnicodeType: unicode } -class TypeVal(ListVal):pass +class TypeVal(ListVal): + def convert_item(self,valeur): + return self.coerce(valeur) class InstanceVal(ListVal):pass class FunctionVal(Valid):pass -class OrVal(Valid):pass - -class AndVal(Valid):pass +class OrVal(Valid): + def convert(self,valeur): + for validator in self.validators: + try: + return validator.verif(valeur) + except: + pass + raise ValidException("%s n'est pas du bon type" % valeur) +class AndVal(Valid): + def convert(self,valeur): + for validator in self.validators: + valeur=validator.convert(valeur) + return valeur -- 2.39.2