/usr/share/pyshared/zope.preference-3.8.0.egg-info/PKG-INFO is in python-zope.preference 3.8.0-0ubuntu4.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | Metadata-Version: 1.1
Name: zope.preference
Version: 3.8.0
Summary: User Preferences Framework
Home-page: http://pypi.python.org/pypi/zope.preference
Author: Zope Corporation and Contributors
Author-email: zope-dev@zope.org
License: ZPL 2.1
Description: This package provides and API to create and maintain hierarchical user
preferences. Preferences can be easily created by defining schemas.
.. contents::
================
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.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.component.hooks
>>> zope.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.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.component import provideAdapter
>>> provideAdapter(PrincipalAnnotations,
... (Principal, zope.interface.Interface), IAnnotations)
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.preference import interfaces
>>> from zope.component import provideUtility
>>> provideUtility(settings, interfaces.IPreferenceGroup,
... name='ZMISettings')
>>> provideUtility(folderSettings, interfaces.IPreferenceGroup,
... name='ZMISettings.Folder')
If we now try to lookup the sub-group again, we should be successful:
>>> settings.Folder #doctest:+ELLIPSIS
<zope.preference.preference.PreferenceGroup object at ...>
>>> settings['Folder'] #doctest:+ELLIPSIS
<zope.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.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.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.preference
>>> context = xmlconfig.file('meta.zcml', zope.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.preference.README.IZMIUserSettings"
... category="true"
... />
...
... </configure>''', context)
>>> prefs.ZMISettings2 #doctest:+ELLIPSIS
<zope.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.preference.README.IFolderSettings"
... />
...
... </configure>''', context)
>>> prefs.ZMISettings2 #doctest:+ELLIPSIS
<zope.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.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
>>> provideAdapter(UserPreferences, [ILocation], interfaces.IUserPreferences)
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
>>> provideAdapter(preference.preferencesNamespace, [None],
... zope.traversing.interfaces.ITraversable,
... '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
=======
CHANGES
=======
3.8.0 (2010-06-12)
------------------
- Split out from `zope.app.preference`.
- Removed dependency on `zope.app.component.hooks` by using
`zope.component.hooks`.
- Removed dependency on `zope.app.container` by using
`zope.container`.
Keywords: bluebream zope zope3 user preference
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Zope Public License
Classifier: Programming Language :: Python
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Framework :: Zope3
|