2 # Copyright (C) 2007-2017 EDF R&D
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.
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.
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
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 Ce module sert à nommer les concepts produits par les commandes.
23 Le nom du concept est obtenu en appelant la fonction getNomConceptResultat
24 du module avec le nom de la commande en argument.
26 Cette fonction parcourt le source dans lequel la commande se trouve, parse le
27 fichier et retrouve le nom du concept qui se trouve à gauche du signe = précédant
28 le nom de la commande.
30 Cette fonction utilise la fonction cur_frame du module N_utils qui retourne la frame
31 d'exécution Python située 2 niveaux au-dessus. C'est à partir de cette frame que
32 l'on retrouve le fichier source et le numéro de ligne où se trouve l'appel à la commande.
37 from __future__ import absolute_import
39 from builtins import str
40 from builtins import range
46 from functools import partial
50 from .strfunc import getEncoding
52 from six.moves import range
54 regex1 = '=?\s*%s\s*\('
55 # commentaire standard precede d'un nombre quelconque de blancs (pas
57 pattern_comment = re.compile(r"^\s*#.*")
60 def _getNomConceptResultat(ope, level=2):
62 Cette fonction recherche dans la pile des appels, l'appel à la commande
63 qui doit etre situé à 2 niveaux au-dessus (cur_frame(2)).
64 On retrouve d'abord la frame d'exécution f. Puis le numéro de la ligne
65 dans le source f.f_lineno et le nom du fichier source (f.f_code.co_filename).
66 A partir de là, on récupère la ligne de source avec linecache.getline
67 et on vérifie que cette ligne correspond véritablement à l'appel.
69 En effet, lorsque les commandes tiennent sur plusieurs lignes, on retrouve
70 la dernière ligne. Il faut donc remonter dans le source jusqu'à la première
73 Enfin la fonction evalnom forme un nom acceptable lorsque le concept est un
74 élément d'une liste, par exemple.
77 f = N_utils.cur_frame(level)
78 lineno = f.f_lineno # XXX Too bad if -O is used
79 # lineno = f_lineno(f) # Ne marche pas toujours
81 if sys.version_info >= (3,0) :
82 filename = co.co_filename
84 filename = six.text_type(co.co_filename, getEncoding())
86 # pattern pour identifier le debut de la commande
87 pattern_oper = re.compile(regex1 % ope)
91 line = linecache.getline(filename, lineno)
93 if pattern_comment.match(line):
96 if pattern_oper.search(line):
97 l = pattern_oper.split(line)
99 # On suppose que le concept resultat a bien ete
100 # isole en tete de la ligne de source
101 m = evalnom(l[0].strip(), f.f_locals)
107 # print "appel inconnu"
111 def evalnom(text, d):
113 Retourne un nom pour le concept resultat identifie par text
114 Pour obtenir ce nom il y a plusieurs possibilites :
115 1. text est un identificateur python c'est le nom du concept
116 2. text est un element d'une liste on construit le nom en
117 evaluant la partie indice dans le contexte de l'appelant d
119 l = re.split('([\[\]]+)', text)
126 ll = re.split('[ ,]+', s)
134 if i + 1 < len(l) and l[i + 1] == '[': # le nom est suivi d un subscript
136 nom = id0 + '_' + str(eval(sub, d))
147 Calcule le numero de ligne courant
148 Devrait marcher meme avec -O
149 Semble ne pas marcher en présence de tuples longs
152 if not hasattr(c, 'co_lnotab'):
155 line = c.co_firstlineno
158 for i in range(0, len(tab), 2):
159 addr = addr + ord(tab[i])
162 line = line + ord(tab[i + 1])
166 class NamingSystem(N_utils.Singleton):
168 """Cette classe définit un système de nommage dynamique des concepts."""
169 _singleton_id = 'nommage.NamingSystem'
173 self.native = _getNomConceptResultat
174 self.useGlobalNaming()
176 def useNamingFunction(self, function):
177 """Utilise une fonction particulière de nommage."""
178 self.naming_func = function
180 def useGlobalNaming(self):
181 """Utilise la fonction native de nommage."""
182 self.naming_func = partial(self.native, level=3)
184 def __call__(self, *args):
185 """Appel à la fonction de nommage."""
186 return self.naming_func(*args)
188 getNomConceptResultat = NamingSystem()