def test_repeated_subtypes_lookup(self): fti = DexterityFTI(u"testtype") self.mock_utility(fti, IDexterityFTI, name=u"testtype") # Mock a test behavior class ITestSchema(Interface): pass class ITestMarker(Interface): pass fti.behaviors = [ITestSchema.__identifier__] from plone.behavior.registration import BehaviorRegistration registration = BehaviorRegistration( title=u"Test Behavior", description=u"Provides test behavior", interface=ITestSchema, marker=ITestMarker, factory=None ) from plone.behavior.interfaces import IBehavior self.mock_utility( registration, IBehavior, ITestSchema.__identifier__ ) s1 = SCHEMA_CACHE.subtypes(u"testtype") s2 = SCHEMA_CACHE.subtypes(u"testtype") self.assertTrue(s1[0] is s2[0] is ITestMarker)
def __getattr__(self, name): # python basics: __getattr__ is only invoked if the attribute wasn't # found by __getattribute__ # # optimization: sometimes we're asked for special attributes # such as __conform__ that we can disregard (because we # wouldn't be in here if the class had such an attribute # defined). if name.startswith('__'): raise AttributeError(name) # attribute was not found; try to look it up in the schema and return # a default value = _default_from_schema( self, SCHEMA_CACHE.get(self.portal_type), name ) if value is not _marker: return value # do the same for each subtype for schema in SCHEMA_CACHE.subtypes(self.portal_type): value = _default_from_schema(self, schema, name) if value is not _marker: return value raise AttributeError(name)
def __get__(self, inst, cls=None): # We're looking at a class - fall back on default if inst is None: return getObjectSpecification(cls) # Find the data we need to know if our cache needs to be invalidated direct_spec = getattr(inst, '__provides__', None) portal_type = getattr(inst, 'portal_type', None) spec = direct_spec # If the instance doesn't have a __provides__ attribute, get the # interfaces implied by the class as a starting point. if spec is None: spec = implementedBy(cls) # If the instance has no portal type, then we're done. if portal_type is None: return spec fti = queryUtility(IDexterityFTI, name=portal_type) if fti is None: return spec schema = SCHEMA_CACHE.get(portal_type) subtypes = SCHEMA_CACHE.subtypes(portal_type) # Find the cached value. This calculation is expensive and called # hundreds of times during each request, so we require a fast cache cache = getattr(inst, '_v__providedBy__', None) updated = inst._p_mtime, schema, subtypes, direct_spec # See if we have a valid cache. Reasons to do this include: # # - The schema was modified. # - The subtypes were modified. # - The instance was modified and persisted since the cache was built. # - The instance has a different direct specification. if cache is not None: cached_mtime, cached_schema, cached_subtypes, \ cached_direct_spec, cached_spec = cache if cache[:-1] == updated: return cached_spec dynamically_provided = [] if schema is None else [schema] dynamically_provided.extend(subtypes) # If we have neither a schema, nor a subtype, then we're also done. if not dynamically_provided: return spec dynamically_provided.append(spec) spec = Implements(*dynamically_provided) inst._v__providedBy__ = updated + (spec, ) return spec
def __getattr__(self, name): # attribute was not found; try to look it up in the schema and return # a default schema = SCHEMA_CACHE.get(self.portal_type) if schema is not None: field = schema.get(name, None) if field is not None: return deepcopy(field.default) # do the same for each subtype for schema in SCHEMA_CACHE.subtypes(self.portal_type): field = schema.get(name, None) if field is not None: return deepcopy(field.default) raise AttributeError(name)
def __getattr__(self, name): # optimization: sometimes we're asked for special attributes # such as __conform__ that we can disregard (because we # wouldn't be in here if the class had such an attribute # defined). if name.startswith('__'): raise AttributeError(name) # attribute was not found; try to look it up in the schema and return # a default schema = SCHEMA_CACHE.get(self.portal_type) if schema is not None: field = schema.get(name, None) if field is not None: return deepcopy(field.default) # do the same for each subtype for schema in SCHEMA_CACHE.subtypes(self.portal_type): field = schema.get(name, None) if field is not None: return deepcopy(field.default) raise AttributeError(name)
def __get__(self, inst, cls=None): # We're looking at a class - fall back on default if inst is None: return getObjectSpecification(cls) # Find the cached value. This calculation is expensive and called # hundreds of times during each request, so we require a fast cache cache = getattr(inst, '_v__providedBy__', None) # Find the data we need to know if our cache needs to be invalidated direct_spec = getattr(inst, '__provides__', None) portal_type = getattr(inst, 'portal_type', None) fti_counter = -1 if portal_type is not None: fti_counter = SCHEMA_CACHE.counter(portal_type) # See if we have a valid cache. Reasons to do this include: # # - We don't have a portal_type yet, so we can't have found the schema # - The FTI was modified, and the schema cache invalidated globally. # The fti_counter will have advanced. # - The instance was modified and persisted since the cache was built. # - The instance now has a different __provides__, which means that someone # called directlyProvides/alsoProvides on it. if cache is not None and portal_type is not None: cached_mtime, cached_fti_counter, cached_direct_spec, cached_spec = cache if inst._p_mtime == cached_mtime and \ fti_counter == cached_fti_counter and \ direct_spec is cached_direct_spec: return cached_spec # We don't have a cache, so we need to build a new spec and maybe cache it spec = direct_spec # If the instance doesn't have a __provides__ attribute, get the # interfaces implied by the class as a starting point. if spec is None: spec = implementedBy(cls) # Add the schema from the FTI and behavior subtypes dynamically_provided = [] if portal_type is not None: schema = SCHEMA_CACHE.get(portal_type) if schema is not None: dynamically_provided.append(schema) subtypes = SCHEMA_CACHE.subtypes(portal_type) if subtypes: dynamically_provided.extend(subtypes) # If we have any dynamically provided interface, prepend them to the spec # and cache. We can't cache until we have at least the schema, because # it's possible that we were called before traversal and so could not # find the schema yet. if dynamically_provided: dynamically_provided.append(spec) spec = Implements(*dynamically_provided) inst._v__providedBy__ = inst._p_mtime, SCHEMA_CACHE.counter( portal_type), direct_spec, spec return spec
def __get__(self, inst, cls=None): # We're looking at a class - fall back on default if inst is None: return getObjectSpecification(cls) # Find the cached value. This calculation is expensive and called # hundreds of times during each request, so we require a fast cache cache = getattr(inst, '_v__providedBy__', None) # Find the data we need to know if our cache needs to be invalidated direct_spec = getattr(inst, '__provides__', None) portal_type = getattr(inst, 'portal_type', None) fti_counter = -1 if portal_type is not None: fti_counter = SCHEMA_CACHE.counter(portal_type) # See if we have a valid cache. Reasons to do this include: # # - We don't have a portal_type yet, so we can't have found the schema # - The FTI was modified, and the schema cache invalidated globally. # The fti_counter will have advanced. # - The instance was modified and persisted since the cache was built. # - The instance now has a different __provides__, which means that someone # called directlyProvides/alsoProvides on it. if cache is not None and portal_type is not None: cached_mtime, cached_fti_counter, cached_direct_spec, cached_spec = cache if inst._p_mtime == cached_mtime and \ fti_counter == cached_fti_counter and \ direct_spec is cached_direct_spec: return cached_spec # We don't have a cache, so we need to build a new spec and maybe cache it spec = direct_spec # If the instance doesn't have a __provides__ attribute, get the # interfaces implied by the class as a starting point. if spec is None: spec = implementedBy(cls) # Add the schema from the FTI and behavior subtypes dynamically_provided = [] if portal_type is not None: schema = SCHEMA_CACHE.get(portal_type) if schema is not None: dynamically_provided.append(schema) subtypes = SCHEMA_CACHE.subtypes(portal_type) if subtypes: dynamically_provided.extend(subtypes) # If we have any dynamically provided interface, prepend them to the spec # and cache. We can't cache until we have at least the schema, because # it's possible that we were called before traversal and so could not # find the schema yet. if dynamically_provided: dynamically_provided.append(spec) spec = Implements(*dynamically_provided) inst._v__providedBy__ = inst._p_mtime, SCHEMA_CACHE.counter(portal_type), direct_spec, spec return spec