Merge pull request #9 from headnet/master
Default value provided by subtype field
This commit is contained in:
commit
fd32e11102
|
@ -4,6 +4,10 @@ Changelog
|
|||
2.0.1 (unreleased)
|
||||
------------------
|
||||
|
||||
- The default attribute accessor now also looks through subtypes
|
||||
(behaviors) to find a field default.
|
||||
[malthe]
|
||||
|
||||
- Added support in the FTI to look up behaviors by utility name when
|
||||
getting additional schemata (i.e. fields provided by behaviors).
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ class FTIAwareSpecification(ObjectSpecificationDescriptor):
|
|||
"""
|
||||
|
||||
def __get__(self, inst, cls=None):
|
||||
|
||||
# We're looking at a class - fall back on default
|
||||
if inst is None:
|
||||
return getObjectSpecification(cls)
|
||||
|
@ -186,7 +185,13 @@ class DexterityContent(DAVResourceMixin, PortalContent, DefaultDublinCoreImpl, C
|
|||
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)
|
||||
|
||||
# Let __name__ and id be identical. Note that id must be ASCII in Zope 2,
|
||||
|
@ -316,16 +321,11 @@ class Container(DAVCollectionMixin, BrowserDefaultMixin, CMFCatalogAware, CMFOrd
|
|||
setattr(self, k, v)
|
||||
|
||||
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)
|
||||
|
||||
try:
|
||||
return DexterityContent.__getattr__(self, name)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# Be specific about the implementation we use
|
||||
return CMFOrderedBTreeFolderBase.__getattr__(self, name)
|
||||
|
||||
|
|
|
@ -77,12 +77,13 @@ class SchemaCache(object):
|
|||
if cached is None:
|
||||
subtypes = []
|
||||
fti = queryUtility(IDexterityFTI, name=portal_type)
|
||||
if fti is not None:
|
||||
for behavior_name in fti.behaviors:
|
||||
behavior = queryUtility(IBehavior, name=behavior_name)
|
||||
if behavior is not None and behavior.marker is not None:
|
||||
subtypes.append(behavior.marker)
|
||||
cached = self.subtypes_cache[portal_type] = tuple(subtypes)
|
||||
if fti is None:
|
||||
return ()
|
||||
for behavior_name in fti.behaviors:
|
||||
behavior = queryUtility(IBehavior, name=behavior_name)
|
||||
if behavior is not None and behavior.marker is not None:
|
||||
subtypes.append(behavior.marker)
|
||||
cached = self.subtypes_cache[portal_type] = tuple(subtypes)
|
||||
return cached
|
||||
|
||||
@synchronized(lock)
|
||||
|
|
|
@ -231,7 +231,7 @@ class TestContent(MockTestCase):
|
|||
pass
|
||||
|
||||
class ISubtype(Interface):
|
||||
pass
|
||||
baz = zope.schema.TextLine(title=u"baz", default=u"baz")
|
||||
|
||||
behavior1 = BehaviorRegistration(u"Behavior1", "", IBehavior1, None, None)
|
||||
behavior2 = BehaviorRegistration(u"Behavior2", "", IBehavior2, ISubtype, None)
|
||||
|
@ -258,7 +258,10 @@ class TestContent(MockTestCase):
|
|||
# the cache. This is not the case, as evidenced by .count(1) above.
|
||||
self.assertEquals(True, ISubtype.providedBy(item))
|
||||
self.assertEquals(True, ISchema.providedBy(item))
|
||||
|
||||
|
||||
# Subtypes provide field defaults.
|
||||
self.assertEquals(u"baz", getattr(item, "baz", None))
|
||||
|
||||
# We also need to ensure that the _v_ attribute doesn't hide any
|
||||
# interface set directly on the instance with alsoProvides() or
|
||||
# directlyProvides(). This is done by clearing the cache when these
|
||||
|
|
Reference in New Issue