Dolmen zodb blob handlers
Project description
===========
dolmen.blob
===========
`dolmen.blob` is a layer above `dolmen.file`, using the ZODB blobs as
a storage facility. It respects the `zope.app.file` IFile and the
`dolmen.file` INamedFile interfaces.
Compatibility
=============
In order to make sure that our BlobFile is functional, we test it
against some common uses, implemented by `zope.file.file.File`,
`zope.app.file.file.File` and `dolmen.file.NamedFile`::
>>> from dolmen.blob import BlobFile, IBlobFile
>>> blob = BlobFile()
>>> print blob.contentType
application/octet-stream
>>> blob.data
''
>>> blob.filename
u''
>>> blob = BlobFile(data='mydata', filename="foo.txt")
>>> blob.filename
u'foo.txt'
>>> blob.data
'mydata'
>>> blob.contentType
'text/plain'
>>> blob.mimeType
'text/plain'
>>> blob = BlobFile(data=u'some random data', filename="foo.txt")
>>> blob.filename
u'foo.txt'
>>> blob.data
'some random data'
>>> import cStringIO
>>> data = cStringIO.StringIO("mydata")
>>> blob = BlobFile(data=data)
>>> blob.data
'mydata'
>>> blob.getSize()
6L
>>> blob.size
6
>>> from zope.size.interfaces import ISized
>>> sized = ISized(blob)
>>> sized
<zope.file.browser.Sized object at ...>
>>> sized.sizeForDisplay()
u'1 KB'
>>> sized.sizeForSorting()
('byte', 6)
>>> from zope.filerepresentation.interfaces import IReadFile, IWriteFile
>>> reader = IReadFile(blob)
>>> writer = IWriteFile(blob)
>>> reader.read()
'mydata'
>>> reader.size()
6
>>> writer.write('changing data')
>>> reader.read()
'changing data'
>>> reader.size()
13
Let's verify the implementation in depth::
>>> from dolmen.file import INamedFile
>>> from zope.interface import verify
>>> import zope.file
>>> import zope.app.file
>>> blob = BlobFile(data='my data')
>>> verify.verifyObject(IBlobFile, blob)
True
>>> verify.verifyObject(INamedFile, blob)
True
>>> verify.verifyObject(zope.app.file.interfaces.IFile, blob)
True
>>> verify.verifyObject(zope.file.interfaces.IFile, blob)
True
Storage
=======
The ZODB blobs mimic a basic Python file and implement basic methods,
like read, write, readlines, seek, etc. In order to provide a very
pluggable and performant way to persist the datas, `dolmen.file`
proposes a storage mechanism, based on adapters. This idea, originally
implemented in z3c.blobfile, has been enhanced to rely on multi
adapters, adapting an ZODB.interfaces.IBlob and a data object.
As seen above, in the ``compatibility`` section, the
dolmen.blob.BlobFile handles String, Unicode and file-like objects,
out of the box.
Errors
------
If the storage can't find a way to persist the data, a
`dolmen.blob.StorageError` exception is raised::
>>> blob = BlobFile(data={'something': 1})
Traceback (most recent call last):
...
StorageError: An error occured during the blob storage. Check the value type
(<type 'dict'>). This value should implement IFile, IString or IUnicode (see
`dolmen.builtins`).
Storage implementation
----------------------
The example above shows us that the Dict object is not handled by
dolmen.blob, out of the box. Let's implement a storage for this
usecase::
>>> import zope.component
>>> from ZODB.interfaces import IBlob
>>> from dolmen.builtins import IDict
>>> from dolmen.blob import IFileStorage
>>> def store_dict(blob, dictionnary):
... dict_repr = repr(dictionnary.items())
... fp = blob.open('w')
... fp.write(dict_repr)
... fp.close()
... return True
>>> zope.component.provideAdapter(
... store_dict, adapts=(IBlob, IDict), provides=IFileStorage)
>>> blob = BlobFile(data={'something': 1})
>>> blob.data
"[('something', 1)]"
Mimetype and charset
====================
`dolmen.blob` provides components implementing the `zope.mimetype`
IContentTypeAware interface. It allows your content to be manipulated
in order to set a mimetype and extensive headers coptions.
Several adapters are provided by `zope.mimetype`. We don't want to
review them all, but there are some interesting ones.
The IContentInfo components allow you to get detailed information for
your content, formatted in a convenient way, to publish them easily::
>>> from zope.interface import alsoProvides
>>> from zope.mimetype.interfaces import IContentInfo
>>> blob = BlobFile(data=u'some random data', filename="foo.txt")
>>> info = IContentInfo(blob)
>>> print info
<zope.mimetype.contentinfo.ContentInfo object at ...>
>>> print info.effectiveMimeType
text/plain
>>> print info.effectiveParameters
{}
It allows a rough handling of the data encoding too::
>>> from zope.mimetype.interfaces import IContentTypeEncoded
>>> encoded = BlobFile(data=u'La Pe\xf1a',
... parameters={'charset': 'utf-8'})
>>> info = IContentInfo(encoded)
>>> print info.effectiveParameters
{}
>>> alsoProvides(encoded, IContentTypeEncoded)
>>> info = IContentInfo(encoded)
>>> info.effectiveParameters
{'charset': 'utf-8'}
>>> info.effectiveMimeType
'application/octet-stream'
>>> info.contentType
'application/octet-stream;charset=utf-8'
>>> codec = info.getCodec()
>>> codec.name
'utf-8'
>>> print info.decode(encoded.data)
La Peña
Accesses
========
Filesystem access
-----------------
In some cases, it's useful to be able to be able to get the location
of the physical blob file on the filesystem. This is possible through
the attribute `physical_path`. However, this attribute is available
only when the file has been persisted and the transaction commited::
>>> import transaction
>>> root = getRootFolder()
>>> root['myblob'] = BlobFile(data='my data', filename="data.txt")
The transaction has not been commited, we try to access the attribute::
>>> myblob = root['myblob']
>>> print myblob.physical_path
None
We now commit the transaction and retry::
>>> transaction.commit()
>>> print myblob.physical_path
/tmp/tmp.../....blob
Browser access
--------------
.. attention::
Please read `dolmen.file` README.txt for more information.
As an dolmen.file.INamedFile, the BlobFile can bee accessed by the
browser, using a "file_publish" view::
>>> from zope.component import getMultiAdapter
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> view = getMultiAdapter((myblob, request), name='file_publish')
>>> view
<dolmen.blob.access.FilePublisher object at ...>
>>> view.update()
>>> for key, value in view.response.getHeaders(): print key, repr(value)
X-Powered-By 'Zope (www.zope.org), Python (www.python.org)'
Content-Length '7'
Content-Type 'text/plain'
Content-Disposition 'attachment; filename="data.txt"'
>>> view.render()
<zope.file.download.DownloadResult object at ...>
Property
========
.. attention::
Please read `dolmen.file` README.txt for more information.
The persistency of the data can be handled, in complex object, by a
FileField using a BlobProperty::
>>> from persistent import Persistent
>>> from dolmen.file import FileField
>>> from dolmen.blob import BlobProperty
>>> from zope.interface import Interface, implements
>>> class IContent(Interface):
... binary = FileField(title=u"Binary data")
>>> class MyContent(Persistent):
... implements(IContent)
... binary = BlobProperty(IContent['binary'])
>>> root['mammoth'] = MyContent()
>>> manfred = root['mammoth']
>>> manfred.binary = 'Foobar'
>>> manfred.binary
<dolmen.blob.file.BlobValue object at ...>
>>> verify.verifyObject(IBlobFile, manfred.binary)
True
>>> ISized(manfred.binary).sizeForDisplay()
u'1 KB'
Changelog
=========
0.2 (2009-10-23)
----------------
* Added a bunch of new tests for the compatibility with the new
packages used.
* A new access view is available for `IBlobFile` objects, returning a
`zope.file.download.DownloadResult`. This access view also uses
an adapter to `zope.mimetype.interfaces.IContentInfo` to get the
header values.
* `IBlobFile` now inherits from `zope.file.interfaces.IFile`. This
brings in a lot of new features, including the compatibility with
the `zope.mimetype` package and its adapters.
* `dolmen.blob` now proposes a non `Persistent` blob, called
BlobValue. It allows to have object storing an attribute value in a
blob, without getting an independant connection to the database
(Blob already do that). The BlobProperty uses this new component
now.
0.1 (2009-10-19)
----------------
* Initial release
dolmen.blob
===========
`dolmen.blob` is a layer above `dolmen.file`, using the ZODB blobs as
a storage facility. It respects the `zope.app.file` IFile and the
`dolmen.file` INamedFile interfaces.
Compatibility
=============
In order to make sure that our BlobFile is functional, we test it
against some common uses, implemented by `zope.file.file.File`,
`zope.app.file.file.File` and `dolmen.file.NamedFile`::
>>> from dolmen.blob import BlobFile, IBlobFile
>>> blob = BlobFile()
>>> print blob.contentType
application/octet-stream
>>> blob.data
''
>>> blob.filename
u''
>>> blob = BlobFile(data='mydata', filename="foo.txt")
>>> blob.filename
u'foo.txt'
>>> blob.data
'mydata'
>>> blob.contentType
'text/plain'
>>> blob.mimeType
'text/plain'
>>> blob = BlobFile(data=u'some random data', filename="foo.txt")
>>> blob.filename
u'foo.txt'
>>> blob.data
'some random data'
>>> import cStringIO
>>> data = cStringIO.StringIO("mydata")
>>> blob = BlobFile(data=data)
>>> blob.data
'mydata'
>>> blob.getSize()
6L
>>> blob.size
6
>>> from zope.size.interfaces import ISized
>>> sized = ISized(blob)
>>> sized
<zope.file.browser.Sized object at ...>
>>> sized.sizeForDisplay()
u'1 KB'
>>> sized.sizeForSorting()
('byte', 6)
>>> from zope.filerepresentation.interfaces import IReadFile, IWriteFile
>>> reader = IReadFile(blob)
>>> writer = IWriteFile(blob)
>>> reader.read()
'mydata'
>>> reader.size()
6
>>> writer.write('changing data')
>>> reader.read()
'changing data'
>>> reader.size()
13
Let's verify the implementation in depth::
>>> from dolmen.file import INamedFile
>>> from zope.interface import verify
>>> import zope.file
>>> import zope.app.file
>>> blob = BlobFile(data='my data')
>>> verify.verifyObject(IBlobFile, blob)
True
>>> verify.verifyObject(INamedFile, blob)
True
>>> verify.verifyObject(zope.app.file.interfaces.IFile, blob)
True
>>> verify.verifyObject(zope.file.interfaces.IFile, blob)
True
Storage
=======
The ZODB blobs mimic a basic Python file and implement basic methods,
like read, write, readlines, seek, etc. In order to provide a very
pluggable and performant way to persist the datas, `dolmen.file`
proposes a storage mechanism, based on adapters. This idea, originally
implemented in z3c.blobfile, has been enhanced to rely on multi
adapters, adapting an ZODB.interfaces.IBlob and a data object.
As seen above, in the ``compatibility`` section, the
dolmen.blob.BlobFile handles String, Unicode and file-like objects,
out of the box.
Errors
------
If the storage can't find a way to persist the data, a
`dolmen.blob.StorageError` exception is raised::
>>> blob = BlobFile(data={'something': 1})
Traceback (most recent call last):
...
StorageError: An error occured during the blob storage. Check the value type
(<type 'dict'>). This value should implement IFile, IString or IUnicode (see
`dolmen.builtins`).
Storage implementation
----------------------
The example above shows us that the Dict object is not handled by
dolmen.blob, out of the box. Let's implement a storage for this
usecase::
>>> import zope.component
>>> from ZODB.interfaces import IBlob
>>> from dolmen.builtins import IDict
>>> from dolmen.blob import IFileStorage
>>> def store_dict(blob, dictionnary):
... dict_repr = repr(dictionnary.items())
... fp = blob.open('w')
... fp.write(dict_repr)
... fp.close()
... return True
>>> zope.component.provideAdapter(
... store_dict, adapts=(IBlob, IDict), provides=IFileStorage)
>>> blob = BlobFile(data={'something': 1})
>>> blob.data
"[('something', 1)]"
Mimetype and charset
====================
`dolmen.blob` provides components implementing the `zope.mimetype`
IContentTypeAware interface. It allows your content to be manipulated
in order to set a mimetype and extensive headers coptions.
Several adapters are provided by `zope.mimetype`. We don't want to
review them all, but there are some interesting ones.
The IContentInfo components allow you to get detailed information for
your content, formatted in a convenient way, to publish them easily::
>>> from zope.interface import alsoProvides
>>> from zope.mimetype.interfaces import IContentInfo
>>> blob = BlobFile(data=u'some random data', filename="foo.txt")
>>> info = IContentInfo(blob)
>>> print info
<zope.mimetype.contentinfo.ContentInfo object at ...>
>>> print info.effectiveMimeType
text/plain
>>> print info.effectiveParameters
{}
It allows a rough handling of the data encoding too::
>>> from zope.mimetype.interfaces import IContentTypeEncoded
>>> encoded = BlobFile(data=u'La Pe\xf1a',
... parameters={'charset': 'utf-8'})
>>> info = IContentInfo(encoded)
>>> print info.effectiveParameters
{}
>>> alsoProvides(encoded, IContentTypeEncoded)
>>> info = IContentInfo(encoded)
>>> info.effectiveParameters
{'charset': 'utf-8'}
>>> info.effectiveMimeType
'application/octet-stream'
>>> info.contentType
'application/octet-stream;charset=utf-8'
>>> codec = info.getCodec()
>>> codec.name
'utf-8'
>>> print info.decode(encoded.data)
La Peña
Accesses
========
Filesystem access
-----------------
In some cases, it's useful to be able to be able to get the location
of the physical blob file on the filesystem. This is possible through
the attribute `physical_path`. However, this attribute is available
only when the file has been persisted and the transaction commited::
>>> import transaction
>>> root = getRootFolder()
>>> root['myblob'] = BlobFile(data='my data', filename="data.txt")
The transaction has not been commited, we try to access the attribute::
>>> myblob = root['myblob']
>>> print myblob.physical_path
None
We now commit the transaction and retry::
>>> transaction.commit()
>>> print myblob.physical_path
/tmp/tmp.../....blob
Browser access
--------------
.. attention::
Please read `dolmen.file` README.txt for more information.
As an dolmen.file.INamedFile, the BlobFile can bee accessed by the
browser, using a "file_publish" view::
>>> from zope.component import getMultiAdapter
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> view = getMultiAdapter((myblob, request), name='file_publish')
>>> view
<dolmen.blob.access.FilePublisher object at ...>
>>> view.update()
>>> for key, value in view.response.getHeaders(): print key, repr(value)
X-Powered-By 'Zope (www.zope.org), Python (www.python.org)'
Content-Length '7'
Content-Type 'text/plain'
Content-Disposition 'attachment; filename="data.txt"'
>>> view.render()
<zope.file.download.DownloadResult object at ...>
Property
========
.. attention::
Please read `dolmen.file` README.txt for more information.
The persistency of the data can be handled, in complex object, by a
FileField using a BlobProperty::
>>> from persistent import Persistent
>>> from dolmen.file import FileField
>>> from dolmen.blob import BlobProperty
>>> from zope.interface import Interface, implements
>>> class IContent(Interface):
... binary = FileField(title=u"Binary data")
>>> class MyContent(Persistent):
... implements(IContent)
... binary = BlobProperty(IContent['binary'])
>>> root['mammoth'] = MyContent()
>>> manfred = root['mammoth']
>>> manfred.binary = 'Foobar'
>>> manfred.binary
<dolmen.blob.file.BlobValue object at ...>
>>> verify.verifyObject(IBlobFile, manfred.binary)
True
>>> ISized(manfred.binary).sizeForDisplay()
u'1 KB'
Changelog
=========
0.2 (2009-10-23)
----------------
* Added a bunch of new tests for the compatibility with the new
packages used.
* A new access view is available for `IBlobFile` objects, returning a
`zope.file.download.DownloadResult`. This access view also uses
an adapter to `zope.mimetype.interfaces.IContentInfo` to get the
header values.
* `IBlobFile` now inherits from `zope.file.interfaces.IFile`. This
brings in a lot of new features, including the compatibility with
the `zope.mimetype` package and its adapters.
* `dolmen.blob` now proposes a non `Persistent` blob, called
BlobValue. It allows to have object storing an attribute value in a
blob, without getting an independant connection to the database
(Blob already do that). The BlobProperty uses this new component
now.
0.1 (2009-10-19)
----------------
* Initial release
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
dolmen.blob-0.2.tar.gz
(9.4 kB
view hashes)