Salome HOME
BOUNDARY... dans Telemac2D
[tools/eficas.git] / generator / generator_python.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2013   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.appli=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,appli=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       self.appli=obj.get_jdc_root().appli
106       #self.appli=obj.appli
107       liste= self.generator(obj)
108       #format='standard'
109       if format == 'brut':
110          self.text=liste
111       elif format == 'standard':
112          self.text=''.join(liste)
113       elif format == 'beautifie':
114          jdc_formate = Formatage(liste,mode='.py')
115          #import cProfile, pstats, StringIO
116          #pr = cProfile.Profile()
117          #pr.enable()
118          self.text=jdc_formate.formate_jdc()
119          #pr.disable()
120          #s = StringIO.StringIO()
121          #sortby = 'cumulative'
122          #ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
123          #ps.print_stats()
124          #print (s.getvalue())
125
126       elif format == 'Ligne':
127          jdc_formate = FormatageLigne(liste,mode='.py')
128          self.text=jdc_formate.formate_jdc()
129       else:
130          raise EficasException(tr("Format non implemente ") +format)
131       return self.text
132
133    def generator(self,obj):
134       """
135          Cette methode joue un role d'aiguillage en fonction du type de obj
136          On pourrait utiliser les methodes accept et visitxxx a la 
137          place (depend des gouts !!!)
138       """
139       # ATTENTION a l'ordre des tests : il peut avoir de l'importance (heritage)
140       if isinstance(obj,Accas.PROC_ETAPE):
141          return self.generPROC_ETAPE(obj)
142       # Attention doit etre place avant MACRO (raison : heritage)
143       elif isinstance(obj,Accas.FORM_ETAPE):
144          return self.generFORM_ETAPE(obj)
145       elif isinstance(obj,Accas.MACRO_ETAPE):
146          return self.generMACRO_ETAPE(obj)
147       elif isinstance(obj,Accas.ETAPE):
148          return self.generETAPE(obj)
149       elif isinstance(obj,Accas.MCFACT):
150          return self.generMCFACT(obj)
151       elif isinstance(obj,Accas.MCList):
152          return self.generMCList(obj)
153       elif isinstance(obj,Accas.MCBLOC):
154          return self.generMCBLOC(obj)
155       elif isinstance(obj,Accas.MCSIMP):
156          return self.generMCSIMP(obj)
157       elif isinstance(obj,Accas.ASSD):
158          return self.generASSD(obj)
159       elif isinstance(obj,Accas.ETAPE_NIVEAU):
160          return self.generETAPE_NIVEAU(obj)
161       elif isinstance(obj,Accas.COMMENTAIRE):
162          return self.generCOMMENTAIRE(obj)
163       # Attention doit etre place avant PARAMETRE (raison : heritage)
164       elif isinstance(obj,Accas.PARAMETRE_EVAL):
165          return self.generPARAMETRE_EVAL(obj)
166       elif isinstance(obj,Accas.PARAMETRE):
167          return self.generPARAMETRE(obj)
168       elif isinstance(obj,Accas.EVAL):
169          return self.generEVAL(obj)
170       elif isinstance(obj,Accas.COMMANDE_COMM):
171          return self.generCOMMANDE_COMM(obj)
172       elif isinstance(obj,Accas.JDC):
173          return self.generJDC(obj)
174       elif isinstance(obj,Accas.MCNUPLET):
175          return self.generMCNUPLET(obj)
176       elif isinstance(obj,ITEM_PARAMETRE):
177          return self.generITEM_PARAMETRE(obj)
178       elif isinstance(obj,Formula):
179          return self.generFormula(obj)
180       else:
181          raise EficasException(tr("Type d'objet non prevu") +obj)
182
183    def generJDC(self,obj):
184       """
185          Cette methode convertit un objet JDC en une liste de chaines de
186          caracteres a la syntaxe python
187       """
188       l=[]
189       if obj.definition.l_niveaux == ():
190          # Il n'y a pas de niveaux
191          for etape in obj.etapes:
192             l.append(self.generator(etape))
193       else:
194          # Il y a des niveaux
195          for etape_niveau in obj.etapes_niveaux:
196             l.extend(self.generator(etape_niveau))
197       if l != [] :
198          # Si au moins une etape, on ajoute le retour chariot sur la derniere etape
199          if type(l[-1])==list:
200             l[-1][-1] = l[-1][-1]+'\n'
201          elif type(l[-1])==bytes:
202             l[-1] = l[-1]+'\n'
203       return l
204
205    def generMCNUPLET(self,obj):
206       """ 
207           Methode generant une representation de self permettant son ecriture
208           dans le format python
209       """
210       l=[]
211       l.append('(')
212       for v in obj.mc_liste:
213         text = re.sub(".*=","",self.generator(v))
214         l.append(text)
215       l.append('),')
216       return l
217
218    def generCOMMANDE_COMM(self,obj):
219       """
220          Cette methode convertit un COMMANDE_COMM
221          en une liste de chaines de caracteres a la syntaxe python
222       """
223       l_lignes = obj.valeur.split('\n')
224       txt=''
225       for ligne in l_lignes:
226           txt = txt + '##'+ligne+'\n'
227       return txt
228
229    def generEVAL(self,obj):
230       """
231          Cette methode convertit un EVAL
232          en une liste de chaines de caracteres a la syntaxe python
233       """
234       return 'EVAL("""'+ obj.valeur +'""")'
235
236    def generCOMMENTAIRE(self,obj):
237       """
238          Cette methode convertit un COMMENTAIRE
239          en une liste de chaines de caracteres a la syntaxe python
240       """
241       # modification pour repondre a la demande de C. Durand, d'eviter
242       # l'ajout systematique d'un diese, a la suite du commentaire
243       # Dans la chaine de caracteres obj.valeur, on supprime le dernier
244       # saut de ligne
245       sans_saut = re.sub("\n$","",obj.valeur)
246       l_lignes = sans_saut.split('\n')
247       txt=''
248       i=1
249       for ligne in l_lignes:
250         txt = txt + '#'+ligne+'\n'
251
252       # suppression du dernier saut de ligne
253       #txt = re.sub("\n$","",txt)
254       # on ajoute un saut de ligne avant
255       pattern=re.compile(" ?\#")
256       m=pattern.match(txt)
257       if m:
258          txt="\n"+txt
259       return txt
260
261    def generPARAMETRE_EVAL(self,obj):
262       """
263          Cette methode convertit un PARAMETRE_EVAL
264          en une liste de chaines de caracteres a la syntaxe python
265       """
266       if obj.valeur == None:
267          return obj.nom + ' = None ;\n'
268       else:
269          return obj.nom + ' = '+ self.generator(obj.valeur) +';\n'
270
271    def generITEM_PARAMETRE(self,obj):
272        return repr(obj) 
273
274    def generFormula(self,obj):
275        #return repr(obj) 
276        return str(obj) 
277
278    def generPARAMETRE(self,obj):
279       """
280          Cette methode convertit un PARAMETRE
281          en une liste de chaines de caracteres a la syntaxe python
282       """
283       return repr(obj) + ";\n"
284
285    def generETAPE_NIVEAU(self,obj):
286       """
287          Cette methode convertit une etape niveau
288          en une liste de chaines de caracteres a la syntaxe python
289       """
290       l=[]
291       if obj.etapes_niveaux == []:
292         for etape in obj.etapes:
293           l.append(self.generator(etape))
294       else:
295         for etape_niveau in obj.etapes_niveaux:
296           l.extend(self.generator(etape_niveau))
297       return l
298
299    def generETAPE(self,obj):
300       """
301          Cette methode convertit une etape
302          en une liste de chaines de caracteres a la syntaxe python
303       """
304       try:
305         sdname= self.generator(obj.sd)
306         if  sdname.find('SD_') != -1: sdname='sansnom'
307       except:
308         sdname='sansnom'
309       l=[]
310       label=sdname + '='+obj.definition.nom+'('
311       l.append(label)
312       if obj.reuse != None :
313         str = 'reuse ='+ self.generator(obj.reuse) + ','
314         l.append(str)
315       for v in obj.mc_liste:
316         if isinstance(v,Accas.MCBLOC) :
317           liste=self.generator(v)
318           for mocle in liste :
319             l.append(mocle)
320         elif isinstance(v,Accas.MCSIMP) :
321           text=self.generator(v)
322           l.append(v.nom+'='+text)
323         else:
324           # MCFACT ou MCList
325           liste=self.generator(v)
326           liste[0]=v.nom+'='+liste[0]
327           l.append(liste)
328       if len(l) == 1:
329         l[0]=label+');'
330       else :
331         l.append(');')
332       return l
333
334    def generFORM_ETAPE(self,obj):
335         """
336             Methode particuliere pour les objets de type FORMULE
337         """
338         l=[]
339         nom = obj.get_nom()
340         if nom == '' : nom = 'sansnom'
341         l.append(nom + ' = FORMULE(')
342         for v in obj.mc_liste:
343             text=self.generator(v)
344             l.append(v.nom+'='+text)
345         l.append(');')
346         return l
347
348    def generMACRO_ETAPE(self,obj):
349       """
350          Cette methode convertit une macro-etape
351          en une liste de chaines de caracteres a la syntaxe python
352       """
353       try:
354         if obj.sd == None:
355           sdname=''
356         else:
357           sdname= self.generator(obj.sd)+'='
358         if  sdname.find('SD_') != -1: sdname=''
359       except:
360         sdname='sansnom='
361       l=[]
362       label = sdname + obj.definition.nom+'('
363       l.append(label)
364       if obj.reuse != None:
365          # XXX faut il la virgule ou pas ????
366          str = "reuse =" + self.generator(obj.reuse) + ','
367          l.append(str)
368       for v in obj.mc_liste:
369         if isinstance(v,Accas.MCBLOC) :
370           liste=self.generator(v)
371           for mocle in liste :
372             l.append(mocle)
373         elif isinstance(v,Accas.MCSIMP) :
374           text=self.generator(v)
375           l.append(v.nom+'='+text)
376         else:
377           # MCFACT ou MCList
378           liste=self.generator(v)
379           liste[0]=v.nom+'='+liste[0]
380           l.append(liste)
381
382       if len(l) == 1:
383         l[0]=label+');'
384       else :
385         l.append(');')
386       return l
387
388    def generPROC_ETAPE(self,obj):
389       """
390          Cette methode convertit une PROC etape
391          en une liste de chaines de caracteres a la syntaxe python
392       """
393       l=[]
394       label=obj.definition.nom+'('
395       l.append(label)
396       for v in obj.mc_liste:
397         if isinstance(v,Accas.MCBLOC) :
398           liste=self.generator(v)
399           for mocle in liste :
400             l.append(mocle)
401         elif isinstance(v,Accas.MCSIMP) :
402           text=self.generator(v)
403           if text==None : text= ""
404           l.append(v.nom+'='+text)
405         else:
406           # MCFACT ou MCList
407           liste=self.generator(v)
408           liste[0]=v.nom+'='+liste[0]
409           l.append(liste)
410
411       if len(l) == 1:
412         l[0]=label+');'
413       else :
414         l.append(');')
415       return l
416
417    def generASSD(self,obj):
418       """
419           Convertit un objet derive d'ASSD en une chaine de caracteres a la
420           syntaxe python
421       """
422       return obj.get_name()
423
424    def generMCFACT(self,obj):
425       """
426           Convertit un objet MCFACT en une liste de chaines de caracteres a la
427           syntaxe python
428       """
429       l=[]
430       l.append('_F(')
431       for v in obj.mc_liste:
432          if not isinstance(v,Accas.MCSIMP) and not isinstance (v,Accas.MCBLOC) :
433            # on est en presence d'une entite composee : on recupere une liste
434            liste=self.generator(v)
435            liste[0]=v.nom+'='+liste[0]
436            l.append(liste)
437          elif isinstance(v,Accas.MCBLOC):
438            liste=self.generator(v)
439            for arg in liste :
440              l.append(arg)
441          else:
442            # on est en presence d'un MCSIMP : on recupere une string
443            text =self.generator(v)
444            if text== None : text =""
445            if v.nom != "Consigne" :  l.append(v.nom+'='+text)
446       # il faut etre plus subtil dans l'ajout de la virgule en differenciant 
447       # le cas ou elle est obligatoire (si self a des freres cadets 
448       # dans self.parent) ou non
449       # (cas ou self est seul ou le benjamin de self.parent)
450       l.append('),')
451       return l
452
453    def generMCList(self,obj):
454       """
455           Convertit un objet MCList en une liste de chaines de caracteres a la
456           syntaxe python
457       """
458       if len(obj.data) > 1:
459          l=['(']
460          for mcfact in obj.data: l.append(self.generator(mcfact))
461          l.append('),')
462       else:
463          l= self.generator(obj.data[0])
464       return l
465
466    def generMCBLOC(self,obj):
467       """
468           Convertit un objet MCBLOC en une liste de chaines de caracteres a la
469           syntaxe python
470       """
471       l=[]
472       for v in obj.mc_liste:
473         if isinstance(v,Accas.MCBLOC) :
474           liste=self.generator(v)
475           for mocle in liste :
476             l.append(mocle)
477         elif isinstance(v,Accas.MCFACT):
478           liste=self.generator(v)
479         elif isinstance(v,Accas.MCList):
480           liste=self.generator(v)
481           liste[0]=v.nom+'='+liste[0]
482           # PN  essai de correction bug identation
483           if (hasattr(v,'data')) :
484             if (isinstance(v.data[0],Accas.MCFACT) and (len(v.data) == 1)):
485                l.append(liste)
486             else:
487                for mocle in liste :
488                  l.append(mocle)
489           else :
490              for mocle in liste :
491                l.append(mocle)
492         else:
493           data=self.generator(v)
494           if data==None : data= ""
495           if type(data) == list:
496             data[0]=v.nom+'='+data[0]
497           else:
498             data=v.nom+'='+data
499           l.append(data)
500       return l
501
502
503    def format_item(self,valeur,etape,obj,vientDeListe=0):
504       if (type(valeur) == float or 'R' in obj.definition.type) and not(isinstance(valeur,Accas.PARAMETRE)) :
505          # Pour un flottant on utilise str ou repr si on vient d une liste
506          # ou la notation scientifique
507          # On ajoute un . si il n y en a pas dans la valeur
508          s = str(valeur)
509          if vientDeListe and repr(valeur) != str(valeur) : s=repr(valeur)
510          if (s.find('.')== -1 and s.find('e')== -1 and s.find('E')==-1) : s=s+'.0'
511          clefobj=etape.get_sdname()
512          if self.appli.appliEficas and clefobj in self.appli.appliEficas.dict_reels:
513            if valeur in self.appli.appliEficas.dict_reels[clefobj]:
514              s=self.appli.appliEficas.dict_reels[clefobj][valeur]
515          
516       elif type(valeur) == bytes :
517          if valeur.find('\n') == -1:
518             # pas de retour chariot, on utilise repr
519             s = repr(valeur)
520          elif valeur.find('"""') == -1:
521             # retour chariot mais pas de triple ", on formatte
522             s='"""'+valeur+'"""'
523          else:
524             s = repr(valeur)
525       elif isinstance(valeur,Accas.CO) or hasattr(etape,'sdprods') and valeur in etape.sdprods:
526          s = "CO('"+ self.generator(valeur) +"')"
527       elif isinstance(valeur,Accas.ASSD):
528          s = self.generator(valeur)
529       elif isinstance(valeur,Accas.PARAMETRE):
530          # il ne faut pas prendre la string que retourne gener
531          # mais seulement le nom dans le cas d'un parametre
532          s = valeur.nom
533
534       #elif type(valeur) == types.InstanceType or isinstance(valeur,object):
535       #   if valeur.__class__.__name__ == 'CO' or hasattr(etape,'sdprods') and valeur in etape.sdprods :
536       #      s = "CO('"+ self.generator(valeur) +"')"
537       #   elif isinstance(valeur,Accas.PARAMETRE):
538             # il ne faut pas prendre la string que retourne gener
539             # mais seulement le nom dans le cas d'un parametre
540       #      s = valeur.nom
541       #   else:
542       #      s = self.generator(valeur)
543
544       else :
545          # Pour les autres types on utilise repr
546          s = repr(valeur)
547       return s
548
549    def generMCSIMP(self,obj) :
550       """
551           Convertit un objet MCSIMP en une liste de chaines de caracteres a la
552           syntaxe python
553       """
554       waitTuple=0
555       if type(obj.valeur) in (tuple,list) :
556          s = ''
557          for ss_type in obj.definition.type:
558           if repr(ss_type).find('Tuple') != -1 :
559              waitTuple=1
560              break
561
562          if waitTuple :
563             #s = str(obj.valeur) +','
564             #obj.valeurFormatee=obj.valeur
565             s = obj.GetText() +','
566             obj.valeurFormatee=obj.GetText()
567          else :
568             obj.valeurFormatee=[]
569             for val in obj.valeur :
570                s =s +self.format_item(val,obj.etape,obj,1) + ','
571                if obj.wait_TXM() :
572                   obj.valeurFormatee.append(val)
573                else :
574                  obj.valeurFormatee.append(self.format_item(val,obj.etape,obj))
575             if len(obj.valeur) >= 1:
576                s = '(' + s + '),'
577             if obj.valeur==[] or obj.valeur==() : s="(),"
578          if obj.nbrColonnes() :
579             s=self.formatColonnes(obj.nbrColonnes(),obj.valeur,obj)
580       else :
581          obj.valeurFormatee=obj.valeur
582          s=self.format_item(obj.valeur,obj.etape,obj) + ','
583       return s
584
585
586    def formatColonnes(self,nbrColonnes,listeValeurs,obj):
587       #try :
588       if 1 == 1 :
589         indice=0
590         textformat="("
591         while ( indice < len(listeValeurs) ) :
592           try :
593           #if 1 :
594             for l in range(nbrColonnes) :
595                 texteVariable=self.format_item(listeValeurs[indice],obj.etape,obj)
596                 textformat=textformat+texteVariable+" ,"
597                 indice=indice+1
598             textformat=textformat+"\n"
599           except :
600           #else :
601             while ( indice < len(listeValeurs) ) :
602                 texteVariable=self.format_item(listeValeurs[indice],obj.etape,obj)
603                 textformat=textformat+texteVariable+", "
604                 indice=indice+1
605             textformat=textformat+"\n"
606         textformat=textformat[0:-1]+"),\n"
607       #except :
608       else :
609          textformat=str(obj.valeur)
610       return textformat