1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2013 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
21 Description des types de base aster
22 -----------------------------------
24 version 2 - réécrite pour essayer de simplifier
25 le problème des instances/types et instances/instances.
27 Le type de base `Type` permet de représenter une structure
28 de donnée. Une instance de `Type` comme attribut d'une classe
29 dérivée de `Type` représente une sous-structure nommée.
31 Une instance de `Type` 'libre' représente une instance de la
32 structure de donnée complète.
34 C'est ce comportement qui est capturé dans la classe BaseType
36 La classe `Type` hérite de BaseType et y associe la métaclasse MetaType.
42 __docformat__ = "restructuredtext"
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
51 def __new__( mcs, name, bases, classdict ):
52 """Création d'une nouvelle 'classe' dérivant de Type.
54 Cette méthode permet de calculer certains attributs automatiquement:
56 - L'attribut _subtypes qui contient la liste des sous-structures
57 de type 'Type' attributs (directs ou hérités) de cette classe.
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.
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.
67 new_cls = type.__new__( mcs, name, bases, classdict )
68 new_cls._subtypes = []
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
75 for k, v in classdict.items():
76 if not isinstance( v, BaseType ):
78 v.reparent( new_cls, k )
79 new_cls._subtypes.append( k )
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`.
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 )
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.
102 Les attributs de classe deviennent des attributs d'instance.
104 inst = cls.__new__(cls, *args, **kwargs)
105 # reinstantiate and reparent subtypes
107 type(inst).__init__(inst, *args, **kwargs)
114 class BaseType(object):
115 # Le parent de la structure pour les sous-structures
119 def __init__(self, *args, **kwargs):
120 self._initargs = args
121 self._initkwargs = kwargs
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 )
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."""
139 for nam in self._subtypes:
140 obj = getattr(self, nam)
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 # Dans une version précédente, on utilisait l'attribut
146 # sd_deleted pour ne faire qu'une fois, à voir.
147 # Supprimer les références remontantes devrait suffir.
149 #while len(self._subtypes):
150 #nam = self._subtypes.pop(0)
153 #except AttributeError:
157 if self._parent is None:
159 return self._parent.base()
162 class Type(BaseType):
163 __metaclass__ = MetaType