provide additional common attributes for proxy objects
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2615 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
7ef8e4f229
commit
665e9bf650
6 changed files with 205 additions and 38 deletions
|
@ -23,6 +23,7 @@ $Id$
|
|||
"""
|
||||
|
||||
import os
|
||||
from urllib import urlencode
|
||||
from zope.app.container.contained import Contained
|
||||
from zope.cachedescriptors.property import Lazy
|
||||
from zope import component
|
||||
|
@ -35,20 +36,40 @@ from cybertools.integrator.interfaces import IReadContainer, IItem, IFile, IImag
|
|||
|
||||
# proxy base (sample) classes
|
||||
|
||||
class ReadContainer(Contained):
|
||||
|
||||
implements(IReadContainer)
|
||||
class ProxyBase(object):
|
||||
|
||||
__parent__ = None
|
||||
factoryName = 'sample'
|
||||
|
||||
icon = 'folder'
|
||||
internalPath = ''
|
||||
externalUrlInfo = None
|
||||
|
||||
description = u''
|
||||
authors = ()
|
||||
created = modified = None
|
||||
|
||||
def __init__(self, address, **kw):
|
||||
self.address = address
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
@Lazy
|
||||
def title(self):
|
||||
if self.internalPath:
|
||||
return self.internalPath.rsplit('/', 1)[-1]
|
||||
return self.address.rsplit(os.path.sep, 1)[-1]
|
||||
|
||||
|
||||
class ReadContainer(ProxyBase, Contained):
|
||||
|
||||
implements(IReadContainer)
|
||||
|
||||
icon = 'folder'
|
||||
|
||||
@Lazy
|
||||
def properties(self):
|
||||
return {}
|
||||
|
||||
@Lazy
|
||||
def itemFactory(self):
|
||||
return component.getUtility(IItemFactory, name=self.factoryName)
|
||||
|
@ -90,29 +111,21 @@ class ReadContainer(Contained):
|
|||
has_key = __contains__
|
||||
|
||||
|
||||
class Item(object):
|
||||
class Item(ProxyBase, object):
|
||||
|
||||
implements(IItem)
|
||||
|
||||
contentType = None
|
||||
icon = 'item'
|
||||
__parent__ = None
|
||||
|
||||
def __init__(self, address, **kw):
|
||||
self.address = address
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
|
||||
class File(Item):
|
||||
|
||||
implements(IFile)
|
||||
|
||||
def __init__(self, address, contentType, **kw):
|
||||
self.address = address
|
||||
super(File, self).__init__(address, **kw)
|
||||
self.contentType = contentType
|
||||
for k, v in kw.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
def getData(self, num=None):
|
||||
return ''
|
||||
|
@ -137,6 +150,19 @@ class Image(File):
|
|||
return 0, 0
|
||||
|
||||
|
||||
# URL info
|
||||
|
||||
class ExternalUrlInfo(object):
|
||||
|
||||
def __init__(self, baseUrl='', path='', params=None):
|
||||
self.baseUrl, self.path = baseUrl.strip('/'), path.strip('/')
|
||||
self.params = params or {}
|
||||
|
||||
def __str__(self):
|
||||
params = self.params and ('?' + urlencode(self.params)) or ''
|
||||
return '%s/%s%s' % (self.baseUrl, self.path, params)
|
||||
|
||||
|
||||
# factory base (sample) classes
|
||||
|
||||
class Factory(object):
|
||||
|
|
|
@ -32,6 +32,7 @@ from zope.interface import implements, Attribute
|
|||
|
||||
from cybertools.integrator.base import ContainerFactory, ItemFactory, FileFactory
|
||||
from cybertools.integrator.base import ReadContainer, Item, File, Image
|
||||
from cybertools.integrator.base import ExternalUrlInfo
|
||||
from cybertools.text import mimetypes
|
||||
|
||||
|
||||
|
@ -54,14 +55,40 @@ classes = ['cl_core.Folder', 'cl_core.Document', 'cl_core.URL', ]
|
|||
|
||||
# proxy classes
|
||||
|
||||
class ReadContainer(ReadContainer):
|
||||
class BSCWProxyBase(object):
|
||||
|
||||
@Lazy
|
||||
def externalUrlInfo(self):
|
||||
id = self.address
|
||||
if id.startswith('bs_'):
|
||||
id = id[3:]
|
||||
return ExternalUrlInfo(self.baseUrl, id)
|
||||
|
||||
@Lazy
|
||||
def title(self):
|
||||
return self.properties['name']
|
||||
|
||||
@Lazy
|
||||
def description(self):
|
||||
return self.properties.get('descr', u'')
|
||||
|
||||
|
||||
class ReadContainer(BSCWProxyBase, ReadContainer):
|
||||
|
||||
factoryName = 'bscw'
|
||||
|
||||
@Lazy
|
||||
def data(self):
|
||||
data = self.server.get_attributes(self.address,
|
||||
def properties(self):
|
||||
return self.attributes[0]
|
||||
|
||||
@Lazy
|
||||
def attributes(self):
|
||||
return self.server.get_attributes(self.address,
|
||||
['__class__', 'type', 'id', 'name', 'descr', 'url_link'], 1, True)
|
||||
|
||||
@Lazy
|
||||
def data(self):
|
||||
data = self.attributes
|
||||
if len(data) > 1:
|
||||
return dict((item['id'], item) for item in data[1])
|
||||
else:
|
||||
|
@ -83,15 +110,16 @@ class ReadContainer(ReadContainer):
|
|||
return default
|
||||
item = self.data[key]
|
||||
itemType = item['__class__'].split('.')[-1]
|
||||
internalPath = '/'.join((self.internalPath, key)).strip('/')
|
||||
params = dict(server=self.server, internalPath=internalPath,
|
||||
properties=item, baseUrl=self.baseUrl)
|
||||
if itemType == 'Folder':
|
||||
return self.containerFactory(item['id'], server=self.server,
|
||||
name=item['name'])
|
||||
return self.containerFactory(item['id'], **params)
|
||||
elif itemType == 'Document':
|
||||
return self.fileFactory(item['id'], contentType=item['type'],
|
||||
server=self.server, name=item['name'])
|
||||
**params)
|
||||
else:
|
||||
return self.itemFactory(item['id'], server=self.server,
|
||||
name=item['name'], type=itemType)
|
||||
return self.itemFactory(item['id'], **params)
|
||||
|
||||
def values(self):
|
||||
return [self.get(k) for k in self]
|
||||
|
@ -106,18 +134,18 @@ class ReadContainer(ReadContainer):
|
|||
return key in self.keys()
|
||||
|
||||
|
||||
class Item(Item):
|
||||
class Item(BSCWProxyBase, Item):
|
||||
|
||||
@property
|
||||
def icon(self):
|
||||
return self.type.lower()
|
||||
|
||||
|
||||
class File(File):
|
||||
class File(BSCWProxyBase, File):
|
||||
|
||||
contentType = None
|
||||
|
||||
def getData(self):
|
||||
def getData(self, num=None):
|
||||
return self.server.get_document()
|
||||
data = property(getData)
|
||||
|
||||
|
@ -135,7 +163,9 @@ class ContainerFactory(ContainerFactory):
|
|||
server = kw.pop('server')
|
||||
if isinstance(server, basestring): # just a URL, resolve for XML-RPC
|
||||
server = ServerProxy(server)
|
||||
return self.proxyClass(address, server=server, **kw)
|
||||
baseUrl = server
|
||||
baseUrl = kw.pop('baseUrl', '')
|
||||
return self.proxyClass(address, server=server, baseUrl=baseUrl, **kw)
|
||||
|
||||
|
||||
class ItemFactory(ItemFactory):
|
||||
|
|
|
@ -34,13 +34,29 @@ Let's first register the proxy factory utilities.
|
|||
We can now access the root object of the BSCW repository
|
||||
|
||||
>>> from cybertools.integrator.interfaces import IContainerFactory
|
||||
>>> root = component.getUtility(IContainerFactory, name='bscw')('4', server=server)
|
||||
>>> root = component.getUtility(IContainerFactory, name='bscw')('4', server=server,
|
||||
... baseUrl='http://localhost/bscw.cgi/')
|
||||
|
||||
>>> sorted(root.items())
|
||||
[('bs_5', <...ReadContainer object...>)]
|
||||
|
||||
>>> root.address
|
||||
'4'
|
||||
>>> root.internalPath
|
||||
''
|
||||
>>> root.icon
|
||||
'folder'
|
||||
>>> root.properties
|
||||
{...'name': 'public'...}
|
||||
>>> root.title
|
||||
'public'
|
||||
>>> root.description
|
||||
'Public Repository'
|
||||
|
||||
>>> str(root.externalUrlInfo)
|
||||
'http://localhost/bscw.cgi/4'
|
||||
|
||||
Let's also have a look at the item contained in the root object.
|
||||
|
||||
>>> bs_5 = root['bs_5']
|
||||
>>> data = server.get_attributes('bs_5',
|
||||
|
@ -48,5 +64,15 @@ We can now access the root object of the BSCW repository
|
|||
|
||||
>>> bs_5.items()
|
||||
[]
|
||||
>>> bs_5.address
|
||||
'bs_5'
|
||||
>>> bs_5.internalPath
|
||||
'bs_5'
|
||||
>>> bs_5.icon
|
||||
'folder'
|
||||
>>> bs_5.properties
|
||||
{...'name': 'Introduction'...}
|
||||
|
||||
>>> str(bs_5.externalUrlInfo)
|
||||
'http://localhost/bscw.cgi/5'
|
||||
|
||||
|
|
|
@ -60,10 +60,13 @@ class ReadContainer(ReadContainer):
|
|||
if key not in self.keys():
|
||||
return default
|
||||
path = os.path.join(self.address, key)
|
||||
internalPath = '/'.join((self.internalPath, key)).strip('/')
|
||||
if os.path.isdir(path):
|
||||
return self.containerFactory(path, __parent__=self.__parent__)
|
||||
return self.containerFactory(path, internalPath=internalPath,
|
||||
__parent__=self.__parent__)
|
||||
else:
|
||||
return self.fileFactory(path, __parent__=self.__parent__)
|
||||
return self.fileFactory(path, internalPath=internalPath,
|
||||
__parent__=self.__parent__)
|
||||
|
||||
def values(self):
|
||||
return [self.get(k) for k in self]
|
||||
|
|
|
@ -24,33 +24,81 @@ Let's do some basic set up
|
|||
Accessing Objects in the Filesystem
|
||||
===================================
|
||||
|
||||
We access the top-level object (a directory) by calling the container (proxy)
|
||||
factory with the address (path) leading to the directory.
|
||||
|
||||
>>> top = component.getUtility(IContainerFactory, name='filesystem')(testDir)
|
||||
|
||||
This top-level object is a container with some sub-objects, that may be
|
||||
containers themeselves or terminal objects (items or files).
|
||||
|
||||
>>> sorted(top)
|
||||
['index.html', 'sub']
|
||||
>>> len(top)
|
||||
2
|
||||
|
||||
A proxy provides a set of attributes that may be used for viewing the
|
||||
object or navigating to it.
|
||||
|
||||
>>> top.address
|
||||
'...data'
|
||||
>>> top.internalPath
|
||||
''
|
||||
>>> top.icon
|
||||
'folder'
|
||||
>>> top.properties
|
||||
{}
|
||||
>>> top.title
|
||||
'data'
|
||||
|
||||
The external URL information may be used for directly linking to the
|
||||
external object - in the case of filesystem objects this is not possible
|
||||
in a general way, so this attribute is always None.
|
||||
|
||||
>>> top.externalUrlInfo is None
|
||||
True
|
||||
|
||||
Let's now have a look at the sub-objects found in the top-level container.
|
||||
|
||||
>>> sub = top['sub']
|
||||
>>> sorted(sub)
|
||||
['demo.tgz', 'index.html', 'loops_logo.png']
|
||||
>>> sub.address
|
||||
'...sub'
|
||||
>>> sub.internalPath
|
||||
'sub'
|
||||
>>> sub.icon
|
||||
'folder'
|
||||
>>> sub.properties
|
||||
{}
|
||||
>>> sub.externalUrlInfo is None
|
||||
True
|
||||
|
||||
A file object has additional attributes/methods.
|
||||
|
||||
>>> file = sub['demo.tgz']
|
||||
>>> file.address
|
||||
'...demo.tgz'
|
||||
>>> file.internalPath
|
||||
'sub/demo.tgz'
|
||||
>>> file.icon
|
||||
'tar'
|
||||
>>> file.contentType
|
||||
'application/x-tar'
|
||||
>>> file.getSize()
|
||||
432L
|
||||
>>> file.icon
|
||||
'tar'
|
||||
|
||||
>>> logo = sub['loops_logo.png']
|
||||
>>> logo.internalPath
|
||||
'sub/loops_logo.png'
|
||||
>>> logo.icon
|
||||
'image'
|
||||
>>> logo.contentType
|
||||
'image/png'
|
||||
>>> logo.getImageSize()
|
||||
(145, 42)
|
||||
>>> logo.icon
|
||||
'image'
|
||||
|
||||
>>> html = top['index.html']
|
||||
>>> html.internalPath
|
||||
'index.html'
|
||||
>>> html.contentType
|
||||
'text/html'
|
||||
>>> print html.data
|
||||
|
|
|
@ -29,9 +29,39 @@ from zope.interface import Interface, Attribute
|
|||
|
||||
|
||||
class IProxy(Interface):
|
||||
""" An object that represents an external object and provides access
|
||||
to it.
|
||||
"""
|
||||
|
||||
address = Attribute('An external specifier (a name, path, URL, ...) '
|
||||
'that may be used to access the external object.')
|
||||
internalPath = Attribute('A relativ path leading to an internal '
|
||||
'representation of the represented object.')
|
||||
icon = Attribute('The name of an icon that may be used for symbolizing '
|
||||
'this object.')
|
||||
'the represented object.')
|
||||
properties = Attribute('A dictionary with attributes/properties '
|
||||
'characteristic for the type of object the proxy represents.')
|
||||
externalUrlInfo = Attribute('Information necessary for building URLs that link '
|
||||
'directly to the object the proxy represents (optional).')
|
||||
|
||||
title = Attribute('A short string giving basic information about the object.')
|
||||
description = Attribute('A somewhat longer descriptive information.')
|
||||
url = Attribute('An explicit target URL (optional).')
|
||||
authors = Attribute('A list of names of persons who worked on this object.')
|
||||
create = Attribute('A datetime object denoting the data/time of object '
|
||||
'creation.')
|
||||
modified = Attribute('A datetime object denoting the data/time of last '
|
||||
'modification of the object.')
|
||||
|
||||
|
||||
class IExternalUrlInfo(Interface):
|
||||
""" Information necessary to build URLs to external objects.
|
||||
"""
|
||||
baseUrl = Attribute('The base part of the URL, including the protocol and '
|
||||
'the server part + optionally a constant part of the path.')
|
||||
path = Attribute('The relative path leading to the object.')
|
||||
params = Attribute('A dictionary providing a parameter set that will '
|
||||
'be appended urlencoded to the base URL.')
|
||||
|
||||
|
||||
class IReadContainer(IProxy, IReadContainer):
|
||||
|
@ -40,19 +70,23 @@ class IReadContainer(IProxy, IReadContainer):
|
|||
|
||||
|
||||
class IItem(IProxy, Interface):
|
||||
""" A terminal kind of object, i.e. not a container of other objects.
|
||||
""" A proxy for a terminal kind of object, i.e. not a container of
|
||||
other objects.
|
||||
"""
|
||||
|
||||
|
||||
class IFile(IItem, IFile, IFileContent):
|
||||
|
||||
data = Attribute('The data contained in the file.')
|
||||
contentType = Attribute('The MIME type of the object.')
|
||||
|
||||
def getData(num):
|
||||
def getData(num=None):
|
||||
""" Return num bytes from the file`s data.
|
||||
"""
|
||||
|
||||
|
||||
# proxy factories
|
||||
|
||||
class IProxyFactory(Interface):
|
||||
""" Creates proxy objects for external objects.
|
||||
"""
|
||||
|
|
Loading…
Add table
Reference in a new issue