""" utilities $Id: utils.py,v 1.4.2.2 2004/04/21 14:39:51 tesdal Exp $ """ __version__ = "$Revision: 1.4.2.2 $" from types import FunctionType as function # Method generation for IRepresentable content with representation independent fields from Products.Archetypes.ClassGen import Generator as ATGenerator, ClassGenerator as ATClassGenerator, GeneratorError, _modes from Products.Archetypes.ArchetypeTool import registerType as registerATType AT_GENERATE_METHOD = [] _modes.update({ 'x' : { 'prefix' : 'setRepresentation', 'attr' : 'representation_mutator', 'security' : 'write_permission', }, }) class Generator(ATGenerator): """Generate methods for representation independent fields""" def makeMethod(self, klass, field, mode, methodName): name = field.getName() method = None if mode == "r": def generatedAccessor(self, **kw): """Default Accessor.""" if self.isCanonicalRepresentation(): if kw.has_key('schema'): schema = kw['schema'] else: schema = self.Schema() kw['schema'] = schema return schema[name].get(self, **kw) else: return getattr(self.getCanonicalRepresentation(), methodName)(**kw) method = generatedAccessor elif mode == "m": def generatedEditAccessor(self, **kw): """Default Edit Accessor.""" if self.isCanonicalRepresentation(): if kw.has_key('schema'): schema = kw['schema'] else: schema = self.Schema() kw['schema'] = schema return schema[name].getRaw(self, **kw) else: return getattr(self.getCanonicalRepresentation(), methodName)(**kw) method = generatedEditAccessor elif mode == "w": # the generatedMutator doesn't actually mutate, but calls a # representation mutator on all representations, including self. def generatedMutator(self, value, **kw): """Default Mutator.""" if kw.has_key('schema'): schema = kw['schema'] else: schema = self.Schema() kw['schema'] = schema representations = [obj for obj, wf_state in self.getRepresentations()] # reverse to return the result of the canonical representation mutator representations.reverse() representationMethodName = schema[name].representation_mutator res = None for t in representations: res = getattr(t, representationMethodName)(value, **kw) return res method = generatedMutator elif mode == "x": # The representation mutator that changes data def generatedRepresentationMutator(self, value, **kw): """ Delegated Mutator """ if kw.has_key('schema'): schema = kw['schema'] else: schema = self.Schema() kw['schema'] = schema return schema[name].set(self, value, **kw) method = generatedRepresentationMutator else: raise GeneratorError("""Unhandled mode for method creation: %s:%s -> %s:%s""" %(klass.__name__, name, methodName, mode)) # Zope security requires all security protected methods to have a # function name. It uses this name to determine which roles are allowed # to access the method. # This code is renaming the internal name from e.g. generatedAccessor to # methodName. method = function(method.func_code, method.func_globals, methodName, method.func_defaults, method.func_closure, ) setattr(klass, methodName, method) class ClassGenerator(ATClassGenerator): """Generate methods for representation independent fields""" def generateClass(self, klass): # We are going to assert a few things about the class here # before we start, set meta_type, portal_type based on class # name, but only if they are not set yet if (not getattr(klass, 'meta_type', None) or 'meta_type' not in klass.__dict__): klass.meta_type = klass.__name__ if (not getattr(klass, 'portal_type', None) or 'portal_type' not in klass.__dict__): klass.portal_type = klass.__name__ klass.archetype_name = getattr(klass, 'archetype_name', self.generateName(klass)) self.checkSchema(klass) fields = klass.schema.fields() # Find the representationIndependent fields. fields = [field for field in fields if field.representationIndependent] self.generateMethods(klass, fields) def generateMethods(self, klass, fields): generator = Generator() for field in fields: assert not 'm' in field.mode, 'm is an implicit mode' assert not 'x' in field.mode, 'x is an implicit mode' # Make sure we want to muck with the class for this field if "c" not in field.generateMode: continue type = getattr(klass, 'type') for mode in field.mode: #(r, w) self.handle_mode(klass, generator, type, field, mode) if mode == 'w': self.handle_mode(klass, generator, type, field, 'm') self.handle_mode(klass, generator, type, field, 'x') def handle_mode(self, klass, generator, type, field, mode): attr = _modes[mode]['attr'] # Did the field request a specific method name? methodName = getattr(field, attr, None) if not methodName: methodName = generator.computeMethodName(field, mode) # If there is already a mutator, make that the representation mutator if methodName in klass.__dict__.keys() and mode == 'w': setattr(klass, generator.computeMethodName(field, 'x'), getattr(klass, methodName)) delattr(klass, methodName) # Avoid name space conflicts if not methodName in klass.__dict__.keys() \ or getattr(klass, methodName) is AT_GENERATE_METHOD: if type.has_key(methodName): raise GeneratorError("There is a conflict" "between the Field(%s) and the attempt" "to generate a method of the same name on" "class %s" % ( methodName, klass.__name__)) # Make a method for this klass/field/mode generator.makeMethod(klass, field, mode, methodName) self.updateSecurity(klass, field, mode, methodName) # Note on the class what we did (even if the method existed) attr = _modes[mode]['attr'] setattr(field, attr, methodName) _cg = ClassGenerator() generateClass = _cg.generateClass generateMethods = _cg.generateMethods def registerType(klass, package=None): """Overrides the AT registerType to enable method generation for representation independent fields""" # Generate methods for representation independent fields generateClass(klass) # Pass on to the regular AT registerType registerATType(klass, package)