[Checkins] SVN: zope.app.preference/tags/3.5.0/ Tag 3.5.0
Dan Korostelev
nadako at gmail.com
Sat Jan 17 08:36:57 EST 2009
Log message for revision 94793:
Tag 3.5.0
Changed:
A zope.app.preference/tags/3.5.0/
D zope.app.preference/tags/3.5.0/CHANGES.txt
A zope.app.preference/tags/3.5.0/CHANGES.txt
D zope.app.preference/tags/3.5.0/buildout.cfg
A zope.app.preference/tags/3.5.0/buildout.cfg
D zope.app.preference/tags/3.5.0/setup.py
A zope.app.preference/tags/3.5.0/setup.py
D zope.app.preference/tags/3.5.0/src/zope/app/preference/README.txt
A zope.app.preference/tags/3.5.0/src/zope/app/preference/README.txt
D zope.app.preference/tags/3.5.0/src/zope/app/preference/SETUP.cfg
D zope.app.preference/tags/3.5.0/src/zope/app/preference/preference-configure.zcml
D zope.app.preference/tags/3.5.0/src/zope/app/preference/preference-meta.zcml
-=-
Deleted: zope.app.preference/tags/3.5.0/CHANGES.txt
===================================================================
--- zope.app.preference/trunk/CHANGES.txt 2009-01-17 13:10:51 UTC (rev 94790)
+++ zope.app.preference/tags/3.5.0/CHANGES.txt 2009-01-17 13:36:57 UTC (rev 94793)
@@ -1,14 +0,0 @@
-=======
-CHANGES
-=======
-
-3.4.1 (2007-10-30)
-------------------
-
-- Avoid deprecation warnings for ``ZopeMessageFactory``.
-
-
-3.4.0 (2007-10-25)
-------------------
-
-- Initial release independent of the main Zope tree.
Copied: zope.app.preference/tags/3.5.0/CHANGES.txt (from rev 94792, zope.app.preference/trunk/CHANGES.txt)
===================================================================
--- zope.app.preference/tags/3.5.0/CHANGES.txt (rev 0)
+++ zope.app.preference/tags/3.5.0/CHANGES.txt 2009-01-17 13:36:57 UTC (rev 94793)
@@ -0,0 +1,28 @@
+=======
+CHANGES
+=======
+
+3.5.0 (2009-01-17)
+------------------
+
+- Get rid of zope.app.zapi dependency, replacing its
+ uses with direct imports from original places.
+
+- Change mailing address from zope3-dev to zope-dev, as
+ the first one is retired now.
+
+- Fix tests for python 2.6.
+
+- Remove zpkg stuff and zcml include files for
+ old mkzopeinstance-based instances.
+
+3.4.1 (2007-10-30)
+------------------
+
+- Avoid deprecation warnings for ``ZopeMessageFactory``.
+
+
+3.4.0 (2007-10-25)
+------------------
+
+- Initial release independent of the main Zope tree.
Deleted: zope.app.preference/tags/3.5.0/buildout.cfg
===================================================================
--- zope.app.preference/trunk/buildout.cfg 2009-01-17 13:10:51 UTC (rev 94790)
+++ zope.app.preference/tags/3.5.0/buildout.cfg 2009-01-17 13:36:57 UTC (rev 94793)
@@ -1,7 +0,0 @@
-[buildout]
-develop = .
-parts = test
-
-[test]
-recipe = zc.recipe.testrunner
-eggs = zope.app.preference
Copied: zope.app.preference/tags/3.5.0/buildout.cfg (from rev 94792, zope.app.preference/trunk/buildout.cfg)
===================================================================
--- zope.app.preference/tags/3.5.0/buildout.cfg (rev 0)
+++ zope.app.preference/tags/3.5.0/buildout.cfg 2009-01-17 13:36:57 UTC (rev 94793)
@@ -0,0 +1,7 @@
+[buildout]
+develop = .
+parts = test
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = zope.app.preference [test]
Deleted: zope.app.preference/tags/3.5.0/setup.py
===================================================================
--- zope.app.preference/trunk/setup.py 2009-01-17 13:10:51 UTC (rev 94790)
+++ zope.app.preference/tags/3.5.0/setup.py 2009-01-17 13:36:57 UTC (rev 94793)
@@ -1,79 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 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.
-#
-##############################################################################
-"""Setup for zope.app.preference package
-
-$Id$
-"""
-import os
-from setuptools import setup, find_packages
-
-def read(*rnames):
- return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
-
-setup(name = 'zope.app.preference',
- version = '3.5.0',
- author='Zope Corporation and Contributors',
- author_email='zope3-dev at zope.org',
- description='User Preferences Framework',
- long_description=(
- read('README.txt')
- + '\n\n' +
- 'Detailed Dcoumentation\n' +
- '======================\n'
- + '\n\n' +
- read('src', 'zope', 'app', 'preference', 'README.txt')
- + '\n\n' +
- read('CHANGES.txt')
- ),
- keywords = "zope3 user preference",
- classifiers = [
- 'Development Status :: 5 - Production/Stable',
- 'Environment :: Web Environment',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: Zope Public License',
- 'Programming Language :: Python',
- 'Natural Language :: English',
- 'Operating System :: OS Independent',
- 'Topic :: Internet :: WWW/HTTP',
- 'Framework :: Zope3'],
- url='http://cheeseshop.python.org/pypi/zope.app.preference',
- license='ZPL 2.1',
- packages=find_packages('src'),
- package_dir = {'': 'src'},
- namespace_packages=['zope', 'zope.app'],
- extras_require=dict(test=['zope.app.testing',
- 'zope.testing']),
- install_requires = ['setuptools',
- 'ZODB3',
- 'zope.annotation',
- 'zope.app.basicskin',
- 'zope.app.component',
- 'zope.app.container',
- 'zope.app.form',
- 'zope.app.pagetemplate',
- 'zope.app.renderer',
- 'zope.app.tree',
- 'zope.component',
- 'zope.configuration',
- 'zope.i18n',
- 'zope.i18nmessageid',
- 'zope.interface',
- 'zope.location',
- 'zope.schema',
- 'zope.security',
- 'zope.traversing',
- ],
- include_package_data = True,
- zip_safe = False,
- )
Copied: zope.app.preference/tags/3.5.0/setup.py (from rev 94792, zope.app.preference/trunk/setup.py)
===================================================================
--- zope.app.preference/tags/3.5.0/setup.py (rev 0)
+++ zope.app.preference/tags/3.5.0/setup.py 2009-01-17 13:36:57 UTC (rev 94793)
@@ -0,0 +1,79 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Setup for zope.app.preference package
+
+$Id$
+"""
+import os
+from setuptools import setup, find_packages
+
+def read(*rnames):
+ return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(name = 'zope.app.preference',
+ version = '3.5.0',
+ author='Zope Corporation and Contributors',
+ author_email='zope-dev at zope.org',
+ description='User Preferences Framework',
+ long_description=(
+ read('README.txt')
+ + '\n\n' +
+ 'Detailed Dcoumentation\n' +
+ '======================\n'
+ + '\n\n' +
+ read('src', 'zope', 'app', 'preference', 'README.txt')
+ + '\n\n' +
+ read('CHANGES.txt')
+ ),
+ keywords = "zope3 user preference",
+ classifiers = [
+ 'Development Status :: 5 - Production/Stable',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: Zope Public License',
+ 'Programming Language :: Python',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Topic :: Internet :: WWW/HTTP',
+ 'Framework :: Zope3'],
+ url='http://pypi.python.org/pypi/zope.app.preference',
+ license='ZPL 2.1',
+ packages=find_packages('src'),
+ package_dir = {'': 'src'},
+ namespace_packages=['zope', 'zope.app'],
+ extras_require=dict(test=['zope.app.testing',
+ 'zope.testing']),
+ install_requires = ['setuptools',
+ 'ZODB3',
+ 'zope.annotation',
+ 'zope.app.basicskin',
+ 'zope.app.component',
+ 'zope.app.container',
+ 'zope.app.form',
+ 'zope.app.pagetemplate',
+ 'zope.app.renderer',
+ 'zope.app.tree',
+ 'zope.component',
+ 'zope.configuration',
+ 'zope.i18n',
+ 'zope.i18nmessageid',
+ 'zope.interface',
+ 'zope.location',
+ 'zope.schema',
+ 'zope.security',
+ 'zope.traversing',
+ ],
+ include_package_data = True,
+ zip_safe = False,
+ )
Deleted: zope.app.preference/tags/3.5.0/src/zope/app/preference/README.txt
===================================================================
--- zope.app.preference/trunk/src/zope/app/preference/README.txt 2009-01-17 13:10:51 UTC (rev 94790)
+++ zope.app.preference/tags/3.5.0/src/zope/app/preference/README.txt 2009-01-17 13:36:57 UTC (rev 94793)
@@ -1,482 +0,0 @@
-================
-User Preferences
-================
-
-Implementing user preferences is usually a painful task, since it requires a
-lot of custom coding and constantly changing preferences makes it hard to
-maintain the data and UI. The `preference` package
-
- >>> from zope.app.preference import preference
-
-eases this pain by providing a generic user preferences framework that uses
-schemas to categorize and describe the preferences.
-
-We also have to do some additional setup beforehand:
-
- >>> from zope.app.testing import setup
-
- >>> import zope.app.component.hooks
- >>> zope.app.component.hooks.setHooks()
- >>> setup.setUpTraversal()
- >>> setup.setUpSiteManagerLookup()
-
-
-Preference Groups
-------------------
-
-Preferences are grouped in preference groups and the preferences inside a
-group are specified via the preferences group schema:
-
- >>> import zope.interface
- >>> import zope.schema
- >>> class IZMIUserSettings(zope.interface.Interface):
- ... """Basic User Preferences"""
- ...
- ... email = zope.schema.TextLine(
- ... title=u"E-mail Address",
- ... description=u"E-mail Address used to send notifications")
- ...
- ... skin = zope.schema.Choice(
- ... title=u"Skin",
- ... description=u"The skin that should be used for the ZMI.",
- ... values=['Rotterdam', 'ZopeTop', 'Basic'],
- ... default='Rotterdam')
- ...
- ... showZopeLogo = zope.schema.Bool(
- ... title=u"Show Zope Logo",
- ... description=u"Specifies whether Zope logo should be displayed "
- ... u"at the top of the screen.",
- ... default=True)
-
-Now we can instantiate the preference group. Each preference group must have an
-ID by which it can be accessed and optional title and description fields for UI
-purposes:
-
- >>> settings = preference.PreferenceGroup(
- ... "ZMISettings",
- ... schema=IZMIUserSettings,
- ... title=u"ZMI User Settings",
- ... description=u"")
-
-Note that the preferences group provides the interface it is representing:
-
- >>> IZMIUserSettings.providedBy(settings)
- True
-
-and the id, schema and title of the group are directly available:
-
- >>> settings.__id__
- 'ZMISettings'
- >>> settings.__schema__
- <InterfaceClass zope.app.preference.README.IZMIUserSettings>
- >>> settings.__title__
- u'ZMI User Settings'
-
-So let's ask the preference group for the `skin` setting:
-
- >>> settings.skin #doctest:+ELLIPSIS
- Traceback (most recent call last):
- ...
- NoInteraction
-
-
-So why did the lookup fail? Because we have not specified a principal yet, for
-which we want to lookup the preferences. To do that, we have to create a new
-interaction:
-
- >>> class Principal:
- ... def __init__(self, id):
- ... self.id = id
- >>> principal = Principal('zope.user')
-
- >>> class Participation:
- ... interaction = None
- ... def __init__(self, principal):
- ... self.principal = principal
-
- >>> participation = Participation(principal)
-
- >>> import zope.security.management
- >>> zope.security.management.newInteraction(participation)
-
-We also need an IAnnotations adapter for principals, so we can store the
-settings:
-
- >>> from zope.annotation.interfaces import IAnnotations
- >>> class PrincipalAnnotations(dict):
- ... zope.interface.implements(IAnnotations)
- ... data = {}
- ... def __new__(class_, principal, context):
- ... try:
- ... annotations = class_.data[principal.id]
- ... except KeyError:
- ... annotations = dict.__new__(class_)
- ... class_.data[principal.id] = annotations
- ... return annotations
- ... def __init__(self, principal, context):
- ... pass
-
- >>> from zope.app.testing import ztapi
- >>> ztapi.provideAdapter((Principal, zope.interface.Interface), IAnnotations,
- ... PrincipalAnnotations)
-
-Let's now try to access the settings again:
-
- >>> settings.skin
- 'Rotterdam'
-
-which is the default value, since we have not set it yet. We can now reassign
-the value:
-
- >>> settings.skin = 'Basic'
- >>> settings.skin
- 'Basic'
-
-However, you cannot just enter any value, since it is validated before the
-assignment:
-
- >>> settings.skin = 'MySkin'
- Traceback (most recent call last):
- ...
- ConstraintNotSatisfied: MySkin
-
-
-Preference Group Trees
-----------------------
-
-The preferences would not be very powerful, if you could create a full
-preferences. So let's create a sub-group for our ZMI user settings, where we
-can adjust the look and feel of the folder contents view:
-
- >>> import sets
- >>> class IFolderSettings(zope.interface.Interface):
- ... """Basic User Preferences"""
- ...
- ... shownFields = zope.schema.Set(
- ... title=u"Shown Fields",
- ... description=u"Fields shown in the table.",
- ... value_type=zope.schema.Choice(['name', 'size', 'creator']),
- ... default=sets.Set(['name', 'size']))
- ...
- ... sortedBy = zope.schema.Choice(
- ... title=u"Sorted By",
- ... description=u"Data field to sort by.",
- ... values=['name', 'size', 'creator'],
- ... default='name')
-
- >>> folderSettings = preference.PreferenceGroup(
- ... "ZMISettings.Folder",
- ... schema=IFolderSettings,
- ... title=u"Folder Content View Settings")
-
-Note that the id was chosen so that the parent id is the prefix of the child's
-id. Our new preference sub-group should now be available as an attribute or an
-item on the parent group ...
-
- >>> settings.Folder
- Traceback (most recent call last):
- ...
- AttributeError: 'Folder' is not a preference or sub-group.
-
-... but not before we register the groups as utilities:
-
- >>> from zope.app.preference import interfaces
- >>> from zope.app.testing import ztapi
-
- >>> ztapi.provideUtility(interfaces.IPreferenceGroup, settings,
- ... name='ZMISettings')
- >>> ztapi.provideUtility(interfaces.IPreferenceGroup, folderSettings,
- ... name='ZMISettings.Folder')
-
-If we now try to lookup the sub-group again, we should be successful:
-
- >>> settings.Folder #doctest:+ELLIPSIS
- <zope.app.preference.preference.PreferenceGroup object at ...>
-
- >>> settings['Folder'] #doctest:+ELLIPSIS
- <zope.app.preference.preference.PreferenceGroup object at ...>
-
-While the registry of the preference groups is flat, the careful naming of the
-ids allows us to have a tree of preferences. Note that this pattern is very
-similar to the way modules are handled in Python; they are stored in a flat
-dictionary in ``sys.modules``, but due to the naming they appear to be in a
-namespace tree.
-
-While we are at it, there are also preference categories that can be compared
-to Python packages. They basically are just a higher level grouping concept
-that is used by the UI to better organize the preferences. A preference group
-can be converted to a category by simply providing an additional interface:
-
- >>> zope.interface.alsoProvides(settings, interfaces.IPreferenceCategory)
-
- >>> interfaces.IPreferenceCategory.providedBy(settings)
- True
-
-
-Default Preferences
--------------------
-
-It sometimes desirable to define default settings on a site-by-site basis,
-instead of just using the default value from the schema. The preferences
-package provides a module
-
- >>> from zope.app.preference import default
-
-that implements a default preferences provider that can be added as a unnamed
-utility for each site. So the first step is to create a site:
-
- >>> root = setup.buildSampleFolderTree()
- >>> rsm = setup.createSiteManager(root, True)
-
-Now we can register the default preference provider with the root site:
-
- >>> provider = setup.addUtility(rsm, '',
- ... interfaces.IDefaultPreferenceProvider,
- ... default.DefaultPreferenceProvider())
-
-So before we set an explicit default value for a preference, the schema field
-default is used:
-
- >>> settings.Folder.sortedBy
- 'name'
-
-But if we now set a new default value with the provider,
-
- >>> defaultFolder = provider.getDefaultPreferenceGroup('ZMISettings.Folder')
- >>> defaultFolder.sortedBy = 'size'
-
-then the default of the setting changes:
-
- >>> settings.Folder.sortedBy
- 'size'
-
-The default preference providers also implicitly acquire default values from
-parent sites. So if we make `folder1` a site and set it as the active site
-
- >>> folder1 = root['folder1']
- >>> sm1 = setup.createSiteManager(folder1, True)
-
-and add a default provider there,
-
- >>> provider1 = setup.addUtility(sm1, '',
- ... interfaces.IDefaultPreferenceProvider,
- ... default.DefaultPreferenceProvider())
-
-then we still get the root's default values, because we have not defined any
-in the higher default provider:
-
- >>> settings.Folder.sortedBy
- 'size'
-
-But if we provide the new provider with a default value for `sortedBy`,
-
- >>> defaultFolder1 = provider1.getDefaultPreferenceGroup('ZMISettings.Folder')
- >>> defaultFolder1.sortedBy = 'creator'
-
-then it is used instead:
-
- >>> settings.Folder.sortedBy
- 'creator'
-
-Of course, once the root site becomes our active site again
-
- >>> zope.app.component.hooks.setSite(root)
-
-the default value of the root provider is used:
-
- >>> settings.Folder.sortedBy
- 'size'
-
-Of course, all the defaults in the world are not relevant anymore as soon as
-the user actually provides a value:
-
- >>> settings.Folder.sortedBy = 'name'
- >>> settings.Folder.sortedBy
- 'name'
-
-Oh, and have I mentioned that entered values are always validated? So you
-cannot just assign any old value:
-
- >>> settings.Folder.sortedBy = 'foo'
- Traceback (most recent call last):
- ...
- ConstraintNotSatisfied: foo
-
-Finally, if the user deletes his/her explicit setting, we are back to the
-default value:
-
- >>> del settings.Folder.sortedBy
- >>> settings.Folder.sortedBy
- 'size'
-
-
-Creating Preference Groups Using ZCML
--------------------------------------
-
-If you are using the user preference system in Zope 3, you will not have to
-manually setup the preference groups as we did above (of course). We will use
-ZCML instead. First, we need to register the directives:
-
- >>> from zope.configuration import xmlconfig
- >>> import zope.app.preference
- >>> context = xmlconfig.file('meta.zcml', zope.app.preference)
-
-Then the system sets up a root preference group:
-
- >>> context = xmlconfig.string('''
- ... <configure
- ... xmlns="http://namespaces.zope.org/zope"
- ... i18n_domain="test">
- ...
- ... <preferenceGroup
- ... id=""
- ... title="User Preferences"
- ... />
- ...
- ... </configure>''', context)
-
-Now we can use the preference system in its intended way. We access the folder
-settings as follows:
-
- >>> import zope.component
- >>> prefs = zope.component.getUtility(interfaces.IPreferenceGroup)
- >>> prefs.ZMISettings.Folder.sortedBy
- 'size'
-
-Let's register the ZMI settings again under a new name via ZCML:
-
- >>> context = xmlconfig.string('''
- ... <configure
- ... xmlns="http://namespaces.zope.org/zope"
- ... i18n_domain="test">
- ...
- ... <preferenceGroup
- ... id="ZMISettings2"
- ... title="ZMI Settings NG"
- ... schema="zope.app.preference.README.IZMIUserSettings"
- ... category="true"
- ... />
- ...
- ... </configure>''', context)
-
- >>> prefs.ZMISettings2 #doctest:+ELLIPSIS
- <zope.app.preference.preference.PreferenceGroup object at ...>
-
- >>> prefs.ZMISettings2.__title__
- u'ZMI Settings NG'
-
- >>> IZMIUserSettings.providedBy(prefs.ZMISettings2)
- True
- >>> interfaces.IPreferenceCategory.providedBy(prefs.ZMISettings2)
- True
-
-And the tree can built again by carefully constructing the id:
-
- >>> context = xmlconfig.string('''
- ... <configure
- ... xmlns="http://namespaces.zope.org/zope"
- ... i18n_domain="test">
- ...
- ... <preferenceGroup
- ... id="ZMISettings2.Folder"
- ... title="Folder Settings"
- ... schema="zope.app.preference.README.IFolderSettings"
- ... />
- ...
- ... </configure>''', context)
-
- >>> prefs.ZMISettings2 #doctest:+ELLIPSIS
- <zope.app.preference.preference.PreferenceGroup object at ...>
-
- >>> prefs.ZMISettings2.Folder.__title__
- u'Folder Settings'
-
- >>> IFolderSettings.providedBy(prefs.ZMISettings2.Folder)
- True
- >>> interfaces.IPreferenceCategory.providedBy(prefs.ZMISettings2.Folder)
- False
-
-
-Simple Python-Level Access
---------------------------
-
-If a site is set, getting the user preferences is very simple:
-
- >>> from zope.app.preference import UserPreferences
- >>> prefs2 = UserPreferences()
- >>> prefs2.ZMISettings.Folder.sortedBy
- 'size'
-
-This function is also commonly registered as an adapter,
-
- >>> from zope.location.interfaces import ILocation
- >>> ztapi.provideAdapter(ILocation, interfaces.IUserPreferences,
- ... UserPreferences)
-
-so that you can adapt any location to the user preferences:
-
- >>> prefs3 = interfaces.IUserPreferences(folder1)
- >>> prefs3.ZMISettings.Folder.sortedBy
- 'creator'
-
-
-Traversal
----------
-
-Okay, so all these objects are nice, but they do not make it any easier to
-access the preferences in page templates. Thus, a special traversal namespace
-has been created that makes it very simple to access the preferences via a
-traversal path. But before we can use the path expressions, we have to
-register all necessary traversal components and the special `preferences`
-namespace:
-
- >>> import zope.traversing.interfaces
- >>> ztapi.provideAdapter(None,
- ... zope.traversing.interfaces.ITraversable,
- ... preference.preferencesNamespace,
- ... 'preferences')
-
-We can now access the preferences as follows:
-
- >>> from zope.traversing.api import traverse
- >>> traverse(None, '++preferences++ZMISettings/skin')
- 'Basic'
- >>> traverse(None, '++preferences++/ZMISettings/skin')
- 'Basic'
-
-
-Security
---------
-
-You might already wonder under which permissions the preferences are
-available. They are actually available publicly (`CheckerPublic`), but that
-is not a problem, since the available values are looked up specifically for
-the current user. And why should a user not have full access to his/her
-preferences?
-
-Let's create a checker using the function that the security machinery is
-actually using:
-
- >>> checker = preference.PreferenceGroupChecker(settings)
- >>> checker.permission_id('skin')
- Global(CheckerPublic,zope.security.checker)
- >>> checker.setattr_permission_id('skin')
- Global(CheckerPublic,zope.security.checker)
-
-The id, title, description, and schema are publicly available for access,
-but are not available for mutation at all:
-
- >>> checker.permission_id('__id__')
- Global(CheckerPublic,zope.security.checker)
- >>> checker.setattr_permission_id('__id__') is None
- True
-
-
-The only way security could be compromised is when one could override the
-annotations property. However, this property is not available for public
-consumption at all, including read access:
-
- >>> checker.permission_id('annotation') is None
- True
- >>> checker.setattr_permission_id('annotation') is None
- True
Copied: zope.app.preference/tags/3.5.0/src/zope/app/preference/README.txt (from rev 94791, zope.app.preference/trunk/src/zope/app/preference/README.txt)
===================================================================
--- zope.app.preference/tags/3.5.0/src/zope/app/preference/README.txt (rev 0)
+++ zope.app.preference/tags/3.5.0/src/zope/app/preference/README.txt 2009-01-17 13:36:57 UTC (rev 94793)
@@ -0,0 +1,481 @@
+================
+User Preferences
+================
+
+Implementing user preferences is usually a painful task, since it requires a
+lot of custom coding and constantly changing preferences makes it hard to
+maintain the data and UI. The `preference` package
+
+ >>> from zope.app.preference import preference
+
+eases this pain by providing a generic user preferences framework that uses
+schemas to categorize and describe the preferences.
+
+We also have to do some additional setup beforehand:
+
+ >>> from zope.app.testing import setup
+
+ >>> import zope.app.component.hooks
+ >>> zope.app.component.hooks.setHooks()
+ >>> setup.setUpTraversal()
+ >>> setup.setUpSiteManagerLookup()
+
+
+Preference Groups
+------------------
+
+Preferences are grouped in preference groups and the preferences inside a
+group are specified via the preferences group schema:
+
+ >>> import zope.interface
+ >>> import zope.schema
+ >>> class IZMIUserSettings(zope.interface.Interface):
+ ... """Basic User Preferences"""
+ ...
+ ... email = zope.schema.TextLine(
+ ... title=u"E-mail Address",
+ ... description=u"E-mail Address used to send notifications")
+ ...
+ ... skin = zope.schema.Choice(
+ ... title=u"Skin",
+ ... description=u"The skin that should be used for the ZMI.",
+ ... values=['Rotterdam', 'ZopeTop', 'Basic'],
+ ... default='Rotterdam')
+ ...
+ ... showZopeLogo = zope.schema.Bool(
+ ... title=u"Show Zope Logo",
+ ... description=u"Specifies whether Zope logo should be displayed "
+ ... u"at the top of the screen.",
+ ... default=True)
+
+Now we can instantiate the preference group. Each preference group must have an
+ID by which it can be accessed and optional title and description fields for UI
+purposes:
+
+ >>> settings = preference.PreferenceGroup(
+ ... "ZMISettings",
+ ... schema=IZMIUserSettings,
+ ... title=u"ZMI User Settings",
+ ... description=u"")
+
+Note that the preferences group provides the interface it is representing:
+
+ >>> IZMIUserSettings.providedBy(settings)
+ True
+
+and the id, schema and title of the group are directly available:
+
+ >>> settings.__id__
+ 'ZMISettings'
+ >>> settings.__schema__
+ <InterfaceClass zope.app.preference.README.IZMIUserSettings>
+ >>> settings.__title__
+ u'ZMI User Settings'
+
+So let's ask the preference group for the `skin` setting:
+
+ >>> settings.skin #doctest:+ELLIPSIS
+ Traceback (most recent call last):
+ ...
+ NoInteraction
+
+
+So why did the lookup fail? Because we have not specified a principal yet, for
+which we want to lookup the preferences. To do that, we have to create a new
+interaction:
+
+ >>> class Principal:
+ ... def __init__(self, id):
+ ... self.id = id
+ >>> principal = Principal('zope.user')
+
+ >>> class Participation:
+ ... interaction = None
+ ... def __init__(self, principal):
+ ... self.principal = principal
+
+ >>> participation = Participation(principal)
+
+ >>> import zope.security.management
+ >>> zope.security.management.newInteraction(participation)
+
+We also need an IAnnotations adapter for principals, so we can store the
+settings:
+
+ >>> from zope.annotation.interfaces import IAnnotations
+ >>> class PrincipalAnnotations(dict):
+ ... zope.interface.implements(IAnnotations)
+ ... data = {}
+ ... def __new__(class_, principal, context):
+ ... try:
+ ... annotations = class_.data[principal.id]
+ ... except KeyError:
+ ... annotations = dict.__new__(class_)
+ ... class_.data[principal.id] = annotations
+ ... return annotations
+ ... def __init__(self, principal, context):
+ ... pass
+
+ >>> from zope.app.testing import ztapi
+ >>> ztapi.provideAdapter((Principal, zope.interface.Interface), IAnnotations,
+ ... PrincipalAnnotations)
+
+Let's now try to access the settings again:
+
+ >>> settings.skin
+ 'Rotterdam'
+
+which is the default value, since we have not set it yet. We can now reassign
+the value:
+
+ >>> settings.skin = 'Basic'
+ >>> settings.skin
+ 'Basic'
+
+However, you cannot just enter any value, since it is validated before the
+assignment:
+
+ >>> settings.skin = 'MySkin'
+ Traceback (most recent call last):
+ ...
+ ConstraintNotSatisfied: MySkin
+
+
+Preference Group Trees
+----------------------
+
+The preferences would not be very powerful, if you could create a full
+preferences. So let's create a sub-group for our ZMI user settings, where we
+can adjust the look and feel of the folder contents view:
+
+ >>> class IFolderSettings(zope.interface.Interface):
+ ... """Basic User Preferences"""
+ ...
+ ... shownFields = zope.schema.Set(
+ ... title=u"Shown Fields",
+ ... description=u"Fields shown in the table.",
+ ... value_type=zope.schema.Choice(['name', 'size', 'creator']),
+ ... default=set(['name', 'size']))
+ ...
+ ... sortedBy = zope.schema.Choice(
+ ... title=u"Sorted By",
+ ... description=u"Data field to sort by.",
+ ... values=['name', 'size', 'creator'],
+ ... default='name')
+
+ >>> folderSettings = preference.PreferenceGroup(
+ ... "ZMISettings.Folder",
+ ... schema=IFolderSettings,
+ ... title=u"Folder Content View Settings")
+
+Note that the id was chosen so that the parent id is the prefix of the child's
+id. Our new preference sub-group should now be available as an attribute or an
+item on the parent group ...
+
+ >>> settings.Folder
+ Traceback (most recent call last):
+ ...
+ AttributeError: 'Folder' is not a preference or sub-group.
+
+... but not before we register the groups as utilities:
+
+ >>> from zope.app.preference import interfaces
+ >>> from zope.app.testing import ztapi
+
+ >>> ztapi.provideUtility(interfaces.IPreferenceGroup, settings,
+ ... name='ZMISettings')
+ >>> ztapi.provideUtility(interfaces.IPreferenceGroup, folderSettings,
+ ... name='ZMISettings.Folder')
+
+If we now try to lookup the sub-group again, we should be successful:
+
+ >>> settings.Folder #doctest:+ELLIPSIS
+ <zope.app.preference.preference.PreferenceGroup object at ...>
+
+ >>> settings['Folder'] #doctest:+ELLIPSIS
+ <zope.app.preference.preference.PreferenceGroup object at ...>
+
+While the registry of the preference groups is flat, the careful naming of the
+ids allows us to have a tree of preferences. Note that this pattern is very
+similar to the way modules are handled in Python; they are stored in a flat
+dictionary in ``sys.modules``, but due to the naming they appear to be in a
+namespace tree.
+
+While we are at it, there are also preference categories that can be compared
+to Python packages. They basically are just a higher level grouping concept
+that is used by the UI to better organize the preferences. A preference group
+can be converted to a category by simply providing an additional interface:
+
+ >>> zope.interface.alsoProvides(settings, interfaces.IPreferenceCategory)
+
+ >>> interfaces.IPreferenceCategory.providedBy(settings)
+ True
+
+
+Default Preferences
+-------------------
+
+It sometimes desirable to define default settings on a site-by-site basis,
+instead of just using the default value from the schema. The preferences
+package provides a module
+
+ >>> from zope.app.preference import default
+
+that implements a default preferences provider that can be added as a unnamed
+utility for each site. So the first step is to create a site:
+
+ >>> root = setup.buildSampleFolderTree()
+ >>> rsm = setup.createSiteManager(root, True)
+
+Now we can register the default preference provider with the root site:
+
+ >>> provider = setup.addUtility(rsm, '',
+ ... interfaces.IDefaultPreferenceProvider,
+ ... default.DefaultPreferenceProvider())
+
+So before we set an explicit default value for a preference, the schema field
+default is used:
+
+ >>> settings.Folder.sortedBy
+ 'name'
+
+But if we now set a new default value with the provider,
+
+ >>> defaultFolder = provider.getDefaultPreferenceGroup('ZMISettings.Folder')
+ >>> defaultFolder.sortedBy = 'size'
+
+then the default of the setting changes:
+
+ >>> settings.Folder.sortedBy
+ 'size'
+
+The default preference providers also implicitly acquire default values from
+parent sites. So if we make `folder1` a site and set it as the active site
+
+ >>> folder1 = root['folder1']
+ >>> sm1 = setup.createSiteManager(folder1, True)
+
+and add a default provider there,
+
+ >>> provider1 = setup.addUtility(sm1, '',
+ ... interfaces.IDefaultPreferenceProvider,
+ ... default.DefaultPreferenceProvider())
+
+then we still get the root's default values, because we have not defined any
+in the higher default provider:
+
+ >>> settings.Folder.sortedBy
+ 'size'
+
+But if we provide the new provider with a default value for `sortedBy`,
+
+ >>> defaultFolder1 = provider1.getDefaultPreferenceGroup('ZMISettings.Folder')
+ >>> defaultFolder1.sortedBy = 'creator'
+
+then it is used instead:
+
+ >>> settings.Folder.sortedBy
+ 'creator'
+
+Of course, once the root site becomes our active site again
+
+ >>> zope.app.component.hooks.setSite(root)
+
+the default value of the root provider is used:
+
+ >>> settings.Folder.sortedBy
+ 'size'
+
+Of course, all the defaults in the world are not relevant anymore as soon as
+the user actually provides a value:
+
+ >>> settings.Folder.sortedBy = 'name'
+ >>> settings.Folder.sortedBy
+ 'name'
+
+Oh, and have I mentioned that entered values are always validated? So you
+cannot just assign any old value:
+
+ >>> settings.Folder.sortedBy = 'foo'
+ Traceback (most recent call last):
+ ...
+ ConstraintNotSatisfied: foo
+
+Finally, if the user deletes his/her explicit setting, we are back to the
+default value:
+
+ >>> del settings.Folder.sortedBy
+ >>> settings.Folder.sortedBy
+ 'size'
+
+
+Creating Preference Groups Using ZCML
+-------------------------------------
+
+If you are using the user preference system in Zope 3, you will not have to
+manually setup the preference groups as we did above (of course). We will use
+ZCML instead. First, we need to register the directives:
+
+ >>> from zope.configuration import xmlconfig
+ >>> import zope.app.preference
+ >>> context = xmlconfig.file('meta.zcml', zope.app.preference)
+
+Then the system sets up a root preference group:
+
+ >>> context = xmlconfig.string('''
+ ... <configure
+ ... xmlns="http://namespaces.zope.org/zope"
+ ... i18n_domain="test">
+ ...
+ ... <preferenceGroup
+ ... id=""
+ ... title="User Preferences"
+ ... />
+ ...
+ ... </configure>''', context)
+
+Now we can use the preference system in its intended way. We access the folder
+settings as follows:
+
+ >>> import zope.component
+ >>> prefs = zope.component.getUtility(interfaces.IPreferenceGroup)
+ >>> prefs.ZMISettings.Folder.sortedBy
+ 'size'
+
+Let's register the ZMI settings again under a new name via ZCML:
+
+ >>> context = xmlconfig.string('''
+ ... <configure
+ ... xmlns="http://namespaces.zope.org/zope"
+ ... i18n_domain="test">
+ ...
+ ... <preferenceGroup
+ ... id="ZMISettings2"
+ ... title="ZMI Settings NG"
+ ... schema="zope.app.preference.README.IZMIUserSettings"
+ ... category="true"
+ ... />
+ ...
+ ... </configure>''', context)
+
+ >>> prefs.ZMISettings2 #doctest:+ELLIPSIS
+ <zope.app.preference.preference.PreferenceGroup object at ...>
+
+ >>> prefs.ZMISettings2.__title__
+ u'ZMI Settings NG'
+
+ >>> IZMIUserSettings.providedBy(prefs.ZMISettings2)
+ True
+ >>> interfaces.IPreferenceCategory.providedBy(prefs.ZMISettings2)
+ True
+
+And the tree can built again by carefully constructing the id:
+
+ >>> context = xmlconfig.string('''
+ ... <configure
+ ... xmlns="http://namespaces.zope.org/zope"
+ ... i18n_domain="test">
+ ...
+ ... <preferenceGroup
+ ... id="ZMISettings2.Folder"
+ ... title="Folder Settings"
+ ... schema="zope.app.preference.README.IFolderSettings"
+ ... />
+ ...
+ ... </configure>''', context)
+
+ >>> prefs.ZMISettings2 #doctest:+ELLIPSIS
+ <zope.app.preference.preference.PreferenceGroup object at ...>
+
+ >>> prefs.ZMISettings2.Folder.__title__
+ u'Folder Settings'
+
+ >>> IFolderSettings.providedBy(prefs.ZMISettings2.Folder)
+ True
+ >>> interfaces.IPreferenceCategory.providedBy(prefs.ZMISettings2.Folder)
+ False
+
+
+Simple Python-Level Access
+--------------------------
+
+If a site is set, getting the user preferences is very simple:
+
+ >>> from zope.app.preference import UserPreferences
+ >>> prefs2 = UserPreferences()
+ >>> prefs2.ZMISettings.Folder.sortedBy
+ 'size'
+
+This function is also commonly registered as an adapter,
+
+ >>> from zope.location.interfaces import ILocation
+ >>> ztapi.provideAdapter(ILocation, interfaces.IUserPreferences,
+ ... UserPreferences)
+
+so that you can adapt any location to the user preferences:
+
+ >>> prefs3 = interfaces.IUserPreferences(folder1)
+ >>> prefs3.ZMISettings.Folder.sortedBy
+ 'creator'
+
+
+Traversal
+---------
+
+Okay, so all these objects are nice, but they do not make it any easier to
+access the preferences in page templates. Thus, a special traversal namespace
+has been created that makes it very simple to access the preferences via a
+traversal path. But before we can use the path expressions, we have to
+register all necessary traversal components and the special `preferences`
+namespace:
+
+ >>> import zope.traversing.interfaces
+ >>> ztapi.provideAdapter(None,
+ ... zope.traversing.interfaces.ITraversable,
+ ... preference.preferencesNamespace,
+ ... 'preferences')
+
+We can now access the preferences as follows:
+
+ >>> from zope.traversing.api import traverse
+ >>> traverse(None, '++preferences++ZMISettings/skin')
+ 'Basic'
+ >>> traverse(None, '++preferences++/ZMISettings/skin')
+ 'Basic'
+
+
+Security
+--------
+
+You might already wonder under which permissions the preferences are
+available. They are actually available publicly (`CheckerPublic`), but that
+is not a problem, since the available values are looked up specifically for
+the current user. And why should a user not have full access to his/her
+preferences?
+
+Let's create a checker using the function that the security machinery is
+actually using:
+
+ >>> checker = preference.PreferenceGroupChecker(settings)
+ >>> checker.permission_id('skin')
+ Global(CheckerPublic,zope.security.checker)
+ >>> checker.setattr_permission_id('skin')
+ Global(CheckerPublic,zope.security.checker)
+
+The id, title, description, and schema are publicly available for access,
+but are not available for mutation at all:
+
+ >>> checker.permission_id('__id__')
+ Global(CheckerPublic,zope.security.checker)
+ >>> checker.setattr_permission_id('__id__') is None
+ True
+
+
+The only way security could be compromised is when one could override the
+annotations property. However, this property is not available for public
+consumption at all, including read access:
+
+ >>> checker.permission_id('annotation') is None
+ True
+ >>> checker.setattr_permission_id('annotation') is None
+ True
Deleted: zope.app.preference/tags/3.5.0/src/zope/app/preference/SETUP.cfg
===================================================================
--- zope.app.preference/trunk/src/zope/app/preference/SETUP.cfg 2009-01-17 13:10:51 UTC (rev 94790)
+++ zope.app.preference/tags/3.5.0/src/zope/app/preference/SETUP.cfg 2009-01-17 13:36:57 UTC (rev 94793)
@@ -1,5 +0,0 @@
-# Tell zpkg how to install the ZCML slugs.
-
-<data-files zopeskel/etc/package-includes>
- preference-*.zcml
-</data-files>
Deleted: zope.app.preference/tags/3.5.0/src/zope/app/preference/preference-configure.zcml
===================================================================
--- zope.app.preference/trunk/src/zope/app/preference/preference-configure.zcml 2009-01-17 13:10:51 UTC (rev 94790)
+++ zope.app.preference/tags/3.5.0/src/zope/app/preference/preference-configure.zcml 2009-01-17 13:36:57 UTC (rev 94793)
@@ -1 +0,0 @@
-<include package="zope.app.preference" />
Deleted: zope.app.preference/tags/3.5.0/src/zope/app/preference/preference-meta.zcml
===================================================================
--- zope.app.preference/trunk/src/zope/app/preference/preference-meta.zcml 2009-01-17 13:10:51 UTC (rev 94790)
+++ zope.app.preference/tags/3.5.0/src/zope/app/preference/preference-meta.zcml 2009-01-17 13:36:57 UTC (rev 94793)
@@ -1 +0,0 @@
-<include package="zope.app.preference" file="meta.zcml" />
More information about the Checkins
mailing list