[Checkins] SVN: z3ext.preferences/trunk/ - 'schema' field for
z3ext:preferenceGroup is required now
Nikolay Kim
fafhrd at datacom.kz
Thu Apr 17 04:37:23 EDT 2008
Log message for revision 85451:
- 'schema' field for z3ext:preferenceGroup is required now
- Added adapter for IPrincipal to 'schema' with automatic binding
Changed:
U z3ext.preferences/trunk/CHANGES.txt
U z3ext.preferences/trunk/setup.py
U z3ext.preferences/trunk/src/z3ext/preferences/README.txt
U z3ext.preferences/trunk/src/z3ext/preferences/configure.zcml
U z3ext.preferences/trunk/src/z3ext/preferences/interfaces.py
U z3ext.preferences/trunk/src/z3ext/preferences/preference.py
U z3ext.preferences/trunk/src/z3ext/preferences/preferencetype.py
U z3ext.preferences/trunk/src/z3ext/preferences/root.py
A z3ext.preferences/trunk/src/z3ext/preferences/storage.py
U z3ext.preferences/trunk/src/z3ext/preferences/tests.py
U z3ext.preferences/trunk/src/z3ext/preferences/utils.py
U z3ext.preferences/trunk/src/z3ext/preferences/zcml.py
-=-
Modified: z3ext.preferences/trunk/CHANGES.txt
===================================================================
--- z3ext.preferences/trunk/CHANGES.txt 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/CHANGES.txt 2008-04-17 08:37:22 UTC (rev 85451)
@@ -2,6 +2,14 @@
CHANGES
=======
+1.2.0 (2008-04-18)
+------------------
+
+- 'schema' field for z3ext:preferenceGroup is required now
+
+- Added adapter for IPrincipal to 'schema' with automatic binding
+
+
1.1.1 (2008-04-15)
------------------
@@ -51,4 +59,4 @@
0.9.0 (2008-02-01)
------------------
-- Initial release.
+- Initial release
Modified: z3ext.preferences/trunk/setup.py
===================================================================
--- z3ext.preferences/trunk/setup.py 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/setup.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -21,7 +21,7 @@
def read(*rnames):
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
-version='1.1.2dev'
+version='1.2.0dev'
setup(name = 'z3ext.preferences',
Modified: z3ext.preferences/trunk/src/z3ext/preferences/README.txt
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/README.txt 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/README.txt 2008-04-17 08:37:22 UTC (rev 85451)
@@ -59,6 +59,11 @@
... IZMIUserSettings,
... title=u"ZMI User Settings", description=u"")
+We should set 'preferenceID' to schema with preference group id,
+This value is used by data storage to store data in annotations
+
+ >>> IZMIUserSettings.setTaggedValue('preferenceID', 'ZMISettings')
+
Now we can instantiate the preference group.
>>> settings = settingsClass()
@@ -68,7 +73,7 @@
>>> settings.__schema__ = IZMIUserSettings
Traceback (most recent call last):
...
- AttributeError: Can't set __schema__
+ AttributeError: Can't change __schema__
Note that the preferences group provides the interface it is representing:
@@ -118,20 +123,25 @@
>>> class PrincipalAnnotations(dict):
... zope.interface.implements(IAnnotations)
... data = {}
- ... def __new__(class_, principal, context):
+ ... def __new__(class_, principal):
... try:
... annotations = class_.data[principal.id]
... except KeyError:
... annotations = dict.__new__(class_)
... class_.data[principal.id] = annotations
... return annotations
- ... def __init__(self, principal, context):
+ ... def __init__(self, principal):
... pass
>>> from zope import component
+ >>> component.provideAdapter(PrincipalAnnotations, (Principal,), IAnnotations)
+
+Also we need IDataStorage for preferenceGroup schema, because preference group
+doesn't use IAnnotations directly.
+
+ >>> from z3ext.preferences import storage
>>> component.provideAdapter(
- ... PrincipalAnnotations,
- ... (Principal, zope.interface.Interface), IAnnotations)
+ ... storage.getDefaultStorage, (Principal, zope.interface.Interface))
And now we need bind preferences to principal. We can just call __bind__
method in this case preference will use principal from current interaction.
@@ -146,7 +156,7 @@
Or we can explicitly set principal, this is usefull when we want to know
preferences for principal.
- >>> settings = settings.__bind__(principal=principal)
+ >>> settings = settings.__bind__(principal)
>>> interfaces.IBound.providedBy(nsettings)
True
@@ -199,6 +209,8 @@
... IFolderSettings,
... title=u"Folder Content View Settings")
+ >>> IFolderSettings.setTaggedValue('preferenceID', 'ZMISettings.Folder')
+
>>> folderSettings = folderSettingsClass()
Note that the id was chosen so that the parent id is the prefix of the child's
@@ -284,7 +296,7 @@
... id="ZMISettings"
... schema="z3ext.preferences.README.IZMIUserSettings"
... title="ZMI User Settings" />
- ...
+ ...
... <z3ext:preferenceGroup
... id="ZMISettings.Folder"
... schema="z3ext.preferences.README.IFolderSettings"
@@ -296,10 +308,24 @@
settings as follows:
>>> prefs = component.getUtility(interfaces.IPreferenceGroup)
+ >>> prefs.isAvailable()
+ False
+ >>> prefs['ZMISettings']['Folder'].isAvailable()
+ False
+
+
Don't forget to bind preferences to principal
- >>> prefs = prefs.__bind__(principal=principal)
+ >>> prefs = prefs.__bind__(principal)
+ >>> prefs.isAvailable()
+ True
+
+ >>> p = prefs['ZMISettings']['Folder'].__bind__(parent=prefs)
+
+ >>> prefs['ZMISettings']['Folder'].isAvailable()
+ True
+
>>> prefs['ZMISettings']['Folder'].sortedBy
'size'
@@ -324,6 +350,11 @@
Let's register the ZMI settings again under a new name via ZCML:
+ >>> class IZMIUserSettings2(IZMIUserSettings):
+ ... pass
+
+ >>> IZMIUserSettings2.setTaggedValue('preferenceID', 'ZMISettings.Folder')
+
>>> context = xmlconfig.string('''
... <configure
... xmlns:z3ext="http://namespaces.zope.org/z3ext"
@@ -411,17 +442,18 @@
>>> new_prefs.isAvailable()
True
+ >>> prefs['ZMISettings2'].remove('Folder10')
+
Simple Python-Level Access
--------------------------
If a site is set, getting the user preferences is very simple:
- >>> prefs2 = component.getUtility(interfaces.IPreferenceGroup, 'ZMISettings.Folder')
- >>> prefs2 = prefs2.__bind__(principal=principal)
+ >>> prefs2 = IFolderSettings(principal)
>>> prefs2.sortedBy
- 'size'
+ 'name'
Security
@@ -451,8 +483,9 @@
... schema="z3ext.preferences.README.IZMIUserSettings"
... provides="z3ext.preferences.interfaces.IPreferenceCategory"
... permission="zope.View">
+ ... <allow attributes="email" />
... <require
- ... attributes="showZopeLogo" permission="zope.Manage" />
+ ... attributes="showZopeLogo" permission="zope.Manage" set_attributes="skin" />
... </z3ext:preferenceGroup>
...
... </configure>''', context)
Modified: z3ext.preferences/trunk/src/z3ext/preferences/configure.zcml
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/configure.zcml 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/configure.zcml 2008-04-17 08:37:22 UTC (rev 85451)
@@ -17,6 +17,9 @@
permission="z3ext.ModifyPreference"
role="preference.Owner" />
+ <!-- default preference group storage -->
+ <adapter factory=".storage.getDefaultStorage" />
+
<!-- root preference group -->
<utility
provides=".interfaces.IPreferenceGroup"
@@ -48,7 +51,7 @@
id="portal"
title="Portal preferences"
description="These are all the preferences related to common portal settings."
- provides="z3ext.preferences.interfaces.IPreferenceCategory" />
+ schema="z3ext.preferences.interfaces.IPortalPreferences" />
<!-- browser views -->
<include package=".browser" />
Modified: z3ext.preferences/trunk/src/z3ext/preferences/interfaces.py
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/interfaces.py 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/interfaces.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -19,7 +19,9 @@
from zope.configuration import fields
from zope.location.interfaces import ILocation
+ANNOTATION_KEY = 'zope.app.user.UserPreferences'
+
class UnboundPreferenceGroup(Exception):
""" Prefernce group is not bound to principal """
@@ -95,3 +97,11 @@
def __bind__(principal=None, parent=None):
""" bind preferences """
+
+
+class IDataStorage(interface.Interface):
+ """ data storage, set/get values as attributes """
+
+
+class IPortalPreferences(IPreferenceCategory):
+ """ portal preferences """
Modified: z3ext.preferences/trunk/src/z3ext/preferences/preference.py
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/preference.py 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/preference.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -15,22 +15,15 @@
$Id$
"""
-from BTrees.OOBTree import OOBTree
-
from zope import interface
-from zope.interface.common.mapping import IEnumerableMapping
-from zope.component import getGlobalSiteManager
-from zope.component import queryUtility, getMultiAdapter
from zope.cachedescriptors.property import Lazy
+from zope.interface.common.mapping import IEnumerableMapping
from zope.security.management import getInteraction
-from zope.annotation.interfaces import IAnnotations
-from zope.app.component.hooks import getSite
-from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
+from zope.component import queryUtility, getMultiAdapter, getGlobalSiteManager
-from interfaces import IPreferenceGroup, IBound, UnboundPreferenceGroup
+from interfaces import UnboundPreferenceGroup
+from interfaces import IPreferenceGroup, IBound, IDataStorage
-pref_key = 'zope.app.user.UserPreferences'
-
_marker = object()
@@ -48,25 +41,15 @@
clone = self.__class__.__new__(self.__class__)
clone.__dict__.update(self.__dict__)
- if parent is None:
- parent = getSite()
-
+ # set parent
clone.__parent__ = parent
+ # set principal
if principal is None:
if IBound.providedBy(parent):
clone.__principal__ = parent.__principal__
else:
- principal = getInteraction().participations[0].principal
-
- auth = queryUtility(IAuthentication)
- if auth is not None:
- try:
- principal = auth.getPrincipal(principal.id)
- except PrincipalLookupError:
- pass
-
- clone.__principal__ = principal
+ clone.__principal__ = getInteraction().participations[0].principal
else:
clone.__principal__ = principal
@@ -78,29 +61,15 @@
if not IBound.providedBy(self):
raise UnboundPreferenceGroup()
- ann = getMultiAdapter((self.__principal__, self), IAnnotations)
+ return getMultiAdapter((self.__principal__, self), IDataStorage)
- # If no preferences exist, create the root preferences object.
- if ann.get(pref_key) is None:
- ann[pref_key] = OOBTree()
- prefs = ann[pref_key]
-
- # If no entry for the group exists, create a new entry.
- if self.__id__ not in prefs.keys():
- prefs[self.__id__] = OOBTree()
-
- return prefs[self.__id__]
-
def isAvailable(self):
if IPreferenceGroup.providedBy(self.__parent__):
if not self.__parent__.isAvailable():
return False
for test in self.__tests__:
- if callable(test):
- if not test(self):
- return False
- elif not bool(test):
+ if not test(self):
return False
return True
@@ -118,6 +87,8 @@
name = id + grp_id
group = queryUtility(IPreferenceGroup, name)
+
+ # this code for support z3c.baseregistry package
if group is None:
group = getGlobalSiteManager().queryUtility(
IPreferenceGroup, name)
@@ -139,7 +110,7 @@
group = queryUtility(IPreferenceGroup, id, default)
if group is default:
return default
- return group.__bind__(parent=self)
+ return group.__bind__(self.__principal__, self)
def items(self):
id = self.__id__
@@ -151,7 +122,7 @@
name = id + key
group = queryUtility(IPreferenceGroup, name)
if group is not None:
- items.append((name, group.__bind__(parent=self)))
+ items.append((name, group.__bind__(self.__principal__, self)))
return items
def __getitem__(self, key):
@@ -175,7 +146,7 @@
name = id + key
group = queryUtility(IPreferenceGroup, name)
if group is not None:
- yield group.__bind__(parent=self)
+ yield group.__bind__(self.__principal__, self)
def values(self):
return [group for id, group in self.items()]
Modified: z3ext.preferences/trunk/src/z3ext/preferences/preferencetype.py
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/preferencetype.py 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/preferencetype.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -106,7 +106,7 @@
return self.schema
def __set__(self, inst, value):
- raise AttributeError("Can't set __schema__")
+ raise AttributeError("Can't change __schema__")
class PreferenceProperty(object):
@@ -121,6 +121,8 @@
... default = u'default value')
>>> field.__name__ = 'attr1'
+ >>> from z3ext.preferences.storage import DataStorage
+
Now we need content class
>>> from z3ext.preferences.preferencetype import PreferenceProperty
@@ -131,7 +133,7 @@
Lets create class instance and add field values storage
>>> ob = Content()
- >>> ob.data = {}
+ >>> ob.data = DataStorage({}, None)
By default we should get field default value
@@ -151,7 +153,7 @@
If storage contains field value we shuld get it
- >>> ob.data['attr1'] = u'value2'
+ >>> ob.data.attr1 = u'value2'
>>> ob.attr1
u'value2'
@@ -180,7 +182,7 @@
if inst is None:
return self
- value = inst.data.get(self._name, _marker)
+ value = getattr(inst.data, self._name, _marker)
if value is _marker:
return self._field.default
@@ -189,10 +191,10 @@
def __set__(self, inst, value):
field = self._field.bind(inst)
field.validate(value)
- if field.readonly and self._name in inst.data:
+ if field.readonly and hasattr(inst.data, self._name):
raise ValueError(self._name, _(u'Field is readonly'))
- inst.data[self._name] = value
+ setattr(inst.data, self._name, value)
def __delete__(self, inst):
- if self._name in inst.data:
- del inst.data[self._name]
+ if hasattr(inst.data, self._name):
+ delattr(inst.data, self._name)
Modified: z3ext.preferences/trunk/src/z3ext/preferences/root.py
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/root.py 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/root.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -16,11 +16,12 @@
$Id$
"""
from zope import interface
+from zope.app.component.hooks import getSite
from zope.app.security.interfaces import IUnauthenticatedPrincipal
from i18n import _
from preference import PreferenceGroup
-from interfaces import IRootPreferences, IPreferenceCategory
+from interfaces import IBound, IRootPreferences, IPreferenceCategory
class PersonalPreferences(PreferenceGroup):
@@ -36,7 +37,13 @@
def __init__(self):
self.__subgroups__ = ()
+ def __bind__(self, principal=None, parent=None):
+ if parent is None:
+ parent = getSite()
+ return super(PersonalPreferences, self).__bind__(principal, parent)
+
def isAvailable(self):
- if IUnauthenticatedPrincipal.providedBy(self.__principal__):
+ if (not IBound.providedBy(self) or
+ IUnauthenticatedPrincipal.providedBy(self.__principal__)):
return False
return True
Added: z3ext.preferences/trunk/src/z3ext/preferences/storage.py
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/storage.py (rev 0)
+++ z3ext.preferences/trunk/src/z3ext/preferences/storage.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -0,0 +1,63 @@
+##############################################################################
+#
+# Copyright (c) 2008 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+
+$Id$
+"""
+from BTrees.OOBTree import OOBTree
+
+from zope import interface, component
+from zope.security.interfaces import IPrincipal
+from zope.annotation.interfaces import IAnnotations
+
+from interfaces import ANNOTATION_KEY, IDataStorage, IPreferenceGroup
+
+
+ at interface.implementer(IDataStorage)
+ at component.adapter(IPrincipal, IPreferenceGroup)
+def getDefaultStorage(principal, preference):
+ ann = IAnnotations(principal)
+
+ # If no preferences exist, create the root preferences object.
+ if ann.get(ANNOTATION_KEY) is None:
+ ann[ANNOTATION_KEY] = OOBTree()
+ prefs = ann[ANNOTATION_KEY]
+
+ # If no entry for the group exists, create a new entry.
+ id = preference.__schema__.getTaggedValue('preferenceID')
+ if id not in prefs:
+ prefs[id] = OOBTree()
+
+ return DataStorage(prefs[id], preference.__schema__)
+
+
+class DataStorage(object):
+ interface.implements(IDataStorage)
+
+ def __init__(self, btree, schema):
+ self.__dict__['__btree__'] = btree
+ self.__dict__['__schema__'] = schema
+
+ def __getattr__(self, attr):
+ if attr in self.__btree__:
+ return self.__btree__[attr]
+ else:
+ raise AttributeError()
+
+ def __setattr__(self, attr, value):
+ self.__btree__[attr] = value
+
+ def __delattr__(self, attr):
+ if attr in self.__btree__:
+ del self.__btree__[attr]
Property changes on: z3ext.preferences/trunk/src/z3ext/preferences/storage.py
___________________________________________________________________
Name: svn:keywords
+ Id
Modified: z3ext.preferences/trunk/src/z3ext/preferences/tests.py
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/tests.py 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/tests.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -36,6 +36,9 @@
globs={'pprint': doctestunit.pprint},
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
doctest.DocTestSuite(
+ 'z3ext.preferences.utils',
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
+ doctest.DocTestSuite(
'z3ext.preferences.preferencetype',
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
))
Modified: z3ext.preferences/trunk/src/z3ext/preferences/utils.py
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/utils.py 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/utils.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -14,7 +14,33 @@
"""
$Id$
+
+ >>> from zope import interface
+ >>> from zope.security.interfaces import IPrincipal, IGroup
+ >>> class P(object):
+ ... interface.implements(IPrincipal)
+
+ >>> class Prefs(object):
+ ... __principal__ = None
+
+ >>> prefs = Prefs()
+ >>> prefs.__principal__ = P()
+
+ >>> import utils
+ >>> print utils.isUser(prefs)
+ True
+ >>> print utils.isGroup(prefs)
+ False
+
+ >>> interface.directlyProvides(prefs.__principal__, IGroup)
+ >>> print utils.isUser(prefs)
+ False
+ >>> print utils.isGroup(prefs)
+ True
+ >>> print utils.isMemberAwareGroup(prefs)
+ False
"""
+
from zope import interface
from zope.security.interfaces import IPrincipal, IGroup, IMemberAwareGroup
Modified: z3ext.preferences/trunk/src/z3ext/preferences/zcml.py
===================================================================
--- z3ext.preferences/trunk/src/z3ext/preferences/zcml.py 2008-04-17 05:56:06 UTC (rev 85450)
+++ z3ext.preferences/trunk/src/z3ext/preferences/zcml.py 2008-04-17 08:37:22 UTC (rev 85451)
@@ -22,10 +22,11 @@
from zope.security.zcml import Permission
from zope.security.checker import Checker, CheckerPublic
+from zope.security.interfaces import IPrincipal
from zope.interface.common.mapping import IEnumerableMapping
-from zope.component.zcml import utility
+from zope.component.zcml import utility, adapter
from zope.component.interface import provideInterface
from zope.configuration import fields
@@ -59,7 +60,7 @@
title=u"Schema",
description=u"Schema of the preference group used defining the "
u"preferences of the group.",
- required=False)
+ required=True)
title = fields.MessageID(
title=u"Title",
@@ -98,11 +99,20 @@
required = False)
+class PreferenceGroupAdapter(object):
+
+ def __init__(self, name):
+ self.name = name
+
+ def __call__(self, principal, context=None):
+ prefs = getUtility(IPreferenceGroup, self.name)
+ return prefs.__bind__(principal, context)
+
+
class PreferenceGroupDirective(object):
- def __init__(self, _context, id, title,
- for_=None, schema=interface.Interface,
- description=u'', category=False, class_=None, provides=[],
+ def __init__(self, _context, id, schema, title,
+ for_=None, description=u'', class_=None, provides=[],
permission='z3ext.ModifyPreference', tests=(), order = 9999):
Class = PreferenceType(str(id), schema, class_, title, description)
@@ -114,6 +124,10 @@
group = Class(tests)
utility(_context, IPreferenceGroup, group, name=id)
+ adapter(_context, (PreferenceGroupAdapter(id),), schema,
+ (for_ or IPrincipal,))
+ adapter(_context, (PreferenceGroupAdapter(id),), schema,
+ (for_ or IPrincipal, interface.Interface))
interface.classImplements(Class, *provides)
@@ -126,8 +140,10 @@
self.require(_context, CheckerPublic,
interface=(IEnumerableMapping,), attributes=('isAvailable',))
+ schema.setTaggedValue('preferenceID', id)
+
_context.action(
- discriminator=('z3ext:preferences', group),
+ discriminator=('z3ext:preferences', schema),
callable=addSubgroup, args=(group,))
def require(self, _context,
More information about the Checkins
mailing list