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