Salome HOME
Tuples avec concept
[tools/eficas.git] / Noyau / basetype.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
22 Description des types de base aster
23 -----------------------------------
24
25 version 2 - réécrite pour essayer de simplifier
26 le problème des instances/types et instances/instances.
27
28 Le type de base `Type` permet de représenter une structure
29 de donnée. Une instance de `Type` comme attribut d'une classe
30 dérivée de `Type` représente une sous-structure nommée.
31
32 Une instance de `Type` 'libre' représente une instance de la
33 structure de donnée complète.
34
35 C'est ce comportement qui est capturé dans la classe BaseType
36
37 La classe `Type` hérite de BaseType et y associe la métaclasse MetaType.
38
39 """
40
41 import cPickle
42
43 __docformat__ = "restructuredtext"
44
45
46 class MetaType(type):
47
48     """Métaclasse d'un type représentant une structure de données.
49     Les méthodes spéciales __new__ et __call__ sont réimplémentées
50     """
51     def __new__(mcs, name, bases, classdict):
52         """Création d'une nouvelle 'classe' dérivant de Type.
53
54         Cette méthode permet de calculer certains attributs automatiquement:
55
56          - L'attribut _subtypes qui contient la liste des sous-structures
57            de type 'Type' attributs (directs ou hérités) de cette classe.
58
59         Pour chaque attribut de classe héritant de Type, on recrée une nouvelle
60         instance des attributs hérités pour pouvoir maintenir une structure de
61         parentée entre l'attribut de classe et sa nouvelle classe.
62
63         L'effet obtenu est que tous les attributs de classe ou des classes parentes
64         de cette classe sont des attributs associés à la classe feuille. Ces attributs
65         ont eux-meme un attribut parent qui pointe sur la classe qui les contient.
66         """
67         new_cls = type.__new__(mcs, name, bases, classdict)
68         new_cls._subtypes = []
69         for b in bases:
70             if hasattr(b, '_subtypes'):
71                 new_cls._subtypes += b._subtypes
72         # affecte la classe comme parent des attributs de classe
73         # et donne l'occasion aux attributs de se renommer à partir
74         # du nom utilisé.
75         for k, v in classdict.items():
76             if not isinstance(v, BaseType):
77                 continue
78             v.reparent(new_cls, k)
79             new_cls._subtypes.append(k)
80         return new_cls
81
82     def dup_attr(cls, inst):
83         """Duplique les attributs de la classe `cls` pour qu'ils deviennent
84         des attributs de l'instance `inst`.
85         """
86         # reinstantiate and reparent subtypes
87         for nam in cls._subtypes:
88             obj = getattr(cls, nam)
89             # permet de dupliquer completement l'instance
90             cpy = cPickle.dumps(obj)
91             newobj = cPickle.loads(cpy)
92             newobj.reparent(inst, None)
93             setattr(inst, nam, newobj)
94
95     def __call__(cls, *args, **kwargs):
96         """Instanciation d'un Type structuré.
97         Lors de l'instanciation on effectue un travail similaire à la
98         création de classe: Les attributs sont re-parentés à l'instance
99         et réinstanciés pour obtenir une instanciation de toute la structure
100         et de ses sous-structures.
101
102         Les attributs de classe deviennent des attributs d'instance.
103         """
104         inst = cls.__new__(cls, *args, **kwargs)
105         # reinstantiate and reparent subtypes
106         cls.dup_attr(inst)
107         type(inst).__init__(inst, *args, **kwargs)
108         return inst
109
110     def mymethod(cls):
111         pass
112
113
114 class BaseType(object):
115     # Le parent de la structure pour les sous-structures
116     _parent = None
117     _name = None
118
119     def __init__(self, *args, **kwargs):
120         self._initargs = args
121         self._initkwargs = kwargs
122         self._name = None
123         self._parent = None
124
125     def reparent(self, parent, new_name):
126         self._parent = parent
127         self._name = new_name
128         for nam in self._subtypes:
129             obj = getattr(self, nam)
130             obj.reparent(self, nam)
131
132     def supprime(self, delete=False):
133         """Permet de casser les boucles de références pour que les ASSD
134         puissent être détruites.
135         Si `delete` vaut True, on supprime l'objet lui-même et pas
136         seulement les références remontantes."""
137         self._parent = None
138         self._name = None
139         for nam in self._subtypes:
140             obj = getattr(self, nam)
141             obj.supprime(delete)
142         # XXX MC : avec ce code, j'ai l'impression qu'on supprime aussi
143         # des attributs de classe, ce qui pose problème pour une
144         # instanciation future...
145         # Supprimer les références remontantes devrait suffir.
146         # if delete:
147             # while len(self._subtypes):
148                 # nam = self._subtypes.pop(0)
149                 # try:
150                     # delattr(self, nam)
151                 # except AttributeError:
152                     # pass
153
154     def base(self):
155         if self._parent is None:
156             return self
157         return self._parent.base()
158
159
160 class Type(BaseType):
161     __metaclass__ = MetaType