Salome HOME
Update version
[tools/eficas.git] / generator / generator_python.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2021   EDF R&D
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 """
21     Ce module contient le plugin generateur de fichier au format
22     python pour EFICAS.
23
24 """
25 from __future__ import absolute_import
26 try :
27     from builtins import str
28     from builtins import object
29     from builtins import range
30 except : pass
31
32 import traceback
33 import types,re
34
35 from Noyau import N_CR
36 from Noyau.N_utils import repr_float
37 import Accas
38 import Extensions
39 from Extensions.parametre import ITEM_PARAMETRE
40 from .Formatage import Formatage
41 from .Formatage import FormatageLigne
42 from Extensions.param2 import Formula
43 from Extensions.eficas_exception import EficasException
44 from Extensions.i18n import tr
45
46
47 def entryPoint():
48     """
49         Retourne les informations necessaires pour le chargeur de plugins
50
51         Ces informations sont retournees dans un dictionnaire
52     """
53     return {
54          # Le nom du plugin
55            'name' : 'python',
56          # La factory pour creer une instance du plugin
57            'factory' : PythonGenerator,
58            }
59
60
61 class PythonGenerator(object):
62     """
63         Ce generateur parcourt un objet de type JDC et produit
64         un fichier au format python
65
66         L'acquisition et le parcours sont realises par la methode
67         generator.gener(objet_jdc,format)
68
69         L'ecriture du fichier au format ini par appel de la methode
70         generator.writeFile(nom_fichier)
71
72         Ses caracteristiques principales sont exposees dans des attributs
73         de classe :
74           - extensions : qui donne une liste d'extensions de fichier preconisees
75
76     """
77     # Les extensions de fichier preconisees
78     extensions=('.comm',)
79
80     def __init__(self,cr=None):
81         # Si l'objet compte-rendu n'est pas fourni, on utilise le compte-rendu standard
82         if cr :
83             self.cr=cr
84         else:
85             self.cr=N_CR.CR(debut='CR generateur format python pour python',
86                             fin='fin CR format python pour python')
87         # Le texte au format python est stocke dans l'attribut text
88         self.text=''
89         self.appliEficas=None
90
91     def writeFile(self,filename):
92         fp=open(filename,'w')
93         fp.write(self.text)
94         fp.close()
95
96     def gener(self,obj,format='brut',config=None,appliEficas=None):
97         """
98             Retourne une representation du JDC obj sous une
99             forme qui est parametree par format.
100             Si format vaut 'brut', retourne une liste de listes de ...
101             Si format vaut 'standard', retourne un texte obtenu par concatenation de la liste
102             Si format vaut 'beautifie', retourne le meme texte beautifie
103         """
104         import logging
105         if obj == None :
106             print ('appel a gener avec None')
107             return
108         self.appliEficas=appliEficas
109         liste= self.generator(obj)
110         #format='standard'
111         if format == 'brut':
112             self.text=liste
113         elif format == 'standard':
114             self.text=''.join(liste)
115         elif format == 'beautifie':
116             jdc_formate = Formatage(liste,mode='.py')
117             #import cProfile, pstats, StringIO
118             #pr = cProfile.Profile()
119             #pr.enable()
120             self.text=jdc_formate.formateJdc()
121             #pr.disable()
122             #s = StringIO.StringIO()
123             #sortby = 'cumulative'
124             #ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
125             #ps.print_stats()
126             #print (s.getValue())
127
128         elif format == 'Ligne':
129             jdc_formate = FormatageLigne(liste,mode='.py')
130             self.text=jdc_formate.formateJdc()
131         else:
132             raise EficasException(tr("Format non implemente ") +format)
133         return self.text
134
135     def generator(self,obj):
136         """
137            Cette methode joue un role d'aiguillage en fonction du type de obj
138            On pourrait utiliser les methodes accept et visitxxx a la
139            place (depend des gouts !!!)
140         """
141         # ATTENTION a l'ordre des tests : il peut avoir de l'importance (heritage)
142         if isinstance(obj,Accas.PROC_ETAPE):
143             return self.generPROC_ETAPE(obj)
144         # Attention doit etre place avant MACRO (raison : heritage)
145         elif isinstance(obj,Accas.FORM_ETAPE):
146             return self.generFORM_ETAPE(obj)
147         elif isinstance(obj,Accas.MACRO_ETAPE):
148             return self.generMACRO_ETAPE(obj)
149         elif isinstance(obj,Accas.ETAPE):
150             return self.generETAPE(obj)
151         elif isinstance(obj,Accas.MCFACT):
152             return self.generMCFACT(obj)
153         elif isinstance(obj,Accas.MCList):
154             return self.generMCList(obj)
155         elif isinstance(obj,Accas.MCBLOC):
156             return self.generMCBLOC(obj)
157         elif isinstance(obj,Accas.MCSIMP):
158             return self.generMCSIMP(obj)
159         elif isinstance(obj,Accas.ASSD):
160             return self.generASSD(obj)
161         elif isinstance(obj,Accas.ETAPE_NIVEAU):
162             return self.generETAPE_NIVEAU(obj)
163         elif isinstance(obj,Accas.COMMENTAIRE):
164             return self.generCOMMENTAIRE(obj)
165         # Attention doit etre place avant PARAMETRE (raison : heritage)
166         elif isinstance(obj,Accas.PARAMETRE_EVAL):
167             return self.generPARAMETRE_EVAL(obj)
168         elif isinstance(obj,Accas.PARAMETRE):
169             return self.generPARAMETRE(obj)
170         elif isinstance(obj,Accas.EVAL):
171             return self.generEVAL(obj)
172         elif isinstance(obj,Accas.COMMANDE_COMM):
173             return self.generCOMMANDE_COMM(obj)
174         elif isinstance(obj,Accas.JDC):
175             return self.generJDC(obj)
176         elif isinstance(obj,Accas.MCNUPLET):
177             return self.generMCNUPLET(obj)
178         elif isinstance(obj,ITEM_PARAMETRE):
179             return self.generITEM_PARAMETRE(obj)
180         elif isinstance(obj,Formula):
181             return self.generFormula(obj)
182         else:
183             raise EficasException(tr("Type d'objet non prevu") +obj)
184
185     def generJDC(self,obj):
186         """
187            Cette methode convertit un objet JDC en une liste de chaines de
188            caracteres a la syntaxe python
189         """
190         l=[]
191
192         #print ('generJDC', obj.sdsDict)
193         for objRef in obj.sdsDict :
194             if (isinstance(obj.sdsDict[objRef],Accas.UserASSD)):
195                 l.append(self.generUserASSD(obj.sdsDict[objRef]))
196         if obj.definition.l_niveaux == ():
197             # Il n'y a pas de niveaux
198             for etape in obj.etapes:
199                 l.append(self.generator(etape))
200         else:
201             # Il y a des niveaux
202             for etape_niveau in obj.etapes_niveaux:
203                 l.extend(self.generator(etape_niveau))
204         if l != [] :
205             # Si au moins une etape, on ajoute le retour chariot sur la derniere etape
206             if type(l[-1])==list:
207                 l[-1][-1] = l[-1][-1]+'\n'
208             elif type(l[-1])==bytes or  type(l[-1])==str:
209                 l[-1] = l[-1]+'\n'
210         return l
211
212     def generUserASSD(self,obj):
213         classeName =  obj.__class__.__name__
214         if obj.valeur == None :
215             texte = obj.nom + '=' + classeName + '()'
216             return texte
217
218     def generMCNUPLET(self,obj):
219         """
220             Methode generant une representation de self permettant son ecriture
221             dans le format python
222         """
223         l=[]
224         l.append('(')
225         for v in obj.mcListe:
226             text = re.sub(".*=","",self.generator(v))
227             l.append(text)
228         l.append('),')
229         return l
230
231     def generCOMMANDE_COMM(self,obj):
232         """
233            Cette methode convertit un COMMANDE_COMM
234            en une liste de chaines de caracteres a la syntaxe python
235         """
236         l_lignes = obj.valeur.split('\n')
237         txt=''
238         for ligne in l_lignes:
239             txt = txt + '##'+ligne+'\n'
240         return txt
241
242     def generEVAL(self,obj):
243         """
244            Cette methode convertit un EVAL
245            en une liste de chaines de caracteres a la syntaxe python
246         """
247         return 'EVAL("""'+ obj.valeur +'""")'
248
249     def generCOMMENTAIRE(self,obj):
250         """
251            Cette methode convertit un COMMENTAIRE
252            en une liste de chaines de caracteres a la syntaxe python
253         """
254         # modification pour repondre a la demande de C. Durand, d'eviter
255         # l'ajout systematique d'un diese, a la suite du commentaire
256         # Dans la chaine de caracteres obj.valeur, on supprime le dernier
257         # saut de ligne
258         sans_saut = re.sub("\n$","",obj.valeur)
259         l_lignes = sans_saut.split('\n')
260         txt=''
261         i=1
262         for ligne in l_lignes:
263             txt = txt + '#'+ligne+'\n'
264
265         # suppression du dernier saut de ligne
266         #txt = re.sub("\n$","",txt)
267         # on ajoute un saut de ligne avant
268         pattern=re.compile(" ?\#")
269         m=pattern.match(txt)
270         if m:
271             txt="\n"+txt
272         return txt
273
274     def generPARAMETRE_EVAL(self,obj):
275         """
276            Cette methode convertit un PARAMETRE_EVAL
277            en une liste de chaines de caracteres a la syntaxe python
278         """
279         if obj.valeur == None:
280             return obj.nom + ' = None ;\n'
281         else:
282             return obj.nom + ' = '+ self.generator(obj.valeur) +';\n'
283
284     def generITEM_PARAMETRE(self,obj):
285         return repr(obj)
286
287     def generFormula(self,obj):
288         #return repr(obj)
289         return str(obj)
290
291     def generPARAMETRE(self,obj):
292         """
293            Cette methode convertit un PARAMETRE
294            en une liste de chaines de caracteres a la syntaxe python
295         """
296         return repr(obj) + ";\n"
297
298     def generETAPE_NIVEAU(self,obj):
299         """
300            Cette methode convertit une etape niveau
301            en une liste de chaines de caracteres a la syntaxe python
302         """
303         l=[]
304         if obj.etapes_niveaux == []:
305             for etape in obj.etapes:
306                 l.append(self.generator(etape))
307         else:
308             for etape_niveau in obj.etapes_niveaux:
309                 l.extend(self.generator(etape_niveau))
310         return l
311
312     def generETAPE(self,obj):
313         """
314            Cette methode convertit une etape
315            en une liste de chaines de caracteres a la syntaxe python
316         """
317         try:
318             sdname= self.generator(obj.sd)
319             if  sdname.find('SD_') != -1: sdname='sansnom'
320         except:
321             sdname='sansnom'
322         l=[]
323         label=sdname + '='+obj.definition.nom+'('
324         l.append(label)
325         if obj.reuse != None :
326             str = 'reuse ='+ self.generator(obj.reuse) + ','
327             l.append(str)
328         for v in obj.mcListe:
329             if isinstance(v,Accas.MCBLOC) :
330                 liste=self.generator(v)
331                 for mocle in liste :
332                     l.append(mocle)
333             elif isinstance(v,Accas.MCSIMP) :
334                 text=self.generator(v)
335                 l.append(v.nom+'='+text)
336             else:
337                 # MCFACT ou MCList
338                 liste=self.generator(v)
339                 liste[0]=v.nom+'='+liste[0]
340                 l.append(liste)
341         if len(l) == 1:
342             l[0]=label+');'
343         else :
344             l.append(');')
345         return l
346
347     def generFORM_ETAPE(self,obj):
348         """
349             Methode particuliere pour les objets de type FORMULE
350         """
351         l=[]
352         nom = obj.getNom()
353         if nom == '' : nom = 'sansnom'
354         l.append(nom + ' = FORMULE(')
355         for v in obj.mcListe:
356             text=self.generator(v)
357             l.append(v.nom+'='+text)
358         l.append(');')
359         return l
360
361     def generMACRO_ETAPE(self,obj):
362         """
363            Cette methode convertit une macro-etape
364            en une liste de chaines de caracteres a la syntaxe python
365         """
366         try:
367             if obj.sd == None:
368                 sdname=''
369             else:
370                 sdname= self.generator(obj.sd)+'='
371             if  sdname.find('SD_') != -1: sdname=''
372         except:
373             sdname='sansnom='
374         l=[]
375         label = sdname + obj.definition.nom+'('
376         l.append(label)
377         if obj.reuse != None:
378             # XXX faut il la virgule ou pas ????
379             str = "reuse =" + self.generator(obj.reuse) + ','
380             l.append(str)
381         for v in obj.mcListe:
382             if isinstance(v,Accas.MCBLOC) :
383                 liste=self.generator(v)
384                 for mocle in liste :
385                     l.append(mocle)
386             elif isinstance(v,Accas.MCSIMP) :
387                 text=self.generator(v)
388                 l.append(v.nom+'='+text)
389             else:
390                 # MCFACT ou MCList
391                 liste=self.generator(v)
392                 liste[0]=v.nom+'='+liste[0]
393                 l.append(liste)
394
395         if len(l) == 1:
396             l[0]=label+');'
397         else :
398             l.append(');')
399         return l
400
401     def generPROC_ETAPE(self,obj):
402         """
403            Cette methode convertit une PROC etape
404            en une liste de chaines de caracteres a la syntaxe python
405         """
406         l=[]
407         label=obj.definition.nom+'('
408         l.append(label)
409         for v in obj.mcListe:
410             if isinstance(v,Accas.MCBLOC) :
411                 liste=self.generator(v)
412                 for mocle in liste :
413                     l.append(mocle)
414             elif isinstance(v,Accas.MCSIMP) :
415                 text=self.generator(v)
416                 if text==None : text= ""
417                 l.append(v.nom+'='+text)
418             else:
419                 # MCFACT ou MCList
420                 liste=self.generator(v)
421                 liste[0]=v.nom+'='+liste[0]
422                 l.append(liste)
423
424         if len(l) == 1:
425             l[0]=label+');'
426         else :
427             l.append(');')
428         return l
429
430     def generASSD(self,obj):
431         """
432             Convertit un objet derive d'ASSD en une chaine de caracteres a la
433             syntaxe python
434         """
435         return obj.getName()
436
437
438     def generMCFACT(self,obj):
439         """
440             Convertit un objet MCFACT en une liste de chaines de caracteres a la
441             syntaxe python
442         """
443         l=[]
444         l.append('_F(')
445         for v in obj.mcListe:
446             if not isinstance(v,Accas.MCSIMP) and not isinstance (v,Accas.MCBLOC) :
447                 # on est en presence d'une entite composee : on recupere une liste
448                 liste=self.generator(v)
449                 liste[0]=v.nom+'='+liste[0]
450                 l.append(liste)
451             elif isinstance(v,Accas.MCBLOC):
452                 liste=self.generator(v)
453                 for arg in liste :
454                     l.append(arg)
455             else:
456                 # on est en presence d'un MCSIMP : on recupere une string
457                 text =self.generator(v)
458                 if text== None : text =""
459                 if v.nom != "Consigne" :  l.append(v.nom+'='+text)
460         # il faut etre plus subtil dans l'ajout de la virgule en differenciant
461         # le cas ou elle est obligatoire (si self a des freres cadets
462         # dans self.parent) ou non
463         # (cas ou self est seul ou le benjamin de self.parent)
464         l.append('),')
465         return l
466
467     def generMCList(self,obj):
468         """
469             Convertit un objet MCList en une liste de chaines de caracteres a la
470             syntaxe python
471         """
472         if len(obj.data) > 1:
473             l=['(']
474             for mcfact in obj.data: l.append(self.generator(mcfact))
475             l.append('),')
476         else:
477             l= self.generator(obj.data[0])
478         return l
479
480     def generMCBLOC(self,obj):
481         """
482             Convertit un objet MCBLOC en une liste de chaines de caracteres a la
483             syntaxe python
484         """
485         l=[]
486         for v in obj.mcListe:
487             if isinstance(v,Accas.MCBLOC) :
488                 liste=self.generator(v)
489                 for mocle in liste :
490                     l.append(mocle)
491             elif isinstance(v,Accas.MCFACT):
492                 liste=self.generator(v)
493             elif isinstance(v,Accas.MCList):
494                 liste=self.generator(v)
495                 liste[0]=v.nom+'='+liste[0]
496                 # PN  essai de correction bug identation
497                 if (hasattr(v,'data')) :
498                     if (isinstance(v.data[0],Accas.MCFACT) and (len(v.data) == 1)):
499                         l.append(liste)
500                     else:
501                         for mocle in liste :
502                             l.append(mocle)
503                 else :
504                     for mocle in liste :
505                         l.append(mocle)
506             else:
507                 data=self.generator(v)
508                 if data==None : data= ""
509                 if type(data) == list:
510                     data[0]=v.nom+'='+data[0]
511                 else:
512                     data=v.nom+'='+data
513                 l.append(data)
514         return l
515
516
517     def formatItem(self,valeur,etape,obj,vientDeListe=0,matriceDAssd=0):
518         if (type(valeur) == float or 'R' in obj.definition.type) and not(isinstance(valeur,Accas.PARAMETRE)) :
519             # Pour un flottant on utilise str ou repr si on vient d une liste
520             # ou la notation scientifique
521             # On ajoute un . si il n y en a pas dans la valeur
522             s = str(valeur)
523             if vientDeListe and repr(valeur) != str(valeur) : s=repr(valeur)
524             if (s.find('.')== -1 and s.find('e')== -1 and s.find('E')==-1) : s=s+'.0'
525             clefobj=etape.getSdname()
526             if self.appliEficas and clefobj in self.appliEficas.dict_reels:
527                 if valeur in self.appliEficas.dict_reels[clefobj]:
528                     s=self.appliEficas.dict_reels[clefobj][valeur]
529
530         elif type(valeur) == bytes or type(valeur) == str :
531             if valeur.find('\n') == -1:
532                     # pas de retour chariot, on utilise repr
533                 s = repr(valeur)
534             elif valeur.find('"""') == -1:
535                 # retour chariot mais pas de triple ", on formatte
536                 s='"""'+valeur+'"""'
537             else:
538                 s = repr(valeur)
539         elif isinstance(valeur,Accas.CO) or hasattr(etape,'sdprods') and valeur in etape.sdprods:
540             s = "CO('"+ self.generator(valeur) +"')"
541         elif isinstance(valeur,Accas.UserASSD):
542         # ici on ne prend que la reference
543             s = valeur.nom
544         elif isinstance(valeur,Accas.ASSD):
545             s = self.generator(valeur)
546         elif isinstance(valeur,Accas.PARAMETRE):
547             # il ne faut pas prendre la string que retourne gener
548             # mais seulement le nom dans le cas d'un parametre
549             s = valeur.nom
550
551         #elif type(valeur) == types.InstanceType or isinstance(valeur,object):
552         #   if valeur.__class__.__name__ == 'CO' or hasattr(etape,'sdprods') and valeur in etape.sdprods :
553         #      s = "CO('"+ self.generator(valeur) +"')"
554         #   elif isinstance(valeur,Accas.PARAMETRE):
555                 # il ne faut pas prendre la string que retourne gener
556                 # mais seulement le nom dans le cas d'un parametre
557         #      s = valeur.nom
558         #   else:
559         #      s = self.generator(valeur)
560
561         elif matriceDAssd :
562            s='['
563            for v in valeur :
564                s=s+str(self.generator(v))+', '
565                
566            s=s+']'
567         else :
568             # Pour les autres types on utilise repr
569             s = repr(valeur)
570         return s
571
572     def generMCSIMP(self,obj) :
573         """
574             Convertit un objet MCSIMP en une liste de chaines de caracteres a la
575             syntaxe python
576         """
577         waitTuple=0
578         matriceDAssd=0
579         for ssType in obj.definition.type:
580             if hasattr(ssType,'typElt') :
581                 if ssType.typElt not in ('R','I','C','TXM') : 
582                     matriceDAssd=1
583                     break
584         if type(obj.valeur) in (tuple,list) :
585             s = ''
586             for ss_type in obj.definition.type:
587                 if repr(ss_type).find('Tuple') != -1 :
588                     waitTuple=1
589                     break
590             if waitTuple :
591                 #s = str(obj.valeur) +','
592                 #obj.valeurFormatee=obj.valeur
593                 s = obj.getText() +','
594                 obj.valeurFormatee=obj.getText()
595             else :
596                 obj.valeurFormatee=[]
597                 for val in obj.valeur :
598                     s =s +self.formatItem(val,obj.etape,obj,1,matriceDAssd) + ','
599                     if obj.waitTxm() :
600                         obj.valeurFormatee.append(val)
601                     else :
602                         obj.valeurFormatee.append(self.formatItem(val,obj.etape,obj))
603                 if len(obj.valeur) >= 1:
604                     s = '(' + s + '),'
605                 if obj.valeur==[] or obj.valeur==() : s="(),"
606             if obj.nbrColonnes() :
607                 s=self.formatColonnes(obj.nbrColonnes(),obj.valeur,obj)
608         else :
609             obj.valeurFormatee=obj.valeur
610             s=self.formatItem(obj.valeur,obj.etape,obj) + ','
611         return s
612
613
614     def formatColonnes(self,nbrColonnes,listeValeurs,obj):
615         try :
616         #if 1 == 1 :
617             indice=0
618             textformat="("
619             while ( indice < len(listeValeurs) ) :
620                 try :
621                 #if 1 :
622                     for l in range(nbrColonnes) :
623                         texteVariable=self.formatItem(listeValeurs[indice],obj.etape,obj)
624                         textformat=textformat+texteVariable+" ,"
625                         indice=indice+1
626                     textformat=textformat+"\n"
627                 except :
628                 #else :
629                     while ( indice < len(listeValeurs) ) :
630                         texteVariable=self.formatItem(listeValeurs[indice],obj.etape,obj)
631                         textformat=textformat+texteVariable+", "
632                         indice=indice+1
633                     textformat=textformat+"\n"
634             textformat=textformat[0:-1]+"),\n"
635         except :
636         #else :
637             textformat=str(obj.valeur)
638         return textformat