source: products/quintagroup.transmogrifier/branches/plone-2.1/quintagroup.transmogrifier/quintagroup/transmogrifier/propertymanager.py @ 1433

Last change on this file since 1433 was 1433, checked in by piv, 14 years ago

remove debugging code

File size: 10.0 KB
Line 
1from copy import deepcopy
2from xml.dom import minidom
3
4from zope.interface import classProvides, implements
5
6from collective.transmogrifier.interfaces import ISection, ISectionBlueprint
7from collective.transmogrifier.utils import defaultMatcher
8
9try:
10    from Products.GenericSetup.exceptions import BadRequest
11except ImportError:
12    from Products.CMFSetup.exceptions import BadRequest
13
14from interfaces import IPropertyManager
15
16class Helper(object):
17
18    """PropertyManager im- and export helpers.
19    """
20
21    _encoding = 'utf-8'
22
23    def _getNodeText(self, node):
24        text = ''
25        for child in node.childNodes:
26            if child.nodeName != '#text':
27                continue
28            text += child.nodeValue.strip()
29        return text
30
31    def _convertToBoolean(self, val):
32        return val.lower() in ('true', 'yes', '1')
33
34    def _extractProperties(self):
35        fragment = self._doc.createDocumentFragment()
36
37        for prop_map in self.context._propertyMap():
38            prop_id = prop_map['id']
39            if prop_id == 'i18n_domain':
40                continue
41
42            # Don't export read-only nodes
43            if 'w' not in prop_map.get('mode', 'wd'):
44                continue
45
46            node = self._doc.createElement('property')
47            node.setAttribute('name', prop_id)
48
49            prop = self.context.getProperty(prop_id)
50            if isinstance(prop, (tuple, list)):
51                for value in prop:
52                    if isinstance(value, str):
53                        value = value.decode(self._encoding)
54                    child = self._doc.createElement('element')
55                    child.appendChild(self._doc.createTextNode(value))
56                    node.appendChild(child)
57            else:
58                if prop_map.get('type') == 'boolean':
59                    prop = unicode(bool(prop))
60                elif isinstance(prop, str):
61                    prop = prop.decode(self._encoding)
62                elif not isinstance(prop, basestring):
63                    prop = unicode(prop)
64                child = self._doc.createTextNode(prop)
65                node.appendChild(child)
66
67            if 'd' in prop_map.get('mode', 'wd') and not prop_id == 'title':
68                prop_type = prop_map.get('type', 'string')
69                node.setAttribute('type', unicode(prop_type))
70                select_variable = prop_map.get('select_variable', None)
71                if select_variable is not None:
72                    node.setAttribute('select_variable', select_variable)
73
74            if hasattr(self, '_i18n_props') and prop_id in self._i18n_props:
75                node.setAttribute('i18n:translate', '')
76
77            fragment.appendChild(node)
78
79        return fragment
80
81    def _purgeProperties(self):
82        for prop_map in self.context._propertyMap():
83            mode = prop_map.get('mode', 'wd')
84            if 'w' not in mode:
85                continue
86            prop_id = prop_map['id']
87            if 'd' in mode and not prop_id == 'title':
88                self.context._delProperty(prop_id)
89            else:
90                prop_type = prop_map.get('type')
91                if prop_type == 'multiple selection':
92                    prop_value = ()
93                elif prop_type in ('int', 'float'):
94                    prop_value = 0
95                else:
96                    prop_value = ''
97                self.context._updateProperty(prop_id, prop_value)
98
99    def _initProperties(self, node):
100        obj = self.context
101        if node.hasAttribute('i18n:domain'):
102            i18n_domain = str(node.getAttribute('i18n:domain'))
103            obj._updateProperty('i18n_domain', i18n_domain)
104        for child in node.childNodes:
105            if child.nodeName != 'property':
106                continue
107            prop_id = str(child.getAttribute('name'))
108            prop_map = obj.propdict().get(prop_id, None)
109
110            if prop_map is None:
111                if child.hasAttribute('type'):
112                    val = str(child.getAttribute('select_variable'))
113                    prop_type = str(child.getAttribute('type'))
114                    obj._setProperty(prop_id, val, prop_type)
115                    prop_map = obj.propdict().get(prop_id, None)
116                else:
117                    raise ValueError("undefined property '%s'" % prop_id)
118
119            if not 'w' in prop_map.get('mode', 'wd'):
120                raise BadRequest('%s cannot be changed' % prop_id)
121
122            elements = []
123            for sub in child.childNodes:
124                if sub.nodeName == 'element':
125                    if len(sub.childNodes) > 0:
126                        value = sub.childNodes[0].nodeValue
127                        if isinstance(value, unicode):
128                            value = value.encode(self._encoding)
129                        elements.append(value)
130
131            if elements or prop_map.get('type') == 'multiple selection':
132                prop_value = tuple(elements) or ()
133            elif prop_map.get('type') == 'boolean':
134                prop_value = self._convertToBoolean(self._getNodeText(child))
135            else:
136                # if we pass a *string* to _updateProperty, all other values
137                # are converted to the right type
138                prop_value = self._getNodeText(child).encode(self._encoding)
139
140            if not self._convertToBoolean(child.getAttribute('purge')
141                                          or 'True'):
142                # If the purge attribute is False, merge sequences
143                prop = obj.getProperty(prop_id)
144                if isinstance(prop, (tuple, list)):
145                    prop_value = (tuple([p for p in prop
146                                         if p not in prop_value]) +
147                                  tuple(prop_value))
148
149            obj._updateProperty(prop_id, prop_value)
150
151class PropertiesExporterSection(object):
152    classProvides(ISectionBlueprint)
153    implements(ISection)
154
155    def __init__(self, transmogrifier, name, options, previous):
156        self.previous = previous
157        self.context = transmogrifier.context
158
159        self.pathkey = defaultMatcher(options, 'path-key', name, 'path')
160        self.fileskey = options.get('files-key', '_files').strip()
161
162        self.excludekey = defaultMatcher(options, 'exclude-key', name, 'excluded_properties')
163        self.exclude = filter(None, [i.strip() for i in 
164                              options.get('exclude', '').splitlines()])
165
166        self.helper = Helper()
167        self.doc = minidom.Document()
168        self.helper._doc = self.doc
169
170    def __iter__(self):
171        helper = self.helper
172        doc = self.doc
173
174        for item in self.previous:
175            pathkey = self.pathkey(*item.keys())[0]
176
177            if not pathkey:
178                yield item; continue
179
180            path = item[pathkey]
181            obj = self.context.unrestrictedTraverse(path, None)
182            if obj is None:         # path doesn't exist
183                yield item; continue
184
185            if IPropertyManager.providedBy(obj):
186                data = None
187                excludekey = self.excludekey(*item.keys())[0]
188                excluded_props = tuple(self.exclude)
189                if excludekey:
190                    excluded_props = tuple(set(item[excludekey]) | set(excluded_props))
191
192                helper.context = obj
193                node = doc.createElement('properties')
194                for elem in helper._extractProperties().childNodes:
195                    if elem.nodeName != 'property':
196                        continue
197                    if elem.getAttribute('name') not in excluded_props:
198                        node.appendChild(deepcopy(elem))
199                if node.hasChildNodes():
200                    doc.appendChild(node)
201                    data = doc.toprettyxml(indent='  ', encoding='utf-8')
202                    doc.unlink()
203
204                if data:
205                    files = item.setdefault(self.fileskey, {})
206                    item[self.fileskey]['propertymanager'] = {
207                        'name': '.properties.xml',
208                        'data': data,
209                    }
210
211            yield item
212
213class PropertiesImporterSection(object):
214    classProvides(ISectionBlueprint)
215    implements(ISection)
216
217    def __init__(self, transmogrifier, name, options, previous):
218        self.previous = previous
219        self.context = transmogrifier.context
220
221        self.pathkey = defaultMatcher(options, 'path-key', name, 'path')
222        self.fileskey = defaultMatcher(options, 'files-key', name, 'files')
223
224        self.excludekey = defaultMatcher(options, 'exclude-key', name, 'excluded_properties')
225        self.exclude = filter(None, [i.strip() for i in 
226                            options.get('exclude', '').splitlines()])
227
228        self.helper = Helper()
229        self.helper._encoding = 'utf-8'
230
231    def __iter__(self):
232        helper = self.helper
233
234        for item in self.previous:
235            pathkey = self.pathkey(*item.keys())[0]
236            fileskey = self.fileskey(*item.keys())[0]
237
238            if not (pathkey and fileskey):
239                yield item; continue
240            if 'propertymanager' not in item[fileskey]:
241                yield item; continue
242
243            path = item[pathkey]
244            obj = self.context.unrestrictedTraverse(path, None)
245            if obj is None:         # path doesn't exist
246                yield item; continue
247
248            if IPropertyManager.providedBy(obj):
249                data = None
250                excludekey = self.excludekey(*item.keys())[0]
251                excluded_props = self.exclude
252                if excludekey:
253                    excluded_props = tuple(set(item[excludekey]) | set(excluded_props))
254
255                data = item[fileskey]['propertymanager']['data']
256                doc = minidom.parseString(data)
257                root = doc.documentElement
258                for child in root.childNodes:
259                    if child.nodeName != 'property':
260                        continue
261                    if child.getAttribute('name') in excluded_props:
262                        root.removeChild(child)
263
264                helper.context = obj
265                helper._initProperties(root)
266
267            yield item
Note: See TracBrowser for help on using the repository browser.