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:
parent
b43d1475c2
commit
1b0652a555
13 changed files with 336 additions and 8 deletions
|
@ -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
|
||||
|
||||
|
|
@ -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.')
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
57
typology/README.txt
Normal 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
4
typology/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
"""
|
||||
$Id$
|
||||
"""
|
||||
|
4
typology/browser/__init__.py
Normal file
4
typology/browser/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
"""
|
||||
$Id$
|
||||
"""
|
||||
|
8
typology/configure.zcml
Normal file
8
typology/configure.zcml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<!-- $Id$ -->
|
||||
|
||||
<configure
|
||||
xmlns="http://namespaces.zope.org/zope"
|
||||
xmlns:browser="http://namespaces.zope.org/browser"
|
||||
i18n_domain="zope">
|
||||
|
||||
</configure>
|
1
typology/cybertools.typology-configure.zcml
Normal file
1
typology/cybertools.typology-configure.zcml
Normal file
|
@ -0,0 +1 @@
|
|||
<include package="cybertools.typology" />
|
4
typology/example/__init__.py
Normal file
4
typology/example/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
"""
|
||||
$Id$
|
||||
"""
|
||||
|
60
typology/example/person.py
Normal file
60
typology/example/person.py
Normal 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
66
typology/interfaces.py
Normal 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
27
typology/tests.py
Executable 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')
|
Loading…
Add table
Reference in a new issue