created the cybertools.typology package; + some related extensions and improvements on other packages

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1116 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-03-07 18:00:39 +00:00
parent b43d1475c2
commit 1b0652a555
13 changed files with 336 additions and 8 deletions

View file

@ -18,20 +18,59 @@
""" """
A set of simple application classes for contact management to be used A set of simple application classes for contact management to be used
as an example for the cybertools.reporter package. as an example for some of the cybertools packages.
$Id$ $Id$
""" """
from zope.component import adapts from zope.component import adapts
from zope.interface import implements from zope.interface import implements
from cybertools.contact.interfaces import IPerson
from datetime import date
class Person(object): class Person(object):
implements(IPerson)
def __init__(self, firstName, lastName, birthDate): def __init__(self, firstName, lastName, birthDate):
self.firstName = firstName self.firstName = firstName
self.lastName = lastName self.lastName = lastName
self.birthDate = birthDate self.birthDate = birthDate
self.moreFirstNames = []
self.personalAddress = 'mrs' # or 'mr', 'ms', None (unknown)
self.academicTitle = None
self.communicationInfos = []
self.addresses = {} # keys: 'standard', ...?
self.affiliations = {} # keys: 'employed', ...?
@property
def age(self):
return (date.today() - self.birthDate).days/365.25
class Address(object):
def __init__(self, title, lines, street, zipcode, city, country):
self.title = title
self.lines = lines # a sequence of address lines
self.street = street
self.zipcode = zipcode
self.city = city
self.country = country # 'de', 'at', 'us', ...
class Institution(object):
def __init__(self, title):
self.title = title
self.addresses = {}
class CommunicationInfo(object):
def __init__(self, commType, qualifier, address):
self.commType = commType # e.g. 'email', 'phone', ...
self.qualifier = qualifier # e.g. 'private', or institution
self.address = address # the real address or number

View file

@ -23,4 +23,10 @@ as an example for some of the cybertools packages.
$Id$ $Id$
""" """
from zope.interface import Interface from zope.interface import Interface, Attribute
class IPerson(Interface):
""" Just a person...
"""
age = Attribute('A float representing the age in years. Read-only.')

View file

@ -20,18 +20,20 @@ then provide a listing of persons...
>>> from cybertools.reporter.example.interfaces import IContactsDataSource >>> from cybertools.reporter.example.interfaces import IContactsDataSource
>>> from cybertools.reporter.example.contact import Contacts >>> from cybertools.reporter.example.contact import Contacts
>>> import time >>> from datetime import date
>>> format = '%Y-%m-%d'
>>> pdata = ((u'John', u'Smith', '1956-08-01'), >>> pdata = ((u'John', u'Smith', '1956-08-01'),
... (u'David', u'Waters', '1972-12-24'), ... (u'David', u'Waters', '1972-12-24'),
... (u'Carla', u'Myers', '1981-10-11')) ... (u'Carla', u'Myers', '1981-10-11'))
>>> persons = DataSource([Person(f, s, time.strptime(b, format)) >>> persons = DataSource([Person(f, s, date(*[int(d) for d in b.split('-')]))
... for f, s, b in pdata]) ... for f, s, b in pdata])
>>> directlyProvides(persons, IContactsDataSource) >>> directlyProvides(persons, IContactsDataSource)
>>> ztapi.provideAdapter(IContactsDataSource, IResultSet, Contacts) >>> ztapi.provideAdapter(IContactsDataSource, IResultSet, Contacts)
>>> rset = IResultSet(persons) >>> rset = IResultSet(persons)
>>> len(rset)
3
For the browser presentation we can also use a browser view providing For the browser presentation we can also use a browser view providing
the result set with extended attributes: the result set with extended attributes:

View file

@ -23,12 +23,52 @@ cybertools.contact package
$Id$ $Id$
""" """
# TODO: move the generic stuff to cybertools.reporter.result
from zope.component import adapts from zope.component import adapts
from zope.interface import implements from zope.interface import implements
from cybertools.reporter.interfaces import IResultSet from cybertools.reporter.interfaces import IResultSet, IRow, ICell
from cybertools.reporter.example.interfaces import IContactsDataSource from cybertools.reporter.example.interfaces import IContactsDataSource
class Cell(object):
implements(ICell)
def __init__(self, field, value, row):
self.field = field
self.value = value
self.row = row
@property
def text(self):
return value
@property
def token(self):
return value
def sortKey(self):
return value
class Row(object):
implements(IRow)
def __init__(self, context, resultSet):
self.context = context # a single object (in this case)
self.resultSet = resultSet
@property
def cells(self):
schema = self.resultSet.schema
if schema is None:
return {}
return dict([(f.__name__, getattr(self.context, f.__name__))
for f in schema.fields])
class Contacts(object): class Contacts(object):
implements(IResultSet) implements(IResultSet)
@ -37,4 +77,14 @@ class Contacts(object):
def __init__(self, context): def __init__(self, context):
self.context = context self.context = context
_schema = None
def setSchema(self, schema): self._schema = schema
def getSchema(self): return self._schema
schema = property(getSchema, setSchema)
@property
def rows(self):
return [Row(o, self) for o in iter(self.context)]
def __len__(self):
return len(self.rows)

57
typology/README.txt Normal file
View file

@ -0,0 +1,57 @@
Quickstart Instructions
=======================
($Id$)
>>> from zope.app import zapi
>>> from zope.app.testing import ztapi
>>> from zope.interface import directlyProvides
A Basic API for Dynamic Typing
==============================
>>> from cybertools.typology.interfaces import IType, ITypeManager
Let's start with the Person class from the cybertools.contact package -
we will then apply dynamic typing to Person objects:
>>> from cybertools.contact.interfaces import IPerson
>>> from cybertools.contact import Person
>>> from datetime import date
>>> pdata = ((u'John', u'Smith', '1956-08-01'),
... (u'David', u'Waters', '1972-12-24'),
... (u'Carla', u'Myers', '1999-10-11'))
>>> persons = [Person(f, s, date(*[int(d) for d in b.split('-')]))
... for f, s, b in pdata]
Now we want to express that any person younger than 18 years is a
child, and from 18 years on a person is an adult. (Note that this test
will only work until November 2017 ;-))
The example package gives us a class for this type that we use as an
adapter to IPerson:
>>> from cybertools.typology.example.person import BasicAgeGroup
>>> ztapi.provideAdapter(IPerson, IType, BasicAgeGroup)
>>> john_type = IType(persons[0])
>>> david_type = IType(persons[1])
>>> carla_type = IType(persons[2])
We can now look what the type is telling us about the persons:
>>> john_type.title
u'Adult'
>>> john_type.token
'contact.person.agetype.adult'
>>> david_type.token
'contact.person.agetype.adult'
>>> carla_type.token
'contact.person.agetype.child'
Usually types are equal if they have the same token:
>>> john_type == david_type
True
>>> john_type == carla_type
False

4
typology/__init__.py Normal file
View file

@ -0,0 +1,4 @@
"""
$Id$
"""

View file

@ -0,0 +1,4 @@
"""
$Id$
"""

8
typology/configure.zcml Normal file
View file

@ -0,0 +1,8 @@
<!-- $Id$ -->
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
i18n_domain="zope">
</configure>

View file

@ -0,0 +1 @@
<include package="cybertools.typology" />

View file

@ -0,0 +1,4 @@
"""
$Id$
"""

View file

@ -0,0 +1,60 @@
#
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Example classes for the cybertools.reporter package. These use the
cybertools.contact package
$Id$
"""
# TODO: move generic stuff to type.Type class
from zope.component import adapts
from zope.interface import implements
from cybertools.contact.interfaces import IPerson
from cybertools.typology.interfaces import IType
class BasicAgeGroup(object):
implements(IType)
adapts(IPerson)
def __init__(self, context):
self.context = context
def __eq__(self, other):
return self.token == other.token
# IType attributes
@property
def title(self):
return self.isChild() and u'Child' or u'Adult'
@property
def token(self): return 'contact.person.agetype.' + str(self.title.lower())
@property
def tokenForSearch(self): return self.token
# helper methods
def isChild(self):
return self.context.age < 18.0

66
typology/interfaces.py Normal file
View file

@ -0,0 +1,66 @@
#
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
interface definitions for the typology package.
$Id$
"""
from zope.app.container.interfaces import IContainer
from zope import schema
from zope.configuration.fields import GlobalObject
from zope.interface import Interface, Attribute
class IType(Interface):
""" Associated with an object (typically as an adapter) giving
information about the object's type.
"""
title = schema.TextLine(title=u'Title',
description=u'A readable representation',
required=True)
token = schema.ASCIILine(title=u'Token',
description=u'A representation used for identifying a type '
'temporarily, e.g. on forms',
required=True)
tokenForSearch = schema.ASCIILine(title=u'Token for Search',
description=u'A fairly unique token that may be used '
'e.g. for identifying types via a catalog index')
interfaceToProvide = GlobalObject(title=u'Interface to Provide',
description=u'An (optional) interface that objects of this '
'type will provide')
factory = GlobalObject(title=u'Factory',
description=u'A factory (or class) that may be used for '
'creating an object of this type')
defaultContainer = schema.Object(IContainer,
title=u'Default Container',
description=u'Where objects of this type will be created in '
'when no explicit container is given')
typeProvider = schema.Object(Interface,
title=u'Type Provider',
description=u'A usually long-living object that corresponds '
'to the type. Note that this object need not '
'provide the IType interface itself')
class ITypeManager(Interface):
""" A utility or utility-like object (e.g. a container) that may
manage (store, retrieve, assign) types.
"""

27
typology/tests.py Executable file
View file

@ -0,0 +1,27 @@
# $Id$
import unittest
from zope.testing.doctestunit import DocFileSuite
from zope.app.testing import ztapi
from zope.interface.verify import verifyClass
from zope.interface import implements
from zope.app import zapi
from cybertools.typology.interfaces import IType, ITypeManager
class TestTypology(unittest.TestCase):
"Basic tests for the typology package."
def testInterfaces(self):
pass
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestTypology),
DocFileSuite('README.txt'),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')