Back to index

plone3  3.1.7
Transform.py
Go to the documentation of this file.
00001 from logging import ERROR
00002 from UserDict import UserDict
00003 
00004 from Products.PageTemplates.PageTemplateFile import PageTemplateFile
00005 from Globals import InitializeClass
00006 from Globals import PersistentMapping
00007 try:
00008     from ZODB.PersistentList import PersistentList
00009 except ImportError:
00010     from persistent.list import PersistentList
00011 from OFS.SimpleItem import SimpleItem
00012 from AccessControl import ClassSecurityInfo
00013 
00014 from Products.CMFCore.permissions import ManagePortal
00015 from Products.CMFCore.utils import getToolByName
00016 
00017 from Products.PortalTransforms.interfaces import itransform
00018 from Products.PortalTransforms.utils import TransformException, log, _www
00019 from Products.PortalTransforms.transforms.broken import BrokenTransform
00020 
00021 __revision__ = '$Id: Transform.py 7958 2007-04-27 22:09:16Z wichert $'
00022 
00023 def import_from_name(module_name):
00024     """ import and return a module by its name """
00025     __traceback_info__ = (module_name, )
00026     m = __import__(module_name)
00027     try:
00028         for sub in module_name.split('.')[1:]:
00029             m = getattr(m, sub)
00030     except AttributeError, e:
00031         raise ImportError(str(e))
00032     return m
00033 
00034 def make_config_persistent(kwargs):
00035     """ iterates on the given dictionnary and replace list by persistent list,
00036     dictionary by persistent mapping.
00037     """
00038     for key, value in kwargs.items():
00039         if type(value) == type({}):
00040             p_value = PersistentMapping(value)
00041             kwargs[key] = p_value
00042         elif type(value) in (type(()), type([])):
00043             p_value = PersistentList(value)
00044             kwargs[key] = p_value
00045 
00046 def make_config_nonpersistent(kwargs):
00047     """ iterates on the given dictionary and replace ListClass by python List,
00048         and DictClass by python Dict
00049     """
00050     for key, value in kwargs.items():
00051         if isinstance(value, PersistentMapping):
00052             p_value = dict(value)
00053             kwargs[key] = p_value
00054         elif isinstance(value, PersistentList):
00055             p_value = list(value)
00056             kwargs[key] = p_value
00057 
00058 VALIDATORS = {
00059     'int' : int,
00060     'string' : str,
00061     'list' : PersistentList,
00062     'dict' : PersistentMapping,
00063     }
00064 
00065 class Transform(SimpleItem):
00066     """A transform is an external method with
00067     additional configuration information
00068     """
00069 
00070     __implements__ = itransform
00071 
00072     meta_type = 'Transform'
00073 
00074     meta_types = all_meta_types = ()
00075 
00076     manage_options = (
00077                       ({'label':'Configure',
00078                        'action':'manage_main'},
00079                        {'label':'Reload',
00080                        'action':'manage_reloadTransform'},) +
00081                       SimpleItem.manage_options
00082                       )
00083 
00084     manage_main = PageTemplateFile('configureTransform', _www)
00085     manage_reloadTransform = PageTemplateFile('reloadTransform', _www)
00086     tr_widgets = PageTemplateFile('tr_widgets', _www)
00087 
00088     security = ClassSecurityInfo()
00089     __allow_access_to_unprotected_subobjects__ = 1
00090 
00091     def __init__(self, id, module, transform=None):
00092         self.id = id
00093         self.module = module
00094         # DM 2004-09-09: 'Transform' instances are stored as
00095         #  part of a module level configuration structure
00096         #  Therefore, they must not contain persistent objects
00097         self._config = UserDict()
00098         self._config.__allow_access_to_unprotected_subobjects__ = 1
00099         self._config_metadata = UserDict()
00100         self._tr_init(1, transform)
00101 
00102     def __setstate__(self, state):
00103         """ __setstate__ is called whenever the instance is loaded
00104             from the ZODB, like when Zope is restarted.
00105 
00106             We should reload the wrapped transform at this time
00107         """
00108         Transform.inheritedAttribute('__setstate__')(self, state)
00109         self._tr_init()
00110 
00111     def _tr_init(self, set_conf=0, transform=None):
00112         """ initialize the zope transform by loading the wrapped transform """
00113         __traceback_info__ = (self.module, )
00114         if transform is None:
00115             transform = self._load_transform()
00116         else:
00117             self._v_transform = transform
00118         # check this is a valid transform
00119         if not hasattr(transform, '__class__'):
00120             raise TransformException('Invalid transform : transform is not a class')
00121         if not itransform.isImplementedBy(transform):
00122             raise TransformException('Invalid transform : itransform is not implemented by %s' % transform.__class__)
00123         if not hasattr(transform, 'inputs'):
00124             raise TransformException('Invalid transform : missing required "inputs" attribute')
00125         if not hasattr(transform, 'output'):
00126             raise TransformException('Invalid transform : missing required "output" attribute')
00127         # manage configuration
00128         if set_conf and hasattr(transform, 'config'):
00129             conf = dict(transform.config)
00130             self._config.update(conf)
00131             make_config_persistent(self._config)
00132             if hasattr(transform, 'config_metadata'):
00133                 conf = dict(transform.config_metadata)
00134                 self._config_metadata.update(conf)
00135                 make_config_persistent(self._config_metadata)
00136         transform.config = dict(self._config)
00137         make_config_nonpersistent(transform.config)
00138         transform.config_metadata = dict(self._config_metadata)
00139         make_config_nonpersistent(transform.config_metadata)
00140 
00141         self.inputs = transform.inputs
00142         self.output = transform.output
00143         self.output_encoding = getattr(transform, 'output_encoding', None)
00144         return transform
00145 
00146     def _load_transform(self):
00147         try:
00148             m = import_from_name(self.module)
00149         except ImportError, err:
00150             transform = BrokenTransform(self.id, self.module, err)
00151             msg = "Cannot register transform %s (ImportError), using BrokenTransform: Error\n %s" % (self.id, err)
00152             self.title = 'BROKEN'
00153             log(msg, severity=ERROR)
00154             return transform
00155         if not hasattr(m, 'register'):
00156             msg = 'Invalid transform module %s: no register function defined' % self.module
00157             raise TransformException(msg)
00158         try:
00159             transform = m.register()
00160         except Exception, err:
00161             transform = BrokenTransform(self.id, self.module, err)
00162             msg = "Cannot register transform %s, using BrokenTransform: Error\n %s" % (self.id, err)
00163             self.title = 'BROKEN'
00164             log(msg, severity=ERROR)
00165         else:
00166             self.title = ''
00167         self._v_transform = transform
00168         return transform
00169 
00170     security.declarePrivate('manage_beforeDelete')
00171     def manage_beforeDelete(self, item, container):
00172         SimpleItem.manage_beforeDelete(self, item, container)
00173         if self is item:
00174             # unregister self from catalog on deletion
00175             tr_tool = getToolByName(self, 'portal_transforms')
00176             tr_tool._unmapTransform(self)
00177 
00178     security.declarePublic('get_documentation')
00179     def get_documentation(self):
00180         """ return transform documentation """
00181         if not hasattr(self, '_v_transform'):
00182             self._load_transform()
00183         return self._v_transform.__doc__
00184 
00185     security.declarePublic('get_documentation')
00186     def convert(self, *args, **kwargs):
00187         """ return apply the transform and return the result """
00188         if not hasattr(self, '_v_transform'):
00189             self._load_transform()
00190         return self._v_transform.convert(*args, **kwargs)
00191 
00192     security.declarePublic('name')
00193     def name(self):
00194         """return the name of the transform instance"""
00195         return self.id
00196 
00197     security.declareProtected(ManagePortal, 'get_parameters')
00198     def get_parameters(self):
00199         """ get transform's parameters names """
00200         if not hasattr(self, '_v_transform'):
00201             self._load_transform()
00202         keys = self._v_transform.config.keys()
00203         keys.sort()
00204         return keys
00205 
00206     security.declareProtected(ManagePortal, 'get_parameter_value')
00207     def get_parameter_value(self, key):
00208         """ get value of a transform's parameter """
00209         value = self._config[key]
00210         type = self.get_parameter_infos(key)[0]
00211         if type == 'dict':
00212             result = {}
00213             for key, val in value.items():
00214                 result[key] = val
00215         elif type == 'list':
00216             result = list(value)
00217         else:
00218             result = value
00219         return result
00220 
00221     security.declareProtected(ManagePortal, 'get_parameter_infos')
00222     def get_parameter_infos(self, key):
00223         """ get informations about a parameter
00224 
00225         return a tuple (type, label, description [, type specific data])
00226         where type in (string, int, list, dict)
00227               label and description are two string describing the field
00228         there may be some additional elements specific to the type :
00229              (key label, value label) for the dict type
00230         """
00231         try:
00232             return tuple(self._config_metadata[key])
00233         except KeyError:
00234             return 'string', '', ''
00235 
00236     security.declareProtected(ManagePortal, 'set_parameters')
00237     def set_parameters(self, REQUEST=None, **kwargs):
00238         """ set transform's parameters """
00239         if not kwargs:
00240             kwargs = REQUEST.form
00241         self.preprocess_param(kwargs)
00242         for param, value in kwargs.items():
00243             try:
00244                 self.get_parameter_value(param)
00245             except KeyError:
00246                 log('Warning: ignored parameter %r' % param)
00247                 continue
00248             meta = self.get_parameter_infos(param)
00249             self._config[param] = VALIDATORS[meta[0]](value)
00250 
00251         tr_tool = getToolByName(self, 'portal_transforms')
00252         # need to remap transform if necessary (i.e. configurable inputs / output)
00253         if kwargs.has_key('inputs') or kwargs.has_key('output'):
00254             tr_tool._unmapTransform(self)
00255             if not hasattr(self, '_v_transform'):
00256                 self._load_transform()
00257             self.inputs = kwargs.get('inputs', self._v_transform.inputs)
00258             self.output = kwargs.get('output', self._v_transform.output)
00259             tr_tool._mapTransform(self)
00260         # track output encoding
00261         if kwargs.has_key('output_encoding'):
00262             self.output_encoding = kwargs['output_encoding']
00263         if REQUEST is not None:
00264             REQUEST['RESPONSE'].redirect(tr_tool.absolute_url()+'/manage_main')
00265 
00266 
00267     security.declareProtected(ManagePortal, 'reload')
00268     def reload(self):
00269         """ reload the module where the transformation class is defined """
00270         log('Reloading transform %s' % self.module)
00271         m = import_from_name(self.module)
00272         reload(m)
00273         self._tr_init()
00274 
00275     def preprocess_param(self, kwargs):
00276         """ preprocess param fetched from an http post to handle optional dictionary
00277         """
00278         for param in self.get_parameters():
00279             if self.get_parameter_infos(param)[0] == 'dict':
00280                 try:
00281                     keys = kwargs[param + '_key']
00282                     del kwargs[param + '_key']
00283                 except:
00284                     keys = ()
00285                 try:
00286                     values = kwargs[param + '_value']
00287                     del kwargs[param + '_value']
00288                 except:
00289                     values = ()
00290                 kwargs[param] = dict = {}
00291                 for key, value in zip(keys, values):
00292                     key = key.strip()
00293                     if key:
00294                         value = value.strip()
00295                         if value:
00296                             dict[key] = value
00297 
00298 InitializeClass(Transform)
00299