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
|
import os
|
||||||
|
from urllib import urlencode
|
||||||
from zope.app.container.contained import Contained
|
from zope.app.container.contained import Contained
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope import component
|
from zope import component
|
||||||
|
@ -35,20 +36,40 @@ from cybertools.integrator.interfaces import IReadContainer, IItem, IFile, IImag
|
||||||
|
|
||||||
# proxy base (sample) classes
|
# proxy base (sample) classes
|
||||||
|
|
||||||
class ReadContainer(Contained):
|
class ProxyBase(object):
|
||||||
|
|
||||||
implements(IReadContainer)
|
|
||||||
|
|
||||||
__parent__ = None
|
__parent__ = None
|
||||||
factoryName = 'sample'
|
factoryName = 'sample'
|
||||||
|
|
||||||
icon = 'folder'
|
internalPath = ''
|
||||||
|
externalUrlInfo = None
|
||||||
|
|
||||||
|
description = u''
|
||||||
|
authors = ()
|
||||||
|
created = modified = None
|
||||||
|
|
||||||
def __init__(self, address, **kw):
|
def __init__(self, address, **kw):
|
||||||
self.address = address
|
self.address = address
|
||||||
for k, v in kw.items():
|
for k, v in kw.items():
|
||||||
setattr(self, k, v)
|
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
|
@Lazy
|
||||||
def itemFactory(self):
|
def itemFactory(self):
|
||||||
return component.getUtility(IItemFactory, name=self.factoryName)
|
return component.getUtility(IItemFactory, name=self.factoryName)
|
||||||
|
@ -90,29 +111,21 @@ class ReadContainer(Contained):
|
||||||
has_key = __contains__
|
has_key = __contains__
|
||||||
|
|
||||||
|
|
||||||
class Item(object):
|
class Item(ProxyBase, object):
|
||||||
|
|
||||||
implements(IItem)
|
implements(IItem)
|
||||||
|
|
||||||
contentType = None
|
|
||||||
icon = 'item'
|
icon = 'item'
|
||||||
__parent__ = None
|
__parent__ = None
|
||||||
|
|
||||||
def __init__(self, address, **kw):
|
|
||||||
self.address = address
|
|
||||||
for k, v in kw.items():
|
|
||||||
setattr(self, k, v)
|
|
||||||
|
|
||||||
|
|
||||||
class File(Item):
|
class File(Item):
|
||||||
|
|
||||||
implements(IFile)
|
implements(IFile)
|
||||||
|
|
||||||
def __init__(self, address, contentType, **kw):
|
def __init__(self, address, contentType, **kw):
|
||||||
self.address = address
|
super(File, self).__init__(address, **kw)
|
||||||
self.contentType = contentType
|
self.contentType = contentType
|
||||||
for k, v in kw.items():
|
|
||||||
setattr(self, k, v)
|
|
||||||
|
|
||||||
def getData(self, num=None):
|
def getData(self, num=None):
|
||||||
return ''
|
return ''
|
||||||
|
@ -137,6 +150,19 @@ class Image(File):
|
||||||
return 0, 0
|
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
|
# factory base (sample) classes
|
||||||
|
|
||||||
class Factory(object):
|
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 ContainerFactory, ItemFactory, FileFactory
|
||||||
from cybertools.integrator.base import ReadContainer, Item, File, Image
|
from cybertools.integrator.base import ReadContainer, Item, File, Image
|
||||||
|
from cybertools.integrator.base import ExternalUrlInfo
|
||||||
from cybertools.text import mimetypes
|
from cybertools.text import mimetypes
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,14 +55,40 @@ classes = ['cl_core.Folder', 'cl_core.Document', 'cl_core.URL', ]
|
||||||
|
|
||||||
# proxy classes
|
# 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'
|
factoryName = 'bscw'
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def data(self):
|
def properties(self):
|
||||||
data = self.server.get_attributes(self.address,
|
return self.attributes[0]
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def attributes(self):
|
||||||
|
return self.server.get_attributes(self.address,
|
||||||
['__class__', 'type', 'id', 'name', 'descr', 'url_link'], 1, True)
|
['__class__', 'type', 'id', 'name', 'descr', 'url_link'], 1, True)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def data(self):
|
||||||
|
data = self.attributes
|
||||||
if len(data) > 1:
|
if len(data) > 1:
|
||||||
return dict((item['id'], item) for item in data[1])
|
return dict((item['id'], item) for item in data[1])
|
||||||
else:
|
else:
|
||||||
|
@ -83,15 +110,16 @@ class ReadContainer(ReadContainer):
|
||||||
return default
|
return default
|
||||||
item = self.data[key]
|
item = self.data[key]
|
||||||
itemType = item['__class__'].split('.')[-1]
|
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':
|
if itemType == 'Folder':
|
||||||
return self.containerFactory(item['id'], server=self.server,
|
return self.containerFactory(item['id'], **params)
|
||||||
name=item['name'])
|
|
||||||
elif itemType == 'Document':
|
elif itemType == 'Document':
|
||||||
return self.fileFactory(item['id'], contentType=item['type'],
|
return self.fileFactory(item['id'], contentType=item['type'],
|
||||||
server=self.server, name=item['name'])
|
**params)
|
||||||
else:
|
else:
|
||||||
return self.itemFactory(item['id'], server=self.server,
|
return self.itemFactory(item['id'], **params)
|
||||||
name=item['name'], type=itemType)
|
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
return [self.get(k) for k in self]
|
return [self.get(k) for k in self]
|
||||||
|
@ -106,18 +134,18 @@ class ReadContainer(ReadContainer):
|
||||||
return key in self.keys()
|
return key in self.keys()
|
||||||
|
|
||||||
|
|
||||||
class Item(Item):
|
class Item(BSCWProxyBase, Item):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
return self.type.lower()
|
return self.type.lower()
|
||||||
|
|
||||||
|
|
||||||
class File(File):
|
class File(BSCWProxyBase, File):
|
||||||
|
|
||||||
contentType = None
|
contentType = None
|
||||||
|
|
||||||
def getData(self):
|
def getData(self, num=None):
|
||||||
return self.server.get_document()
|
return self.server.get_document()
|
||||||
data = property(getData)
|
data = property(getData)
|
||||||
|
|
||||||
|
@ -135,7 +163,9 @@ class ContainerFactory(ContainerFactory):
|
||||||
server = kw.pop('server')
|
server = kw.pop('server')
|
||||||
if isinstance(server, basestring): # just a URL, resolve for XML-RPC
|
if isinstance(server, basestring): # just a URL, resolve for XML-RPC
|
||||||
server = ServerProxy(server)
|
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):
|
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
|
We can now access the root object of the BSCW repository
|
||||||
|
|
||||||
>>> from cybertools.integrator.interfaces import IContainerFactory
|
>>> 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())
|
>>> sorted(root.items())
|
||||||
[('bs_5', <...ReadContainer object...>)]
|
[('bs_5', <...ReadContainer object...>)]
|
||||||
|
|
||||||
|
>>> root.address
|
||||||
|
'4'
|
||||||
|
>>> root.internalPath
|
||||||
|
''
|
||||||
>>> root.icon
|
>>> root.icon
|
||||||
'folder'
|
'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']
|
>>> bs_5 = root['bs_5']
|
||||||
>>> data = server.get_attributes('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.items()
|
||||||
[]
|
[]
|
||||||
|
>>> bs_5.address
|
||||||
|
'bs_5'
|
||||||
|
>>> bs_5.internalPath
|
||||||
|
'bs_5'
|
||||||
>>> bs_5.icon
|
>>> bs_5.icon
|
||||||
'folder'
|
'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():
|
if key not in self.keys():
|
||||||
return default
|
return default
|
||||||
path = os.path.join(self.address, key)
|
path = os.path.join(self.address, key)
|
||||||
|
internalPath = '/'.join((self.internalPath, key)).strip('/')
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
return self.containerFactory(path, __parent__=self.__parent__)
|
return self.containerFactory(path, internalPath=internalPath,
|
||||||
|
__parent__=self.__parent__)
|
||||||
else:
|
else:
|
||||||
return self.fileFactory(path, __parent__=self.__parent__)
|
return self.fileFactory(path, internalPath=internalPath,
|
||||||
|
__parent__=self.__parent__)
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
return [self.get(k) for k in 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
|
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)
|
>>> 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)
|
>>> sorted(top)
|
||||||
['index.html', 'sub']
|
['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']
|
>>> sub = top['sub']
|
||||||
>>> sorted(sub)
|
>>> sorted(sub)
|
||||||
['demo.tgz', 'index.html', 'loops_logo.png']
|
['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 = sub['demo.tgz']
|
||||||
|
>>> file.address
|
||||||
|
'...demo.tgz'
|
||||||
|
>>> file.internalPath
|
||||||
|
'sub/demo.tgz'
|
||||||
|
>>> file.icon
|
||||||
|
'tar'
|
||||||
>>> file.contentType
|
>>> file.contentType
|
||||||
'application/x-tar'
|
'application/x-tar'
|
||||||
>>> file.getSize()
|
>>> file.getSize()
|
||||||
432L
|
432L
|
||||||
>>> file.icon
|
|
||||||
'tar'
|
|
||||||
|
|
||||||
>>> logo = sub['loops_logo.png']
|
>>> logo = sub['loops_logo.png']
|
||||||
|
>>> logo.internalPath
|
||||||
|
'sub/loops_logo.png'
|
||||||
|
>>> logo.icon
|
||||||
|
'image'
|
||||||
>>> logo.contentType
|
>>> logo.contentType
|
||||||
'image/png'
|
'image/png'
|
||||||
>>> logo.getImageSize()
|
>>> logo.getImageSize()
|
||||||
(145, 42)
|
(145, 42)
|
||||||
>>> logo.icon
|
|
||||||
'image'
|
|
||||||
|
|
||||||
>>> html = top['index.html']
|
>>> html = top['index.html']
|
||||||
|
>>> html.internalPath
|
||||||
|
'index.html'
|
||||||
>>> html.contentType
|
>>> html.contentType
|
||||||
'text/html'
|
'text/html'
|
||||||
>>> print html.data
|
>>> print html.data
|
||||||
|
|
|
@ -29,9 +29,39 @@ from zope.interface import Interface, Attribute
|
||||||
|
|
||||||
|
|
||||||
class IProxy(Interface):
|
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 '
|
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):
|
class IReadContainer(IProxy, IReadContainer):
|
||||||
|
@ -40,19 +70,23 @@ class IReadContainer(IProxy, IReadContainer):
|
||||||
|
|
||||||
|
|
||||||
class IItem(IProxy, Interface):
|
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):
|
class IFile(IItem, IFile, IFileContent):
|
||||||
|
|
||||||
|
data = Attribute('The data contained in the file.')
|
||||||
contentType = Attribute('The MIME type of the object.')
|
contentType = Attribute('The MIME type of the object.')
|
||||||
|
|
||||||
def getData(num):
|
def getData(num=None):
|
||||||
""" Return num bytes from the file`s data.
|
""" Return num bytes from the file`s data.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# proxy factories
|
||||||
|
|
||||||
class IProxyFactory(Interface):
|
class IProxyFactory(Interface):
|
||||||
""" Creates proxy objects for external objects.
|
""" Creates proxy objects for external objects.
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Add table
Reference in a new issue