root/tags/Release-0_3_2/RBFoundation/RBFoundation/XMLClassBuilder.py

Revision 284, 9.6 kB (checked in by sholloway, 6 years ago)

Changed the interface of SkinContext? in order to be more flexable
Fixed some naming and comparison problems in WeakBind?
Fixed some itereation issues in DOT Skinning
Added an invisible DOT skin element
Added a LazyProperty? that calls ClassFactory? to instantiate a variable on the first reference.
Added a hash method to WeakBind?

Line 
1 #!/usr/bin/env python
2 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 ##~ License
4 ##~
5 ##- The RuneBlade Foundation library is intended to ease some
6 ##- aspects of writing intricate Jabber, XML, and User Interface (wxPython, etc.)
7 ##- applications, while providing the flexibility to modularly change the
8 ##- architecture. Enjoy.
9 ##~
10 ##~ Copyright (C) 2002  TechGame Networks, LLC.
11 ##~
12 ##~ This library is free software; you can redistribute it and/or
13 ##~ modify it under the terms of the BSD style License as found in the
14 ##~ LICENSE file included with this distribution.
15 ##~
16 ##~ TechGame Networks, LLC can be reached at:
17 ##~ 3578 E. Hartsel Drive #211
18 ##~ Colorado Springs, Colorado, USA, 80920
19 ##~
20 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 #~ Imports
24 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25
26 from Foundation import XMLBuilder
27 import keyword
28
29 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 #~ Definitions
31 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32
33 class ElementFactory(object):
34     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35     #~ Definitions
36     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
37
38     class Static(object):
39         def __init__(self, result):
40             self.result = result
41         def __call__(self, *args, **kw):
42             return self.result
43
44     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45
46     class InheritFromNextFactory(Exception):
47         def __call__(self, *args, **kw):
48             raise InheritFromNextFactory, (args, kw)
49
50     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
51
52     class BaseImport(object):
53         def __init__(self, PyPathRoot=''):
54             self.PyPathRoot = PyPathRoot
55             self._CachedElementFactories = {}
56
57         def _DoImport(self, PyPath, Name):
58             if self.PyPathRoot and PyPath:
59                 PyPath = '.'.join((self.PyPathRoot, PyPath))
60             elif not PyPath:
61                 PyPath = self.PyPathRoot
62             module = __import__(PyPath, globals(), {}, Name)
63             result = getattr(module, Name)
64             return result
65
66         def __call__(self, owner, parent, node, attributes, namespacemap):
67             result = self._CachedElementFactories.get(node, None)
68             if not result:
69                 ns, name = node
70                 if keyword.iskeyword(name): name = name + '_'
71                 result = self._DoImport('', name)
72
73                 ## The following works for another scheme
74                 ##result = self.DoImport(*node)
75
76                 self._CachedElementFactories[node] = result
77             return result
78     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79
80     class StaticImport(BaseImport):
81         def __init__(self, PyPath, Name, *args, **kw):
82             ElementFactory.BaseImport.__init__(self, *args, **kw)
83             self.ImportArgs = PyPath, Name
84             self.result = None
85
86         def __call__(self, *args, **kw):
87             if not self.result:
88                 self.result = self._DoImport(*self.ImportArgs)
89             return self.result
90            
91     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92
93     class NodeImport(BaseImport):
94         def __call__(self, owner, parent, node, attributes, namespacemap):
95             result = self._CachedElementFactories.get(node, None)
96             if not result:
97                 ns, name = node
98                 if keyword.iskeyword(name): name = name + '_'
99                 result = self._DoImport(name, name)
100
101                 ## The following works for another scheme
102                 ##result = self.DoImport(*node)
103
104                 self._CachedElementFactories[node] = result
105             return result
106            
107     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108
109     class NamespaceImport(BaseImport):
110         def __call__(self, owner, parent, node, attributes, namespacemap):
111             result = self._CachedElementFactories.get(node, None)
112             if not result:
113                 ns, name = node
114                 if keyword.iskeyword(name): name = name + '_'
115                 result = self._DoImport('%s.%s' % (ns, name), name)
116
117                 ## The following works for another scheme
118                 ##result = self.DoImport(*node)
119
120                 self._CachedElementFactories[node] = result
121             return result
122
123     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124
125     class TryList(object):
126         def __init__(self, trylist, ignoreExceptions=[ImportError, AttributeError, KeyError]):
127             self._trylist = trylist
128             self._ignoreExceptions = tuple(ignoreExceptions)
129
130         def __call__(self, *args, **kw):
131             for each in self._trylist:
132                 try:
133                     return each(*args, **kw)
134                 except self._ignoreExceptions:
135                     pass
136
137     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
138
139     class CachedTryList(TryList):
140         def __init__(self, *args, **kw):
141             ElementFactory.TryList.__init__(self, *args, **kw)
142             self._CachedElementFactories = {}
143
144         def __call__(self, owner, parent, node, attributes, namespacemap):
145             result = self._CachedElementFactories.get(node, None)
146             if result:
147                 return result
148             for each in self._trylist:
149                 try:
150                     result = each(owner, parent, node, attributes, namespacemap)
151                     self._CachedElementFactories[node] = result
152                     return result
153                 except self._ignoreExceptions:
154                     pass
155
156 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157
158 class ElementFactorySet(dict):
159     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
160     #~ Constants / Variables / Etc.
161     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
162
163     NextFactorySet = None
164
165     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
166     #~ Public Methods
167     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
168
169     def PushFactorySet(self, FactorySet):
170         self.NextFactorySet = FactorySet
171         return self
172
173     def PopFactorySet(self):
174         result = self.NextFactorySet
175         self.NextFactorySet = None
176         return result
177
178     def copy(self):
179         return ElementFactorySet(dict.copy(self))
180
181     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
182     #~ Protected Methods
183     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
184
185     def _GetElementFactory(self, owner, parent, node, attributes, namespacemap):
186         try:
187             idx = node
188             while idx:
189                 FactoryFactory = self.get(idx, None)
190                 if FactoryFactory:
191                     result = FactoryFactory(owner, parent, node, attributes, namespacemap)
192                     if result:
193                         return result
194                 idx = idx[:-1]
195
196             # Resort to the default
197             FactoryFactory = self.get(None, None)
198             if FactoryFactory:
199                 result = FactoryFactory(owner, parent, node, attributes, namespacemap)
200                 if result:
201                     return result
202            
203         except ElementFactory.InheritFromNextFactory, (args, kw):
204             if self.NextFactorySet:
205                 return self.NextFactorySet._GetElementFactory(*args, **kw)
206
207         raise KeyError, "Could not find a class to build for node %r" % (node,)
208
209 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
210
211 class XMLClassBuilderMixin(XMLBuilder.XMLBuilderMixin):
212     """Mixin that forms the python import indirectly from a dictionary lookup of the namespace,
213     and then combines the result with the node name."""
214
215     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
216     #~ Constants / Variables / Etc.
217     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
218
219     ElementFactories = ElementFactorySet()
220
221     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222     #~ Public Methods
223     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
224
225     def AddElementFactory(self, idx, Factory):
226         self.ElementFactorySet[idx] = Factory
227
228     def RemoveElementFactory(self, idx):
229         del self.ElementFactorySet[idx]
230
231     def AddElementFactories(self, Factories):
232         """Registeres a new mapping between xmlns and python import strings."""
233         # Did they send us a real change?
234         if Factories:
235             # And now update with what they gave us
236             self.ElementFactorySet.update(Factories)
237
238     def PushElementFactorySet(self, FactorySet):
239         result = self.ElementFactories
240         self.ElementFactories = FactorySet.PushFactorySet(result)
241         return result
242
243     def PopElementFactorySet(self):
244         result = self.ElementFactories
245         self.ElementFactories = result.PopFactorySet()
246         return result
247  
248     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
249     #~ Protected Methods
250     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
251
252     def _GetModifableElementFactoryDict(self):
253         # Are we working on the class dictionary?
254         if self.ElementFactories is self.__class__.ElementFactories:
255             # If so, lets get an instance copy
256             self.ElementFactories = self.ElementFactories.copy()
257         return self.ElementFactories
258     ElementFactorySet = property(_GetModifableElementFactoryDict)
259
260     def _GetElementFactory(self, owner, parent, node, attributes, namespacemap):
261         if self._elements:
262             result = self._elements[-1]._xmlChildFactory(owner, parent, node, attributes, namespacemap)
263             if result: return result
264         return self.ElementFactorySet._GetElementFactory(owner, parent, node, attributes, namespacemap)
265
266 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
267
268 class XMLClassBuilder(XMLClassBuilderMixin, XMLBuilder.XMLBuilder):
269     pass
Note: See TracBrowser for help on using the browser.