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
as an example for the cybertools.reporter package.
as an example for some of the cybertools packages.
$Id$
"""
from zope.component import adapts
from zope.interface import implements
from cybertools.contact.interfaces import IPerson
from datetime import date
class Person(object):
implements(IPerson)
def __init__(self, firstName, lastName, birthDate):
self.firstName = firstName
self.lastName = lastName
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$
"""
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.contact import Contacts
>>> import time
>>> format = '%Y-%m-%d'
>>> from datetime import date
>>> pdata = ((u'John', u'Smith', '1956-08-01'),
... (u'David', u'Waters', '1972-12-24'),
... (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])
>>> directlyProvides(persons, IContactsDataSource)
>>> ztapi.provideAdapter(IContactsDataSource, IResultSet, Contacts)
>>> rset = IResultSet(persons)
>>> len(rset)
3
For the browser presentation we can also use a browser view providing
the result set with extended attributes:

View file

@ -23,12 +23,52 @@ cybertools.contact package
$Id$
"""
# TODO: move the generic stuff to cybertools.reporter.result
from zope.component import adapts
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
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):
implements(IResultSet)
@ -37,4 +77,14 @@ class Contacts(object):
def __init__(self, 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')