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