[Checkins] SVN: z3c.blobfile/trunk/src/z3c/blobfile/ - starting with an export of zope.app.file (without the test directories, will remove unnecessary fiels later)

Grégoire Weber zope.org at incept.ch
Sat Nov 10 08:39:31 EST 2007


Log message for revision 81707:
  - starting with an export of zope.app.file (without the test directories, will remove unnecessary fiels later)

Changed:
  A   z3c.blobfile/trunk/src/z3c/blobfile/
  A   z3c.blobfile/trunk/src/z3c/blobfile/PACKAGE.cfg
  A   z3c.blobfile/trunk/src/z3c/blobfile/SETUP.cfg
  A   z3c.blobfile/trunk/src/z3c/blobfile/__init__.py
  A   z3c.blobfile/trunk/src/z3c/blobfile/configure.zcml
  A   z3c.blobfile/trunk/src/z3c/blobfile/file-configure.zcml
  A   z3c.blobfile/trunk/src/z3c/blobfile/file.py
  A   z3c.blobfile/trunk/src/z3c/blobfile/ftesting.zcml
  A   z3c.blobfile/trunk/src/z3c/blobfile/i18n.py
  A   z3c.blobfile/trunk/src/z3c/blobfile/image.py
  A   z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py
  A   z3c.blobfile/trunk/src/z3c/blobfile/testing.py

-=-
Added: z3c.blobfile/trunk/src/z3c/blobfile/PACKAGE.cfg
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/PACKAGE.cfg	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/PACKAGE.cfg	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,3 @@
+# The fssync support is a separate component:
+<collection>
+</collection>

Added: z3c.blobfile/trunk/src/z3c/blobfile/SETUP.cfg
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/SETUP.cfg	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/SETUP.cfg	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,5 @@
+# Tell zpkg how to install the ZCML slugs.
+
+<data-files zopeskel/etc/package-includes>
+  file-*.zcml
+</data-files>

Added: z3c.blobfile/trunk/src/z3c/blobfile/__init__.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/__init__.py	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/__init__.py	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,21 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""File and Image content components
+
+$Id: __init__.py 26745 2004-07-24 04:02:18Z pruggera $
+"""
+__docformat__ = 'restructuredtext'
+
+from file import File
+from image import Image

Added: z3c.blobfile/trunk/src/z3c/blobfile/configure.zcml
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/configure.zcml	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/configure.zcml	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,103 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    i18n_domain='zope'
+    >
+
+
+  <!-- setting up content types -->
+
+  <interface 
+      interface=".interfaces.IFile" 
+      type="zope.app.content.interfaces.IContentType"
+      /> 
+
+  <interface 
+      interface=".interfaces.IImage" 
+      type="zope.app.content.interfaces.IContentType"
+      /> 
+
+  <permission
+      id="zope.AddImages"
+      title="[add-images-permission] Add Images"
+      />
+
+
+  <!-- content classes -->
+
+  <class class=".file.File">
+    <factory
+        id="zope.app.content.File"
+        title="File"
+        description="A File"
+        />
+
+    <require
+        permission="zope.View"
+        interface=".interfaces.IFile"
+        />
+
+    <require
+        permission="zope.ManageContent"
+        set_schema=".interfaces.IFile"
+        />
+
+    <implements
+       interface="zope.annotation.interfaces.IAttributeAnnotatable"
+       />
+  </class>
+
+  <class class=".image.Image">
+    <factory
+        id="zope.app.content.Image"
+        title="Image"
+        description="An Image"
+        />
+
+    <require
+        permission="zope.View"
+        interface="zope.app.file.interfaces.IImage"
+        />
+
+    <require
+        permission="zope.ManageContent"
+        set_schema="zope.app.file.interfaces.IFile"
+        />
+
+    <implements
+        interface="zope.annotation.interfaces.IAttributeAnnotatable"
+        />
+  </class>
+
+  <adapter
+      factory=".image.ImageSized"
+      provides="zope.size.interfaces.ISized"
+      for=".interfaces.IImage"
+      />
+
+  <adapter 
+      for=".interfaces.IFile"
+      provides="zope.filerepresentation.interfaces.IReadFile"
+      factory=".file.FileReadFile"
+      permission="zope.View"
+      />
+
+  <adapter 
+      for=".interfaces.IFile"
+      provides="zope.filerepresentation.interfaces.IWriteFile"
+      factory=".file.FileWriteFile"
+      permission="zope.ManageContent"
+      />
+
+  <adapter
+      for="zope.app.folder.interfaces.IFolder"
+      provides="zope.filerepresentation.interfaces.IFileFactory"
+      factory=".image.FileFactory"
+      permission="zope.ManageContent"
+      />
+
+
+  <!-- include browser package -->
+
+  <include package=".browser" />
+
+</configure>

Added: z3c.blobfile/trunk/src/z3c/blobfile/file-configure.zcml
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/file-configure.zcml	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/file-configure.zcml	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1 @@
+<include package="zope.app.file"/>

Added: z3c.blobfile/trunk/src/z3c/blobfile/file.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/file.py	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/file.py	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,284 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""File content component
+
+$Id: file.py 38759 2005-10-04 21:40:46Z tim_one $
+"""
+__docformat__ = 'restructuredtext'
+
+from persistent import Persistent
+import transaction
+from zope.interface import implements
+import zope.app.publication.interfaces
+from zope.app.file import interfaces
+
+# set the size of the chunks
+MAXCHUNKSIZE = 1 << 16
+
+class File(Persistent):
+    """A persistent content component storing binary file data
+
+    Let's test the constructor:
+
+    >>> file = File()
+    >>> file.contentType
+    ''
+    >>> file.data
+    ''
+
+    >>> file = File('Foobar')
+    >>> file.contentType
+    ''
+    >>> file.data
+    'Foobar'
+
+    >>> file = File('Foobar', 'text/plain')
+    >>> file.contentType
+    'text/plain'
+    >>> file.data
+    'Foobar'
+
+    >>> file = File(data='Foobar', contentType='text/plain')
+    >>> file.contentType
+    'text/plain'
+    >>> file.data
+    'Foobar'
+
+
+    Let's test the mutators:
+
+    >>> file = File()
+    >>> file.contentType = 'text/plain'
+    >>> file.contentType
+    'text/plain'
+
+    >>> file.data = 'Foobar'
+    >>> file.data
+    'Foobar'
+
+    >>> file.data = None
+    Traceback (most recent call last):
+    ...
+    TypeError: Cannot set None data on a file.
+
+
+    Let's test large data input:
+
+    >>> file = File()
+
+    Insert as string:
+
+    >>> file.data = 'Foobar'*60000
+    >>> file.getSize()
+    360000
+    >>> file.data == 'Foobar'*60000
+    True
+
+    Insert data as FileChunk:
+
+    >>> fc = FileChunk('Foobar'*4000)
+    >>> file.data = fc
+    >>> file.getSize()
+    24000
+    >>> file.data == 'Foobar'*4000
+    True
+
+    Insert data from file object:
+
+    >>> import cStringIO
+    >>> sio = cStringIO.StringIO()
+    >>> sio.write('Foobar'*100000)
+    >>> sio.seek(0)
+    >>> file.data = sio
+    >>> file.getSize()
+    600000
+    >>> file.data == 'Foobar'*100000
+    True
+
+
+    Last, but not least, verify the interface:
+
+    >>> from zope.interface.verify import verifyClass
+    >>> interfaces.IFile.implementedBy(File)
+    True
+    >>> verifyClass(interfaces.IFile, File)
+    True
+    """
+
+    implements(zope.app.publication.interfaces.IFileContent, interfaces.IFile)
+
+    def __init__(self, data='', contentType=''):
+        self.data = data
+        self.contentType = contentType
+
+    def _getData(self):
+        if isinstance(self._data, FileChunk):
+            return str(self._data)
+        else:
+            return self._data
+
+    def _setData(self, data) :
+
+        # Handle case when data is a string
+        if isinstance(data, unicode):
+            data = data.encode('UTF-8')
+
+        if isinstance(data, str):
+            self._data, self._size = FileChunk(data), len(data)
+            return
+
+        # Handle case when data is None
+        if data is None:
+            raise TypeError('Cannot set None data on a file.')
+
+        # Handle case when data is already a FileChunk
+        if isinstance(data, FileChunk):
+            size = len(data)
+            self._data, self._size = data, size
+            return
+
+        # Handle case when data is a file object
+        seek = data.seek
+        read = data.read
+
+        seek(0, 2)
+        size = end = data.tell()
+
+        if size <= 2*MAXCHUNKSIZE:
+            seek(0)
+            if size < MAXCHUNKSIZE:
+                self._data, self._size = read(size), size
+                return
+            self._data, self._size = FileChunk(read(size)), size
+            return
+
+        # Make sure we have an _p_jar, even if we are a new object, by
+        # doing a sub-transaction commit.
+        transaction.savepoint(optimistic=True)
+
+        jar = self._p_jar
+
+        if jar is None:
+            # Ugh
+            seek(0)
+            self._data, self._size = FileChunk(read(size)), size
+            return
+
+        # Now we're going to build a linked list from back
+        # to front to minimize the number of database updates
+        # and to allow us to get things out of memory as soon as
+        # possible.
+        next = None
+        while end > 0:
+            pos = end - MAXCHUNKSIZE
+            if pos < MAXCHUNKSIZE:
+                pos = 0 # we always want at least MAXCHUNKSIZE bytes
+            seek(pos)
+            data = FileChunk(read(end - pos))
+
+            # Woooop Woooop Woooop! This is a trick.
+            # We stuff the data directly into our jar to reduce the
+            # number of updates necessary.
+            jar.add(data)
+
+            # This is needed and has side benefit of getting
+            # the thing registered:
+            data.next = next
+
+            # Now make it get saved in a sub-transaction!
+            transaction.savepoint(optimistic=True)
+
+            # Now make it a ghost to free the memory.  We
+            # don't need it anymore!
+            data._p_changed = None
+
+            next = data
+            end = pos
+
+        self._data, self._size = next, size
+        return
+
+    def getSize(self):
+        '''See `IFile`'''
+        return self._size
+
+    # See IFile.
+    data = property(_getData, _setData)
+
+
+class FileChunk(Persistent):
+    """Wrapper for possibly large data"""
+
+    next = None
+
+    def __init__(self, data):
+        self._data = data
+
+    def __getslice__(self, i, j):
+        return self._data[i:j]
+
+    def __len__(self):
+        data = str(self)
+        return len(data)
+
+    def __str__(self):
+        next = self.next
+        if next is None:
+            return self._data
+
+        result = [self._data]
+        while next is not None:
+            self = next
+            result.append(self._data)
+            next = self.next
+
+        return ''.join(result)
+
+
+class FileReadFile(object):
+    '''Adapter for file-system style read access.
+
+    >>> file = File()
+    >>> content = "This is some file\\ncontent."
+    >>> file.data = content
+    >>> file.contentType = "text/plain"
+    >>> FileReadFile(file).read() == content
+    True
+    >>> FileReadFile(file).size() == len(content)
+    True
+    '''
+    def __init__(self, context):
+        self.context = context
+
+    def read(self):
+        return self.context.data
+
+    def size(self):
+        return len(self.context.data)
+
+
+class FileWriteFile(object):
+    """Adapter for file-system style write access.
+
+    >>> file = File()
+    >>> content = "This is some file\\ncontent."
+    >>> FileWriteFile(file).write(content)
+    >>> file.data == content
+    True
+    """
+    def __init__(self, context):
+        self.context = context
+
+    def write(self, data):
+        self.context.data = data

Added: z3c.blobfile/trunk/src/z3c/blobfile/ftesting.zcml
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/ftesting.zcml	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/ftesting.zcml	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,55 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   i18n_domain="zope"
+   package="zope.app.file"
+   >
+
+  <!-- This file is the equivalent of site.zcml and it is -->
+  <!-- used for functional testing setup -->
+
+  <include package="zope.app.securitypolicy" file="meta.zcml" />
+
+  <include package="zope.app.zcmlfiles" />
+  <include package="zope.app.authentication" />
+  <include package="zope.app.securitypolicy" />
+  <include package="zope.app.file"/>
+
+  <securityPolicy
+      component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy" />
+
+  <role id="zope.Anonymous" title="Everybody"
+                 description="All users have this role implicitly" />
+  <role id="zope.Manager" title="Site Manager" />
+
+  <!-- Replace the following directive if you don't want public access -->
+  <grant permission="zope.View"
+                  role="zope.Anonymous" />
+  <grant permission="zope.app.dublincore.view"
+                  role="zope.Anonymous" />
+
+  <grantAll role="zope.Manager" />
+  <include package="zope.app.securitypolicy.tests" file="functional.zcml" />
+
+  <!-- Principals -->
+
+  <unauthenticatedPrincipal
+      id="zope.anybody"
+      title="Unauthenticated User" />
+
+  <!-- Principal that tests generally run as -->
+  <principal
+      id="zope.mgr"
+      title="Manager"
+      login="mgr"
+      password="mgrpw" />
+
+  <!-- Bootstrap principal used to make local grant to the principal above -->
+  <principal
+      id="zope.globalmgr"
+      title="Manager"
+      login="globalmgr"
+      password="globalmgrpw" />
+
+  <grant role="zope.Manager" principal="zope.globalmgr" />
+
+</configure>

Added: z3c.blobfile/trunk/src/z3c/blobfile/i18n.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/i18n.py	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/i18n.py	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,22 @@
+##############################################################################
+#
+# Copyright (c) 2003 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Customization of zope.i18n for the Zope application server
+
+$Id: i18n.py 73772 2007-03-27 15:09:19Z dobe $
+"""
+__docformat__ = 'restructuredtext'
+
+# import this as _ to create i18n messages in the zope domain
+from zope.i18nmessageid import MessageFactory
+ZopeMessageFactory = MessageFactory('zope')

Added: z3c.blobfile/trunk/src/z3c/blobfile/image.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/image.py	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/image.py	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,162 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Image content type implementation
+
+$Id: image.py 76693 2007-06-14 13:39:36Z mgedmin $
+"""
+__docformat__ = 'restructuredtext'
+
+import struct
+from cStringIO import StringIO
+
+from zope.interface import implements
+from zope.size.interfaces import ISized
+from zope.size import byteDisplay
+from zope.contenttype import guess_content_type
+
+from zope.app.file.i18n import ZopeMessageFactory as _
+from zope.app.file.file import File
+from zope.app.file.interfaces import IImage
+
+class Image(File):
+    implements(IImage)
+
+    def __init__(self, data=''):
+        '''See interface `IFile`'''
+        self.contentType, self._width, self._height = getImageInfo(data)
+        self.data = data
+
+    def _setData(self, data):
+        super(Image, self)._setData(data)
+
+        contentType, self._width, self._height = getImageInfo(self._data)
+        if contentType:
+            self.contentType = contentType
+
+    def getImageSize(self):
+        '''See interface `IImage`'''
+        return (self._width, self._height)
+
+    data = property(File._getData, _setData)
+
+class ImageSized(object):
+    implements(ISized)
+
+    def __init__(self, image):
+        self._image = image
+
+    def sizeForSorting(self):
+        '''See `ISized`'''
+        return ('byte', self._image.getSize())
+
+    def sizeForDisplay(self):
+        '''See `ISized`'''
+        w, h = self._image.getImageSize()
+        if w < 0:
+            w = '?'
+        if h < 0:
+            h = '?'
+        bytes = self._image.getSize()
+        byte_size = byteDisplay(bytes)
+        mapping = byte_size.mapping
+        if mapping is None:
+            mapping = {}
+        mapping.update({'width': str(w), 'height': str(h)})
+        #TODO the way this message id is defined, it won't be picked up by
+        # i18nextract and never show up in message catalogs
+        return _(byte_size + ' ${width}x${height}', mapping=mapping)
+
+class FileFactory(object):
+
+    def __init__(self, context):
+        self.context = context
+
+    def __call__(self, name, content_type, data):
+        if not content_type and data:
+            content_type, width, height = getImageInfo(data)
+        if not content_type:
+            content_type, encoding = guess_content_type(name, data, '')
+
+        if content_type.startswith('image/'):
+            return Image(data)
+
+        return File(data, content_type)
+
+def getImageInfo(data):
+    data = str(data)
+    size = len(data)
+    height = -1
+    width = -1
+    content_type = ''
+
+    # handle GIFs
+    if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
+        # Check to see if content_type is correct
+        content_type = 'image/gif'
+        w, h = struct.unpack("<HH", data[6:10])
+        width = int(w)
+        height = int(h)
+
+    # See PNG 2. Edition spec (http://www.w3.org/TR/PNG/)
+    # Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
+    # and finally the 4-byte width, height
+    elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
+          and (data[12:16] == 'IHDR')):
+        content_type = 'image/png'
+        w, h = struct.unpack(">LL", data[16:24])
+        width = int(w)
+        height = int(h)
+
+    # Maybe this is for an older PNG version.
+    elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
+        # Check to see if we have the right content type
+        content_type = 'image/png'
+        w, h = struct.unpack(">LL", data[8:16])
+        width = int(w)
+        height = int(h)
+
+    # handle JPEGs
+    elif (size >= 2) and data.startswith('\377\330'):
+        content_type = 'image/jpeg'
+        jpeg = StringIO(data)
+        jpeg.read(2)
+        b = jpeg.read(1)
+        try:
+            w = -1
+            h = -1
+            while (b and ord(b) != 0xDA):
+                while (ord(b) != 0xFF): b = jpeg.read(1)
+                while (ord(b) == 0xFF): b = jpeg.read(1)
+                if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
+                    jpeg.read(3)
+                    h, w = struct.unpack(">HH", jpeg.read(4))
+                    break
+                else:
+                    jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
+                b = jpeg.read(1)
+            width = int(w)
+            height = int(h)
+        except struct.error:
+            pass
+        except ValueError:
+            pass
+
+    # handle BMPs
+    elif (size >= 30) and data.startswith('BM'):
+        kind = struct.unpack("<H", data[14:16])[0]
+        if kind == 40: # Windows 3.x bitmap
+            content_type = 'image/x-ms-bmp'
+            width, height = struct.unpack("<LL", data[18:26])
+
+    return content_type, width, height

Added: z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,53 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Basic File interfaces.
+
+$Id: interfaces.py 73772 2007-03-27 15:09:19Z dobe $
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.schema import BytesLine, Bytes
+from zope.interface import Interface
+from zope.app.file.i18n import ZopeMessageFactory as _
+
+
+class IFile(Interface):
+
+    contentType = BytesLine(
+        title = _(u'Content Type'),
+        description=_(u'The content type identifies the type of data.'),
+        default='',
+        required=False,
+        missing_value=''
+        )
+
+    data = Bytes(
+        title=_(u'Data'),
+        description=_(u'The actual content of the object.'),
+        default='',
+        missing_value='',
+        required=False,
+        )
+
+    def getSize():
+        """Return the byte-size of the data of the object."""
+
+class IImage(IFile):
+    """This interface defines an Image that can be displayed.
+    """
+
+    def getImageSize():
+        """Return a tuple (x, y) that describes the dimensions of
+        the object.
+        """

Added: z3c.blobfile/trunk/src/z3c/blobfile/testing.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/testing.py	                        (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/testing.py	2007-11-10 13:39:30 UTC (rev 81707)
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""zope.app.file common test related classes/functions/objects.
+
+$Id: testing.py 72426 2007-02-07 13:57:45Z baijum $
+"""
+
+__docformat__ = "reStructuredText"
+
+import os
+from zope.app.testing.functional import ZCMLLayer
+
+AppFileLayer = ZCMLLayer(
+    os.path.join(os.path.split(__file__)[0], 'ftesting.zcml'),
+    __name__, 'AppFileLayer', allow_teardown=True)



More information about the Checkins mailing list