def get_aq_provider(obj):
     parent = obj.aq_parent
     if parent is app:
         raise SchemaEditorError(self.translate('atse_no_provider',
                                                default="No Schema provider found"))
     if ISchemaEditor.providedBy(parent):
         return parent
     else:
         return get_aq_provider(parent)
    def lookup_provider(self):
        """ First searches for parent provider then checks tool """

        provider = None
        try:
            provider = self.aq_parent
            if not ISchemaEditor.providedBy(provider):
                if provider.__class__.__name__ == 'FactoryTool':
                    return provider.aq_parent
                raise SchemaEditorError, ''

        # We redirect lookup per default to the tool
        except SchemaEditorError:
            tool = getToolByName(self, config.TOOL_NAME, None)
            if not tool:
                raise LookupError('Tool %s for managing schema not found!' % config.TOOL_NAME)
            provider = tool

        return provider
    def Schema(self, schema_id=None):
        """ Retrieve schema from parent object. The client class should
            override the method as Schema(self) and then call his method
            of the baseclass with the corresponding schema_id.
        """

        # Schema() seems to be called during the construction phase when there is
        # no acquisition context. So we return the default schema itself.
        # ATT: mind the difference btn 'hasattr' and 'shasattr' (latter strips acq)
        if not hasattr(self, 'aq_parent') or self.id.find('atse-ptypedummy')>=0:
            if shasattr(self, 'schema'):
                return self._wrap_schema(self.schema)
            else:
                raise ValueError('Instance has no "schema" attribute defined')
            
        provider = self.lookup_provider()
        if not ISchemaEditor.providedBy(provider):
            raise SchemaEditorError, 'Provider -- %s -- can not be recognized as Archetypes Schema Editor! Perhaps you are using ParentManagedSchema derived objects with Tool. A tool can only manage ToolManagedSchema (ParentOrToolManagedSchema) derived objects.' % str(provider).replace('<', '').replace('>','')

        if not self.lookup_provider().atse_isSchemaRegistered(self.portal_type):
            return self._wrap_schema(self.schema)

        # If we're called by the generated methods we can not rely on
        # the id and need to check for portal_type
        if not schema_id:
            schema_id = self.portal_type
            
        # Otherwise get the schema from the parent through
        # acquisition and assign it to a volatile attribute for performance
        # reasons
        self._v_schema = getattr(self, '_v_schema', None)
        if self._v_schema is None:

            # looking for changes in the schema held by the object
            LOG('ATSchemaEditorNG', INFO, 'Looking up changes via lookupChanges() - _v_schema is None')
            self._v_schema = self._lookupChanges(schema_id)

            if not shasattr(self, '_md'):
                self.initializeArchetype()

            for field in self._v_schema.fields():

                ##########################################################
                # Fake accessor and mutator methods
                ##########################################################

                # XXX currently only honoring explicitly specified mutators
                #     or accessors if the method exists on the object.  if
                #     the methods are autogenerated the specified names will
                #     not be honored.

                name = field.getName()

                def atse_get_method(self=self, name=name, *args, **kw):
                    return self.getField(name).get(self, **kw)

                def atse_getRaw_method(self=self, name=name, *args, **kw):
                    return self.getField(name).getRaw(self, **kw)

                # workaround for buggy widget/keyword AT template that
                # uses field.accessor as catalog index name *grrrr*
                # XXX find another way to fix that
                if name != 'subject':
                    accessor_name = getattr(field, 'accessor', None)
                    if accessor_name and shasattr(self, accessor_name):
                        pass # the accessor exists, we're cool
                    else:
                        v_name = '_v_%s_accessor' % name
                        accessor_name = v_name
                        setattr(self, v_name, atse_get_method)
                    field.accessor = accessor_name
                    
                    # the edit accessor and the regular accessor can be the
                    # same in most cases, but not for ReferenceFields
                    # XXX any other cases?
                    
                    # test for special cases where there is no
                    # getter with conformant naming scheme
                    con_name = capitalize(field.getName())
                    dogenerate = not shasattr(self, 'get%s' % con_name)

                    edit_accessor_name = getattr(field, 'edit_accessor', None)
                    if edit_accessor_name and shasattr(self, edit_accessor_name) and not dogenerate:
                        pass # the edit_accessor_name exists, we're cool
                    else:
                        edit_v_name = '_v_%s_edit_accessor' % name
                        edit_accessor_name = edit_v_name
                        field_type = str(field.type).upper()
                        if field_type == 'REFERENCE':
                            setattr(self, edit_accessor_name, atse_getRaw_method)
                        else:
                            setattr(self, edit_accessor_name, atse_get_method)
                    field.edit_accessor = edit_accessor_name

                def atse_set_method(value, self=self, name=name, *args, **kw):
                    if name != 'id':
                         self.getField(name).set(self, value, **kw)
                        
                    # saving id directly (avoiding unicode problems)
                    else: self.setId(value)

                mutator_name = getattr(field, 'mutator', None)
                if mutator_name and shasattr(self, mutator_name):
                    pass # the mutator exists, we're cool
                else:
                    v_name = '_v_%s_mutator' % name
                    mutator_name = v_name
                    setattr(self, v_name, atse_set_method)
                field.mutator = mutator_name

                # Check if we need to update our own properties
                try:
                    value = field.get(self)
                except:
                    field.set(self, field.default)

        return self._wrap_schema(self._v_schema)