[Checkins] SVN: z3c.blobfile/trunk/ Added an evolution script and
functional doctests for replacing zope.app.file files with
blobfiles.
Uwe Oestermeier
u.oestermeier at iwm-kmrc.de
Wed Nov 14 07:07:51 EST 2007
Log message for revision 81827:
Added an evolution script and functional doctests for replacing zope.app.file files with blobfiles.
Changed:
U z3c.blobfile/trunk/buildout.cfg
U z3c.blobfile/trunk/src/z3c/blobfile/blobfile.txt
U z3c.blobfile/trunk/src/z3c/blobfile/configure.zcml
U z3c.blobfile/trunk/src/z3c/blobfile/file.py
U z3c.blobfile/trunk/src/z3c/blobfile/ftesting.zcml
A z3c.blobfile/trunk/src/z3c/blobfile/ftests.py
A z3c.blobfile/trunk/src/z3c/blobfile/generations/
A z3c.blobfile/trunk/src/z3c/blobfile/generations/__init__.py
A z3c.blobfile/trunk/src/z3c/blobfile/generations/evolve1.py
A z3c.blobfile/trunk/src/z3c/blobfile/generations/install.py
U z3c.blobfile/trunk/src/z3c/blobfile/image.py
U z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py
A z3c.blobfile/trunk/src/z3c/blobfile/overrides.zcml
U z3c.blobfile/trunk/src/z3c/blobfile/testing.py
U z3c.blobfile/trunk/src/z3c/blobfile/tests.py
-=-
Modified: z3c.blobfile/trunk/buildout.cfg
===================================================================
--- z3c.blobfile/trunk/buildout.cfg 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/buildout.cfg 2007-11-14 12:07:51 UTC (rev 81827)
@@ -6,3 +6,4 @@
[test]
recipe = zc.recipe.testrunner
eggs = z3c.blobfile [test]
+defaults = ['--tests-pattern', '^f?tests$', '-v']
\ No newline at end of file
Modified: z3c.blobfile/trunk/src/z3c/blobfile/blobfile.txt
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/blobfile.txt 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/src/z3c/blobfile/blobfile.txt 2007-11-14 12:07:51 UTC (rev 81827)
@@ -1,15 +1,69 @@
Blob File Implementation
========================
+This implementation of zope.app.file.interfaces.IFile takes advantage
+of the new ZODB blob support and tries to be completely backward compatible to
+the existing file implementation in zope.app.file.
+Let's assume that you have already an existing database with zope.app.file
+content types:
+ >>> root = getRootFolder()
+ >>> from zope.app.file import File, Image
+
+ >>> from z3c.blobfile import testing
+ >>> root[u'file'] = File('A text file', contentType='text/plain')
+ >>> root[u'image'] = Image(testing.zptlogo)
+
+Note that we cannot assume that these objects exist in isolation. Many of
+them probably are annotated, indexed, some even may be registered as utility
+etc.
+Therefore we need a very conservative evolution strategy. We simply replace
+the __class__ attribute and the data section. We will not test all relations
+to all other objects, since this is largely application dependent. Here
+we only take the ZopeDublinCore timestamps as an example that our evolution
+step leaves as many things untouched as possible.
+
+ >>> from zope.dublincore.interfaces import IZopeDublinCore
+ >>> import datetime
+
+ >>> IZopeDublinCore(root[u'file']).created = datetime.datetime.utcnow()
+ >>> t1 = IZopeDublinCore(root[u'file']).created
+ >>> IZopeDublinCore(root[u'file']).title = u'No evolution'
+
+Now we perform the basic evolution steps:
+
+ >>> from z3c.blobfile.generations.evolve1 import evolveZopeAppFile
+ >>> evolveZopeAppFile(root)
+
+The file data remain the same ...
+
+ >>> root[u'file'].data
+ 'A text file'
+ >>> root[u'file'].contentType
+ 'text/plain'
+
+ >>> root[u'image'].data == testing.zptlogo
+ True
+
+and so are the annotations:
+
+ >>> IZopeDublinCore(root[u'file']).created == t1
+ True
+ >>> IZopeDublinCore(root[u'file']).title
+ u'No evolution'
+
+IMPORTANT: If your application needs to be aware of the hidden type change,
+you must provide your own evolution procedure.
+
+
Compatibility with zope.app.file.File
-------------------------------------
-This test mimics exactly the tests of the zope.app.file package:
+The following tests mimic exactly the tests of the zope.app.file package.
- Let's test the constructor:
+Let's test the constructor:
>>> file = File()
>>> file.contentType
@@ -36,7 +90,7 @@
'Foobar'
- Let's test the mutators:
+Let's test the mutators:
>>> file = File()
>>> file.contentType = 'text/plain'
@@ -53,11 +107,11 @@
TypeError: Cannot set None data on a file.
- Let's test large data input:
+Let's test large data input:
>>> file = File()
- Insert as string:
+Insert as string:
>>> file.data = 'Foobar'*60000
>>> file.getSize()
@@ -65,8 +119,9 @@
>>> file.data == 'Foobar'*60000
True
- Insert data as FileChunk:
+Insert data as FileChunk:
+ >>> from zope.app.file.file import FileChunk
>>> fc = FileChunk('Foobar'*4000)
>>> file.data = fc
>>> file.getSize()
@@ -74,7 +129,7 @@
>>> file.data == 'Foobar'*4000
True
- Insert data from file object:
+Insert data from file object:
>>> import cStringIO
>>> sio = cStringIO.StringIO()
@@ -87,7 +142,7 @@
True
- Last, but not least, verify the interface:
+Last, but not least, verify the interface:
>>> from zope.interface.verify import verifyClass
>>> zope.app.file.interfaces.IFile.implementedBy(File)
@@ -99,6 +154,7 @@
Test of Filerepresentation Adapters
-----------------------------------
+ >>> from zope.app.file.file import FileReadFile
>>> file = File()
>>> content = "This is some file\\ncontent."
>>> file.data = content
@@ -108,7 +164,7 @@
>>> FileReadFile(file).size() == len(content)
True
-
+ >>> from zope.app.file.file import FileWriteFile
>>> file = File()
>>> content = "This is some file\\ncontent."
>>> FileWriteFile(file).write(content)
Modified: z3c.blobfile/trunk/src/z3c/blobfile/configure.zcml
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/configure.zcml 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/src/z3c/blobfile/configure.zcml 2007-11-14 12:07:51 UTC (rev 81827)
@@ -10,6 +10,40 @@
in the add menu or not
-->
+ <class class=".file.File">
+
+ <require
+ permission="zope.View"
+ interface=".interfaces.IBlobFile"
+ />
+
+ <require
+ permission="zope.ManageContent"
+ set_schema=".interfaces.IBlobFile"
+ />
+
+ <implements
+ interface="zope.annotation.interfaces.IAttributeAnnotatable"
+ />
+ </class>
+
+ <class class=".image.Image">
+
+ <require
+ permission="zope.View"
+ interface=".interfaces.IBlobImage"
+ />
+
+ <require
+ permission="zope.ManageContent"
+ set_schema="zope.app.file.interfaces.IFile"
+ />
+
+ <implements
+ interface="zope.annotation.interfaces.IAttributeAnnotatable"
+ />
+ </class>
+
<!-- `IStorage` utilities should be named with the dotted name
referencing the implementation.
-->
Modified: z3c.blobfile/trunk/src/z3c/blobfile/file.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/file.py 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/src/z3c/blobfile/file.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -11,12 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""File content component
-
-TODO:
-- we should rename `_data` to `_blob` in `File`
-- should we then keep `_data` in `File` for backwards compatibility?
-"""
+"""File content component"""
__docformat__ = 'restructuredtext'
from persistent import Persistent
@@ -42,12 +37,12 @@
size = 0
def __init__(self, data='', contentType=''):
- self._data = Blob()
+ self._blob = Blob()
self.contentType = contentType
self._setData(data)
def open(self, mode="r"):
- return self._data.open(mode)
+ return self._blob.open(mode)
def _setData(self, data):
# Search for a storable that is able to store the data
@@ -55,21 +50,22 @@
data.__class__.__name__))
storable = zope.component.getUtility(interfaces.IStorage,
name=dottedName)
- storable.store(data, self._data)
+ storable.store(data, self._blob)
def _getData(self):
- fp = self._data.open('r')
+ fp = self._blob.open('r')
data = fp.read()
fp.close()
return data
-
+
+ _data = property(_getData, _setData)
data = property(_getData, _setData)
@property
def size(self):
- if self._data == "":
+ if self._blob == "":
return 0
- reader = self._data.open()
+ reader = self._blob.open()
reader.seek(0,2)
size = int(reader.tell())
reader.close()
Modified: z3c.blobfile/trunk/src/z3c/blobfile/ftesting.zcml
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/ftesting.zcml 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/src/z3c/blobfile/ftesting.zcml 2007-11-14 12:07:51 UTC (rev 81827)
@@ -13,7 +13,10 @@
<include package="zope.app.authentication" />
<include package="zope.app.securitypolicy" />
<include package="zope.app.file"/>
-
+ <include package="zope.annotation"/>
+ <include package="zope.dublincore"/>
+ <include package="z3c.blobfile"/>
+
<securityPolicy
component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy" />
Added: z3c.blobfile/trunk/src/z3c/blobfile/ftests.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/ftests.py (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/ftests.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -0,0 +1,33 @@
+import unittest
+
+import zope, transaction
+import os.path
+from zope.testing import doctest, doctestunit, module
+
+import testing
+
+def setUp(test):
+ module.setUp(test, 'z3c.blobfile.readme_txt')
+
+def tearDown(test):
+ module.tearDown(test, 'z3c.blobfile.readme_txt')
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+
+ globs = {'zope': zope,
+ 'transaction': transaction,
+ 'pprint': doctestunit.pprint}
+
+ test = testing.FunctionalBlobDocFileSuite('blobfile.txt',
+ package='z3c.blobfile',
+ globs=globs,
+ optionflags=doctest.NORMALIZE_WHITESPACE+doctest.ELLIPSIS)
+ test.layer = testing.BlobFileLayer
+
+ suite.addTests((test,))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
Added: z3c.blobfile/trunk/src/z3c/blobfile/generations/__init__.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/generations/__init__.py (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/generations/__init__.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -0,0 +1,10 @@
+
+from zope.app.generations.generations import SchemaManager
+
+
+package_name = 'z3c.blobfile.generations'
+
+BebopPersonSchemaManager = SchemaManager(
+ minimum_generation=1,
+ generation=2,
+ package_name=package_name)
Added: z3c.blobfile/trunk/src/z3c/blobfile/generations/evolve1.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/generations/evolve1.py (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/generations/evolve1.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -0,0 +1,43 @@
+
+import zope.interface
+import zope.component
+
+from zope.app.generations.utility import findObjectsProviding
+from zope.app.zopeappgenerations import getRootFolder
+
+from zope.app.file.interfaces import IFile
+import zope.app.file
+from ZODB.blob import Blob
+import z3c.blobfile.file
+import z3c.blobfile.image
+
+
+def evolveZopeAppFile(root):
+ """Replaces the classes and data of zope.app.file objects.
+
+ Leaves annotations, key references, int id etc. intact.
+ Doesn't throw an ObjectModify event.
+ """
+ for file in findObjectsProviding(root, IFile):
+ data = file.data
+
+ file._blob = Blob()
+
+ if isinstance(file, zope.app.file.File):
+ file.__class__ = z3c.blobfile.file.File
+
+ if isinstance(file, zope.app.file.Image):
+ file.__class__ = z3c.blobfile.image.Image
+
+ file.data = data
+
+
+def evolve(context):
+ """
+ Replaces all zope.app.file content objects with z3c.blobfile counterparts.
+ """
+
+ root = getRootFolder(context)
+
+ evolveCatalog(root)
+ evolvePerson(root)
Added: z3c.blobfile/trunk/src/z3c/blobfile/generations/install.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/generations/install.py (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/generations/install.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -0,0 +1,19 @@
+
+from z3c.blobfile.generations import package_name
+
+
+def evolve(context):
+ """run all evolutions beginning with generation 1"""
+
+ print "SchemaManager(%s): install" % package_name
+ generation = 1
+ while True:
+ name = "%s.evolve%d" % (package_name, generation)
+ try:
+ evolver = __import__(name, {}, {}, ['*'])
+ except ImportError:
+ break
+ else:
+ print "SchemaManager(%s): evolve%s" % (package_name, generation)
+ evolver.evolve(context)
+ generation += 1
Modified: z3c.blobfile/trunk/src/z3c/blobfile/image.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/image.py 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/src/z3c/blobfile/image.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -11,10 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Image content type implementation
-
-$Id: image.py 76693 2007-06-14 13:39:36Z mgedmin $
-"""
+"""Image content type implementation"""
__docformat__ = 'restructuredtext'
import struct
@@ -31,29 +28,42 @@
from ZODB.blob import Blob
+IMAGE_INFO_BYTES = 1024
+
class Image(File):
implements(IImage)
def __init__(self, data=''):
'''See interface `IFile`'''
- self._data = Blob()
- self.contentType, self._width, self._height = getImageInfo(data)
+ self._blob = Blob()
self.data = data
+ firstbytes = self.getFirstBytes()
+ self.contentType, self._width, self._height = getImageInfo(firstbytes)
def _setData(self, data):
- fp = self._data.open('w')
- fp.write(data)
- fp.close()
- contentType, self._width, self._height = getImageInfo(data)
+ super(Image, self)._setData(data)
+ firstbytes = self.getFirstBytes()
+ contentType, self._width, self._height = getImageInfo(firstbytes)
if contentType:
self.contentType = contentType
+ def getFirstBytes(self):
+ """Returns the first bytes of the file.
+
+ Returns an amount which is sufficient to determine the image type.
+ """
+ fp = self.open('r')
+ firstbytes = fp.read(IMAGE_INFO_BYTES)
+ fp.close()
+ return firstbytes
+
def getImageSize(self):
- '''See interface `IImage`'''
+ """See interface `IImage`"""
return (self._width, self._height)
data = property(File._getData, _setData)
+
class ImageSized(object):
implements(ISized)
@@ -81,6 +91,7 @@
# i18nextract and never show up in message catalogs
return _(byte_size + ' ${width}x${height}', mapping=mapping)
+
class FileFactory(object):
def __init__(self, context):
@@ -91,12 +102,11 @@
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)
Modified: z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/src/z3c/blobfile/interfaces.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -21,7 +21,22 @@
import zope.app.file.interfaces
+class IOpenable(zope.interface.Interface):
+ """Openable file
+ """
+ def open(mode):
+ """Open file and return the file descriptor
+ """
+
+class IBlobFile(zope.app.file.interfaces.IFile, IOpenable):
+ """A file that uses Blobs as data storage."""
+
+
+class IBlobImage(zope.app.file.interfaces.IImage, IOpenable):
+ """An image that uses Blobs as data storage."""
+
+
class IStorage(zope.interface.Interface):
"""Store file data
"""
@@ -29,19 +44,9 @@
def store(data, blob):
"""Store the data into the blob
- Raises NonStorable if data is not storable.
+ Raises NonStorable if data is not storable.
"""
-
-class IOpenable(zope.interface.Interface):
- """Openable file
- """
-
- def open(mode):
- """Open file and return the file descriptor
- """
-
-
class NotStorable(Exception):
"""Data is not storable
"""
Added: z3c.blobfile/trunk/src/z3c/blobfile/overrides.zcml
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/overrides.zcml (rev 0)
+++ z3c.blobfile/trunk/src/z3c/blobfile/overrides.zcml 2007-11-14 12:07:51 UTC (rev 81827)
@@ -0,0 +1,28 @@
+<configure xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser">
+
+ <!-- Provide local overrides of standard configurations -->
+
+ <!-- content classes -->
+
+ <class class=".file.File">
+
+ <factory
+ id="zope.app.content.File"
+ title="File"
+ description="A File"
+ />
+
+ </class>
+
+ <class class=".image.Image">
+
+ <factory
+ id="zope.app.content.Image"
+ title="Image"
+ description="An Image"
+ />
+
+ </class>
+
+</configure>
Modified: z3c.blobfile/trunk/src/z3c/blobfile/testing.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/testing.py 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/src/z3c/blobfile/testing.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -18,9 +18,117 @@
__docformat__ = "reStructuredText"
-import os
-from zope.app.testing.functional import ZCMLLayer
+import os.path
+import shutil
+import tempfile
-AppFileLayer = ZCMLLayer(
+import transaction
+from ZODB.DB import DB
+from ZODB.DemoStorage import DemoStorage
+from ZODB.blob import BlobStorage
+from zope.testing import doctest
+import zope.app.testing.functional
+from zope.app.component.hooks import setSite
+
+here = os.path.dirname(os.path.realpath(__file__))
+
+zptlogo = (
+ 'GIF89a\x10\x00\x10\x00\xd5\x00\x00\xff\xff\xff\xff\xff\xfe\xfc\xfd\xfd'
+ '\xfa\xfb\xfc\xf7\xf9\xfa\xf5\xf8\xf9\xf3\xf6\xf8\xf2\xf5\xf7\xf0\xf4\xf6'
+ '\xeb\xf1\xf3\xe5\xed\xef\xde\xe8\xeb\xdc\xe6\xea\xd9\xe4\xe8\xd7\xe2\xe6'
+ '\xd2\xdf\xe3\xd0\xdd\xe3\xcd\xdc\xe1\xcb\xda\xdf\xc9\xd9\xdf\xc8\xd8\xdd'
+ '\xc6\xd7\xdc\xc4\xd6\xdc\xc3\xd4\xda\xc2\xd3\xd9\xc1\xd3\xd9\xc0\xd2\xd9'
+ '\xbd\xd1\xd8\xbd\xd0\xd7\xbc\xcf\xd7\xbb\xcf\xd6\xbb\xce\xd5\xb9\xcd\xd4'
+ '\xb6\xcc\xd4\xb6\xcb\xd3\xb5\xcb\xd2\xb4\xca\xd1\xb2\xc8\xd0\xb1\xc7\xd0'
+ '\xb0\xc7\xcf\xaf\xc6\xce\xae\xc4\xce\xad\xc4\xcd\xab\xc3\xcc\xa9\xc2\xcb'
+ '\xa8\xc1\xca\xa6\xc0\xc9\xa4\xbe\xc8\xa2\xbd\xc7\xa0\xbb\xc5\x9e\xba\xc4'
+ '\x9b\xbf\xcc\x98\xb6\xc1\x8d\xae\xbaFgs\x00\x00\x00\x00\x00\x00\x00\x00'
+ '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ '\x00,\x00\x00\x00\x00\x10\x00\x10\x00\x00\x06z@\x80pH,\x12k\xc8$\xd2f\x04'
+ '\xd4\x84\x01\x01\xe1\xf0d\x16\x9f\x80A\x01\x91\xc0ZmL\xb0\xcd\x00V\xd4'
+ '\xc4a\x87z\xed\xb0-\x1a\xb3\xb8\x95\xbdf8\x1e\x11\xca,MoC$\x15\x18{'
+ '\x006}m\x13\x16\x1a\x1f\x83\x85}6\x17\x1b $\x83\x00\x86\x19\x1d!%)\x8c'
+ '\x866#\'+.\x8ca`\x1c`(,/1\x94B5\x19\x1e"&*-024\xacNq\xba\xbb\xb8h\xbeb'
+ '\x00A\x00;'
+ )
+
+class FunctionalBlobTestSetup(zope.app.testing.functional.FunctionalTestSetup):
+
+ temp_dir_name = None
+
+ def setUp(self):
+ """Prepares for a functional test case."""
+ # Tear down the old demo storage (if any) and create a fresh one
+ transaction.abort()
+ self.db.close()
+ storage = DemoStorage("Demo Storage", self.base_storage)
+ # make a dir
+ temp_dir_name = self.temp_dir_name = tempfile.mkdtemp()
+ # wrap storage with BlobStorage
+ storage = BlobStorage(temp_dir_name, storage)
+ self.db = self.app.db = DB(storage)
+ self.connection = None
+
+ def tearDown(self):
+ """Cleans up after a functional test case."""
+ transaction.abort()
+ if self.connection:
+ self.connection.close()
+ self.connection = None
+ self.db.close()
+ # del dir named '__blob_test__%s' % self.name
+ if self.temp_dir_name is not None:
+ shutil.rmtree(self.temp_dir_name, True)
+ self.temp_dir_name = None
+ setSite(None)
+
+
+class ZCMLLayer(zope.app.testing.functional.ZCMLLayer):
+
+ def setUp(self):
+ self.setup = FunctionalBlobTestSetup(self.config_file)
+
+
+class ZCMLLayer(zope.app.testing.functional.ZCMLLayer):
+
+ def setUp(self):
+ self.setup = FunctionalBlobTestSetup(self.config_file)
+
+def FunctionalBlobDocFileSuite(*paths, **kw):
+ globs = kw.setdefault('globs', {})
+ globs['http'] = zope.app.testing.functional.HTTPCaller()
+ globs['getRootFolder'] = zope.app.testing.functional.getRootFolder
+ globs['sync'] = zope.app.testing.functional.sync
+
+ kw['package'] = doctest._normalize_module(kw.get('package'))
+
+ kwsetUp = kw.get('setUp')
+ def setUp(test):
+ FunctionalBlobTestSetup().setUp()
+
+ if kwsetUp is not None:
+ kwsetUp(test)
+ kw['setUp'] = setUp
+
+ kwtearDown = kw.get('tearDown')
+ def tearDown(test):
+ if kwtearDown is not None:
+ kwtearDown(test)
+ FunctionalBlobTestSetup().tearDown()
+ kw['tearDown'] = tearDown
+
+ if 'optionflags' not in kw:
+ old = doctest.set_unittest_reportflags(0)
+ doctest.set_unittest_reportflags(old)
+ kw['optionflags'] = (old
+ | doctest.ELLIPSIS
+ | doctest.REPORT_NDIFF
+ | doctest.NORMALIZE_WHITESPACE)
+
+ suite = doctest.DocFileSuite(*paths, **kw)
+ suite.layer = zope.app.testing.functional.Functional
+ return suite
+
+BlobFileLayer = ZCMLLayer(
os.path.join(os.path.split(__file__)[0], 'ftesting.zcml'),
- __name__, 'AppFileLayer', allow_teardown=True)
+ __name__, 'BlobFileLayer', allow_teardown=True)
Modified: z3c.blobfile/trunk/src/z3c/blobfile/tests.py
===================================================================
--- z3c.blobfile/trunk/src/z3c/blobfile/tests.py 2007-11-14 11:26:48 UTC (rev 81826)
+++ z3c.blobfile/trunk/src/z3c/blobfile/tests.py 2007-11-14 12:07:51 UTC (rev 81827)
@@ -11,44 +11,20 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Test Image content component
-
-$Id: test_image.py 76693 2007-06-14 13:39:36Z mgedmin $
-"""
+"""Test Image content component"""
import unittest
+import zope.component
+
from zope.interface.verify import verifyClass
from zope.app.file.interfaces import IImage
-from z3c.blobfile.image import Image, FileFactory, ImageSized
+from z3c.blobfile.image import Image, FileFactory, ImageSized, getImageInfo
from z3c.blobfile.file import File, FileWriteFile, FileReadFile
-zptlogo = (
- 'GIF89a\x10\x00\x10\x00\xd5\x00\x00\xff\xff\xff\xff\xff\xfe\xfc\xfd\xfd'
- '\xfa\xfb\xfc\xf7\xf9\xfa\xf5\xf8\xf9\xf3\xf6\xf8\xf2\xf5\xf7\xf0\xf4\xf6'
- '\xeb\xf1\xf3\xe5\xed\xef\xde\xe8\xeb\xdc\xe6\xea\xd9\xe4\xe8\xd7\xe2\xe6'
- '\xd2\xdf\xe3\xd0\xdd\xe3\xcd\xdc\xe1\xcb\xda\xdf\xc9\xd9\xdf\xc8\xd8\xdd'
- '\xc6\xd7\xdc\xc4\xd6\xdc\xc3\xd4\xda\xc2\xd3\xd9\xc1\xd3\xd9\xc0\xd2\xd9'
- '\xbd\xd1\xd8\xbd\xd0\xd7\xbc\xcf\xd7\xbb\xcf\xd6\xbb\xce\xd5\xb9\xcd\xd4'
- '\xb6\xcc\xd4\xb6\xcb\xd3\xb5\xcb\xd2\xb4\xca\xd1\xb2\xc8\xd0\xb1\xc7\xd0'
- '\xb0\xc7\xcf\xaf\xc6\xce\xae\xc4\xce\xad\xc4\xcd\xab\xc3\xcc\xa9\xc2\xcb'
- '\xa8\xc1\xca\xa6\xc0\xc9\xa4\xbe\xc8\xa2\xbd\xc7\xa0\xbb\xc5\x9e\xba\xc4'
- '\x9b\xbf\xcc\x98\xb6\xc1\x8d\xae\xbaFgs\x00\x00\x00\x00\x00\x00\x00\x00'
- '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
- '\x00,\x00\x00\x00\x00\x10\x00\x10\x00\x00\x06z@\x80pH,\x12k\xc8$\xd2f\x04'
- '\xd4\x84\x01\x01\xe1\xf0d\x16\x9f\x80A\x01\x91\xc0ZmL\xb0\xcd\x00V\xd4'
- '\xc4a\x87z\xed\xb0-\x1a\xb3\xb8\x95\xbdf8\x1e\x11\xca,MoC$\x15\x18{'
- '\x006}m\x13\x16\x1a\x1f\x83\x85}6\x17\x1b $\x83\x00\x86\x19\x1d!%)\x8c'
- '\x866#\'+.\x8ca`\x1c`(,/1\x94B5\x19\x1e"&*-024\xacNq\xba\xbb\xb8h\xbeb'
- '\x00A\x00;'
- )
+import testing
+import storages
+import interfaces
-
-
-
-# XXX: Don't know how to set up utilities for tests correctly::
def registerUtilities():
- import zope.component
- import storages
- import interfaces
zope.component.provideUtility(storages.StringStorable(),
interfaces.IStorage,
name="__builtin__.str")
@@ -86,8 +62,8 @@
image.contentType = 'image/jpeg'
self.assertEqual(image.contentType, 'image/jpeg')
- image._setData(zptlogo)
- self.assertEqual(image.data, zptlogo)
+ image._setData(testing.zptlogo)
+ self.assertEqual(image.data, testing.zptlogo)
self.assertEqual(image.contentType, 'image/gif')
self.assertEqual(image.getImageSize(), (16, 16))
@@ -143,7 +119,7 @@
factory = FileFactory(None)
f = factory("spam.txt", "image/foo", "hello world")
self.assert_(isinstance(f, Image), f)
- f = factory("spam.txt", "", zptlogo)
+ f = factory("spam.txt", "", testing.zptlogo)
self.assert_(isinstance(f, Image), f)
def test_text(self):
@@ -154,10 +130,10 @@
f = factory("spam.txt", "", "\0\1\2\3\4")
self.assert_(isinstance(f, File), f)
self.assert_(not isinstance(f, Image), f)
- f = factory("spam.txt", "text/splat", zptlogo)
+ f = factory("spam.txt", "text/splat", testing.zptlogo)
self.assert_(isinstance(f, File), f)
self.assert_(not isinstance(f, Image), f)
- f = factory("spam.txt", "application/splat", zptlogo)
+ f = factory("spam.txt", "application/splat", testing.zptlogo)
self.assert_(isinstance(f, File), f)
self.assert_(not isinstance(f, Image), f)
@@ -193,21 +169,21 @@
self.assertEqual(s.sizeForDisplay().mapping['height'], '?')
def test_getImageInfo(self):
- from zope.app.file.image import getImageInfo
- t, w, h = getImageInfo("\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C")
+ t, w, h = getImageInfo('\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01'
+ '\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C')
+ self.assertEqual(t, "image/jpeg")
+
+ def test_getImageInfo_bmp(self):
+ t, w, h = getImageInfo('BMl\x05\x00\x00\x00\x00\x00\x006\x04\x00\x00('
+ '\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00'
+ '\x01\x00\x08\x00\x01\x00\x00\x006\x01\x00\x00'
+ '\x12\x0b\x00\x00\x12\x0b\x00\x00\x00\x01\x00'
+ '... and so on ...')
+ self.assertEqual(t, "image/x-ms-bmp")
+ self.assertEqual(w, 16)
+ self.assertEqual(h, 16)
-# def test_getImageInfo_bmp(self):
-# from zope.app.file.image import getImageInfo
-# t, w, h = getImageInfo('BMl\x05\x00\x00\x00\x00\x00\x006\x04\x00\x00('
-# '\x00\x00\x00\x10\x00\x00\x00\x10\x00\x00\x00'
-# '\x01\x00\x08\x00\x01\x00\x00\x006\x01\x00\x00'
-# '\x12\x0b\x00\x00\x12\x0b\x00\x00\x00\x01\x00'
-# '... and so on ...')
-# self.assertEqual(t, "image/x-ms-bmp")
-# self.assertEqual(w, 16)
-# self.assertEqual(h, 16)
-
def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestImage),
More information about the Checkins
mailing list