zope.dublincore-3.8.2/ 0000755 0001750 0001750 00000000000 11527746337 014551 5 ustar tseaver tseaver zope.dublincore-3.8.2/buildout.cfg 0000644 0001750 0001750 00000000426 11527746247 017063 0 ustar tseaver tseaver [buildout]
extends =
http://download.zope.org/zopetoolkit/index/1.0.1/zopeapp-versions.cfg
http://download.zope.org/zopetoolkit/index/1.0.1/ztk-versions.cfg
versions = versions
develop = .
parts = test
[test]
recipe = zc.recipe.testrunner
eggs = zope.dublincore [test]
zope.dublincore-3.8.2/COPYRIGHT.txt 0000644 0001750 0001750 00000000040 11527746247 016654 0 ustar tseaver tseaver Zope Foundation and Contributors zope.dublincore-3.8.2/README.txt 0000644 0001750 0001750 00000001225 11527746247 016247 0 ustar tseaver tseaver ``zope.dublincore`` provides a Dublin Core support for Zope-based web
applications. This includes:
* an ``IZopeDublinCore`` interface definition that can be implemented
by objects directly or via an adapter to support DublinCore
metadata.
* an ``IZopeDublinCore`` adapter for annotatable objects (objects
providing ``IAnnotatable`` from ``zope.annotation``).
* a partial adapter for objects that already implement some of the
``IZopeDublinCore`` API,
* a "Metadata" browser page (which by default appears in the ZMI),
* subscribers to various object lifecycle events that automatically
set the created and modified date and some other metadata.
zope.dublincore-3.8.2/LICENSE.txt 0000644 0001750 0001750 00000004026 11527746247 016376 0 ustar tseaver tseaver Zope Public License (ZPL) Version 2.1
A copyright notice accompanies this license document that identifies the
copyright holders.
This license has been certified as open source. It has also been designated as
GPL compatible by the Free Software Foundation (FSF).
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions in source code must retain the accompanying copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the accompanying copyright
notice, this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Names of the copyright holders must not be used to endorse or promote
products derived from this software without prior written permission from the
copyright holders.
4. The right to distribute this software or to use it for any purpose does not
give you the right to use Servicemarks (sm) or Trademarks (tm) of the
copyright
holders. Use of them is covered by separate agreement with the copyright
holders.
5. If any files are modified, you must cause the modified files to carry
prominent notices stating that you changed the files and the date of any
change.
Disclaimer
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
zope.dublincore-3.8.2/bootstrap.py 0000644 0001750 0001750 00000003302 11527746247 017136 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2006 Zope Foundation 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.
#
##############################################################################
"""Bootstrap a buildout-based project
Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
"""
import os, shutil, sys, tempfile, urllib2
tmpeggs = tempfile.mkdtemp()
ez = {}
exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
).read() in ez
ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
import pkg_resources
cmd = 'from setuptools.command.easy_install import main; main()'
if sys.platform == 'win32':
cmd = '"%s"' % cmd # work around spawn lamosity on windows
ws = pkg_resources.working_set
assert os.spawnle(
os.P_WAIT, sys.executable, sys.executable,
'-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
dict(os.environ,
PYTHONPATH=
ws.find(pkg_resources.Requirement.parse('setuptools')).location
),
) == 0
ws.add_entry(tmpeggs)
ws.require('zc.buildout')
import zc.buildout.buildout
zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
shutil.rmtree(tmpeggs)
zope.dublincore-3.8.2/setup.py 0000644 0001750 0001750 00000004742 11527746247 016272 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2007 Zope Foundation 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.
#
##############################################################################
# This package is developed by the Zope Toolkit project, documented here:
# http://docs.zope.org/zopetoolkit
# When developing and releasing this package, please follow the documented
# Zope Toolkit policies as described by this documentation.
##############################################################################
"""Setup for zope.dublincore package
"""
from setuptools import setup, find_packages
import os.path
def read(*path):
return open(os.path.join(*path)).read() + '\n\n'
version = '3.8.2'
long_description = (
'.. contents::\n\n' +
'========\n' +
'Overview\n' +
'========\n' +
read('README.txt') +
read('src', 'zope', 'dublincore', 'property.txt') +
read('src', 'zope', 'dublincore', 'tests', 'partial.txt') +
read('src', 'zope', 'dublincore', 'tests', 'timeannotators.txt') +
read('CHANGES.txt')
)
setup(
name="zope.dublincore",
version=version,
url='http://pypi.python.org/pypi/zope.dublincore',
license='ZPL 2.1',
description='Zope Dublin Core implementation',
long_description=long_description,
author='Zope Foundation and Contributors',
author_email='zope-dev@zope.org',
packages=find_packages('src'),
package_dir={'':'src'},
namespace_packages=['zope'],
include_package_data=True,
extras_require=dict(
test=['zope.testing >= 3.8',
'zope.annotation',
'zope.configuration',
]
),
install_requires = ['setuptools',
'pytz',
'zope.component[zcml]',
'zope.datetime',
'zope.interface',
'zope.lifecycleevent',
'zope.location',
'zope.schema',
'zope.security[zcml]>=3.8',
],
zip_safe = False
)
zope.dublincore-3.8.2/src/ 0000755 0001750 0001750 00000000000 11527746337 015340 5 ustar tseaver tseaver zope.dublincore-3.8.2/src/zope/ 0000755 0001750 0001750 00000000000 11527746337 016315 5 ustar tseaver tseaver zope.dublincore-3.8.2/src/zope/dublincore/ 0000755 0001750 0001750 00000000000 11527746337 020443 5 ustar tseaver tseaver zope.dublincore-3.8.2/src/zope/dublincore/property.py 0000644 0001750 0001750 00000006436 11527746247 022712 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2005 Zope Foundation 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.
#
##############################################################################
"""Base DublinCore property adapter.
"""
__docformat__ = 'restructuredtext'
from zope import schema
from zope.dublincore.interfaces import IZopeDublinCore
from zope.dublincore.zopedublincore import SequenceProperty
_marker = object()
class DCProperty(object):
"""Adapt to a dublin core property
Handles DC list properties as scalar property.
"""
def __init__(self, name):
self.__name = name
def __get__(self, inst, klass):
if inst is None:
return self
name = self.__name
inst = IZopeDublinCore(inst)
value = getattr(inst, name, _marker)
if value is _marker:
field = IZopeDublinCore[name].bind(inst)
value = getattr(field, 'default', _marker)
if value is _marker:
raise AttributeError(name)
if isinstance(value, (list, tuple)):
value = value[0]
return value
def __set__(self, inst, value):
name = self.__name
inst = IZopeDublinCore(inst)
field = IZopeDublinCore[name].bind(inst)
if isinstance(field, schema.List):
if isinstance(value, tuple):
value = list(value)
else:
value = [value]
elif isinstance(field, schema.Tuple):
if isinstance(value, list):
value = tuple(value)
else:
value = (value,)
field.validate(value)
if field.readonly and inst.__dict__.has_key(name):
raise ValueError(name, 'field is readonly')
setattr(inst, name, value)
def __getattr__(self, name):
return getattr(IZopeDublinCore[self.__name], name)
class DCListProperty(DCProperty):
"""Adapt to a dublin core list property
Returns the DC property unchanged.
"""
def __init__(self, name):
self.__name = name
def __get__(self, inst, klass):
if inst is None:
return self
name = self.__name
inst = IZopeDublinCore(inst)
value = getattr(inst, name, _marker)
if value is _marker:
field = IZopeDublinCore[name].bind(inst)
value = getattr(field, 'default', _marker)
if value is _marker:
raise AttributeError(name)
return value
def __set__(self, inst, value):
name = self.__name
inst = IZopeDublinCore(inst)
field = IZopeDublinCore[name].bind(inst)
if isinstance(field, schema.Tuple):
value = tuple(value)
field.validate(value)
if field.readonly and inst.__dict__.has_key(name):
raise ValueError(name, 'field is readonly')
setattr(inst, name, value)
zope.dublincore-3.8.2/src/zope/dublincore/dcterms.py 0000644 0001750 0001750 00000015474 11527746247 022471 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2003 Zope Foundation 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.
#
##############################################################################
"""Support information for qualified Dublin Core Metadata.
"""
__docformat__ = 'restructuredtext'
from zope.dublincore import dcsv
# useful namespace URIs
DC_NS = "http://purl.org/dc/elements/1.1/"
DCTERMS_NS = "http://purl.org/dc/terms/"
XSI_NS = "http://www.w3.org/2001/XMLSchema-instance"
W3CDTF = "W3CDTF"
def splitEncoding(name):
if "." not in name:
return name, None
parts = name.split(".")
if parts[-1] in encodings:
if len(parts) == 2:
return parts
else:
return ".".join(parts[:-1]), parts[-1]
else:
return name, None
# The type validator function must raise an exception if the value
# passed isn't valid for the type being check, other just return.
_dcmitypes = {}
for x in ("Collection Dataset Event Image InteractiveResource"
" Service Software Sound Text PhysicalObject").split():
_dcmitypes[x.lower()] = x
del x
def check_dcmitype(value):
if value.lower() not in _dcmitypes:
raise ValueError("%r not a valid DCMIType")
def check_imt(value):
pass
def check_iso639_2(value):
pass
def check_rfc1766(value):
pass
def check_uri(value):
pass
def check_point(value):
pass
def check_iso3166(value):
pass
def check_box(value):
pass
def check_tgn(value):
pass
_period_fields = "name start end scheme".split()
def check_period(value):
# checks a Period in DCSV format; see:
# http://dublincore.org/documents/dcmi-period/
items = dcsv.decode(value)
d = dcsv.createMapping(items)
for k in d:
if k not in _period_fields:
raise ValueError("unknown field label %r" % k)
if d.get("scheme", W3CDTF).upper() == W3CDTF:
if "start" in d:
check_w3cdtf(d["start"])
if "end" in d:
check_w3cdtf(d["end"])
def check_w3cdtf(value):
pass
def check_rfc3066(value):
pass
encodings = {
# name --> (allowed for, validator|None),
"LCSH": (("Subject",), None),
"MESH": (("Subject",), None),
"DDC": (("Subject",), None),
"LCC": (("Subject",), None),
"UDC": (("Subject",), None),
"DCMIType": (("Type",), check_dcmitype),
"IMT": (("Format",), check_imt),
"ISO639-2": (("Language",), check_iso639_2),
"RFC1766": (("Language",), check_rfc1766),
"URI": (("Identifier", "Relation", "Source",), check_uri),
"Point": (("Coverage.Spatial",), check_point),
"ISO3166": (("Coverage.Spatial",), check_iso3166),
"Box": (("Coverage.Spatial",), check_box),
"TGN": (("Coverage.Spatial",), check_tgn),
"Period": (("Coverage.Temporal",), check_period),
W3CDTF: (("Coverage.Temporal", "Date",), check_w3cdtf),
"RFC3066": (("Language",), check_rfc3066),
}
name_to_element = {
# unqualified DCMES 1.1
"Title": ("dc:title", ""),
"Creator": ("dc:creator", ""),
"Subject": ("dc:subject", ""),
"Description": ("dc:description", ""),
"Publisher": ("dc:publisher", ""),
"Contributor": ("dc:contributor", ""),
"Date": ("dc:date", "dcterms:"+W3CDTF),
"Type": ("dc:type", ""),
"Format": ("dc:format", ""),
"Identifier": ("dc:identifier", ""),
"Source": ("dc:source", ""),
"Language": ("dc:language", ""),
"Relation": ("dc:relation", ""),
"Coverage": ("dc:coverage", ""),
"Rights": ("dc:rights", ""),
# qualified DCMES 1.1 (directly handled by Zope)
"Date.Created": ("dcterms:created", "dcterms:"+W3CDTF),
"Date.Modified": ("dcterms:modified", "dcterms:"+W3CDTF),
# qualified DCMES 1.1 (not used by Zope)
"Audience": ("dcterms:audience", ""),
"Audience.Education Level": ("dcterms:educationLevel", ""),
"Audience.Mediator": ("dcterms:mediator", ""),
"Coverage.Spatial": ("dcterms:spatial", ""),
"Coverage.Temporal": ("dcterms:temporal", ""),
"Date.Accepted": ("dcterms:accepted", "dcterms:"+W3CDTF),
"Date.Available": ("dcterms:available", "dcterms:"+W3CDTF),
"Date.Copyrighted": ("dcterms:copyrighted","dcterms:"+W3CDTF),
"Date.Issued": ("dcterms:issued", "dcterms:"+W3CDTF),
"Date.Submitted": ("dcterms:submitted", "dcterms:"+W3CDTF),
"Date.Valid": ("dcterms:valid", "dcterms:"+W3CDTF),
"Description.Abstract": ("dcterms:abstract", ""),
"Description.Table Of Contents": ("dcterms:tableOfContents", ""),
"Format": ("dc:format", ""),
"Format.Extent": ("dcterms:extent", ""),
"Format.Medium": ("dcterms:medium", ""),
"Identifier.Bibliographic Citation": ("dcterms:bibliographicCitation", ""),
"Relation.Is Version Of": ("dcterms:isVersionOf", ""),
"Relation.Has Version": ("dcterms:hasVersion", ""),
"Relation.Is Replaced By": ("dcterms:isReplacedBy", ""),
"Relation.Replaces": ("dcterms:replaces", ""),
"Relation.Is Required By": ("dcterms:isRequiredBy", ""),
"Relation.Requires": ("dcterms:requires", ""),
"Relation.Is Part Of": ("dcterms:isPartOf", ""),
"Relation.Has Part": ("dcterms:hasPart", ""),
"Relation.Is Referenced By": ("dcterms:isReferencedBy", ""),
"Relation.References": ("dcterms:references", ""),
"Relation.Is Format Of": ("dcterms:isFormatOf", ""),
"Relation.Has Format": ("dcterms:hasFormat", ""),
"Relation.Conforms To": ("dcterms:conformsTo", ""),
"Rights.Access Rights": ("dcterms:accessRights", ""),
"Title.Alternative": ("dcterms:alternative", ""),
}
_prefix_to_ns = {
"dc": DC_NS,
"dcterms": DCTERMS_NS,
# "xsi": XSI_NS, dont' use this for element names, only attrs
}
element_to_name = {}
for name, (qname, attrs) in name_to_element.iteritems():
prefix, localname = qname.split(":")
elem_name = _prefix_to_ns[prefix], localname
element_to_name[elem_name] = name
name_to_element[name] = (elem_name, attrs)
zope.dublincore-3.8.2/src/zope/dublincore/browser/ 0000755 0001750 0001750 00000000000 11527746337 022126 5 ustar tseaver tseaver zope.dublincore-3.8.2/src/zope/dublincore/browser/metadataedit.py 0000644 0001750 0001750 00000004014 11527746247 025125 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2002 Zope Foundation 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.
#
##############################################################################
"""Dublin Core Meta Data View
"""
__docformat__ = 'restructuredtext'
from datetime import datetime
from zope.event import notify
from zope.dublincore.interfaces import IZopeDublinCore
from zope.lifecycleevent import ObjectModifiedEvent, Attributes
from zope.i18nmessageid import MessageFactory
_ = MessageFactory('zope')
class MetaDataEdit(object):
"""Provide view for editing basic dublin-core meta-data."""
def edit(self):
request = self.request
formatter = self.request.locale.dates.getFormatter('dateTime', 'medium')
dc = IZopeDublinCore(self.context)
message=''
if 'dctitle' in request:
dc.title = unicode(request['dctitle'])
dc.description = unicode(request['dcdescription'])
description = Attributes(IZopeDublinCore, 'title', 'description')
notify(ObjectModifiedEvent(self.context, description))
message = _("Changed data ${datetime}",
mapping={'datetime': formatter.format(datetime.utcnow())})
return {
'message': message,
'dctitle': dc.title,
'dcdescription': dc.description,
'modified': (dc.modified or dc.created) and \
formatter.format(dc.modified or dc.created) or '',
'created': dc.created and formatter.format(dc.created) or '',
'creators': dc.creators
}
zope.dublincore-3.8.2/src/zope/dublincore/browser/box.pt 0000644 0001750 0001750 00000001410 11527746247 023257 0 ustar tseaver tseaver
Title:
Description:
Created:
2000-01-01 01:01:01
Modified:
2000-01-01 01:01:01
zope.dublincore-3.8.2/src/zope/dublincore/browser/configure.zcml 0000644 0001750 0001750 00000001217 11527746247 024777 0 ustar tseaver tseaver
zope.dublincore-3.8.2/src/zope/dublincore/browser/__init__.py 0000644 0001750 0001750 00000000075 11527746247 024241 0 ustar tseaver tseaver #
# This file is necessary to make this directory a package.
zope.dublincore-3.8.2/src/zope/dublincore/browser/edit.pt 0000644 0001750 0001750 00000003362 11527746247 023424 0 ustar tseaver tseaver
zope.dublincore-3.8.2/src/zope/dublincore/property.txt 0000644 0001750 0001750 00000002142 11527746247 023067 0 ustar tseaver tseaver ======================
Dublin Core Properties
======================
A dublin core property allows us to use properties from dublin core
by simply defining a property as DCProperty.
>>> from zope.dublincore import property
>>> from zope import interface
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> class DC(object):
... interface.implements(IAttributeAnnotatable)
... title = property.DCProperty('title')
... author = property.DCProperty('creators')
... authors = property.DCListProperty('creators')
>>> obj = DC()
>>> obj.title = u'My title'
>>> obj.title
u'My title'
Let's see if the title is really stored in dublin core:
>>> from zope.dublincore.interfaces import IZopeDublinCore
>>> IZopeDublinCore(obj).title
u'My title'
Even if a dublin core property is a list property we can set and get the
property as scalar type:
>>> obj.author = u'me'
>>> obj.author
u'me'
DCListProperty acts on the list:
>>> obj.authors
(u'me',)
>>> obj.authors = [u'I', u'others']
>>> obj.authors
(u'I', u'others')
>>> obj.author
u'I'
zope.dublincore-3.8.2/src/zope/dublincore/testing.py 0000644 0001750 0001750 00000001732 11527746247 022475 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2005 Zope Foundation 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.
#
##############################################################################
"""Testing support
"""
__docformat__ = 'restructuredtext'
from zope import component
from annotatableadapter import ZDCAnnotatableAdapter
from interfaces import IWriteZopeDublinCore
def setUpDublinCore():
component.provideAdapter(ZDCAnnotatableAdapter,
provides=IWriteZopeDublinCore,
)
zope.dublincore-3.8.2/src/zope/dublincore/interfaces.py 0000644 0001750 0001750 00000034136 11527746247 023147 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2002 Zope Foundation 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.
#
##############################################################################
"""Dublin Core interfaces
"""
__docformat__ = 'restructuredtext'
from zope.interface import Interface
from zope.schema import Text, TextLine, Datetime, Tuple
class IDublinCoreElementItem(Interface):
"""A qualified dublin core element"""
qualification = TextLine(
title = u"Qualification",
description = u"The element qualification"
)
value = Text(
title = u"Value",
description = u"The element value",
)
class IGeneralDublinCore(Interface):
"""Dublin-core data access interface
The Dublin Core, http://dublincore.org/, is a meta data standard
that specifies a set of standard data elements. It provides
flexibility of interpretation of these elements by providing for
element qualifiers that specialize the meaning of specific
elements. For example, a date element might have a qualifier, like
"creation" to indicate that the date is a creation date. In
addition, any element may be repeated. For some elements, like
subject, and contributor, this is obviously necessary, but for
other elements, like title and description, allowing repetitions
is not very useful and adds complexity.
This interface provides methods for retrieving data in full
generality, to be compliant with the Dublin Core standard.
Other interfaces will provide more convenient access methods
tailored to specific element usage patterns.
"""
def getQualifiedTitles():
"""Return a sequence of Title IDublinCoreElementItem.
"""
def getQualifiedCreators():
"""Return a sequence of Creator IDublinCoreElementItem.
"""
def getQualifiedSubjects():
"""Return a sequence of Subject IDublinCoreElementItem.
"""
def getQualifiedDescriptions():
"""Return a sequence of Description IDublinCoreElementItem.
"""
def getQualifiedPublishers():
"""Return a sequence of Publisher IDublinCoreElementItem.
"""
def getQualifiedContributors():
"""Return a sequence of Contributor IDublinCoreElementItem.
"""
def getQualifiedDates():
"""Return a sequence of Date IDublinCoreElementItem.
"""
def getQualifiedTypes():
"""Return a sequence of Type IDublinCoreElementItem.
"""
def getQualifiedFormats():
"""Return a sequence of Format IDublinCoreElementItem.
"""
def getQualifiedIdentifiers():
"""Return a sequence of Identifier IDublinCoreElementItem.
"""
def getQualifiedSources():
"""Return a sequence of Source IDublinCoreElementItem.
"""
def getQualifiedLanguages():
"""Return a sequence of Language IDublinCoreElementItem.
"""
def getQualifiedRelations():
"""Return a sequence of Relation IDublinCoreElementItem.
"""
def getQualifiedCoverages():
"""Return a sequence of Coverage IDublinCoreElementItem.
"""
def getQualifiedRights():
"""Return a sequence of Rights IDublinCoreElementItem.
"""
class IWritableGeneralDublinCore(Interface):
"""Provide write access to dublin core data
This interface augments `IStandardDublinCore` with methods for
writing elements.
"""
def setQualifiedTitles(qualified_titles):
"""Set the qualified Title elements.
The argument must be a sequence of `IDublinCoreElementItem`.
"""
def setQualifiedCreators(qualified_creators):
"""Set the qualified Creator elements.
The argument must be a sequence of Creator `IDublinCoreElementItem`.
"""
def setQualifiedSubjects(qualified_subjects):
"""Set the qualified Subjects elements.
The argument must be a sequence of Subject `IDublinCoreElementItem`.
"""
def setQualifiedDescriptions(qualified_descriptions):
"""Set the qualified Descriptions elements.
The argument must be a sequence of Description `IDublinCoreElementItem`.
"""
def setQualifiedPublishers(qualified_publishers):
"""Set the qualified Publishers elements.
The argument must be a sequence of Publisher `IDublinCoreElementItem`.
"""
def setQualifiedContributors(qualified_contributors):
"""Set the qualified Contributors elements.
The argument must be a sequence of Contributor `IDublinCoreElementItem`.
"""
def setQualifiedDates(qualified_dates):
"""Set the qualified Dates elements.
The argument must be a sequence of Date `IDublinCoreElementItem`.
"""
def setQualifiedTypes(qualified_types):
"""Set the qualified Types elements.
The argument must be a sequence of Type `IDublinCoreElementItem`.
"""
def setQualifiedFormats(qualified_formats):
"""Set the qualified Formats elements.
The argument must be a sequence of Format `IDublinCoreElementItem`.
"""
def setQualifiedIdentifiers(qualified_identifiers):
"""Set the qualified Identifiers elements.
The argument must be a sequence of Identifier `IDublinCoreElementItem`.
"""
def setQualifiedSources(qualified_sources):
"""Set the qualified Sources elements.
The argument must be a sequence of Source `IDublinCoreElementItem`.
"""
def setQualifiedLanguages(qualified_languages):
"""Set the qualified Languages elements.
The argument must be a sequence of Language `IDublinCoreElementItem`.
"""
def setQualifiedRelations(qualified_relations):
"""Set the qualified Relations elements.
The argument must be a sequence of Relation `IDublinCoreElementItem`.
"""
def setQualifiedCoverages(qualified_coverages):
"""Set the qualified Coverages elements.
The argument must be a sequence of Coverage `IDublinCoreElementItem`.
"""
def setQualifiedRights(qualified_rights):
"""Set the qualified Rights elements.
The argument must be a sequence of Rights `IDublinCoreElementItem`.
"""
class IDCDescriptiveProperties(Interface):
"""Basic descriptive meta-data properties
"""
title = TextLine(
title = u'Title',
description =
u"The first unqualified Dublin Core 'Title' element value."
)
description = Text(
title = u'Description',
description =
u"The first unqualified Dublin Core 'Description' element value.",
)
class IDCTimes(Interface):
"""Time properties
"""
created = Datetime(
title = u'Creation Date',
description =
u"The date and time that an object is created. "
u"\nThis is normally set automatically."
)
modified = Datetime(
title = u'Modification Date',
description =
u"The date and time that the object was last modified in a\n"
u"meaningful way."
)
class IDCPublishing(Interface):
"""Publishing properties
"""
effective = Datetime(
title = u'Effective Date',
description =
u"The date and time that an object should be published. "
)
expires = Datetime(
title = u'Expiration Date',
description =
u"The date and time that the object should become unpublished."
)
class IDCExtended(Interface):
"""Extended properties
This is a mixed bag of properties we want but that we probably haven't
quite figured out yet.
"""
creators = Tuple(
title = u'Creators',
description = u"The unqualified Dublin Core 'Creator' element values",
value_type = TextLine(),
)
subjects = Tuple(
title = u'Subjects',
description = u"The unqualified Dublin Core 'Subject' element values",
value_type = TextLine(),
)
publisher = Text(
title = u'Publisher',
description =
u"The first unqualified Dublin Core 'Publisher' element value.",
)
contributors = Tuple(
title = u'Contributors',
description =
u"The unqualified Dublin Core 'Contributor' element values",
value_type = TextLine(),
)
class ICMFDublinCore(Interface):
"""This interface duplicates the CMF dublin core interface.
"""
def Title():
"""Return the resource title.
The first unqualified Dublin Core `Title` element value is
returned as a unicode string if an unqualified element is
defined, otherwise, an empty unicode string is returned.
"""
def Creator():
"""Return the resource creators.
Return the full name(s) of the author(s) of the content
object.
The unqualified Dublin Core `Creator` element values are
returned as a sequence of unicode strings.
"""
def Subject():
"""Return the resource subjects.
The unqualified Dublin Core `Subject` element values are
returned as a sequence of unicode strings.
"""
def Description():
"""Return the resource description
Return a natural language description of this object.
The first unqualified Dublin Core `Description` element value is
returned as a unicode string if an unqualified element is
defined, otherwise, an empty unicode string is returned.
"""
def Publisher():
"""Dublin Core element - resource publisher
Return full formal name of the entity or person responsible
for publishing the resource.
The first unqualified Dublin Core `Publisher` element value is
returned as a unicode string if an unqualified element is
defined, otherwise, an empty unicode string is returned.
"""
def Contributors():
"""Return the resource contributors
Return any additional collaborators.
The unqualified Dublin Core `Contributor` element values are
returned as a sequence of unicode strings.
"""
def Date():
"""Return the default date
The first unqualified Dublin Core `Date` element value is
returned as a unicode string if an unqualified element is
defined, otherwise, an empty unicode string is returned. The
string is formatted 'YYYY-MM-DD H24:MN:SS TZ'.
"""
def CreationDate():
"""Return the creation date.
The value of the first Dublin Core `Date` element qualified by
'creation' is returned as a unicode string if a qualified
element is defined, otherwise, an empty unicode string is
returned. The string is formatted 'YYYY-MM-DD H24:MN:SS TZ'.
"""
def EffectiveDate():
"""Return the effective date
The value of the first Dublin Core `Date` element qualified by
'effective' is returned as a unicode string if a qualified
element is defined, otherwise, an empty unicode string is
returned. The string is formatted 'YYYY-MM-DD H24:MN:SS TZ'.
"""
def ExpirationDate():
"""Date resource expires.
The value of the first Dublin Core `Date` element qualified by
'expiration' is returned as a unicode string if a qualified
element is defined, otherwise, an empty unicode string is
returned. The string is formatted 'YYYY-MM-DD H24:MN:SS TZ'.
"""
def ModificationDate():
"""Date resource last modified.
The value of the first Dublin Core `Date` element qualified by
'modification' is returned as a unicode string if a qualified
element is defined, otherwise, an empty unicode string is
returned. The string is formatted 'YYYY-MM-DD H24:MN:SS TZ'.
"""
def Type():
"""Return the resource type
Return a human-readable type name for the resource.
The first unqualified Dublin Core `Type` element value is
returned as a unicode string if an unqualified element is
defined, otherwise, an empty unicode string is returned.
"""
def Format():
"""Return the resource format.
Return the resource's MIME type (e.g., 'text/html',
'image/png', etc.).
The first unqualified Dublin Core `Format` element value is
returned as a unicode string if an unqualified element is
defined, otherwise, an empty unicode string is returned.
"""
def Identifier():
"""Return the URL of the resource.
This value is computed. It is included in the output of
qualifiedIdentifiers with the qualification 'url'.
"""
def Language():
"""Return the resource language.
Return the RFC language code (e.g., 'en-US', 'pt-BR')
for the resource.
The first unqualified Dublin Core `Language` element value is
returned as a unicode string if an unqualified element is
defined, otherwise, an empty unicode string is returned.
"""
def Rights():
"""Return the resource rights.
Return a string describing the intellectual property status,
if any, of the resource. for the resource.
The first unqualified Dublin Core `Rights` element value is
returned as a unicode string if an unqualified element is
defined, otherwise, an empty unicode string is returned.
"""
class IZopeDublinCore(
IGeneralDublinCore,
ICMFDublinCore,
IDCDescriptiveProperties,
IDCTimes,
IDCPublishing,
IDCExtended,
):
"""Zope Dublin Core properties"""
class IWriteZopeDublinCore(
IZopeDublinCore,
IWritableGeneralDublinCore,
):
"""Zope Dublin Core properties with generate update support"""
zope.dublincore-3.8.2/src/zope/dublincore/zopedublincore.py 0000644 0001750 0001750 00000024071 11527746247 024045 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2002 Zope Foundation 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.
#
##############################################################################
"""Zope's Dublin Core Implementation
"""
__docformat__ = 'restructuredtext'
from datetime import datetime
from zope.interface import implements
from zope.datetime import parseDatetimetz
from zope.dublincore.interfaces import IZopeDublinCore
class SimpleProperty(object):
def __init__(self, name):
self.__name__ = name
class ScalarProperty(SimpleProperty):
def __get__(self, inst, klass):
if inst is None:
return self
data = inst._mapping.get(self.__name__, ())
if data:
return data[0]
else:
return u''
def __set__(self, inst, value):
if not isinstance(value, unicode):
raise TypeError("Element must be unicode")
dict = inst._mapping
__name__ = self.__name__
inst._changed()
dict[__name__] = (value, ) + dict.get(__name__, ())[1:]
def _scalar_get(inst, name):
data = inst._mapping.get(name, ())
if data:
return data[0]
else:
return u''
class DateProperty(ScalarProperty):
def __get__(self, inst, klass):
if inst is None:
return self
data = inst._mapping.get(self.__name__, ())
if data:
return parseDatetimetz(data[0])
else:
return None
def __set__(self, inst, value):
if not isinstance(value, datetime):
raise TypeError("Element must be %s", datetime)
value = unicode(value.isoformat('T'), 'ascii')
super(DateProperty, self).__set__(inst, value)
class SequenceProperty(SimpleProperty):
def __get__(self, inst, klass):
if inst is None:
return self
return inst._mapping.get(self.__name__, ())
def __set__(self, inst, value):
value = tuple(value)
for v in value:
if not isinstance(v, unicode):
raise TypeError("Elements must be unicode")
inst._changed()
inst._mapping[self.__name__] = value
class ZopeDublinCore(object):
"""Zope Dublin Core Mixin
Subclasses should define either `_changed()` or `_p_changed`.
Just mix with `Persistence` to get a persistent version.
"""
implements(IZopeDublinCore)
def __init__(self, mapping=None):
if mapping is None:
mapping = {}
self._mapping = mapping
def _changed(self):
self._p_changed = True
title = ScalarProperty(u'Title')
def Title(self):
"See `IZopeDublinCore`"
return self.title
creators = SequenceProperty(u'Creator')
def Creator(self):
"See `IZopeDublinCore`"
return self.creators
subjects = SequenceProperty(u'Subject')
def Subject(self):
"See `IZopeDublinCore`"
return self.subjects
description = ScalarProperty(u'Description')
def Description(self):
"See `IZopeDublinCore`"
return self.description
publisher = ScalarProperty(u'Publisher')
def Publisher(self):
"See IZopeDublinCore"
return self.publisher
contributors = SequenceProperty(u'Contributor')
def Contributors(self):
"See `IZopeDublinCore`"
return self.contributors
def Date(self):
"See IZopeDublinCore"
return _scalar_get(self, u'Date')
created = DateProperty(u'Date.Created')
def CreationDate(self):
"See `IZopeDublinCore`"
return _scalar_get(self, u'Date.Created')
effective = DateProperty(u'Date.Effective')
def EffectiveDate(self):
"See `IZopeDublinCore`"
return _scalar_get(self, u'Date.Effective')
expires = DateProperty(u'Date.Expires')
def ExpirationDate(self):
"See `IZopeDublinCore`"
return _scalar_get(self, u'Date.Expires')
modified = DateProperty(u'Date.Modified')
def ModificationDate(self):
"See `IZopeDublinCore`"
return _scalar_get(self, u'Date.Modified')
type = ScalarProperty(u'Type')
def Type(self):
"See `IZopeDublinCore`"
return self.type
format = ScalarProperty(u'Format')
def Format(self):
"See `IZopeDublinCore`"
return self.format
identifier = ScalarProperty(u'Identifier')
def Identifier(self):
"See `IZopeDublinCore`"
return self.identifier
language = ScalarProperty(u'Language')
def Language(self):
"See `IZopeDublinCore`"
return self.language
rights = ScalarProperty(u'Rights')
def Rights(self):
"See `IZopeDublinCore`"
return self.rights
def setQualifiedTitles(self, qualified_titles):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Title', qualified_titles)
def setQualifiedCreators(self, qualified_creators):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Creator', qualified_creators)
def setQualifiedSubjects(self, qualified_subjects):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Subject', qualified_subjects)
def setQualifiedDescriptions(self, qualified_descriptions):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Description', qualified_descriptions)
def setQualifiedPublishers(self, qualified_publishers):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Publisher', qualified_publishers)
def setQualifiedContributors(self, qualified_contributors):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Contributor', qualified_contributors)
def setQualifiedDates(self, qualified_dates):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Date', qualified_dates)
def setQualifiedTypes(self, qualified_types):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Type', qualified_types)
def setQualifiedFormats(self, qualified_formats):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Format', qualified_formats)
def setQualifiedIdentifiers(self, qualified_identifiers):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Identifier', qualified_identifiers)
def setQualifiedSources(self, qualified_sources):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Source', qualified_sources)
def setQualifiedLanguages(self, qualified_languages):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Language', qualified_languages)
def setQualifiedRelations(self, qualified_relations):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Relation', qualified_relations)
def setQualifiedCoverages(self, qualified_coverages):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Coverage', qualified_coverages)
def setQualifiedRights(self, qualified_rights):
"See `IWritableDublinCore`"
return _set_qualified(self, u'Rights', qualified_rights)
def getQualifiedTitles(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Title')
def getQualifiedCreators(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Creator')
def getQualifiedSubjects(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Subject')
def getQualifiedDescriptions(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Description')
def getQualifiedPublishers(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Publisher')
def getQualifiedContributors(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Contributor')
def getQualifiedDates(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Date')
def getQualifiedTypes(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Type')
def getQualifiedFormats(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Format')
def getQualifiedIdentifiers(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Identifier')
def getQualifiedSources(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Source')
def getQualifiedLanguages(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Language')
def getQualifiedRelations(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Relation')
def getQualifiedCoverages(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Coverage')
def getQualifiedRights(self):
"See `IStandardDublinCore`"
return _get_qualified(self, u'Rights')
def _set_qualified(self, name, qvalue):
data = {}
dict = self._mapping
for qualification, value in qvalue:
data[qualification] = data.get(qualification, ()) + (value, )
self._changed()
for qualification, values in data.iteritems():
qname = qualification and (name + '.' + qualification) or name
dict[qname] = values
def _get_qualified(self, name):
result = []
for aname, avalue in self._mapping.iteritems():
if aname == name:
qualification = u''
for value in avalue:
result.append((qualification, value))
elif aname.startswith(name):
qualification = aname[len(name)+1:]
for value in avalue:
result.append((qualification, value))
return tuple(result)
__doc__ = ZopeDublinCore.__doc__ + __doc__
zope.dublincore-3.8.2/src/zope/dublincore/annotatableadapter.py 0000644 0001750 0001750 00000010300 11527746247 024640 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2002 Zope Foundation 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.
#
##############################################################################
"""Dublin Core Annotatable Adapter
"""
__docformat__ = 'restructuredtext'
from persistent.dict import PersistentDict
from zope.annotation.interfaces import IAnnotatable
from zope.annotation.interfaces import IAnnotations
from zope.component import adapts
from zope.interface import implements
from zope.location import Location
from zope.dublincore.interfaces import IWriteZopeDublinCore
from zope.dublincore.zopedublincore import DateProperty
from zope.dublincore.zopedublincore import ScalarProperty
from zope.dublincore.zopedublincore import ZopeDublinCore
DCkey = "zope.app.dublincore.ZopeDublinCore"
class ZDCAnnotatableAdapter(ZopeDublinCore, Location):
"""Adapt annotatable objects to Zope Dublin Core."""
implements(IWriteZopeDublinCore)
adapts(IAnnotatable)
annotations = None
def __init__(self, context):
annotations = IAnnotations(context)
dcdata = annotations.get(DCkey)
if dcdata is None:
self.annotations = annotations
dcdata = ZDCAnnotationData()
super(ZDCAnnotatableAdapter, self).__init__(dcdata)
def _changed(self):
if self.annotations is not None:
self.annotations[DCkey] = self._mapping
self.annotations = None
class ZDCAnnotationData(PersistentDict):
"""Data for a Dublin Core annotation.
A specialized class is used to allow an alternate fssync
serialization to be registered. See the
zope.dublincore.fssync package.
"""
# Hybrid adapters.
#
# Adapter factories created using this support the Dublin Core using a
# mixture of annotations and data on the context object.
class DirectProperty(object):
def __init__(self, name, attrname):
self.__name__ = name
self.__attrname = attrname
def __get__(self, inst, klass):
if inst is None:
return self
context = inst._ZDCPartialAnnotatableAdapter__context
return getattr(context, self.__attrname, u"")
def __set__(self, inst, value):
if not isinstance(value, unicode):
raise TypeError("Element must be unicode")
context = inst._ZDCPartialAnnotatableAdapter__context
oldvalue = getattr(context, self.__attrname, None)
if oldvalue != value:
setattr(context, self.__attrname, value)
def partialAnnotatableAdapterFactory(direct_fields):
if not direct_fields:
raise ValueError("only use partialAnnotatableAdapterFactory()"
" if at least one DC field is implemented directly")
fieldmap = {}
try:
# is direct_fields a sequence or a mapping?
direct_fields[0]
except KeyError:
# direct_fields: { dc_name: attribute_name }
fieldmap.update(direct_fields)
else:
for attrname in direct_fields:
fieldmap[attrname] = attrname
class ZDCPartialAnnotatableAdapter(ZDCAnnotatableAdapter):
def __init__(self, context):
self.__context = context
# can't use super() since this isn't a globally available class
ZDCAnnotatableAdapter.__init__(self, context)
for dcname, attrname in fieldmap.iteritems():
oldprop = ZopeDublinCore.__dict__.get(dcname)
if oldprop is None:
raise ValueError("%r is not a valid DC field" % dcname)
if (isinstance(oldprop, DateProperty)
or not isinstance(oldprop, ScalarProperty)):
raise ValueError("%r is not a supported DC field" % dcname)
prop = DirectProperty(dcname, attrname)
setattr(ZDCPartialAnnotatableAdapter, dcname, prop)
return ZDCPartialAnnotatableAdapter
zope.dublincore-3.8.2/src/zope/dublincore/timeannotators.py 0000644 0001750 0001750 00000003425 11527746247 024070 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2002 Zope Foundation 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.
#
##############################################################################
"""Objects that take care of annotating dublin core meta data times
"""
__docformat__ = 'restructuredtext'
from datetime import datetime
import pytz
from zope.dublincore.interfaces import IZopeDublinCore
from zope.security.proxy import removeSecurityProxy
def ModifiedAnnotator(object, event=None):
if event is None:
# annotator was only called the event as only argument
object = object.object
dc = IZopeDublinCore(object, None)
if dc is not None:
# Principals that can modify objects do not necessary have permissions
# to arbitrarily modify DC data, see issue 373
dc = removeSecurityProxy(dc)
dc.modified = datetime.now(pytz.utc)
def CreatedAnnotator(object, event=None):
if event is None:
# annotator was only called the event as only argument
object = object.object
dc = IZopeDublinCore(object, None)
if dc is not None:
# Principals that can create objects do not necessary have permissions
# to arbitrarily modify DC data, see issue 373
dc = removeSecurityProxy(dc)
now = datetime.now(pytz.utc)
dc.created = now
dc.modified = now
zope.dublincore-3.8.2/src/zope/dublincore/configure.zcml 0000644 0001750 0001750 00000003724 11527746247 023321 0 ustar tseaver tseaver
zope.dublincore-3.8.2/src/zope/dublincore/xmlmetadata.py 0000644 0001750 0001750 00000017123 11527746247 023322 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2003 Zope Foundation 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.
#
##############################################################################
"""Dublin Core XML data parser and writer
"""
__docformat__ = 'restructuredtext'
import xml.sax
import xml.sax.handler
from cStringIO import StringIO
from xml.sax.saxutils import escape, quoteattr
from zope.dublincore import dcterms
XSI_TYPE = (dcterms.XSI_NS, "type")
dublin_core_namespaces = dcterms.DC_NS, dcterms.DCTERMS_NS
DEFAULT_NAMESPACE_PREFIXES = {
# uri: prefix,
dcterms.DC_NS: "dc",
dcterms.DCTERMS_NS: "dcterms",
dcterms.XSI_NS: "xsi",
}
class NamespaceTracker(object):
def __init__(self, mapping=None):
self._mapping = {}
self._used = {}
if mapping:
self._mapping.update(mapping)
self._counter = 0
def encode(self, (uri, localname)):
if not uri:
return localname
if uri not in self._mapping:
self._counter += 1
prefix = "ns%d" % self._counter
self._mapping[uri] = prefix
self._used[prefix] = uri
else:
prefix = self._mapping[uri]
if prefix not in self._used:
self._used[prefix] = uri
if prefix:
return "%s:%s" % (prefix, localname)
else:
return localname
def getPrefixMappings(self):
return self._used.items()
def dumpString(mapping):
sio = StringIO()
nsmap = NamespaceTracker(DEFAULT_NAMESPACE_PREFIXES)
items = mapping.items()
items.sort()
prev = None
for name, values in items:
name, type = dcterms.splitEncoding(name)
group = name.split(".", 1)[0]
if prev != group:
sio.write("\n")
prev = group
if name in dcterms.name_to_element:
element, t = dcterms.name_to_element[name]
qname = nsmap.encode(element)
if not type:
type = t
if type:
type = " %s=%s" % (nsmap.encode((dcterms.XSI_NS, "type")),
quoteattr(type))
for value in values:
sio.write(" <%s%s>\n %s\n %s>\n"
% (qname, type, _encode_string(value), qname))
else:
raise RuntimeError("could not serialize %r metadata element"
% name)
content = sio.getvalue()
sio = StringIO()
sio.write("\n"
"\n")
sio.write(content)
sio.write("\n")
return sio.getvalue()
try:
unicode
except NameError:
_encode_string = escape
else:
def _encode_string(s):
if isinstance(s, unicode):
s = s.encode('utf-8')
return escape(s)
def parse(source, error_handler=None):
parser, ch = _setup_parser(error_handler)
parser.parse(source)
return ch.mapping
def parseString(text, error_handler=None):
parser, ch = _setup_parser(error_handler)
parser.feed(text)
parser.close()
return ch.mapping
def _setup_parser(error_handler):
parser = xml.sax.make_parser()
ch = DublinCoreHandler()
parser.setFeature(xml.sax.handler.feature_namespaces, True)
parser.setContentHandler(ch)
if error_handler is not None:
parser.setErrorHandler(error_handler)
return parser, ch
class PrefixManager(object):
# We don't use this other than in the DublinCoreHandler, but it's
# entirely general so we'll separate it out for now.
"""General handler for namespace prefixes.
This should be used as a mix-in when creating a ContentHandler.
"""
__prefix_map = None
def startPrefixMapping(self, prefix, uri):
if self.__prefix_map is None:
self.__prefix_map = {}
pm = self.__prefix_map
pm.setdefault(prefix, []).append(uri)
def endPrefixMapping(self, prefix):
pm = self.__prefix_map
uris = pm[prefix]
del uris[-1]
if not uris:
del pm[prefix]
def get_uri(self, prefix):
pm = self.__prefix_map
if pm is None:
return None
if prefix in pm:
return pm[prefix][-1]
else:
return None
class DublinCoreHandler(PrefixManager, xml.sax.handler.ContentHandler):
def startDocument(self):
self.mapping = {}
self.stack = []
def get_dc_container(self):
name = None
for (uri, localname), dcelem, validator in self.stack:
if uri in dublin_core_namespaces:
name = uri, localname
if name in dcterms.element_to_name:
# dcelem contains type info, so go back to the mapping
return dcterms.element_to_name[name]
else:
return None
def startElementNS(self, name, qname, attrs):
self.buffer = u""
# TODO: need convert element to metadata element name
dcelem = validator = None
if name in dcterms.element_to_name:
dcelem = dcterms.element_to_name[name]
type = attrs.get(XSI_TYPE)
if type:
if not dcelem:
raise ValueError(
"data type specified for unknown metadata element: %s"
% qname)
if ":" in type:
prefix, t = type.split(":", 1)
ns = self.get_uri(prefix)
if ns != dcterms.DCTERMS_NS:
raise ValueError("unknown data type namespace: %s" % t)
type = t
if type not in dcterms.encodings:
raise ValueError("unknown data type: %r" % type)
allowed_in, validator = dcterms.encodings[type]
dcelem_split = dcelem.split(".")
for elem in allowed_in:
elem_split = elem.split(".")
if dcelem_split[:len(elem_split)] == elem_split:
break
else:
raise ValueError("%s values are not allowed for %r"
% (type, dcelem))
dcelem = "%s.%s" % (dcelem, type)
if dcelem:
cont = self.get_dc_container()
if cont and cont != dcelem:
prefix = cont + "."
if not dcelem.startswith(prefix):
raise ValueError("%s is not a valid refinement for %s"
% (dcelem, cont))
self.stack.append((name, dcelem, validator))
def endElementNS(self, name, qname):
startname, dcelem, validator = self.stack.pop()
assert startname == name
if self.buffer is None:
return
data = self.buffer.strip()
self.buffer = None
if not dcelem:
return
if validator is not None:
validator(data)
if dcelem in self.mapping:
self.mapping[dcelem] += (data,)
else:
self.mapping[dcelem] = (data,)
def characters(self, data):
if self.buffer is not None:
self.buffer += data
zope.dublincore-3.8.2/src/zope/dublincore/security.zcml 0000644 0001750 0001750 00000000744 11527746247 023206 0 ustar tseaver tseaver
zope.dublincore-3.8.2/src/zope/dublincore/tests/ 0000755 0001750 0001750 00000000000 11527746337 021605 5 ustar tseaver tseaver zope.dublincore-3.8.2/src/zope/dublincore/tests/test_zcml.py 0000644 0001750 0001750 00000002441 11527746247 024164 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2010 Zope Foundation 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.
#
##############################################################################
""" Tests that ZCML can be loaded.
"""
import unittest
class ZCMLTests(unittest.TestCase):
from zope.component.testing import setUp
from zope.component.testing import tearDown
def test_loadable(self):
# N.B.: this test deliberately avoids any "ftesting" / layers
# support: its purpose is to ensure that the package's
# ZCML file is loadable *without* loading any other ZCML.
from zope.configuration.xmlconfig import file
import zope.dublincore
return file('configure.zcml', package=zope.dublincore)
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(ZCMLTests),
))
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_property.py 0000644 0001750 0001750 00000002506 11527746247 025105 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2006 Zope Foundation 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.
#
##############################################################################
"""Test the Dublin Core Property implementation
"""
__docformat__ = "reStructuredText"
import doctest
import unittest
from zope import component
from zope.testing import cleanup
from zope.annotation.attribute import AttributeAnnotations
from zope.dublincore import testing
def setUp(test):
cleanup.setUp()
component.provideAdapter(AttributeAnnotations)
testing.setUpDublinCore()
def tearDown(test):
cleanup.tearDown()
def test_suite():
return unittest.TestSuite(
(
doctest.DocFileSuite(
'../property.txt',
setUp=setUp,
tearDown=tearDown,
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
),
))
zope.dublincore-3.8.2/src/zope/dublincore/tests/timeannotators.txt 0000644 0001750 0001750 00000006161 11527746247 025421 0 ustar tseaver tseaver ===============
Time annotators
===============
Time annotators store the creation resp. last modification time of an object.
Set up
======
>>> class Content(object):
... created = None
... modified = None
The annotations are stored on the ``IZopeDublinCore`` adapter. This dummy adapter
reads and writes from/to the context object.
>>> import zope.component
>>> import zope.dublincore.interfaces
>>> class DummyDublinCore(object):
... def __init__(self, context):
... self.__dict__['context'] = context
...
... def __getattr__(self, name):
... return getattr(self.context, name)
...
... def __setattr__(self, name, value):
... setattr(self.context, name, value)
>>> zope.component.provideAdapter(
... DummyDublinCore, (Content,), zope.dublincore.interfaces.IZopeDublinCore)
Created annotator
=================
The created annotator sets creation and modification time to current time.
>>> content = Content()
It is registered for the ``ObjectCreatedEvent``:
>>> import zope.dublincore.timeannotators
>>> import zope.lifecycleevent.interfaces
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.CreatedAnnotator,
... (zope.lifecycleevent.interfaces.IObjectCreatedEvent,))
>>> import zope.event
>>> import zope.lifecycleevent
>>> zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(content))
Both ``created`` and ``modified`` get set:
>>> content.created
datetime.datetime(, tzinfo=)
>>> content.modified
datetime.datetime(, tzinfo=)
The created annotator can also be registered for (object, event):
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.CreatedAnnotator,
... (None,
... zope.lifecycleevent.interfaces.IObjectCreatedEvent,))
>>> content = Content()
>>> ignored = zope.component.subscribers(
... (content, zope.lifecycleevent.ObjectCreatedEvent(content)), None)
Both ``created`` and ``modified`` get set this way, too:
>>> content.created
datetime.datetime(, tzinfo=)
>>> content.modified
datetime.datetime(, tzinfo=)
Modified annotator
==================
The modified annotator only sets the modification time to current time.
>>> content = Content()
It is registered for the ``ObjectModifiedEvent``:
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.ModifiedAnnotator,
... (zope.lifecycleevent.interfaces.IObjectModifiedEvent,))
>>> zope.event.notify(zope.lifecycleevent.ObjectModifiedEvent(content))
Only ``modified`` gets set:
>>> print content.created
None
>>> content.modified
datetime.datetime(, tzinfo=)
The modified annotator can also be registered for (object, event):
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.ModifiedAnnotator,
... (None,
... zope.lifecycleevent.interfaces.IObjectModifiedEvent,))
>>> content = Content()
>>> ignored = zope.component.subscribers(
... (content, zope.lifecycleevent.ObjectModifiedEvent(content)), None)
``modified`` gets set, this way, too:
>>> print content.created
None
>>> content.modified
datetime.datetime(, tzinfo=)
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_timeannotators.py 0000644 0001750 0001750 00000002227 11527746247 026270 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2010 Zope Foundation 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.
#
##############################################################################
"""Test time annotator.
"""
import doctest
import zope.testing.renormalizing
import re
datetime_re = (
'[0-9]{4}, ' # YYYY
'[0-9]{1,2}, ' # MM
'[0-9]{1,2}, ' # DD
'[0-9]{1,2}, ' # HH
'[0-9]{1,2}, ' # MM
'[0-9]{1,2}' # SS
'(, [0-9]{1,6})?' # uSec (skipped if 0)
)
def test_suite():
return doctest.DocFileSuite(
'timeannotators.txt',
checker=zope.testing.renormalizing.RENormalizing(
[(re.compile(datetime_re), '')])
)
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_annotatableadapter.py 0000644 0001750 0001750 00000020561 11527746247 027053 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2009 Zope Foundation 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.
#
##############################################################################
"""Tests annotatableadapter.
"""
import unittest
_marker = object()
class ZDCAnnotatableAdapterTests(unittest.TestCase):
_registered = False
def setUp(self):
from zope.testing.cleanup import cleanUp
cleanUp()
def tearDown(self):
from zope.testing.cleanup import cleanUp
cleanUp()
def _getTargetClass(self):
from zope.dublincore.annotatableadapter import ZDCAnnotatableAdapter
return ZDCAnnotatableAdapter
def _registerAnnotations(self, dcdata=None):
from zope.component import provideAdapter
from zope.interface import Interface
from zope.annotation.interfaces import IAnnotations
from zope.dublincore.annotatableadapter import DCkey
class _Annotations(dict):
pass
instance = _Annotations({DCkey: dcdata})
def _factory(context):
return instance
if not self._registered:
provideAdapter(_factory, (Interface, ), IAnnotations)
self._registered = True
return instance
def _makeOne(self, context=_marker):
if context is _marker:
context = self._makeContext()
return self._getTargetClass()(context)
def _makeContext(self):
class DummyContext(object):
pass
return DummyContext()
def test_class_conforms_to_IWriteZopeDublinCore(self):
from zope.interface.verify import verifyClass
from zope.dublincore.interfaces import IWriteZopeDublinCore
verifyClass(IWriteZopeDublinCore, self._getTargetClass())
def test_instance_conforms_to_IWriteZopeDublinCore(self):
from zope.interface.verify import verifyObject
from zope.dublincore.interfaces import IWriteZopeDublinCore
self._registerAnnotations()
verifyObject(IWriteZopeDublinCore, self._makeOne())
def test_ctor_wo_existing_DC_annotations(self):
from zope.dublincore.annotatableadapter import DCkey
self._registerAnnotations()
context = self._makeContext()
adapter = self._makeOne(context)
self.assertEqual(adapter.annotations[DCkey], None)
self.assertEqual(adapter._mapping, {})
def test_ctor_w_existing_DC_annotations(self):
DCDATA = {'title': 'TITLE'}
self._registerAnnotations(DCDATA)
context = self._makeContext()
adapter = self._makeOne(context)
self.assertEqual(adapter.annotations, None)
self.assertEqual(adapter._mapping, DCDATA)
def test__changed_wo_existing_DC_annotations(self):
from zope.dublincore.annotatableadapter import DCkey
annotations = self._registerAnnotations()
context = self._makeContext()
adapter = self._makeOne(context)
adapter._mapping['title'] = 'NEW TITLE'
adapter._changed()
self.assertEqual(annotations[DCkey]['title'], 'NEW TITLE')
def test__changed_w_existing_DC_annotations(self):
from zope.dublincore.annotatableadapter import DCkey
DCDATA = {'title': 'TITLE'}
annotations = self._registerAnnotations(DCDATA)
context = self._makeContext()
adapter = self._makeOne(context)
adapter._changed()
self.assertEqual(annotations[DCkey]['title'], 'TITLE') #unchanged
class DirectPropertyTests(unittest.TestCase):
def _getTargetClass(self):
from zope.dublincore.annotatableadapter import DirectProperty
return DirectProperty
def _makeOne(self, name, attrname):
return self._getTargetClass()(name, attrname)
def test___get___via_klass(self):
prop = self._makeOne('title', 'headline')
class Testing(object):
title = prop
self.failUnless(Testing.title is prop)
def test___get___via_instance(self):
prop = self._makeOne('title', 'headline')
class Context(object):
headline = u'HEADLINE'
class ZDCPartialAnnotatableAdapter(object):
title = prop
def __init__(self, context):
self.__context = context
context = Context()
testing = ZDCPartialAnnotatableAdapter(context)
self.assertEqual(testing.title, u'HEADLINE')
def test___set___non_unicode_raises(self):
prop = self._makeOne('title', 'headline')
class Context(object):
headline = u'HEADLINE'
class ZDCPartialAnnotatableAdapter(object):
title = prop
def __init__(self, context):
self.__context = context
context = Context()
testing = ZDCPartialAnnotatableAdapter(context)
try:
testing.title = 123
except TypeError:
pass
else:
self.fail("Didn't raise TypeError")
def test___set___unchanged_doesnt_mutate(self):
prop = self._makeOne('title', 'headline')
class Context(object):
headline = u'HEADLINE'
def __setattr__(self, name, value):
assert 0
class ZDCPartialAnnotatableAdapter(object):
title = prop
def __init__(self, context):
self.__context = context
context = Context()
testing = ZDCPartialAnnotatableAdapter(context)
testing.title = u'HEADLINE' # doesn't raise
def test___set___changed_mutates(self):
prop = self._makeOne('title', 'headline')
class Context(object):
headline = u'HEADLINE1'
class ZDCPartialAnnotatableAdapter(object):
title = prop
def __init__(self, context):
self.__context = context
context = Context()
testing = ZDCPartialAnnotatableAdapter(context)
testing.title = u'HEADLINE2'
self.assertEqual(context.headline, u'HEADLINE2')
class Test_partialAnnotatableAdapterFactory(unittest.TestCase):
def _callFUT(self, direct_fields):
from zope.dublincore.annotatableadapter \
import partialAnnotatableAdapterFactory
return partialAnnotatableAdapterFactory(direct_fields)
def test_w_empty_list_raises(self):
self.assertRaises(ValueError, self._callFUT, [])
def test_w_empty_dict_raises(self):
self.assertRaises(ValueError, self._callFUT, {})
def test_w_unknown_field_raises(self):
self.assertRaises(ValueError, self._callFUT, ['nonesuch'])
def test_w_date_fields_raises(self):
self.assertRaises(ValueError, self._callFUT, ['created'])
self.assertRaises(ValueError, self._callFUT, ['modified'])
self.assertRaises(ValueError, self._callFUT, ['effective'])
self.assertRaises(ValueError, self._callFUT, ['expires'])
def test_w_sequence_fields_raises(self):
self.assertRaises(ValueError, self._callFUT, ['creators'])
self.assertRaises(ValueError, self._callFUT, ['subjects'])
self.assertRaises(ValueError, self._callFUT, ['contributors'])
def test_w_scalar_prop_samename(self):
from zope.dublincore.annotatableadapter import DirectProperty
klass = self._callFUT(['title'])
prop = klass.title
self.failUnless(isinstance(prop, DirectProperty))
self.assertEqual(prop.__name__, 'title')
self.assertEqual(prop._DirectProperty__attrname, 'title') # XXX
def test_w_scalar_prop_mapped(self):
from zope.dublincore.annotatableadapter import DirectProperty
klass = self._callFUT({'title': 'headline'})
prop = klass.title
self.failUnless(isinstance(prop, DirectProperty))
self.assertEqual(prop.__name__, 'title')
self.assertEqual(prop._DirectProperty__attrname, 'headline') # XXX
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(ZDCAnnotatableAdapterTests),
unittest.makeSuite(DirectPropertyTests),
unittest.makeSuite(Test_partialAnnotatableAdapterFactory),
))
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_xmlmetadata.py 0000644 0001750 0001750 00000030755 11527746247 025531 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2003 Zope Foundation 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.
#
##############################################################################
"""Test loading of Dublin Core metadata from the XML representation.
"""
import unittest
from zope.dublincore import dcterms
from zope.dublincore.xmlmetadata import dumpString, parseString
class XMLDublinCoreLoadingTests(unittest.TestCase):
# Note: We're not using the 'traditional' namespace prefixes in
# the tests since we want to make sure we're doing the right thing
# in the content handler. Also, we should use something we're not
# using in zope.dublincore.dcterms.
_prefix = ("\n"
"\n"
% (dcterms.DC_NS, dcterms.DCTERMS_NS, dcterms.XSI_NS))
_suffix = "\n"
def parse(self, text):
return parseString("%s%s%s" % (self._prefix, text, self._suffix))
def check1(self, text, name, value, generic=None):
expected = {name: (value,)}
m = self.parse(text)
self.assertEqual(m, expected)
m = self.parse("%s" % text)
self.assertEqual(m, expected)
if generic:
m = self.parse("<%s>%s%s>" % (generic, text, generic))
self.assertEqual(m, expected)
m = self.parse("<%s>%s%s>"
% (generic, text, generic))
self.assertEqual(m, expected)
# tests with acceptable input
def test_empty(self):
m = parseString("")
self.assertEqual(m, {})
# core elements and related refinements
def test_simple_title(self):
self.check1("Foo", "Title", u"Foo")
def test_two_titles(self):
m = self.parse("Foo"
"Bar")
self.assertEqual(m, {"Title": (u"Foo", u"Bar")})
def test_alternative_title(self):
m = self.parse("Foo"
"Bar")
self.assertEqual(m, {"Title": (u"Foo",),
"Title.Alternative": (u"Bar",)})
def test_creator(self):
self.check1("somebody",
"Creator", "somebody")
def test_subject(self):
self.check1("something",
"Subject", "something")
self.check1("something",
"Subject.LCSH", "something")
self.check1("something",
"Subject.MESH", "something")
self.check1("something",
"Subject.DDC", "something")
self.check1("something",
"Subject.LCC", "something")
self.check1("something",
"Subject.UDC", "something")
def test_description(self):
self.check1("foo",
"Description", "foo")
self.check1("foo",
"Description.Abstract", "foo", generic="d:description")
self.check1("foo",
"Description.Table Of Contents", "foo",
generic="d:description")
def test_publisher(self):
self.check1("pub",
"Publisher", "pub")
def test_contributor(self):
self.check1("somebody",
"Contributor", "somebody")
def test_date(self):
self.check1("2003-08-20",
"Date", "2003-08-20")
# refinements used by Zope
self.check1("2003-08-20",
"Date.Created", "2003-08-20", generic="d:date")
self.check1("2003-08-20",
"Date.Modified", "2003-08-20", generic="d:date")
# other refinements
self.check1("2003-08-20",
"Date.Accepted", "2003-08-20", generic="d:date")
self.check1("2003-08-20",
"Date.Available", "2003-08-20", generic="d:date")
self.check1("2003-08-20",
"Date.Copyrighted", "2003-08-20", generic="d:date")
self.check1("2003-08-20",
"Date.Issued", "2003-08-20", generic="d:date")
self.check1("2003-08-20",
"Date.Submitted", "2003-08-20", generic="d:date")
self.check1("2003-08-20",
"Date.Valid", "2003-08-20", generic="d:date")
def test_type(self):
self.check1("some type",
"Type", "some type")
self.check1("Collection",
"Type.DCMIType", "Collection")
def test_format(self):
self.check1("some format",
"Format", "some format")
self.check1("text/xml",
"Format.IMT", "text/xml")
self.check1("1 hour",
"Format.Extent", "1 hour", generic="d:format")
self.check1("70mm IMAX celluloid",
"Format.Medium", "70mm IMAX celluloid", generic="d:format")
def test_identifier(self):
self.check1("ident",
"Identifier", "ident")
self.check1(""
" citation "
"",
"Identifier.Bibliographic Citation", "citation",
generic="d:identifier")
def test_source(self):
self.check1("src",
"Source", "src")
self.check1("http://example.com/",
"Source.URI", "http://example.com/")
def test_language(self):
self.check1("Klingon",
"Language", "Klingon")
self.check1("abc",
"Language.ISO639-2", "abc")
self.check1("en",
"Language.RFC1766", "en")
self.check1("en-GB-oed",
"Language.RFC3066", "en-GB-oed")
def test_relation(self):
self.check1("rel",
"Relation", "rel")
self.check1("that",
"Relation.Is Version Of", "that", generic="d:relation")
self.check1("that",
"Relation.Has Version", "that", generic="d:relation")
self.check1("that",
"Relation.Is Replaced By", "that", generic="d:relation")
self.check1("that",
"Relation.Replaces", "that", generic="d:relation")
self.check1("that",
"Relation.Is Required By", "that", generic="d:relation")
self.check1("that",
"Relation.Requires", "that", generic="d:relation")
self.check1("that",
"Relation.Is Part Of", "that", generic="d:relation")
self.check1("that",
"Relation.Has Part", "that", generic="d:relation")
self.check1("that",
"Relation.Is Referenced By", "that", generic="d:relation")
self.check1("that",
"Relation.References", "that", generic="d:relation")
self.check1("that",
"Relation.Is Format Of", "that", generic="d:relation")
self.check1("that",
"Relation.Has Format", "that", generic="d:relation")
self.check1("that",
"Relation.Conforms To", "that", generic="d:relation")
def test_coverage(self):
self.check1("how much",
"Coverage", "how much")
self.check1("where",
"Coverage.Spatial", "where", generic="d:coverage")
self.check1("when",
"Coverage.Temporal", "when", generic="d:coverage")
self.check1(""
" name=Period Name; start=1812; end=2112; "
"",
"Coverage.Temporal.Period",
"name=Period Name; start=1812; end=2112;",
generic="d:coverage")
self.check1("2003-08-20",
"Coverage.Temporal.W3CDTF", "2003-08-20",
generic="d:coverage")
def test_rights(self):
self.check1("rights",
"Rights", "rights")
self.check1("rights",
"Rights.Access Rights", "rights", generic="d:rights")
# non-core elements
def test_audience(self):
# Audience is the only DCMI element not in the core
self.check1("people",
"Audience", "people")
self.check1("people",
"Audience.Education Level", "people", generic="t:audience")
self.check1("people",
"Audience.Mediator", "people", generic="t:audience")
def test_nested_refinement(self):
# direct nesting
self.check1((""
"Foo"
""),
"Title.Alternative", u"Foo")
# nesting with an intermediate element
self.check1((""
"Foo"
""),
"Title.Alternative", u"Foo")
# tests with errors in the input
def test_invalid_nested_refinement(self):
self.assertRaises(ValueError, self.parse,
(""
"Title"
""))
self.assertRaises(ValueError, self.parse,
(""
"Title"
""))
def test_invalid_type(self):
self.assertRaises(ValueError, self.parse,
"x")
def test_invalid_dcmitype(self):
self.assertRaises(ValueError, self.parse,
"flub")
class XMLDublinCoreSerializationTests(unittest.TestCase):
def roundtrip(self, mapping):
text = dumpString(mapping)
parsed = parseString(text)
self.assertEqual(parsed, mapping)
def test_serialize_empty(self):
self.roundtrip({})
def test_single_entry(self):
self.roundtrip({"Title.Alternative": (u"Foo",)})
def test_two_titles(self):
self.roundtrip({"Title": (u"Foo", u"Bar")})
def test_suite():
suite = unittest.makeSuite(XMLDublinCoreLoadingTests)
suite.addTest(unittest.makeSuite(XMLDublinCoreSerializationTests))
return suite
if __name__ == "__main__":
unittest.main(defaultTest="test_suite")
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_zopedublincore.py 0000644 0001750 0001750 00000016676 11527746247 026262 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation 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.
#
##############################################################################
"""Test Zope's Dublin Core implementation
"""
from unittest import TestCase, TestSuite, main, makeSuite
class Test(TestCase):
def testImplementa(self):
from zope.interface.verify import verifyObject
from zope.dublincore.interfaces import IZopeDublinCore
verifyObject(IZopeDublinCore, self.dc)
def _Test__new(self):
from zope.dublincore.zopedublincore import ZopeDublinCore
return ZopeDublinCore()
def setUp(self):
self.dc = self._Test__new()
def __testGetQualified(self, name, values):
ovalues = getattr(self.dc, 'getQualified'+name)()
ivalues = list(values)
ivalues.sort()
ovalues = list(ovalues)
ovalues.sort()
self.assertEqual(ovalues, ivalues)
def __testQualified(self, name,
values = [
(u'', u'blah blah'),
(u'old', u'bleep bleep'),
(u'old', u'bleep bleep \u1111'),
(u'foo\u1111', u'bleep bleep'),
]
):
getattr(self.dc, 'setQualified'+name)(values)
self.__testGetQualified(name, values)
def testOtherQualified(self):
for name in ('Sources', 'Relations', 'Coverages'):
self.__testQualified(name)
def testScalars(self):
for qname, mname, pname in (
('Titles', 'Title', 'title'),
('Descriptions', 'Description', 'description'),
('Publishers', 'Publisher', 'publisher'),
('Types', 'Type', 'type'),
('Formats', 'Format', 'format'),
('Identifiers', 'Identifier', 'identifier'),
('Languages', 'Language', 'language'),
('Rights', 'Rights', 'rights'),
):
self.__testQualified(qname)
dc = self.dc
self.assertEqual(getattr(dc, pname), u'blah blah')
self.assertEqual(getattr(dc, mname)(), u'blah blah')
self.assertRaises(Exception, setattr, dc, pname, 'foo')
setattr(dc, pname, u'foo')
self.assertEqual(getattr(dc, pname), u'foo')
self.assertEqual(getattr(dc, mname)(), u'foo')
self.__testGetQualified(qname,
[
(u'', u'foo'),
(u'old', u'bleep bleep'),
(u'old', u'bleep bleep \u1111'),
(u'foo\u1111', u'bleep bleep'),
]
)
def testSequences(self):
for qname, mname, pname in (
('Creators', 'Creator', 'creators'),
('Subjects', 'Subject', 'subjects'),
('Contributors', 'Contributors', 'contributors'),
):
self.__testQualified(qname, [
(u'', u'foo'),
(u'', u'bar'),
(u'', u'baz'),
(u'', u'baz\u1111'),
(u'old', u'bleep bleep'),
(u'old', u'bleep bleep \u1111'),
(u'foo\u1111', u'bleep bleep'),
]
)
dc = self.dc
v = getattr(dc, pname)
v = list(v)
v.sort()
self.assertEqual(v, [u'bar', u'baz', u'baz\u1111', u'foo'])
v = getattr(dc, mname)()
v = list(v)
v.sort()
self.assertEqual(v, [u'bar', u'baz', u'baz\u1111', u'foo'])
self.assertRaises(Exception, setattr, dc, pname, 'foo')
self.assertRaises(Exception, setattr, dc, pname, ['foo'])
setattr(dc, pname, [u'high', u'low', u'spam', u'eggs', u'ham', ])
v = getattr(dc, pname)
v = list(v)
v.sort()
self.assertEqual(v, [u'eggs', u'ham', u'high', u'low', u'spam'])
v = getattr(dc, mname)()
v = list(v)
v.sort()
self.assertEqual(v, [u'eggs', u'ham', u'high', u'low', u'spam'])
self.__testGetQualified(qname,
[
(u'', u'high'),
(u'', u'low'),
(u'', u'spam'),
(u'', u'eggs'),
(u'', u'ham'),
(u'old', u'bleep bleep'),
(u'old', u'bleep bleep \u1111'),
(u'foo\u1111', u'bleep bleep'),
]
)
def testDates(self):
self.__testQualified('Dates', [
(u'', u'1990-01-01'),
(u'Created', u'1980-10-01T23:11:10-04:00'),
(u'Modified', u'2002-10-01T12:09:22-04:00'),
(u'Effective', u'2002-10-09T00:00:00-04:00'),
(u'Expires', u'2002-10-16T00:00:00-04:00'),
(u'xxx', u'2000-07-04'),
(u'xxx', u'2001-12-31'),
(u'foo \u1111', u'2001-12-31'),
])
from zope.datetime import parseDatetimetz
dc = self.dc
self.assertEqual(dc.created,
parseDatetimetz('1980-10-01T23:11:10-04:00'))
self.assertEqual(dc.modified,
parseDatetimetz('2002-10-01T12:09:22-04:00'))
self.assertEqual(dc.effective,
parseDatetimetz('2002-10-09T00:00:00-04:00'))
self.assertEqual(dc.expires,
parseDatetimetz('2002-10-16T00:00:00-04:00'))
self.assertEqual(dc.Date(), u'1990-01-01')
self.assertEqual(dc.CreationDate(), u'1980-10-01T23:11:10-04:00')
self.assertEqual(dc.ModificationDate(), u'2002-10-01T12:09:22-04:00')
self.assertEqual(dc.EffectiveDate(), u'2002-10-09T00:00:00-04:00')
self.assertEqual(dc.ExpirationDate(), u'2002-10-16T00:00:00-04:00')
dt = parseDatetimetz('2002-10-03T14:51:55-04:00')
dc.modified = dt
self.assertRaises(Exception, setattr, dc, 'modified', 'foo')
modified = [qv[1]
for qv in dc.getQualifiedDates()
if qv[0] == u'Modified']
self.failIf(len(modified) != 1, "should be only one: %r" % modified)
self.assertEqual(parseDatetimetz(modified[0]), dt)
modified = dc.ModificationDate()
self.assertEqual(parseDatetimetz(modified), dt)
def test_suite():
return TestSuite((
makeSuite(Test),
))
if __name__=='__main__':
main(defaultTest='test_suite')
zope.dublincore-3.8.2/src/zope/dublincore/tests/partial.txt 0000644 0001750 0001750 00000010651 11527746247 024005 0 ustar tseaver tseaver ====================================
Dublin Core metadata as content data
====================================
Sometimes we want to include data in content objects which mirrors one
or more Dublin Core fields. In these cases, we want the Dublin Core
structures to use the data in the content object rather than keeping a
separate value in the annotations typically used. What fields we want
to do this with can vary, however, and we may not want the Dublin Core
APIs to constrain our choices of field names for our content objects.
To deal with this, we can use speciallized adapter implementations
tailored to specific content objects. To make this a bit easier,
there is a factory for such adapters.
Let's take a look at the simplest case of this to start with. We have
some content object with a `title` attribute that should mirror the
Dublin Core `title` field::
>>> import zope.interface
>>> import zope.annotation.interfaces
>>> class Content(object):
...
... zope.interface.implements(
... zope.annotation.interfaces.IAttributeAnnotatable)
...
... title = u""
... description = u""
To avoid having a discrepency between the `title` attribute of our
content object and the equivalent Dublin Core field, we can provide a
specific adapter for our object::
>>> from zope.dublincore import annotatableadapter
>>> factory = annotatableadapter.partialAnnotatableAdapterFactory(
... ["title"])
This creates an adapter factory that maps the Dublin Core `title`
field to the `title` attribute on instances of our `Content` class.
Multiple mappings may be specified by naming the additional fields in
the sequence passed to `partialAnnotatableAdapterFactory()`. (We'll
see later how to use different attribute names for Dublin Core
fields.)
Let's see what happens when we use the adapter.
When using the adapter to retrieve a field set to use the content
object, the value stored on the content object is used::
>>> content = Content()
>>> adapter = factory(content)
>>> adapter.title
u''
>>> content.title = u"New Title"
>>> adapter.title
u'New Title'
If we set the relevant Dublin Core field using the adapter, the
content object is updated::
>>> adapter.title = u"Adapted Title"
>>> content.title
u'Adapted Title'
Dublin Core fields which are not specifically mapped to the content
object do not affect the content object::
>>> adapter.description = u"Some long description."
>>> content.description
u''
>>> adapter.description
u'Some long description.'
Using arbitrary field names
===========================
We've seen the simple approach, allowing a Dublin Core field to be
stored on the content object using an attribute of the same name as
the DC field. However, we may want to use a different name for some
reason. The `partialAnnotatableAdapterFactory()` supports this as
well.
If we call `partialAnnotatableAdapterFactory()` with a mapping instead
of a sequence, the mapping is used to map Dublin Core field names to
attribute names on the content object.
Let's look at an example where we want the `abstract` attribute on the
content object to be used for the `description` Dublin Core field::
>>> class Content(object):
...
... zope.interface.implements(
... zope.annotation.interfaces.IAttributeAnnotatable)
...
... abstract = u""
We can create the adapter factory by passing a mapping to
`partialAnnotatableAdapterFactory()`::
>>> factory = annotatableadapter.partialAnnotatableAdapterFactory(
... {"description": "abstract"})
We can check the effects of the adapter as before::
>>> content = Content()
>>> adapter = factory(content)
>>> adapter.description
u''
>>> content.abstract = u"What it's about."
>>> adapter.description
u"What it's about."
>>> adapter.description = u"Change of plans."
>>> content.abstract
u'Change of plans.'
Limitations
===========
The current implementation has a number of limitations to be aware of;
hopefully these can be removed in the future.
- Only simple string properties, like `title`, are supported. This is
largely because other field types have not been given sufficient
thought. Attempting to use this for other fields will cause a
`ValueError` to be raised by `partialAnnotatableAdapterFactory()`.
- The CMF-like APIs are not supported in the generated adapters. It
is not clear that these APIs are used, but content object
implementations should be aware of this limitation.
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_zdcannotatableadapter.py 0000644 0001750 0001750 00000003240 11527746247 027547 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation 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.
#
##############################################################################
"""Test the Dublin Core annotations adapter.
"""
import unittest
from zope.annotation.interfaces import IAnnotations
from zope.component.testing import PlacelessSetup
from zope.interface import implements
class TestAnnotations(dict):
implements(IAnnotations)
class DublinCoreAdapterTest(PlacelessSetup, unittest.TestCase):
def testZDCAnnotatableAdapter(self):
from zope.dublincore.annotatableadapter import ZDCAnnotatableAdapter
annotations = TestAnnotations()
dc = ZDCAnnotatableAdapter(annotations)
self.failIf(annotations, "There shouldn't be any data yet")
self.assertEqual(dc.title, u'')
self.failIf(annotations, "There shouldn't be any data yet")
dc.title = u"Test title"
self.failUnless(annotations, "There should be data now!")
dc = ZDCAnnotatableAdapter(annotations)
self.assertEqual(dc.title, u'Test title')
def test_suite():
return unittest.makeSuite(DublinCoreAdapterTest)
if __name__=='__main__':
unittest.main(defaultTest='test_suite')
zope.dublincore-3.8.2/src/zope/dublincore/tests/__init__.py 0000644 0001750 0001750 00000000075 11527746247 023720 0 ustar tseaver tseaver #
# This file is necessary to make this directory a package.
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_creatorannotator.py 0000644 0001750 0001750 00000010320 11527746247 026577 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2001, 2002 Zope Foundation 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.
#
##############################################################################
"""Tests creator annotation.
"""
import unittest
class CreatorAnnotatorTests(unittest.TestCase):
def setUp(self):
from zope.testing.cleanup import cleanUp
cleanUp()
self._makeInterface()
self._registerAdapter()
def tearDown(self):
from zope.testing.cleanup import cleanUp
from zope.security.management import endInteraction
endInteraction()
cleanUp()
def _callFUT(self, event):
from zope.dublincore.creatorannotator import CreatorAnnotator
return CreatorAnnotator(event)
def _makeInterface(self):
from zope.interface import Interface
class IDummyContent(Interface):
pass
self._iface = IDummyContent
def _registerAdapter(self):
from zope.component import provideAdapter
from zope.dublincore.interfaces import IZopeDublinCore
provideAdapter(DummyDCAdapter, (self._iface, ), IZopeDublinCore)
def _makeContextAndEvent(self):
from zope.interface import implements
class DummyDublinCore(object):
implements(self._iface)
creators = ()
class DummyEvent(object):
def __init__(self, object):
self.object = object
context = DummyDublinCore()
event = DummyEvent(context)
return context, event
def _setPrincipal(self, id):
from zope.security.management import newInteraction
class DummyPrincipal(object):
title = 'TITLE'
description = 'DESCRIPTION'
def __init__(self, id):
self.id = id
if id is None:
newInteraction(DummyRequest(None))
else:
newInteraction(DummyRequest(DummyPrincipal(id)))
def test_w_no_request(self):
context, event = self._makeContextAndEvent()
self._callFUT(event)
self.assertEqual(context.creators, ())
def test_w_request_no_existing_creators(self):
context, event = self._makeContextAndEvent()
self._setPrincipal('phred')
self._callFUT(event)
self.assertEqual(context.creators, ('phred',))
def test_w_request_w_existing_creator_nomatch(self):
context, event = self._makeContextAndEvent()
context.creators = ('bharney',)
self._setPrincipal('phred')
self._callFUT(event)
self.assertEqual(context.creators, ('bharney', 'phred',))
def test_w_request_w_existing_creator_match(self):
context, event = self._makeContextAndEvent()
context.creators = ('bharney', 'phred')
self._setPrincipal('phred')
self._callFUT(event)
self.assertEqual(context.creators, ('bharney', 'phred',))
def test_w_request_no_principal(self):
context, event = self._makeContextAndEvent()
context.creators = ('bharney', 'phred')
self._setPrincipal(None)
self._callFUT(event)
self.assertEqual(context.creators, ('bharney', 'phred',))
class CreatorAnnotatorObjectEventTests(CreatorAnnotatorTests):
def _callFUT(self, event):
from zope.dublincore.creatorannotator import CreatorAnnotator
return CreatorAnnotator(event.object, event)
class DummyDCAdapter(object):
def _getcreator(self):
return self.context.creators
def _setcreator(self, value):
self.context.creators = value
creators = property(_getcreator, _setcreator, None, "Adapted Creators")
def __init__(self, context):
self.context = context
class DummyRequest(object):
def __init__(self, principal):
self.principal = principal
self.interaction = None
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_partialannotatable.py 0000644 0001750 0001750 00000000710 11527746247 027061 0 ustar tseaver tseaver """Tests of the 'partial' annotatable adapter.
"""
__docformat__ = "reStructuredText"
import doctest
import zope.component.testing
from zope.component.testing import tearDown
from zope.annotation.attribute import AttributeAnnotations
def setUp(test):
zope.component.testing.setUp(test)
zope.component.provideAdapter(AttributeAnnotations)
def test_suite():
return doctest.DocFileSuite(
"partial.txt", setUp=setUp, tearDown=tearDown)
zope.dublincore-3.8.2/src/zope/dublincore/tests/test_dcsv.py 0000644 0001750 0001750 00000016367 11527746247 024172 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2003 Zope Foundation 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.
#
##############################################################################
"""Test the Dublib Core Structured Value support functions.
"""
import unittest
from doctest import DocTestSuite
from zope.dublincore.dcsv import encode, decode
# TODO still need tests for errors, and createMapping()
def test_decode_empty():
"""
>>> decode('')
[]
>>> decode(' ')
[]
"""
def test_decode_simple_value():
"""
>>> decode('v')
[('', 'v')]
>>> decode(' v ')
[('', 'v')]
>>> decode('v;')
[('', 'v')]
>>> decode(' v ; ')
[('', 'v')]
"""
def test_decode_simple_escaped_value():
# Make the docstring a raw string to avoid having escapes
# interpreted twice; each test within the docstring will be parsed
# again!
r"""
>>> decode(r'\v')
[('', 'v')]
>>> decode(r'\;')
[('', ';')]
>>> decode(r'\;;')
[('', ';')]
>>> decode(r'\= ')
[('', '=')]
>>> decode(r'\= ; ')
[('', '=')]
>>> decode(r'\\\=\; ; ')
[('', '\\=;')]
>>> decode(r'\\\=\;')
[('', '\\=;')]
>>> decode(r'\\\=\; = ; ')
[('\\=;', '')]
>>> decode(r'\;\;\;;')
[('', ';;;')]
"""
def test_decode_trailing_backslash():
r"""
>>> decode('\\')
[('', '\\')]
>>> decode('v\\')
[('', 'v\\')]
These are tricky, but for different reasons:
>>> decode(r'v\ ')
[('', 'v\\')]
>>> decode(r'v\ ; ')
[('', 'v')]
"""
def test_decode_simple_list():
"""
>>> decode('a;b;c')
[('', 'a'), ('', 'b'), ('', 'c')]
>>> decode('a;b;c;')
[('', 'a'), ('', 'b'), ('', 'c')]
"""
def test_decode_simple_escaped_list():
r"""
>>> decode(r'\a;\b;\c')
[('', 'a'), ('', 'b'), ('', 'c')]
>>> decode(r' \a ; \b ; \c ; ')
[('', 'a'), ('', 'b'), ('', 'c')]
>>> decode(r'\;;b;c')
[('', ';'), ('', 'b'), ('', 'c')]
>>> decode(r' \=;b;c;')
[('', '='), ('', 'b'), ('', 'c')]
"""
def test_decode_empty_values():
# weird case; hard to know the intent of the specification
"""
>>> decode('=')
[('', '')]
>>> decode(';')
[('', '')]
>>> decode(' ; ')
[('', '')]
>>> decode(';;')
[('', ''), ('', '')]
>>> decode(' ; ; ')
[('', ''), ('', '')]
>>> decode('=;')
[('', '')]
>>> decode(' = ; ')
[('', '')]
>>> decode('=;=;')
[('', ''), ('', '')]
>>> decode(' = ; = ; ')
[('', ''), ('', '')]
>>> decode(' = ; = ; = ')
[('', ''), ('', ''), ('', '')]
"""
def test_decode_labeled_values():
"""
>>> decode('a=b')
[('a', 'b')]
>>> decode('a=b;')
[('a', 'b')]
>>> decode('a=b;c=d')
[('a', 'b'), ('c', 'd')]
Not really sure about this one yet; assuming that the space in 'd ;'
is supposed to be removed until we have information that says
otherwise:
>>> decode('a =b; c= d ;')
[('a', 'b'), ('c', 'd')]
"""
def test_decode_mixed_values():
"""
>>> decode('a;b=c')
[('', 'a'), ('b', 'c')]
>>> decode('a=b;c')
[('a', 'b'), ('', 'c')]
>>> decode('a;b=c; ')
[('', 'a'), ('b', 'c')]
>>> decode('a=b;c ; ')
[('a', 'b'), ('', 'c')]
>>> decode('a;b;c;d=e;f;g;')
[('', 'a'), ('', 'b'), ('', 'c'), ('d', 'e'), ('', 'f'), ('', 'g')]
>>> decode('a=b;c=d;e;f=g')
[('a', 'b'), ('c', 'd'), ('', 'e'), ('f', 'g')]
"""
def test_decode_duplicate_labels():
"""
>>> decode('a=b;a=c; a=d')
[('a', 'b'), ('a', 'c'), ('a', 'd')]
"""
def test_encode_empty_list():
"""
>>> encode([])
''
"""
def test_encode_single_item():
"""
>>> encode([''])
';'
>>> encode([('', '')])
';'
>>> encode(['a'])
'a;'
>>> encode([('', 'a')])
'a;'
>>> encode([('a','')])
'a=;'
>>> encode([('a', 'b')])
'a=b;'
The label from a pair can be any non-true value:
>>> encode([(None, '')])
';'
>>> encode([(None, 'a')])
'a;'
>>> encode([(0, 'a')])
'a;'
>>> encode([((), 'a')])
'a;'
This may be a mis-feature, but seems harmless since no one in
their right mind would use it intentionally (except maybe with
None).
"""
def test_encode_single_value_needing_escapes():
r"""
>>> encode(['='])
'\\=;'
>>> encode([';'])
'\\;;'
>>> encode(['\\'])
'\\\\;'
>>> encode([r'\\'])
'\\\\\\\\;'
"""
def test_encode_labeled_value_needing_escapes():
r"""
Escaping needed in the labels:
>>> encode([('\\', '')])
'\\\\=;'
>>> encode([('\\', 'a')])
'\\\\=a;'
>>> encode([('=', '')])
'\\==;'
>>> encode([(';', 'a')])
'\\;=a;'
Escaping needed in the values:
>>> encode([('a', '\\')])
'a=\\\\;'
>>> encode([('a', '=')])
'a=\\=;'
>>> encode([('a', ';')])
'a=\\;;'
Escaping needed in both:
>>> encode([('\\', '\\')])
'\\\\=\\\\;'
>>> encode([('=', '=')])
'\\==\\=;'
>>> encode([(';', ';')])
'\\;=\\;;'
"""
def test_encode_simple_list():
"""
>>> encode(['a', 'b', 'c'])
'a; b; c;'
>>> encode(['', '', ''])
'; ; ;'
>>> encode(['a b', 'c d'])
'a b; c d;'
"""
def test_encode_labeled_values():
# Single items were tested above; these all demonstrate with more
# than one item.
"""
>>> encode([('a', ''), ('b', '')])
'a=; b=;'
>>> encode([('a', 'b'), ('c', 'd')])
'a=b; c=d;'
"""
def test_encode_mixed_items():
"""
>>> encode(['a', ('b', 'c')])
'a; b=c;'
>>> encode([('', 'a'), ('b', 'c')])
'a; b=c;'
>>> encode([('b', 'c'), 'a'])
'b=c; a;'
>>> encode([('b', 'c'), ('', 'a')])
'b=c; a;'
"""
def test_encode_error_non_strings():
"""
>>> encode([(42, '')])
Traceback (most recent call last):
...
TypeError: labels must be strings; found 42
>>> encode([('', 42)])
Traceback (most recent call last):
...
TypeError: values must be strings; found 42
>>> encode([('label', 42)])
Traceback (most recent call last):
...
TypeError: values must be strings; found 42
"""
def test_encode_error_outer_whitespace():
"""
>>> encode([' a'])
Traceback (most recent call last):
...
ValueError: values may not include leading or trailing spaces: ' a'
>>> encode(['a '])
Traceback (most recent call last):
...
ValueError: values may not include leading or trailing spaces: 'a '
>>> encode([('', 'a ')])
Traceback (most recent call last):
...
ValueError: values may not include leading or trailing spaces: 'a '
>>> encode([('label', 'a ')])
Traceback (most recent call last):
...
ValueError: values may not include leading or trailing spaces: 'a '
"""
def test_suite():
return DocTestSuite()
if __name__ == '__main__':
unittest.main(defaultTest="test_suite")
zope.dublincore-3.8.2/src/zope/dublincore/__init__.py 0000644 0001750 0001750 00000000075 11527746247 022556 0 ustar tseaver tseaver #
# This file is necessary to make this directory a package.
zope.dublincore-3.8.2/src/zope/dublincore/creatorannotator.py 0000644 0001750 0001750 00000003521 11527746247 024403 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2002 Zope Foundation 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.
#
##############################################################################
"""Object that takes care of annotating the dublin core creator field.
"""
__docformat__ = 'restructuredtext'
from zope.dublincore.interfaces import IZopeDublinCore
from zope.security.management import queryInteraction
from zope.security.proxy import removeSecurityProxy
def CreatorAnnotator(object, event=None):
"""Update Dublin-Core creator property"""
if event is None:
# annotator was only called the event as only argument
object = object.object
dc = IZopeDublinCore(object, None)
# Principals that can create objects do not necessarily have
# 'zope.app.dublincore.change' permission.
# https://bugs.launchpad.net/zope3/+bug/98124
dc = removeSecurityProxy(dc)
if dc is None:
return
# Try to find a principal for that one. If there
# is no principal then we don't touch the list
# of creators.
interaction = queryInteraction()
if interaction is not None:
for participation in interaction.participations:
if participation.principal is None:
continue
principalid = participation.principal.id
if not principalid in dc.creators:
dc.creators = dc.creators + (unicode(principalid), )
zope.dublincore-3.8.2/src/zope/dublincore/dcsv.py 0000644 0001750 0001750 00000010070 11527746247 021752 0 ustar tseaver tseaver ##############################################################################
#
# Copyright (c) 2003 Zope Foundation 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.
#
##############################################################################
"""Functions for working with Dublin Core Structured Values (DCSV) scheme.
DCSV is specified in 'DCMI DCSV: A syntax for writing a list of
labelled values in a text string', at:
http://dublincore.org/documents/dcmi-dcsv/
"""
__docformat__ = 'restructuredtext'
import re
__all__ = "encode", "decode"
try:
basestring
except NameError:
# define basestring in Python 2.2.x:
try:
unicode
except NameError:
basestring = str
else:
basestring = str, unicode
def encode(items):
L = []
for item in items:
if isinstance(item, basestring):
L.append(_encode_string(item, "values") + ";")
else:
k, v = item
if not isinstance(v, basestring):
raise TypeError("values must be strings; found %r" % v)
v = _encode_string(v, "values")
if k:
if not isinstance(k, basestring):
raise TypeError("labels must be strings; found %r" % k)
k = _encode_string(k, "labels")
s = "%s=%s;" % (k, v)
else:
s = v + ";"
L.append(s)
return " ".join(L)
def _encode_string(s, what):
if s.strip() != s:
raise ValueError("%s may not include leading or trailing spaces: %r"
% (what, s))
return s.replace("\\", r"\\").replace(";", r"\;").replace("=", r"\=")
def decode(text):
items = []
text = text.strip()
while text:
m = _find_interesting(text)
if m:
prefix, char = m.group(1, 2)
prefix = _decode_string(prefix).rstrip()
if char == ";":
items.append(('', prefix))
text = text[m.end():].lstrip()
continue
else: # char == "="
text = text[m.end():].lstrip()
# else we have a label
m = _find_value(text)
if m:
value = m.group(1)
text = text[m.end():].lstrip()
else:
value = text
text = ''
items.append((prefix, _decode_string(value)))
else:
items.append(('', _decode_string(text)))
break
return items
_prefix = r"((?:[^;\\=]|\\.)*)"
_find_interesting = re.compile(_prefix + "([;=])").match
_find_value = re.compile(_prefix + ";").match
def _decode_string(s):
if "\\" not in s:
return s.rstrip()
r = ""
while s:
c1 = s[0]
if c1 == "\\":
c2 = s[1:2]
if not c2:
return r + c1
r += c2
s = s[2:]
else:
r += c1
s = s[1:]
return r.rstrip()
def createMapping(items, allow_duplicates=False):
mapping = {}
for item in items:
if isinstance(item, basestring):
raise ValueError("can't create mapping with unlabelled data")
k, v = item
if not isinstance(k, basestring):
raise TypeError("labels must be strings; found %r" % k)
if not isinstance(v, basestring):
raise TypeError("values must be strings; found %r" % v)
if k in mapping:
if allow_duplicates:
mapping[k].append(v)
else:
raise ValueError("labels may not have more than one value")
else:
if allow_duplicates:
mapping[k] = [v]
else:
mapping[k] = v
return mapping
zope.dublincore-3.8.2/src/zope/__init__.py 0000644 0001750 0001750 00000000070 11527746247 020423 0 ustar tseaver tseaver __import__('pkg_resources').declare_namespace(__name__)
zope.dublincore-3.8.2/src/zope.dublincore.egg-info/ 0000755 0001750 0001750 00000000000 11527746337 022134 5 ustar tseaver tseaver zope.dublincore-3.8.2/src/zope.dublincore.egg-info/not-zip-safe 0000644 0001750 0001750 00000000001 11527746270 024356 0 ustar tseaver tseaver
zope.dublincore-3.8.2/src/zope.dublincore.egg-info/namespace_packages.txt 0000644 0001750 0001750 00000000005 11527746337 026462 0 ustar tseaver tseaver zope
zope.dublincore-3.8.2/src/zope.dublincore.egg-info/requires.txt 0000644 0001750 0001750 00000000307 11527746337 024534 0 ustar tseaver tseaver setuptools
pytz
zope.component[zcml]
zope.datetime
zope.interface
zope.lifecycleevent
zope.location
zope.schema
zope.security[zcml]>=3.8
[test]
zope.testing >= 3.8
zope.annotation
zope.configuration zope.dublincore-3.8.2/src/zope.dublincore.egg-info/SOURCES.txt 0000644 0001750 0001750 00000003234 11527746337 024022 0 ustar tseaver tseaver CHANGES.txt
COPYRIGHT.txt
LICENSE.txt
README.txt
bootstrap.py
buildout.cfg
setup.py
src/zope/__init__.py
src/zope.dublincore.egg-info/PKG-INFO
src/zope.dublincore.egg-info/SOURCES.txt
src/zope.dublincore.egg-info/dependency_links.txt
src/zope.dublincore.egg-info/namespace_packages.txt
src/zope.dublincore.egg-info/not-zip-safe
src/zope.dublincore.egg-info/requires.txt
src/zope.dublincore.egg-info/top_level.txt
src/zope/dublincore/__init__.py
src/zope/dublincore/annotatableadapter.py
src/zope/dublincore/configure.zcml
src/zope/dublincore/creatorannotator.py
src/zope/dublincore/dcsv.py
src/zope/dublincore/dcterms.py
src/zope/dublincore/interfaces.py
src/zope/dublincore/property.py
src/zope/dublincore/property.txt
src/zope/dublincore/security.zcml
src/zope/dublincore/testing.py
src/zope/dublincore/timeannotators.py
src/zope/dublincore/xmlmetadata.py
src/zope/dublincore/zopedublincore.py
src/zope/dublincore/browser/__init__.py
src/zope/dublincore/browser/box.pt
src/zope/dublincore/browser/configure.zcml
src/zope/dublincore/browser/edit.pt
src/zope/dublincore/browser/metadataedit.py
src/zope/dublincore/tests/__init__.py
src/zope/dublincore/tests/partial.txt
src/zope/dublincore/tests/test_annotatableadapter.py
src/zope/dublincore/tests/test_creatorannotator.py
src/zope/dublincore/tests/test_dcsv.py
src/zope/dublincore/tests/test_partialannotatable.py
src/zope/dublincore/tests/test_property.py
src/zope/dublincore/tests/test_timeannotators.py
src/zope/dublincore/tests/test_xmlmetadata.py
src/zope/dublincore/tests/test_zcml.py
src/zope/dublincore/tests/test_zdcannotatableadapter.py
src/zope/dublincore/tests/test_zopedublincore.py
src/zope/dublincore/tests/timeannotators.txt zope.dublincore-3.8.2/src/zope.dublincore.egg-info/top_level.txt 0000644 0001750 0001750 00000000005 11527746337 024661 0 ustar tseaver tseaver zope
zope.dublincore-3.8.2/src/zope.dublincore.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 11527746337 026202 0 ustar tseaver tseaver
zope.dublincore-3.8.2/src/zope.dublincore.egg-info/PKG-INFO 0000644 0001750 0001750 00000040043 11527746337 023232 0 ustar tseaver tseaver Metadata-Version: 1.0
Name: zope.dublincore
Version: 3.8.2
Summary: Zope Dublin Core implementation
Home-page: http://pypi.python.org/pypi/zope.dublincore
Author: Zope Foundation and Contributors
Author-email: zope-dev@zope.org
License: ZPL 2.1
Description: .. contents::
========
Overview
========
``zope.dublincore`` provides a Dublin Core support for Zope-based web
applications. This includes:
* an ``IZopeDublinCore`` interface definition that can be implemented
by objects directly or via an adapter to support DublinCore
metadata.
* an ``IZopeDublinCore`` adapter for annotatable objects (objects
providing ``IAnnotatable`` from ``zope.annotation``).
* a partial adapter for objects that already implement some of the
``IZopeDublinCore`` API,
* a "Metadata" browser page (which by default appears in the ZMI),
* subscribers to various object lifecycle events that automatically
set the created and modified date and some other metadata.
======================
Dublin Core Properties
======================
A dublin core property allows us to use properties from dublin core
by simply defining a property as DCProperty.
>>> from zope.dublincore import property
>>> from zope import interface
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> class DC(object):
... interface.implements(IAttributeAnnotatable)
... title = property.DCProperty('title')
... author = property.DCProperty('creators')
... authors = property.DCListProperty('creators')
>>> obj = DC()
>>> obj.title = u'My title'
>>> obj.title
u'My title'
Let's see if the title is really stored in dublin core:
>>> from zope.dublincore.interfaces import IZopeDublinCore
>>> IZopeDublinCore(obj).title
u'My title'
Even if a dublin core property is a list property we can set and get the
property as scalar type:
>>> obj.author = u'me'
>>> obj.author
u'me'
DCListProperty acts on the list:
>>> obj.authors
(u'me',)
>>> obj.authors = [u'I', u'others']
>>> obj.authors
(u'I', u'others')
>>> obj.author
u'I'
====================================
Dublin Core metadata as content data
====================================
Sometimes we want to include data in content objects which mirrors one
or more Dublin Core fields. In these cases, we want the Dublin Core
structures to use the data in the content object rather than keeping a
separate value in the annotations typically used. What fields we want
to do this with can vary, however, and we may not want the Dublin Core
APIs to constrain our choices of field names for our content objects.
To deal with this, we can use speciallized adapter implementations
tailored to specific content objects. To make this a bit easier,
there is a factory for such adapters.
Let's take a look at the simplest case of this to start with. We have
some content object with a `title` attribute that should mirror the
Dublin Core `title` field::
>>> import zope.interface
>>> import zope.annotation.interfaces
>>> class Content(object):
...
... zope.interface.implements(
... zope.annotation.interfaces.IAttributeAnnotatable)
...
... title = u""
... description = u""
To avoid having a discrepency between the `title` attribute of our
content object and the equivalent Dublin Core field, we can provide a
specific adapter for our object::
>>> from zope.dublincore import annotatableadapter
>>> factory = annotatableadapter.partialAnnotatableAdapterFactory(
... ["title"])
This creates an adapter factory that maps the Dublin Core `title`
field to the `title` attribute on instances of our `Content` class.
Multiple mappings may be specified by naming the additional fields in
the sequence passed to `partialAnnotatableAdapterFactory()`. (We'll
see later how to use different attribute names for Dublin Core
fields.)
Let's see what happens when we use the adapter.
When using the adapter to retrieve a field set to use the content
object, the value stored on the content object is used::
>>> content = Content()
>>> adapter = factory(content)
>>> adapter.title
u''
>>> content.title = u"New Title"
>>> adapter.title
u'New Title'
If we set the relevant Dublin Core field using the adapter, the
content object is updated::
>>> adapter.title = u"Adapted Title"
>>> content.title
u'Adapted Title'
Dublin Core fields which are not specifically mapped to the content
object do not affect the content object::
>>> adapter.description = u"Some long description."
>>> content.description
u''
>>> adapter.description
u'Some long description.'
Using arbitrary field names
===========================
We've seen the simple approach, allowing a Dublin Core field to be
stored on the content object using an attribute of the same name as
the DC field. However, we may want to use a different name for some
reason. The `partialAnnotatableAdapterFactory()` supports this as
well.
If we call `partialAnnotatableAdapterFactory()` with a mapping instead
of a sequence, the mapping is used to map Dublin Core field names to
attribute names on the content object.
Let's look at an example where we want the `abstract` attribute on the
content object to be used for the `description` Dublin Core field::
>>> class Content(object):
...
... zope.interface.implements(
... zope.annotation.interfaces.IAttributeAnnotatable)
...
... abstract = u""
We can create the adapter factory by passing a mapping to
`partialAnnotatableAdapterFactory()`::
>>> factory = annotatableadapter.partialAnnotatableAdapterFactory(
... {"description": "abstract"})
We can check the effects of the adapter as before::
>>> content = Content()
>>> adapter = factory(content)
>>> adapter.description
u''
>>> content.abstract = u"What it's about."
>>> adapter.description
u"What it's about."
>>> adapter.description = u"Change of plans."
>>> content.abstract
u'Change of plans.'
Limitations
===========
The current implementation has a number of limitations to be aware of;
hopefully these can be removed in the future.
- Only simple string properties, like `title`, are supported. This is
largely because other field types have not been given sufficient
thought. Attempting to use this for other fields will cause a
`ValueError` to be raised by `partialAnnotatableAdapterFactory()`.
- The CMF-like APIs are not supported in the generated adapters. It
is not clear that these APIs are used, but content object
implementations should be aware of this limitation.
===============
Time annotators
===============
Time annotators store the creation resp. last modification time of an object.
Set up
======
>>> class Content(object):
... created = None
... modified = None
The annotations are stored on the ``IZopeDublinCore`` adapter. This dummy adapter
reads and writes from/to the context object.
>>> import zope.component
>>> import zope.dublincore.interfaces
>>> class DummyDublinCore(object):
... def __init__(self, context):
... self.__dict__['context'] = context
...
... def __getattr__(self, name):
... return getattr(self.context, name)
...
... def __setattr__(self, name, value):
... setattr(self.context, name, value)
>>> zope.component.provideAdapter(
... DummyDublinCore, (Content,), zope.dublincore.interfaces.IZopeDublinCore)
Created annotator
=================
The created annotator sets creation and modification time to current time.
>>> content = Content()
It is registered for the ``ObjectCreatedEvent``:
>>> import zope.dublincore.timeannotators
>>> import zope.lifecycleevent.interfaces
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.CreatedAnnotator,
... (zope.lifecycleevent.interfaces.IObjectCreatedEvent,))
>>> import zope.event
>>> import zope.lifecycleevent
>>> zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(content))
Both ``created`` and ``modified`` get set:
>>> content.created
datetime.datetime(, tzinfo=)
>>> content.modified
datetime.datetime(, tzinfo=)
The created annotator can also be registered for (object, event):
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.CreatedAnnotator,
... (None,
... zope.lifecycleevent.interfaces.IObjectCreatedEvent,))
>>> content = Content()
>>> ignored = zope.component.subscribers(
... (content, zope.lifecycleevent.ObjectCreatedEvent(content)), None)
Both ``created`` and ``modified`` get set this way, too:
>>> content.created
datetime.datetime(, tzinfo=)
>>> content.modified
datetime.datetime(, tzinfo=)
Modified annotator
==================
The modified annotator only sets the modification time to current time.
>>> content = Content()
It is registered for the ``ObjectModifiedEvent``:
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.ModifiedAnnotator,
... (zope.lifecycleevent.interfaces.IObjectModifiedEvent,))
>>> zope.event.notify(zope.lifecycleevent.ObjectModifiedEvent(content))
Only ``modified`` gets set:
>>> print content.created
None
>>> content.modified
datetime.datetime(, tzinfo=)
The modified annotator can also be registered for (object, event):
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.ModifiedAnnotator,
... (None,
... zope.lifecycleevent.interfaces.IObjectModifiedEvent,))
>>> content = Content()
>>> ignored = zope.component.subscribers(
... (content, zope.lifecycleevent.ObjectModifiedEvent(content)), None)
``modified`` gets set, this way, too:
>>> print content.created
None
>>> content.modified
datetime.datetime(, tzinfo=)
=======
Changes
=======
3.8.2 (2010-02-19)
==================
- Updated regex normalizer to guard against test failure when
a datetime's microseconds value is zero.
3.8.1 (2010-12-14)
==================
- Added missing test dependency on zope.configuration and missing dependency
of security.zcml on zope.security's meta.zcml.
3.8.0 (2010-09-14)
==================
- Registered the annotators also for (object, event), so copy-pasting a
folder, changes the dublin core data of the contained objects, too. The
changed annotators are the following:
- ``zope.dublincore.timeannotators.ModifiedAnnotator``
- ``zope.dublincore.timeannotators.CreatedAnnotator``
- ``zope.dublincore.creatorannotator.CreatorAnnotator``
3.7.0 (2010-08-19)
==================
- Removed backward-compatibility shims for deprecated ``zope.app.dublincore.*``
permissions.
- Removed include the zcml configuration of ``zope.dublincore.browser``.
- Using python`s doctest instead of deprecated ``zope.testing.doctest``.
3.6.3 (2010-04-23)
==================
- Restored backward-compatible ``zope.app.dublincore.*`` permissions,
mapping them onto the new permissions using the ````
directive. These shims will be removed in 3.7.0.
- Added unit (not functional) test for loadability of ``configure.zcml``.
3.6.2 (2010-04-20)
==================
- Repaired regression introduced in 3.6.1: the renamed permissions were
not updated in other ZCML files.
3.6.1 (2010-04-19)
==================
- Renamed the ``zope.app.dublincore.*`` permissions to
``zope.dublincore.*``. Applications may need to fix up grants based on the
old permissions.
- Added tests for ``zope.dublincore.timeannotators``.
- Added not declared dependency on ``zope.lifecycleevent``.
3.6.0 (2009-12-02)
==================
- Removed the marker interface IZopeDublinCoreAnnotatable which doesn't seem
to be used.
- Made the registration of ZDCAnnotatableAdapter conditional, lifting the
dependency on zope.annotation and thereby the ZODB, leaving it as a test
dependency.
3.5.0 (2009-09-15)
==================
- Add missing dependencies.
- Get rid of any testing dependencies beyond zope.testing.
- Include browser ZCML configuration only if zope.browserpage is installed.
- Specify i18n domain in package's ``configure.zcml``, because we use message
IDs for permission titles.
- Remove unused imports, fix one test that was inactive because of being
overriden by another one by a mistake.
3.4.2 (2009-01-31)
==================
- Declare dependency on zope.datetime.
3.4.1 (2009-01-26)
==================
- Test dependencies are declared in a `test` extra now.
- Fix: Make CreatorAnnotator not to fail if participation principal is None
3.4.0 (2007-09-28)
==================
No further changes since 3.4.0a1.
3.4.0a1 (2007-04-22)
====================
Initial release as a separate project, corresponds to zope.dublincore
from Zope 3.4.0a1
Platform: UNKNOWN
zope.dublincore-3.8.2/CHANGES.txt 0000644 0001750 0001750 00000005661 11527746247 016372 0 ustar tseaver tseaver =======
Changes
=======
3.8.2 (2010-02-19)
==================
- Updated regex normalizer to guard against test failure when
a datetime's microseconds value is zero.
3.8.1 (2010-12-14)
==================
- Added missing test dependency on zope.configuration and missing dependency
of security.zcml on zope.security's meta.zcml.
3.8.0 (2010-09-14)
==================
- Registered the annotators also for (object, event), so copy-pasting a
folder, changes the dublin core data of the contained objects, too. The
changed annotators are the following:
- ``zope.dublincore.timeannotators.ModifiedAnnotator``
- ``zope.dublincore.timeannotators.CreatedAnnotator``
- ``zope.dublincore.creatorannotator.CreatorAnnotator``
3.7.0 (2010-08-19)
==================
- Removed backward-compatibility shims for deprecated ``zope.app.dublincore.*``
permissions.
- Removed include the zcml configuration of ``zope.dublincore.browser``.
- Using python`s doctest instead of deprecated ``zope.testing.doctest``.
3.6.3 (2010-04-23)
==================
- Restored backward-compatible ``zope.app.dublincore.*`` permissions,
mapping them onto the new permissions using the ````
directive. These shims will be removed in 3.7.0.
- Added unit (not functional) test for loadability of ``configure.zcml``.
3.6.2 (2010-04-20)
==================
- Repaired regression introduced in 3.6.1: the renamed permissions were
not updated in other ZCML files.
3.6.1 (2010-04-19)
==================
- Renamed the ``zope.app.dublincore.*`` permissions to
``zope.dublincore.*``. Applications may need to fix up grants based on the
old permissions.
- Added tests for ``zope.dublincore.timeannotators``.
- Added not declared dependency on ``zope.lifecycleevent``.
3.6.0 (2009-12-02)
==================
- Removed the marker interface IZopeDublinCoreAnnotatable which doesn't seem
to be used.
- Made the registration of ZDCAnnotatableAdapter conditional, lifting the
dependency on zope.annotation and thereby the ZODB, leaving it as a test
dependency.
3.5.0 (2009-09-15)
==================
- Add missing dependencies.
- Get rid of any testing dependencies beyond zope.testing.
- Include browser ZCML configuration only if zope.browserpage is installed.
- Specify i18n domain in package's ``configure.zcml``, because we use message
IDs for permission titles.
- Remove unused imports, fix one test that was inactive because of being
overriden by another one by a mistake.
3.4.2 (2009-01-31)
==================
- Declare dependency on zope.datetime.
3.4.1 (2009-01-26)
==================
- Test dependencies are declared in a `test` extra now.
- Fix: Make CreatorAnnotator not to fail if participation principal is None
3.4.0 (2007-09-28)
==================
No further changes since 3.4.0a1.
3.4.0a1 (2007-04-22)
====================
Initial release as a separate project, corresponds to zope.dublincore
from Zope 3.4.0a1
zope.dublincore-3.8.2/setup.cfg 0000644 0001750 0001750 00000000073 11527746337 016372 0 ustar tseaver tseaver [egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
zope.dublincore-3.8.2/PKG-INFO 0000644 0001750 0001750 00000040043 11527746337 015647 0 ustar tseaver tseaver Metadata-Version: 1.0
Name: zope.dublincore
Version: 3.8.2
Summary: Zope Dublin Core implementation
Home-page: http://pypi.python.org/pypi/zope.dublincore
Author: Zope Foundation and Contributors
Author-email: zope-dev@zope.org
License: ZPL 2.1
Description: .. contents::
========
Overview
========
``zope.dublincore`` provides a Dublin Core support for Zope-based web
applications. This includes:
* an ``IZopeDublinCore`` interface definition that can be implemented
by objects directly or via an adapter to support DublinCore
metadata.
* an ``IZopeDublinCore`` adapter for annotatable objects (objects
providing ``IAnnotatable`` from ``zope.annotation``).
* a partial adapter for objects that already implement some of the
``IZopeDublinCore`` API,
* a "Metadata" browser page (which by default appears in the ZMI),
* subscribers to various object lifecycle events that automatically
set the created and modified date and some other metadata.
======================
Dublin Core Properties
======================
A dublin core property allows us to use properties from dublin core
by simply defining a property as DCProperty.
>>> from zope.dublincore import property
>>> from zope import interface
>>> from zope.annotation.interfaces import IAttributeAnnotatable
>>> class DC(object):
... interface.implements(IAttributeAnnotatable)
... title = property.DCProperty('title')
... author = property.DCProperty('creators')
... authors = property.DCListProperty('creators')
>>> obj = DC()
>>> obj.title = u'My title'
>>> obj.title
u'My title'
Let's see if the title is really stored in dublin core:
>>> from zope.dublincore.interfaces import IZopeDublinCore
>>> IZopeDublinCore(obj).title
u'My title'
Even if a dublin core property is a list property we can set and get the
property as scalar type:
>>> obj.author = u'me'
>>> obj.author
u'me'
DCListProperty acts on the list:
>>> obj.authors
(u'me',)
>>> obj.authors = [u'I', u'others']
>>> obj.authors
(u'I', u'others')
>>> obj.author
u'I'
====================================
Dublin Core metadata as content data
====================================
Sometimes we want to include data in content objects which mirrors one
or more Dublin Core fields. In these cases, we want the Dublin Core
structures to use the data in the content object rather than keeping a
separate value in the annotations typically used. What fields we want
to do this with can vary, however, and we may not want the Dublin Core
APIs to constrain our choices of field names for our content objects.
To deal with this, we can use speciallized adapter implementations
tailored to specific content objects. To make this a bit easier,
there is a factory for such adapters.
Let's take a look at the simplest case of this to start with. We have
some content object with a `title` attribute that should mirror the
Dublin Core `title` field::
>>> import zope.interface
>>> import zope.annotation.interfaces
>>> class Content(object):
...
... zope.interface.implements(
... zope.annotation.interfaces.IAttributeAnnotatable)
...
... title = u""
... description = u""
To avoid having a discrepency between the `title` attribute of our
content object and the equivalent Dublin Core field, we can provide a
specific adapter for our object::
>>> from zope.dublincore import annotatableadapter
>>> factory = annotatableadapter.partialAnnotatableAdapterFactory(
... ["title"])
This creates an adapter factory that maps the Dublin Core `title`
field to the `title` attribute on instances of our `Content` class.
Multiple mappings may be specified by naming the additional fields in
the sequence passed to `partialAnnotatableAdapterFactory()`. (We'll
see later how to use different attribute names for Dublin Core
fields.)
Let's see what happens when we use the adapter.
When using the adapter to retrieve a field set to use the content
object, the value stored on the content object is used::
>>> content = Content()
>>> adapter = factory(content)
>>> adapter.title
u''
>>> content.title = u"New Title"
>>> adapter.title
u'New Title'
If we set the relevant Dublin Core field using the adapter, the
content object is updated::
>>> adapter.title = u"Adapted Title"
>>> content.title
u'Adapted Title'
Dublin Core fields which are not specifically mapped to the content
object do not affect the content object::
>>> adapter.description = u"Some long description."
>>> content.description
u''
>>> adapter.description
u'Some long description.'
Using arbitrary field names
===========================
We've seen the simple approach, allowing a Dublin Core field to be
stored on the content object using an attribute of the same name as
the DC field. However, we may want to use a different name for some
reason. The `partialAnnotatableAdapterFactory()` supports this as
well.
If we call `partialAnnotatableAdapterFactory()` with a mapping instead
of a sequence, the mapping is used to map Dublin Core field names to
attribute names on the content object.
Let's look at an example where we want the `abstract` attribute on the
content object to be used for the `description` Dublin Core field::
>>> class Content(object):
...
... zope.interface.implements(
... zope.annotation.interfaces.IAttributeAnnotatable)
...
... abstract = u""
We can create the adapter factory by passing a mapping to
`partialAnnotatableAdapterFactory()`::
>>> factory = annotatableadapter.partialAnnotatableAdapterFactory(
... {"description": "abstract"})
We can check the effects of the adapter as before::
>>> content = Content()
>>> adapter = factory(content)
>>> adapter.description
u''
>>> content.abstract = u"What it's about."
>>> adapter.description
u"What it's about."
>>> adapter.description = u"Change of plans."
>>> content.abstract
u'Change of plans.'
Limitations
===========
The current implementation has a number of limitations to be aware of;
hopefully these can be removed in the future.
- Only simple string properties, like `title`, are supported. This is
largely because other field types have not been given sufficient
thought. Attempting to use this for other fields will cause a
`ValueError` to be raised by `partialAnnotatableAdapterFactory()`.
- The CMF-like APIs are not supported in the generated adapters. It
is not clear that these APIs are used, but content object
implementations should be aware of this limitation.
===============
Time annotators
===============
Time annotators store the creation resp. last modification time of an object.
Set up
======
>>> class Content(object):
... created = None
... modified = None
The annotations are stored on the ``IZopeDublinCore`` adapter. This dummy adapter
reads and writes from/to the context object.
>>> import zope.component
>>> import zope.dublincore.interfaces
>>> class DummyDublinCore(object):
... def __init__(self, context):
... self.__dict__['context'] = context
...
... def __getattr__(self, name):
... return getattr(self.context, name)
...
... def __setattr__(self, name, value):
... setattr(self.context, name, value)
>>> zope.component.provideAdapter(
... DummyDublinCore, (Content,), zope.dublincore.interfaces.IZopeDublinCore)
Created annotator
=================
The created annotator sets creation and modification time to current time.
>>> content = Content()
It is registered for the ``ObjectCreatedEvent``:
>>> import zope.dublincore.timeannotators
>>> import zope.lifecycleevent.interfaces
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.CreatedAnnotator,
... (zope.lifecycleevent.interfaces.IObjectCreatedEvent,))
>>> import zope.event
>>> import zope.lifecycleevent
>>> zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(content))
Both ``created`` and ``modified`` get set:
>>> content.created
datetime.datetime(, tzinfo=)
>>> content.modified
datetime.datetime(, tzinfo=)
The created annotator can also be registered for (object, event):
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.CreatedAnnotator,
... (None,
... zope.lifecycleevent.interfaces.IObjectCreatedEvent,))
>>> content = Content()
>>> ignored = zope.component.subscribers(
... (content, zope.lifecycleevent.ObjectCreatedEvent(content)), None)
Both ``created`` and ``modified`` get set this way, too:
>>> content.created
datetime.datetime(, tzinfo=)
>>> content.modified
datetime.datetime(, tzinfo=)
Modified annotator
==================
The modified annotator only sets the modification time to current time.
>>> content = Content()
It is registered for the ``ObjectModifiedEvent``:
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.ModifiedAnnotator,
... (zope.lifecycleevent.interfaces.IObjectModifiedEvent,))
>>> zope.event.notify(zope.lifecycleevent.ObjectModifiedEvent(content))
Only ``modified`` gets set:
>>> print content.created
None
>>> content.modified
datetime.datetime(, tzinfo=)
The modified annotator can also be registered for (object, event):
>>> zope.component.provideHandler(
... zope.dublincore.timeannotators.ModifiedAnnotator,
... (None,
... zope.lifecycleevent.interfaces.IObjectModifiedEvent,))
>>> content = Content()
>>> ignored = zope.component.subscribers(
... (content, zope.lifecycleevent.ObjectModifiedEvent(content)), None)
``modified`` gets set, this way, too:
>>> print content.created
None
>>> content.modified
datetime.datetime(, tzinfo=)
=======
Changes
=======
3.8.2 (2010-02-19)
==================
- Updated regex normalizer to guard against test failure when
a datetime's microseconds value is zero.
3.8.1 (2010-12-14)
==================
- Added missing test dependency on zope.configuration and missing dependency
of security.zcml on zope.security's meta.zcml.
3.8.0 (2010-09-14)
==================
- Registered the annotators also for (object, event), so copy-pasting a
folder, changes the dublin core data of the contained objects, too. The
changed annotators are the following:
- ``zope.dublincore.timeannotators.ModifiedAnnotator``
- ``zope.dublincore.timeannotators.CreatedAnnotator``
- ``zope.dublincore.creatorannotator.CreatorAnnotator``
3.7.0 (2010-08-19)
==================
- Removed backward-compatibility shims for deprecated ``zope.app.dublincore.*``
permissions.
- Removed include the zcml configuration of ``zope.dublincore.browser``.
- Using python`s doctest instead of deprecated ``zope.testing.doctest``.
3.6.3 (2010-04-23)
==================
- Restored backward-compatible ``zope.app.dublincore.*`` permissions,
mapping them onto the new permissions using the ````
directive. These shims will be removed in 3.7.0.
- Added unit (not functional) test for loadability of ``configure.zcml``.
3.6.2 (2010-04-20)
==================
- Repaired regression introduced in 3.6.1: the renamed permissions were
not updated in other ZCML files.
3.6.1 (2010-04-19)
==================
- Renamed the ``zope.app.dublincore.*`` permissions to
``zope.dublincore.*``. Applications may need to fix up grants based on the
old permissions.
- Added tests for ``zope.dublincore.timeannotators``.
- Added not declared dependency on ``zope.lifecycleevent``.
3.6.0 (2009-12-02)
==================
- Removed the marker interface IZopeDublinCoreAnnotatable which doesn't seem
to be used.
- Made the registration of ZDCAnnotatableAdapter conditional, lifting the
dependency on zope.annotation and thereby the ZODB, leaving it as a test
dependency.
3.5.0 (2009-09-15)
==================
- Add missing dependencies.
- Get rid of any testing dependencies beyond zope.testing.
- Include browser ZCML configuration only if zope.browserpage is installed.
- Specify i18n domain in package's ``configure.zcml``, because we use message
IDs for permission titles.
- Remove unused imports, fix one test that was inactive because of being
overriden by another one by a mistake.
3.4.2 (2009-01-31)
==================
- Declare dependency on zope.datetime.
3.4.1 (2009-01-26)
==================
- Test dependencies are declared in a `test` extra now.
- Fix: Make CreatorAnnotator not to fail if participation principal is None
3.4.0 (2007-09-28)
==================
No further changes since 3.4.0a1.
3.4.0a1 (2007-04-22)
====================
Initial release as a separate project, corresponds to zope.dublincore
from Zope 3.4.0a1
Platform: UNKNOWN