{ "info": { "author": "Martin Aspeli, Wichert Akkerman, Hanno Schlichting", "author_email": "plone-developers@lists.sourceforge.net", "bugtrack_url": null, "classifiers": [ "Framework :: Plone", "Framework :: Plone :: 5.1", "Framework :: Plone :: 5.2", "License :: OSI Approved :: GNU General Public License (GPL)", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "============\nIntroduction\n============\nThis package provides debconf-like (or about:config-like) settings registries\nfor Zope applications. A ``registry``, with a dict-like API, is used to get and\nset values stored in ``records``. Each record contains the actual value, as\nwell as a ``field`` that describes the record in more detail. At a minimum, the\nfield contains information about the type of value allowed, as well as a short\ntitle describing the record's purpose.\n\n.. contents:: Table of Contents\n\n\n================\nUsing registries\n================\n\nYou can create a new registry simply by instantiating the Registry class.\nThe class and its data structures are persistent, so you can store them in the ZODB.\nYou may want to provide the registry object as local utility for easy access as well, though we won't do that here.\n\n::\n\n >>> from plone.registry import Registry\n >>> registry = Registry()\n\nThe registry starts out empty.\nTo access the registry's records, you can use the ``records`` property.\nThis exposes a dict API where keys are strings and values are objects providing ``IRecords``.\n\n::\n\n >>> len(registry.records)\n 0\n\nSimple records\n==============\n\nLet's now create a record.\nA record must have a name.\nThis should be a dotted name, and contain ASCII characters only.\nBy convention, it should be all lowercase and start with the name of the package that defines the record.\n\nIt is also possible to create a number of records based on a single schema interface - see below.\nFor now, we will focus on simple records.\n\nBefore we can create the record, we must create the field that describes it.\nFields are based on the venerable ``zope.schema`` package.\n``plone.registry`` only supports certain fields, and disallows use of a few properties even of those.\nAs a rule of thumb, so long as a field stores a Python primitive, it is supported; the same goes for attributes of fields.\n\nThus:\n\n* Fields like ``Object``, ``InterfaceField`` and so on are *not* supported.\n* A custom ``constraint`` method is *not* supported.\n* The ``order`` attribute will *always* be set to ``-1``.\n* For Choice fields, *only named vocabularies* are supported:\n you can *not* reference a particular *source* or *source binder*.\n* The ``key_type`` and ``value_type`` properties of ``Dict``, ``List``, ``Tuple``, ``Set`` and ``Frozenset`` may *only* contain persistent fields.\n\nSee section \"Persistent fields\" for more details.\n\nCreating a record\n-----------------\n\nThe supported field types are found in the module ``plone.registry.field``.\nThese are named the same as the equivalent field in ``zope.schema``, and have the same constructors.\nYou must use one of these fields when creating records directly::\n\n >>> from plone.registry import field\n >>> age_field = field.Int(title=u\"Age\", min=0, default=18)\n\n >>> from plone.registry import Record\n >>> age_record = Record(age_field)\n\nNote that in this case, we did not supply a value.\nThe value will therefore be the field default::\n\n >>> age_record.value\n 18\n\nWe can set a different value, either in the ``Record`` constructor or via the ``value`` attribute::\n\n >>> age_record.value = 2\n >>> age_record.value\n 2\n\nNote that the value is validated against the field::\n\n >>> age_record.value = -1 # doctest: +SKIP_PYTHON_3\n Traceback (most recent call last):\n ...\n TooSmall: (-1, 0)\n\n >>> age_record.value = -1 # doctest: +SKIP_PYTHON_2\n Traceback (most recent call last):\n ...\n zope.schema._bootstrapinterfaces.TooSmall: (-1, 0)\n\n >>> age_record.value\n 2\n\nWe can now add the field to the registry.\nThis is done via the ``record`` dictionary::\n\n >>> 'plone.registry.tests.age' in registry\n False\n >>> registry.records['plone.registry.tests.age'] = age_record\n\nAt this point, the record will gain ``__name__`` and ``__parent__`` attributes::\n\n >>> age_record.__name__\n 'plone.registry.tests.age'\n\n >>> age_record.__parent__ is registry\n True\n\nCreating a record with an initial value\n---------------------------------------\n\nWe can create records more succinctly in *one go* by\n\n1. creating the field,\n2. creating the Record and setting its value as and\n3. assigning it to the registry,\n\nlike this::\n\n >>> registry.records['plone.registry.tests.cms'] = \\\n ... Record(field.TextLine(title=u\"CMS of choice\"), u\"Plone\")\n\nThe record can now be obtained.\nNote that it has a nice ``__repr__`` to help debugging.\n\n >>> registry.records['plone.registry.tests.cms']\n \n\nAccessing and manipulating record values\n----------------------------------------\n\nOnce a record has been created and added to the registry,\nyou can access its value through dict-like operations on the registry itself::\n\n >>> 'plone.registry.tests.cms' in registry\n True\n\n >>> registry['plone.registry.tests.cms'] # doctest: +IGNORE_U\n u'Plone'\n\n >>> registry['plone.registry.tests.cms'] = u\"Plone 3.x\"\n\nAgain, values are validated::\n\n >>> registry['plone.registry.tests.cms'] = b'Joomla' # doctest: +SKIP_PYTHON_3\n Traceback (most recent call last):\n ...\n WrongType: ('Joomla', ...)\n\n >>> registry['plone.registry.tests.cms'] = b'Joomla' # doctest: +SKIP_PYTHON_2\n Traceback (most recent call last):\n ...\n zope.schema._bootstrapinterfaces.WrongType: (b'Joomla', , 'value')\n\nThere is also a ``get()`` method::\n\n >>> registry.get('plone.registry.tests.cms') # doctest: +IGNORE_U\n u'Plone 3.x'\n >>> registry.get('non-existent-key') is None\n True\n\nDeleting records\n----------------\n\nRecords may be deleted from the ``records`` property::\n\n >>> del registry.records['plone.registry.tests.cms']\n >>> 'plone.registry.tests.cms' in registry.records\n False\n >>> 'plone.registry.tests.cms' in registry\n False\n\nCreating records from interfaces\n================================\n\nAs an application developer, it is often desirable to define settings as traditional interfaces with ``zope.schema fields``.\n``plone.registry`` includes support for creating a set of records from a single interface.\n\nTo test this, we have created an interface, ``IMailSettings``.\nIt has two fields: ``sender`` and ``smtp_host``::\n\n >>> from plone.registry.tests import IMailSettings\n\nNote that this contains standard fields::\n\n >>> IMailSettings['sender']\n \n\n >>> IMailSettings['smtp_host']\n \n\nWe can create records from this interface like this::\n\n >>> registry.registerInterface(IMailSettings)\n\nOne record for each field in the interface has now been created.\nTheir names are the full dotted names to those fields::\n\n >>> sender_record = registry.records['plone.registry.tests.IMailSettings.sender']\n >>> smtp_host_record = registry.records['plone.registry.tests.IMailSettings.smtp_host']\n\nThe fields used in the records will be the equivalent persistent versions of the fields from the original interface::\n\n >>> sender_record.field\n \n\n >>> smtp_host_record.field\n \n\nThis feat is accomplished internally by adapting the field to the ``IPersistentField`` interface.\nThere is a default adapter factory that works for all fields defined in ``plone.registry.field``.\nYou can of course define your own adapter if you have a custom field type.\nBut bear in mind the golden rules of any persistent field::\n\n* The field must store only primitives or other persistent fields\n* It must not reference a function, class, interface or other method that could break if a package is uninstalled.\n\nIf we have a field for which there is no ``IPersistentField`` adapter, we will get an error::\n\n >>> from plone.registry.tests import IMailPreferences\n >>> IMailPreferences['settings']\n \n\n >>> registry.registerInterface(IMailPreferences)\n Traceback (most recent call last):\n ...\n TypeError: There is no persistent field equivalent for the field `settings` of type `Object`.\n\nWhoops!\nWe can, however, tell ``registerInterface()`` to ignore one or more fields::\n\n >>> registry.registerInterface(IMailPreferences, omit=('settings',))\n\nOnce an interface's records have been registered, we can get and set their values as normal::\n\n >>> registry['plone.registry.tests.IMailSettings.sender'] # doctest: +IGNORE_U\n u'root@localhost'\n\n >>> registry['plone.registry.tests.IMailSettings.sender'] = u\"webmaster@localhost\"\n >>> registry['plone.registry.tests.IMailSettings.sender'] # doctest: +IGNORE_U\n u'webmaster@localhost'\n\nIf we sub-sequently re-register the same interface, the value will be retained if possible::\n\n >>> registry.registerInterface(IMailSettings)\n >>> registry['plone.registry.tests.IMailSettings.sender'] # doctest: +IGNORE_U\n u'webmaster@localhost'\n\nHowever, if the value is no longer valid, we will revert to the default.\nTo test that, let's sneakily modify the field for a while::\n\n >>> old_field = IMailSettings['sender']\n >>> IMailSettings._InterfaceClass__attrs['sender'] = field.Int(title=u\"Definitely not a string\", default=2)\n >>> if hasattr(IMailSettings, '_v_attrs'):\n ... del IMailSettings._v_attrs['sender']\n >>> registry.registerInterface(IMailSettings)\n >>> registry['plone.registry.tests.IMailSettings.sender']\n 2\n\nBut let's put it back the way it was::\n\n >>> IMailSettings._InterfaceClass__attrs['sender'] = old_field\n >>> if hasattr(IMailSettings, '_v_attrs'):\n ... del IMailSettings._v_attrs['sender']\n >>> registry.registerInterface(IMailSettings)\n >>> registry['plone.registry.tests.IMailSettings.sender'] # doctest: +IGNORE_U\n u'root@localhost'\n\nSometimes, you may want to use an interface as a template for multiple instances of a set of fields, rather than defining them all by hand.\nThis is especially useful when you want to allow third-party packages to provide information.\nTo accomplish this, we can provide a prefix with the ``registerInterface`` call.\nThis will take precedence over the ``__identifier__`` that is usually used.\n\n >>> registry.registerInterface(IMailSettings, prefix=\"plone.registry.tests.alternativesettings\")\n\nThese values are now available in the same way as the original settings::\n\n >>> sender_record = registry.records['plone.registry.tests.alternativesettings.sender']\n >>> smtp_host_record = registry.records['plone.registry.tests.alternativesettings.smtp_host']\n >>> registry['plone.registry.tests.alternativesettings.sender'] = u'alt@example.org'\n\nAccessing the original interface\n--------------------------------\n\nNow that we have these records, we can look up the original interface.\nThis does not break the golden rules:\ninternally, we only store the name of the interface, and resolve it at runtime.\n\nRecords that know about interfaces are marked with ``IInterfaceAwareRecord`` and have two additional properties:\n``interface`` and ``fieldName``::\n\n >>> from plone.registry.interfaces import IInterfaceAwareRecord\n >>> IInterfaceAwareRecord.providedBy(age_record)\n False\n >>> IInterfaceAwareRecord.providedBy(sender_record)\n True\n\n >>> sender_record.interfaceName\n 'plone.registry.tests.IMailSettings'\n\n >>> sender_record.interface is IMailSettings\n True\n\nUsing the records proxy\n-----------------------\n\nOnce the records for an interface has been created, it is possible to obtain a proxy object that provides the given interface, but reads and writes its values to the registry.\nThis is useful, for example, to create a form using ``zope.formlib`` or ``z3c.form`` that is configured with widgets based on the\ninterface.\nOr simply as a more convenient API when working with multiple, related settings.\n\n::\n\n >>> proxy = registry.forInterface(IMailSettings)\n >>> proxy\n \n\nIf you use your registry values in code which might be encountered on normal HTML rendering paths (e.g. in a viewlet) you need to be aware that records might not exist or they are invalid.\n``forInterface()`` will raise KeyError on this kind of situations::\n\n try:\n proxy = registry.forInterface(IMailSettings)\n except KeyError:\n # Gracefully handled cases\n # when GenericSetup installer has not been run or rerun\n # e.g. by returning or using some default values\n pass\n\nThe proxy is not a persistent object on its own::\n\n >>> from persistent.interfaces import IPersistent\n >>> IPersistent.providedBy(proxy)\n False\n\nIt does, however, provide the requisite interface::\n\n >>> IMailSettings.providedBy(proxy)\n True\n\nYou can distinguish between the proxy and a 'normal' object by checking for the ``IRecordsProxy`` marker interface::\n\n >>> from plone.registry.interfaces import IRecordsProxy\n >>> IRecordsProxy.providedBy(proxy)\n True\n\nWhen we set a value, it is stored in the registry::\n\n >>> proxy.smtp_host = 'http://mail.server.com'\n >>> registry['plone.registry.tests.IMailSettings.smtp_host']\n 'http://mail.server.com'\n\n >>> registry['plone.registry.tests.IMailSettings.smtp_host'] = 'smtp://mail.server.com'\n >>> proxy.smtp_host\n 'smtp://mail.server.com'\n\nValues not in the interface will raise an ``AttributeError``::\n\n >>> proxy.age\n Traceback (most recent call last):\n ...\n AttributeError: age\n\nNote that by default, the forInterface() method will check that the necessary records have been registered.\nFor example, we cannot use any old interface::\n\n >>> registry.forInterface(IInterfaceAwareRecord)\n Traceback (most recent call last):\n ...\n KeyError: 'Interface `plone.registry.interfaces.IInterfaceAwareRecord` defines a field `...`, for which there is no record.'\n\nBy default, we also cannot use an interface for which only some records exist::\n\n >>> registry.forInterface(IMailPreferences)\n Traceback (most recent call last):\n ...\n KeyError: 'Interface `plone.registry.tests.IMailPreferences` defines a field `settings`, for which there is no record.'\n\nIt is possible to disable this check, however.\nThis will be a bit more efficient::\n\n >>> registry.forInterface(IMailPreferences, check=False)\n \n\nA better way, however, is to explicitly declare that some fields are omitted::\n\n >>> pref_proxy = registry.forInterface(IMailPreferences, omit=('settings',))\n\nIn this case, the omitted fields will default to their 'missing' value::\n\n >>> pref_proxy.settings == IMailPreferences['settings'].missing_value\n True\n\nHowever, trying to set the value will result in a ``AttributeError``::\n\n >>> pref_proxy.settings = None\n Traceback (most recent call last):\n ...\n AttributeError: settings\n\nTo access another instance of the field, supply the prefix::\n\n >>> alt_proxy = registry.forInterface(IMailSettings,\n ... prefix=\"plone.registry.tests.alternativesettings\")\n >>> alt_proxy.sender # doctest: +IGNORE_U\n u'alt@example.org'\n\nCollections of records proxies\n------------------------------\n\nA collection of record sets may be accessed using ``collectionOfInterface``::\n\n >>> collection = registry.collectionOfInterface(IMailSettings)\n\nYou can create a new record set::\n\n >>> proxy = collection.setdefault('example')\n >>> proxy.sender = u'collection@example.org'\n >>> proxy.smtp_host = 'smtp://mail.example.org'\n\nRecord sets are stored based under the prefix::\n\n >>> prefix = IMailSettings.__identifier__\n >>> registry.records.values(prefix+'/', prefix+'0')\n [,\n ]\n >>> registry['plone.registry.tests.IMailSettings/example.sender'] # doctest: +IGNORE_U\n u'collection@example.org'\n\nRecords may be set from an existing object::\n\n >>> class MailSettings:\n ... sender = u'someone@example.com'\n ... smtp_host = 'smtp://mail.example.com'\n >>> collection['example_com'] = MailSettings()\n >>> registry.records.values(prefix+'/', prefix+'0')\n [,\n ,\n ,\n ]\n\nThe collection may be iterated over::\n\n >>> for name in collection: print(name)\n example\n example_com\n\nAnd may be deleted::\n\n >>> del collection['example_com']\n >>> registry.records.values(prefix+'/', prefix+'0')\n [,\n ]\n\nUsing field references\n======================\n\nIt is possible for one record to refer to another record's field.\nThis can be used to provide a simple \"override\" mechanism,\nfor example, where one record defines the field and a default value,\nwhilst another provides an override validated against the same field.\n\nLet us first create the base record and set its value::\n\n >>> timeout_field = field.Int(title=u\"Timeout\", min=0)\n >>> registry.records['plone.registry.tests.timeout'] = Record(timeout_field, 10)\n\n >>> timeout_record = registry.records['plone.registry.tests.timeout']\n >>> timeout_record.value\n 10\n\nNext, we create a field reference for this record::\n\n >>> from plone.registry import FieldRef\n >>> timeout_override_field = FieldRef(timeout_record.__name__, timeout_record.field)\n\nWe can use this to create a new record::\n\n >>> registry.records['plone.registry.tests.timeout.override'] = Record(timeout_override_field, 20)\n >>> timeout_override_record = registry.records['plone.registry.tests.timeout.override']\n\nThe two values are separate::\n\n >>> timeout_record.value\n 10\n >>> timeout_override_record.value\n 20\n\n >>> registry['plone.registry.tests.timeout']\n 10\n >>> registry['plone.registry.tests.timeout.override']\n 20\n\nValidation uses the underlying field::\n\n >>> registry['plone.registry.tests.timeout.override'] = -1 # doctest: +SKIP_PYTHON_3\n Traceback (most recent call last):\n ...\n TooSmall: (-1, 0)\n\n >>> registry['plone.registry.tests.timeout.override'] = -1 # doctest: +SKIP_PYTHON_2\n Traceback (most recent call last):\n ...\n zope.schema._bootstrapinterfaces.TooSmall: (-1, 0)\n\nThe reference field exposes the standard field properties, e.g.::\n\n >>> timeout_override_record.field.title # doctest: +SKIP_PYTHON_3\n u'Timeout'\n >>> timeout_override_record.field.min\n 0\n\nTo look up the underlying record name, we can use the ``recordName`` property::\n\n >>> timeout_override_record.field.recordName\n 'plone.registry.tests.timeout'\n\n\n===============\nRegistry events\n===============\n\nThe registry fires certain events. These are:\n\n``plone.registry.interfaces.IRecordAddedEvent``\n when a record has been added to the registry.\n\n``plone.registry.interfaces.IRecordRemovedEvent``\n when a record has been removed from the registry.\n\n``plone.registry.interfaces.IRecordModifiedEvent``,\n when a record's value is modified.\n\nTo test these events, we will create, modify and remove a few records::\n\n >>> from zope.component.eventtesting import clearEvents\n >>> clearEvents()\n >>> from plone.registry import Registry, Record, field\n >>> registry = Registry()\n\nAdding a new record to the registry should fire ``IRecordAddedEvents``::\n\n >>> registry.records['plone.registry.tests.age'] = \\\n ... Record(field.Int(title=u\"Age\", min=0, default=18))\n\n >>> registry.records['plone.registry.tests.cms'] = \\\n ... Record(field.TextLine(title=u\"Preferred CMS\"), value=u\"Plone\")\n\nWhen creating records from an interface, one event is fired for each field in the interface::\n\n >>> from plone.registry.tests import IMailSettings\n >>> registry.registerInterface(IMailSettings)\n\nDeleting a record should fire an ``IRecordRemovedEvent``::\n\n >>> del registry.records['plone.registry.tests.cms']\n\nChanging a record should fire an ``IRecordModifiedEvent``::\n\n >>> registry['plone.registry.tests.age'] = 25\n >>> registry.records['plone.registry.tests.age'].value = 24\n\nLet's take a look at the events that were just fired::\n\n >>> from plone.registry.interfaces import IRecordEvent\n >>> from zope.component.eventtesting import getEvents\n >>> getEvents(IRecordEvent)\n [,\n ,\n ,\n ,\n ,\n ,\n ]\n\nFor the modified events, we can also check the value before and after the change::\n\n >>> from plone.registry.interfaces import IRecordModifiedEvent\n >>> [(repr(e), e.oldValue, e.newValue,) for e in getEvents(IRecordModifiedEvent)]\n [('', 18, 25),\n ('', 25, 24)]\n\nIObjectEvent-style redispatchers\n================================\n\nThere is a special event handler.\nIt takes care of re-dispatching registry events based on the schema interface prescribed by the record.\n\nLet's re-set the event testing framework and register the re-dispatching event subscriber.\nNormally, this would happen automatically by including this package's ZCML.\n\n::\n\n >>> clearEvents()\n >>> from zope.component import provideHandler\n >>> from plone.registry.events import redispatchInterfaceAwareRecordEvents\n >>> provideHandler(redispatchInterfaceAwareRecordEvents)\n\nWe'll then register a schema interface::\n\n >>> from plone.registry.tests import IMailSettings\n >>> registry.registerInterface(IMailSettings)\n\nWe could now register an event handler to print any record event occurring on an ``IMailSettings`` record.\nMore specialised event handlers for e.g. ``IRecordModifiedEvent`` or ``IRecordRemovedEvent`` are of course also possible.\nNote that it is not possible to re-dispatch ``IRecordAddedEvents``, so these are never caught.\n\n >>> from zope.component import adapter\n >>> @adapter(IMailSettings, IRecordEvent)\n ... def print_mail_settings_events(proxy, event):\n ... print(\"Got %s for %s\" % (event, proxy))\n >>> provideHandler(print_mail_settings_events)\n\nLet's now modify one of the records for this interface.\nThe event handler should react immediately::\n\n >>> registry['plone.registry.tests.IMailSettings.sender'] = u\"Some sender\"\n Got for \n\nLet's also modify a non-interface-aware record, for comparison's sake.\nHere, there is nothing printed::\n\n >>> registry['plone.registry.tests.age'] = 3\n\nWe can try a record-removed event as well::\n\n >>> del registry.records['plone.registry.tests.IMailSettings.sender']\n Got for \n\nThe basic events that have been dispatched are::\n\n >>> getEvents(IRecordEvent)\n [,\n ,\n ,\n ,\n ]\n\n\n=================\nPersistent fields\n=================\n\nThe persistent fields that are found in ``plone.registry.field`` are siblings of the ones found in zope.schema,\nwith persistence mixed in.\nTo avoid potentially breaking the registry with persistent references to symbols that may go away,\nwe purposefully limit the number of fields supported.\nWe also disallow some properties, and add some additional checks on others.\n\nThe standard fields\n===================\n\nWe will show each supported field in turn. For all fields, note that:\n\n* the ``order`` property will return ``-1`` no matter what setting the ``constraint`` property is diallowed\n* the ``key_type`` and ``value_type`` properties, where applicable, must be set to a persistent field.\n* for ``Choice`` fields, only named vocabularies and vocabularies based on simple values are supported:\n sources and ``IVocabulary`` objects are not.\n\nImports needed::\n\n >>> from plone.registry import field\n >>> from zope import schema\n >>> from persistent import Persistent\n\nBytes\n-----\n\nThe bytes field describes a string of bytes::\n\n >>> f = field.Bytes(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.Bytes)\n True\n\n >>> f.order\n -1\n\n >>> field.Bytes(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint('ABC')\n True\n\nBytesLine\n---------\n\nThe bytes field describes a string of bytes, disallowing newlines::\n\n >>> f = field.BytesLine(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.BytesLine)\n True\n\n >>> f.order\n -1\n\n >>> field.BytesLine(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(b'AB\\nC')\n False\n\nASCII\n-----\n\nThe ASCII field describes a string containing only ASCII characters::\n\n >>> f = field.ASCII(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.ASCII)\n True\n\n >>> f.order\n -1\n\n >>> field.ASCII(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint('ab\\nc')\n True\n\nASCIILine\n---------\n\nThe ASCII line field describes a string containing only ASCII characters and disallowing newlines::\n\n >>> f = field.ASCIILine(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.ASCIILine)\n True\n\n >>> f.order\n -1\n\n >>> field.ASCIILine(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint('ab\\nc')\n False\n\nText\n----\n\nThe text field describes a unicode string::\n\n >>> f = field.Text(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.Text)\n True\n\n >>> f.order\n -1\n\n >>> field.Text(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(u'ab\\nc')\n True\n\nTextLine\n--------\n\nThe text line field describes a unicode string, disallowing newlines::\n\n >>> f = field.TextLine(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.TextLine)\n True\n\n >>> f.order\n -1\n\n >>> field.TextLine(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(u'ab\\nc')\n False\n\nBool\n----\n\nThe bool field describes a boolean::\n\n >>> f = field.Bool(title=u\"Test\")\n >>> isinstance(f, schema.Bool)\n True\n\n >>> f.order\n -1\n\n >>> field.Bool(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(False)\n True\n\nInt\n---\n\nThe int field describes an integer or long::\n\n >>> f = field.Int(title=u\"Test\", min=-123, max=1234)\n >>> isinstance(f, schema.Int)\n True\n\n >>> f.order\n -1\n\n >>> field.Int(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(123)\n True\n\nFloat\n-----\n\nThe float field describes a float::\n\n >>> f = field.Float(title=u\"Test\", min=-123.0, max=1234.0)\n >>> isinstance(f, schema.Float)\n True\n\n >>> f.order\n -1\n\n >>> field.Float(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(123)\n True\n\nDecimal\n-------\n\nThe decimal field describes a decimal::\n\n >>> import decimal\n >>> f = field.Decimal(title=u\"Test\", min=decimal.Decimal('-123.0'), max=decimal.Decimal('1234.0'))\n >>> isinstance(f, schema.Decimal)\n True\n\n >>> f.order\n -1\n\n >>> field.Decimal(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(123)\n True\n\nPassword\n--------\n\nThe password field describes a unicode string used for a password::\n\n >>> f = field.Password(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.Password)\n True\n\n >>> f.order\n -1\n\n >>> field.Password(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(u'ab\\nc')\n False\n\nSourceText\n----------\n\nThe source text field describes a unicode string with source code::\n\n >>> f = field.SourceText(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.SourceText)\n True\n\n >>> f.order\n -1\n\n >>> field.SourceText(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(u'ab\\nc')\n True\n\nURI\n---\n\nThe URI field describes a URI string::\n\n >>> f = field.URI(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.URI)\n True\n\n >>> f.order\n -1\n\n >>> field.URI(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(u'abc')\n True\n\nId\n--\n\nThe id field describes a URI string or a dotted name::\n\n >>> f = field.Id(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.Id)\n True\n\n >>> f.order\n -1\n\n >>> field.Id(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(u'abc')\n True\n\nDottedName\n----------\n\nThe dotted name field describes a Python dotted name::\n\n >>> f = field.DottedName(title=u\"Test\", min_length=0, max_length=10)\n >>> isinstance(f, schema.DottedName)\n True\n\n >>> f.order\n -1\n\n >>> field.DottedName(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(u'abc')\n True\n\nDatetime\n--------\n\nThe date/time field describes a Python datetime object::\n\n >>> f = field.Datetime(title=u\"Test\")\n >>> isinstance(f, schema.Datetime)\n True\n\n >>> f.order\n -1\n\n >>> field.Datetime(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> import datetime\n >>> f.constraint(datetime.datetime.now())\n True\n\nDate\n----\n\nThe date field describes a Python date object::\n\n >>> f = field.Date(title=u\"Test\")\n >>> isinstance(f, schema.Date)\n True\n\n >>> f.order\n -1\n\n >>> field.Date(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> import datetime\n >>> f.constraint(datetime.date.today())\n True\n\nTimedelta\n---------\n\nThe time-delta field describes a Python timedelta object::\n\n >>> f = field.Timedelta(title=u\"Test\")\n >>> isinstance(f, schema.Timedelta)\n True\n\n >>> f.order\n -1\n\n >>> field.Timedelta(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> import datetime\n >>> f.constraint(datetime.timedelta(1))\n True\n\nTuple\n-----\n\nThe tuple field describes a tuple::\n\n >>> f = field.Tuple(title=u\"Test\", min_length=0, max_length=10,\n ... value_type=field.TextLine(title=u\"Value\"))\n >>> isinstance(f, schema.Tuple)\n True\n\n >>> f.order\n -1\n\n >>> field.Tuple(title=u\"Test\", min_length=0, max_length=10,\n ... value_type=schema.TextLine(title=u\"Value\"))\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> f.value_type = schema.TextLine(title=u\"Value\")\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> field.Tuple(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint((1,2))\n True\n\nList\n----\n\nThe list field describes a tuple::\n\n >>> f = field.List(title=u\"Test\", min_length=0, max_length=10,\n ... value_type=field.TextLine(title=u\"Value\"))\n >>> isinstance(f, schema.List)\n True\n\n >>> f.order\n -1\n\n >>> field.List(title=u\"Test\", min_length=0, max_length=10,\n ... value_type=schema.TextLine(title=u\"Value\"))\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> f.value_type = schema.TextLine(title=u\"Value\")\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> field.List(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint([1,2])\n True\n\nSet\n---\n\nThe set field describes a set::\n\n >>> f = field.Set(title=u\"Test\", min_length=0, max_length=10,\n ... value_type=field.TextLine(title=u\"Value\"))\n >>> isinstance(f, schema.Set)\n True\n\n >>> f.order\n -1\n\n >>> field.Set(title=u\"Test\", min_length=0, max_length=10,\n ... value_type=schema.TextLine(title=u\"Value\"))\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> f.value_type = schema.TextLine(title=u\"Value\")\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> field.Set(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(set([1,2]))\n True\n\nFrozenset\n---------\n\nThe set field describes a frozenset::\n\n >>> f = field.FrozenSet(title=u\"Test\", min_length=0, max_length=10,\n ... value_type=field.TextLine(title=u\"Value\"))\n >>> isinstance(f, schema.FrozenSet)\n True\n\n >>> f.order\n -1\n\n >>> field.FrozenSet(title=u\"Test\", min_length=0, max_length=10,\n ... value_type=schema.TextLine(title=u\"Value\"))\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> f.value_type = schema.TextLine(title=u\"Value\")\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> field.FrozenSet(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(frozenset([1,2]))\n True\n\nDict\n----\n\nThe set field describes a dict::\n\n >>> f = field.Dict(title=u\"Test\", min_length=0, max_length=10,\n ... key_type=field.ASCII(title=u\"Key\"),\n ... value_type=field.TextLine(title=u\"Value\"))\n >>> isinstance(f, schema.Dict)\n True\n\n >>> f.order\n -1\n\n >>> field.Dict(title=u\"Test\", min_length=0, max_length=10,\n ... key_type=schema.ASCII(title=u\"Key\"),\n ... value_type=field.TextLine(title=u\"Value\"))\n Traceback (most recent call last):\n ...\n ValueError: The property `key_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> f.key_type = schema.ASCII(title=u\"Key\")\n Traceback (most recent call last):\n ...\n ValueError: The property `key_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> field.Dict(title=u\"Test\", min_length=0, max_length=10,\n ... key_type=field.ASCII(title=u\"Key\"),\n ... value_type=schema.TextLine(title=u\"Value\"))\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> f.value_type = schema.TextLine(title=u\"Value\")\n Traceback (most recent call last):\n ...\n ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.\n\n >>> field.Dict(title=u\"Test\", constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint(dict())\n True\n\nChoice\n------\n\nA choice field represents a selection from a vocabulary.\nFor persistent fields, the vocabulary cannot be a ``source`` or any kind of object:\nit must either be a list of primitives, or a named vocabulary::\n\n >>> f = field.Choice(title=u\"Test\", values=[1,2,3])\n >>> isinstance(f, schema.Choice)\n True\n\n >>> f.order\n -1\n\nWith a list of values given, the ``vocabulary`` property returns a vocabulary\nconstructed from the values on the fly, and ``vocabularyName`` is ``None``::\n\n >>> f.vocabulary\n \n\n >>> f.vocabularyName is None\n True\n\nWe will get an error if we use anything other than primitives::\n\n >>> f = field.Choice(title=u\"Test\", values=[object(), object()])\n Traceback (most recent call last):\n ...\n ValueError: Vocabulary values may only contain primitive values.\n\nIf a vocabulary name given, it is stored in ``vocabularyName``, and the ``vocabulary`` property returns ``None``::\n\n >>> f = field.Choice(title=u\"Test\", vocabulary='my.vocab')\n >>> f.vocabulary is None\n True\n\n >>> f.vocabularyName\n 'my.vocab'\n\nOther combinations are now allowed, such as specifying no vocabulary::\n\n >>> field.Choice(title=u\"Test\")\n Traceback (most recent call last):\n ...\n AssertionError: You must specify either values or vocabulary.\n\nOr specifying both types::\n\n >>> field.Choice(title=u\"Test\", values=[1,2,3], vocabulary='my.vocab')\n Traceback (most recent call last):\n ...\n AssertionError: You cannot specify both values and vocabulary.\n\nOr specifying an object source::\n\n >>> from zope.schema.vocabulary import SimpleVocabulary\n >>> dummy_vocabulary = SimpleVocabulary.fromValues([1,2,3])\n >>> field.Choice(title=u\"Test\", source=dummy_vocabulary)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields do not support sources, only named vocabularies or vocabularies based on simple value sets.\n\nOr specifying an object vocabulary::\n\n >>> field.Choice(title=u\"Test\", vocabulary=dummy_vocabulary)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields only support named vocabularies or vocabularies based on simple value sets.\n\nAs with other fields, you also cannot set a constraint::\n\n >>> field.Choice(title=u\"Test\", values=[1,2,3], constraint=lambda x: True)\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint = lambda x: False\n Traceback (most recent call last):\n ...\n ValueError: Persistent fields does not support setting the `constraint` property\n\n >>> f.constraint('ABC')\n True\n\n``IPersistentField`` adapters\n=============================\n\nIt is possible to adapt any non-persistent field to its related ``IPersistentField`` using the adapter factories in ``plone.registry`` fieldfactory.\nThese are set up in ``configure.zcml`` and explicitly registered in the test setup in ``tests.py``.\nCustom adapters are of course also possible::\n\n >>> from plone.registry.interfaces import IPersistentField\n\n >>> f = schema.TextLine(title=u\"Test\")\n >>> IPersistentField.providedBy(f)\n False\n\n >>> p = IPersistentField(f)\n >>> IPersistentField.providedBy(p)\n True\n\n >>> isinstance(p, field.TextLine)\n True\n\nUnsupported field types will not be adaptable by default::\n\n >>> f = schema.Object(title=u\"Object\", schema=IPersistentField)\n >>> IPersistentField(f, None) is None\n True\n\n >>> f = schema.InterfaceField(title=u\"Interface\")\n >>> IPersistentField(f, None) is None\n True\n\nAfter adaptation, the rules of persistent fields apply:\nThe ``order`` attribute is perpetually ``-1``.\nCustom constraints are not allowed, and key and value type will be adapted to persistent fields as well.\nIf any of these constraints can not be met, the adaptation will fail.\n\nFor constraints, the non-persistent value is simply ignored and the default method from the class will be used.\n\n::\n\n >>> f = schema.TextLine(title=u\"Test\", constraint=lambda x: False)\n >>> f.constraint\n at ...>\n\n >>> p = IPersistentField(f)\n >>> p.constraint\n >\n\nThe order property is similarly ignored::\n\n >>> f.order > 0\n True\n\n >>> p.order\n -1\n\nKey/value types will be adapted if possible::\n\n >>> f = schema.Dict(title=u\"Test\",\n ... key_type=schema.Id(title=u\"Id\"),\n ... value_type=schema.TextLine(title=u\"Value\"))\n >>> p = IPersistentField(f)\n >>> p.key_type\n \n\n >>> p.value_type\n \n\nIf they cannot be adapted, there will be an error::\n\n >>> f = schema.Dict(title=u\"Test\",\n ... key_type=schema.Id(title=u\"Id\"),\n ... value_type=schema.Object(title=u\"Value\", schema=IPersistentField))\n >>> p = IPersistentField(f)\n Traceback (most recent call last):\n ...\n TypeError: ('Could not adapt', , )\n\n >>> f = schema.Dict(title=u\"Test\",\n ... key_type=schema.InterfaceField(title=u\"Id\"),\n ... value_type=schema.TextLine(title=u\"Value\"))\n >>> p = IPersistentField(f)\n Traceback (most recent call last):\n ...\n TypeError: ('Could not adapt', , )\n\nThere is additional validation for choice fields that warrant a custom adapter.\nThese ensure that vocabularies are either stored as a list of simple values, or as named vocabularies.\n\n::\n\n >>> f = schema.Choice(title=u\"Test\", values=[1,2,3])\n >>> p = IPersistentField(f)\n >>> p.vocabulary\n \n >>> p._values\n [1, 2, 3]\n >>> p.vocabularyName is None\n True\n\n >>> f = schema.Choice(title=u\"Test\", vocabulary='my.vocab')\n >>> p = IPersistentField(f)\n >>> p.vocabulary is None\n True\n >>> p._values is None\n True\n >>> p.vocabularyName\n 'my.vocab'\n\nComplex vocabularies or sources are not allowed::\n\n >>> from zope.schema.vocabulary import SimpleVocabulary\n >>> dummy_vocabulary = SimpleVocabulary.fromItems([('a', 1), ('b', 2)])\n >>> f = schema.Choice(title=u\"Test\", source=dummy_vocabulary)\n >>> p = IPersistentField(f)\n Traceback (most recent call last):\n ...\n TypeError: ('Could not adapt', , )\n\n\n >>> f = schema.Choice(title=u\"Test\", vocabulary=dummy_vocabulary)\n >>> p = IPersistentField(f)\n Traceback (most recent call last):\n ...\n TypeError: ('Could not adapt', , )\n\nChangelog\n=========\n\n1.1.5 (2018-12-14)\n------------------\n\nBug fixes:\n\n- Avoid a deprecation warning that would turn into an error on Python 3.8.\n [gforcada]\n\n\n1.1.4 (2018-11-04)\n------------------\n\nBug fixes:\n\n- Adapt test to changed object field in zope4\n [pbauer]\n\n\n1.1.3 (2018-06-22)\n------------------\n\nBug fixes:\n\n- Improve performance of RecordsProxy.__iter__ which is now invoked more in\n core Plone as part of the requireJS configuration\n [MatthewWilkes]\n\n\n1.1.2 (2016-12-06)\n------------------\n\nBug fixes:\n\n- Fix tests to pass on Python 3.5\n [datakurre]\n\n\n1.1.1 (2016-11-19)\n------------------\n\nBug fixes:\n\n- Fix endless recursion on getting values from broken records proxy objects\n [tomgross]\n\n\n1.1.0 (2016-07-05)\n------------------\n\nNew features:\n\n- Give ``RecordsProxy`` a ``__parent__`` (the registry) in order to make it a good Zope citizen.\n This helps in context of z3cform binders and other similar situations,\n where a records proxy is used as context.\n [jensens]\n\n\n1.0.4 (2016-06-12)\n------------------\n\nFixes:\n\n- More cleanup: PEP8, isort, readability.\n [jensens]\n\n\n1.0.3 (2016-02-26)\n------------------\n\nFixes:\n\n- Replace deprecated ``zope.testing.doctestunit`` import with ``doctest``\n module from stdlib.\n [thet]\n\n- Cleanup: Pep8, utf8 headers, whitespace fixes, readability, ReST-fixes,\n doc-style, etc.\n [jensens]\n\n\n1.0.2 (2014-09-11)\n------------------\n\n- Choice field construction compatible with a simple vocabulary of\n string-based choices, which are converted to values on construction.\n This provides compatibility for plone.registry/plone.app.registry\n integration with plone.supermodel >= 1.2.5.\n [seanupton]\n\n\n1.0.1 (2013-01-13)\n------------------\n\n1.0 - 2011-05-13\n----------------\n\n- Release 1.0 Final\n [esteele]\n\n- Add MANIFEST.in.\n [WouterVH]\n\n\n1.0b5 - 2011-04-06\n------------------\n\n- Make RecordsProxy type customizable through ``factory`` argument to\n ``forInterface`` and ``collectionOfInterface``.\n [elro]\n\n- Add ``collectionOfInterface`` support to registry.\n [elro]\n\n- Fixed bug where prefix was ignored by registry.forInterface.\n [elro]\n\n- Add optional min, max arguments for keys/values/items of _Records.\n [elro]\n\n\n1.0b4 - 2011-02-04\n------------------\n\n- Added support for field references, via the ``FieldRef`` class. See\n ``registry.txt`` for details.\n [optilude]\n\n- Change the internal persistent structure around to make it more efficient.\n The API remains the same. Old registries will be migrated when first\n accessed. Warning: This may lead to a \"write-on-read\" situation for the\n first request in which the registry is being used.\n [optilude]\n\n\n1.0b3 - 2011-01-03\n------------------\n\n - Added prefix option to forInterface (as it was added to registerInterface)\n [garbas]\n\n\n1.0b2 - 2010-04-21\n------------------\n\n- Added support for Decimal fields\n [optilude]\n\n- Add a prefix option to registerInterface to allow an interface to be used as\n a template for a series of values, rather than single use.\n [MatthewWilkes]\n\n\n1.0b1 - 2009-08-02\n------------------\n\n- Fix a bug in bind() for Choice fields.\n [optilude]\n\n\n1.0a2 - 2009-07-12\n------------------\n\n- Changed API methods and arguments to mixedCase to be more consistent with\n the rest of Zope. This is a non-backwards-compatible change. Our profuse\n apologies, but it's now or never. :-/\n\n If you find that you get import errors or unknown keyword arguments in your\n code, please change names from foo_bar too fooBar, e.g. for_interface()\n becomes forInterface().\n [optilude]\n\n\n1.0a1 - 2009-04-17\n------------------\n\n- Initial release\n\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://pypi.org/project/plone.registry", "keywords": "configuration registry", "license": "GPL", "maintainer": "", "maintainer_email": "", "name": "plone.registry", "package_url": "https://pypi.org/project/plone.registry/", "platform": "", "project_url": "https://pypi.org/project/plone.registry/", "project_urls": { "Homepage": "https://pypi.org/project/plone.registry" }, "release_url": "https://pypi.org/project/plone.registry/1.1.5/", "requires_dist": [ "setuptools", "zope.component", "zope.dottedname", "zope.event", "zope.interface", "zope.schema", "BTrees; extra == 'test'" ], "requires_python": "", "summary": "Registry for application settings (like debconf/ about:config)", "version": "1.1.5" }, "last_serial": 4599669, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "ed9359f6942369b82cebcbcb3940afa2", "sha256": "e277baceaca74e77c3f583e2a29f92e1a1a336549b882f551d7b31cf03b8d595" }, "downloads": -1, "filename": "plone.registry-1.0.zip", "has_sig": false, "md5_digest": "ed9359f6942369b82cebcbcb3940afa2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 79416, "upload_time": "2011-05-13T17:33:29", "url": "https://files.pythonhosted.org/packages/1b/78/c0c877364b88feacabbda502befb75d535d1a3a43e58652b28b039690574/plone.registry-1.0.zip" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "6be3d2ec7e2d170e29b8c0bc65049aff", "sha256": "05c148cad81eaa65d3bd4abb24b0797b18420976edc763cd6123c5ac9a880dad" }, "downloads": -1, "filename": "plone.registry-1.0.1.zip", "has_sig": false, "md5_digest": "6be3d2ec7e2d170e29b8c0bc65049aff", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 57168, "upload_time": "2013-01-13T18:24:25", "url": "https://files.pythonhosted.org/packages/92/f6/e9fc2bedca36bb23319b7f144b04730119adbb121990e8147ca0a2a8f0b3/plone.registry-1.0.1.zip" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "100bffff963eed54200fb7da1bebd501", "sha256": "30e110bf02c33979347974f0f8cd5803922c80fc0879b3f6248f3c5b799be8af" }, "downloads": -1, "filename": "plone.registry-1.0.2.zip", "has_sig": false, "md5_digest": "100bffff963eed54200fb7da1bebd501", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 57345, "upload_time": "2014-09-11T19:42:42", "url": "https://files.pythonhosted.org/packages/8f/2b/33454db04bf648a7684519966d46ccbe7756d08e416217f1f165e98c5e9b/plone.registry-1.0.2.zip" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "5e4a5d81975e6f797ceb555e8443d488", "sha256": "81acf4419453a8f3787ec71cc6373629e9627b80c1b953f69ce3c621bee44075" }, "downloads": -1, "filename": "plone.registry-1.0.3.tar.gz", "has_sig": false, "md5_digest": "5e4a5d81975e6f797ceb555e8443d488", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45491, "upload_time": "2016-02-26T18:48:31", "url": "https://files.pythonhosted.org/packages/85/6b/f973f94f931f797a7c6bb76211b59184e3b25a7e88e85d047cca22532f1f/plone.registry-1.0.3.tar.gz" } ], "1.0.4": [ { "comment_text": "", "digests": { "md5": "5842a8e175656a55a769ff629bb7af32", "sha256": "19e1fecedacfa824348ed431e39776c36a2324cfd1e27489948e663503249814" }, "downloads": -1, "filename": "plone.registry-1.0.4.tar.gz", "has_sig": false, "md5_digest": "5842a8e175656a55a769ff629bb7af32", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 45663, "upload_time": "2016-06-11T23:22:44", "url": "https://files.pythonhosted.org/packages/dd/02/ee2512a87741e9d6eba0ba3fdcab03f87efd93b659291d8550f91b6fdc20/plone.registry-1.0.4.tar.gz" } ], "1.0.5": [ { "comment_text": "", "digests": { "md5": "9c446d8356593ec3c3f8e5787a5864f0", "sha256": "9bb3f068a918ed5930989fd6e01755cfe91d81b7a0c6a16ddc26ed5b000b8f44" }, "downloads": -1, "filename": "plone.registry-1.0.5.tar.gz", "has_sig": false, "md5_digest": "9c446d8356593ec3c3f8e5787a5864f0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46082, "upload_time": "2017-02-12T21:22:49", "url": "https://files.pythonhosted.org/packages/ba/00/90524a37a0436f581fdaa587b94ffdf6645d24d6cb74cd1b61c04de8143a/plone.registry-1.0.5.tar.gz" } ], "1.0a1": [ { "comment_text": "", "digests": { "md5": "b6c0445db90ea4d752f3dedf5481a8be", "sha256": "e6f6471944c1f39b095616f1911cc505fc4d166a563e19f47f45fc2ff880231a" }, "downloads": -1, "filename": "plone.registry-1.0a1.tar.gz", "has_sig": false, "md5_digest": "b6c0445db90ea4d752f3dedf5481a8be", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28400, "upload_time": "2009-04-17T06:35:11", "url": "https://files.pythonhosted.org/packages/22/7b/195e883e7cfc9098835dfb59063aaa8954d3f8d454fdf23d458398458e17/plone.registry-1.0a1.tar.gz" } ], "1.0a2": [ { "comment_text": "", "digests": { "md5": "e6d1340a232026c8b50673ca1e357c1a", "sha256": "807834b872b8a072a0d3c4a7142faa4bc906dcda8bbba26702acff2b951d0852" }, "downloads": -1, "filename": "plone.registry-1.0a2.tar.gz", "has_sig": false, "md5_digest": "e6d1340a232026c8b50673ca1e357c1a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 28812, "upload_time": "2009-07-12T10:21:01", "url": "https://files.pythonhosted.org/packages/c5/d4/c77567bfe3bf842a58148c047e12ecac5f9051119ed3c5ac61425a4b1f9b/plone.registry-1.0a2.tar.gz" } ], "1.0b1": [ { "comment_text": "", "digests": { "md5": "26e43bd01eb64e12749d018c463bd1ec", "sha256": "4efa2b658ca4253186f2aa599c2190ad219a2bbb7f500477988472f65ba95002" }, "downloads": -1, "filename": "plone.registry-1.0b1.tar.gz", "has_sig": false, "md5_digest": "26e43bd01eb64e12749d018c463bd1ec", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 29415, "upload_time": "2009-08-02T07:30:45", "url": "https://files.pythonhosted.org/packages/c7/1b/53a090b3dea3302ae6a266a02e39ed34b60eafe08ed3c43fa60a9fb1cbeb/plone.registry-1.0b1.tar.gz" } ], "1.0b2": [ { "comment_text": "", "digests": { "md5": "3889175f99523d3fc811f95aecac763d", "sha256": "970c66d4d7f9aea92d430b561c58c761d4f12208e783e5412b6fb4c1517b40f9" }, "downloads": -1, "filename": "plone.registry-1.0b2.zip", "has_sig": false, "md5_digest": "3889175f99523d3fc811f95aecac763d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49067, "upload_time": "2010-04-21T19:03:04", "url": "https://files.pythonhosted.org/packages/eb/24/320b2f5f153a7410f04917e3651cb5da45b1190e261b91231e2d2eb03f11/plone.registry-1.0b2.zip" } ], "1.0b3": [ { "comment_text": "", "digests": { "md5": "bedc4d8f3f5be7929a45490a0f11f2c7", "sha256": "f5a2529e53eb050084e01f6e32510565ff07434064939d55fa018440f3f6cc97" }, "downloads": -1, "filename": "plone.registry-1.0b3.zip", "has_sig": false, "md5_digest": "bedc4d8f3f5be7929a45490a0f11f2c7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49889, "upload_time": "2011-01-04T04:13:07", "url": "https://files.pythonhosted.org/packages/09/f6/be0dfa3cdd7d14c4faa88485c39a516f15ffc7e4c23e30684d8c5ecb64e2/plone.registry-1.0b3.zip" } ], "1.0b4": [ { "comment_text": "", "digests": { "md5": "1241f1b0e067a354a36e268aa85db005", "sha256": "dd2788c9e55a82bf55df230e9d16f1e1f7cd6c59d6e0e617f47f3c4e3a8d4bc2" }, "downloads": -1, "filename": "plone.registry-1.0b4.zip", "has_sig": false, "md5_digest": "1241f1b0e067a354a36e268aa85db005", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 53870, "upload_time": "2011-02-04T20:51:31", "url": "https://files.pythonhosted.org/packages/07/83/d153992751fce18a3947d549c61dffcd0d1488993f121194e73af3bfd857/plone.registry-1.0b4.zip" } ], "1.0b5": [ { "comment_text": "", "digests": { "md5": "0d588334259540cf846fbf17b2d56be1", "sha256": "5fcfb086c9ac4af2d0e512048f102306bc28dfc43d6f28913ec2c1df475f5acf" }, "downloads": -1, "filename": "plone.registry-1.0b5.zip", "has_sig": false, "md5_digest": "0d588334259540cf846fbf17b2d56be1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 56541, "upload_time": "2011-04-07T01:21:06", "url": "https://files.pythonhosted.org/packages/46/2d/17ccfcdb34cca89db9f474493ace9229d74ee89be2442138419617d19e98/plone.registry-1.0b5.zip" } ], "1.1.0": [ { "comment_text": "", "digests": { "md5": "e4e6bfad49bcf2ebcee71d5e9f0af2c3", "sha256": "3254809482c271d4c48adc7f8b98dd6e964e88855fddc921792f1b520a7fa166" }, "downloads": -1, "filename": "plone.registry-1.1.0.tar.gz", "has_sig": false, "md5_digest": "e4e6bfad49bcf2ebcee71d5e9f0af2c3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46028, "upload_time": "2016-07-05T19:34:28", "url": "https://files.pythonhosted.org/packages/10/7e/571177d2fae471b6e5c5cc5af9b84dc2775b677f50ad0ebe1357ea7caaa0/plone.registry-1.1.0.tar.gz" } ], "1.1.1": [ { "comment_text": "", "digests": { "md5": "24271bd9d6f34dfc57666b6ad21c132e", "sha256": "964d41f160f717cba67e5debd07e075156a253db402299901cfb98fdea3e4391" }, "downloads": -1, "filename": "plone.registry-1.1.1.tar.gz", "has_sig": false, "md5_digest": "24271bd9d6f34dfc57666b6ad21c132e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 46175, "upload_time": "2016-11-19T20:24:17", "url": "https://files.pythonhosted.org/packages/e2/21/f5240eccd4a73abf9a56b987f9e4955c903c99c17ee0748be4fcef417603/plone.registry-1.1.1.tar.gz" } ], "1.1.2": [ { "comment_text": "", "digests": { "md5": "52514bb2a55d68a6af444175f513eab9", "sha256": "1a12af488395e533fb74de8d7b2944f49eb2203459622ae05d38c9e71fff673a" }, "downloads": -1, "filename": "plone.registry-1.1.2.tar.gz", "has_sig": false, "md5_digest": "52514bb2a55d68a6af444175f513eab9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 48237, "upload_time": "2016-12-06T22:07:37", "url": "https://files.pythonhosted.org/packages/bc/8a/4d1638fdaba246d5d835151dc7019f7dabd6c0745d73a401350723fe8fad/plone.registry-1.1.2.tar.gz" } ], "1.1.3": [ { "comment_text": "", "digests": { "md5": "53a547a7419b6c30f07454a2867e46a1", "sha256": "79f4168a871c876945f21f6744abdc10a97f89666f0245f98f7b0d56c3cdcf59" }, "downloads": -1, "filename": "plone.registry-1.1.3-py2-none-any.whl", "has_sig": false, "md5_digest": "53a547a7419b6c30f07454a2867e46a1", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 37964, "upload_time": "2018-06-22T08:06:04", "url": "https://files.pythonhosted.org/packages/ef/8c/2f468e65f6115ac9b9edbe31d4c5ecb098b2364fadbfd63ea5aa09d2912d/plone.registry-1.1.3-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a6f1475433d4b4ec2b9932b5dcad7c16", "sha256": "0e2cd7a73b59e4d1edcfcd3e73f00393f25bb321e8a3a3e0c9a4dbf70d2e3376" }, "downloads": -1, "filename": "plone.registry-1.1.3.tar.gz", "has_sig": false, "md5_digest": "a6f1475433d4b4ec2b9932b5dcad7c16", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49405, "upload_time": "2018-06-22T08:06:06", "url": "https://files.pythonhosted.org/packages/26/6d/61c36dc2eb259be149bf867755a6bfd87268bbe5e450b415eedfadbd0e1b/plone.registry-1.1.3.tar.gz" } ], "1.1.4": [ { "comment_text": "", "digests": { "md5": "f307e03e21765a6353b068d00630d44a", "sha256": "6db7aabd3d7ebe036cbddd362bcfe8467945b82f899ff02429ffca682e929cae" }, "downloads": -1, "filename": "plone.registry-1.1.4-py2-none-any.whl", "has_sig": false, "md5_digest": "f307e03e21765a6353b068d00630d44a", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": null, "size": 38050, "upload_time": "2018-11-04T06:10:27", "url": "https://files.pythonhosted.org/packages/11/32/2fe5f124d2045ffe2899d44d38c9de36d33aba64f512127463a48d076b0d/plone.registry-1.1.4-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "882eb030c624cd7f269c615dfd5de6d0", "sha256": "7359df0446f242d0a93d00625ce9ddf37c6e48decfb6a4e891333e66622ae34b" }, "downloads": -1, "filename": "plone.registry-1.1.4.tar.gz", "has_sig": false, "md5_digest": "882eb030c624cd7f269c615dfd5de6d0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49477, "upload_time": "2018-11-04T06:10:28", "url": "https://files.pythonhosted.org/packages/94/25/915dc7ba094b338b5a94ff2307cea5b02f070be95538f5c3e9d6d0692814/plone.registry-1.1.4.tar.gz" } ], "1.1.5": [ { "comment_text": "", "digests": { "md5": "1a51c76fe5a836328e219f435062c1ff", "sha256": "f2f2d6090b20eb6cd10ef12c7184c4e0248b31e1a8e002eaf4b5eb7c7d46193b" }, "downloads": -1, "filename": "plone.registry-1.1.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1a51c76fe5a836328e219f435062c1ff", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 38107, "upload_time": "2018-12-14T14:53:27", "url": "https://files.pythonhosted.org/packages/cb/bc/08e32c8f8b9dcf9cf3b743a3460573c37a7f6b43c8477c36a4cb0b87aa07/plone.registry-1.1.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "22a32b0462a57fae0becf65f41bdf035", "sha256": "eb8b3ffd2455c81ba939407092a1ad5b39cde67c102aa957714c15aba9fea922" }, "downloads": -1, "filename": "plone.registry-1.1.5.tar.gz", "has_sig": false, "md5_digest": "22a32b0462a57fae0becf65f41bdf035", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49573, "upload_time": "2018-12-14T14:53:29", "url": "https://files.pythonhosted.org/packages/7c/12/630c4f6dc6982707da617252f89697ab604fb8996a63cd8d5ee407ec73fb/plone.registry-1.1.5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "1a51c76fe5a836328e219f435062c1ff", "sha256": "f2f2d6090b20eb6cd10ef12c7184c4e0248b31e1a8e002eaf4b5eb7c7d46193b" }, "downloads": -1, "filename": "plone.registry-1.1.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "1a51c76fe5a836328e219f435062c1ff", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 38107, "upload_time": "2018-12-14T14:53:27", "url": "https://files.pythonhosted.org/packages/cb/bc/08e32c8f8b9dcf9cf3b743a3460573c37a7f6b43c8477c36a4cb0b87aa07/plone.registry-1.1.5-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "22a32b0462a57fae0becf65f41bdf035", "sha256": "eb8b3ffd2455c81ba939407092a1ad5b39cde67c102aa957714c15aba9fea922" }, "downloads": -1, "filename": "plone.registry-1.1.5.tar.gz", "has_sig": false, "md5_digest": "22a32b0462a57fae0becf65f41bdf035", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 49573, "upload_time": "2018-12-14T14:53:29", "url": "https://files.pythonhosted.org/packages/7c/12/630c4f6dc6982707da617252f89697ab604fb8996a63cd8d5ee407ec73fb/plone.registry-1.1.5.tar.gz" } ] }