Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
199 lines (145 sloc) 4.7 KB
##############################################################################
#
# Copyright (c) 2005 Zope Foundation 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.
#
##############################################################################
ZODB Blob support
=================
You create a blob like this::
>>> from ZODB.blob import Blob
>>> myblob = Blob()
A blob implements the IBlob interface::
>>> from ZODB.interfaces import IBlob
>>> IBlob.providedBy(myblob)
True
We can open a new blob file for reading, but it won't have any data::
>>> with myblob.open("r") as fp: fp.read()
''
But we can write data to a new Blob by opening it for writing::
>>> f = myblob.open("w")
>>> _ = f.write(b"Hi, Blob!")
If we try to open a Blob again while it is open for writing, we get an error::
>>> myblob.open("r")
Traceback (most recent call last):
...
BlobError: Already opened for writing.
We can close the file::
>>> f.close()
Now we can open it for reading::
>>> f2 = myblob.open("r")
And we get the data back::
>>> f2.read()
'Hi, Blob!'
If we want to, we can open it again::
>>> f3 = myblob.open("r")
>>> f3.read()
'Hi, Blob!'
But we can't open it for writing, while it is opened for reading::
>>> myblob.open("a")
Traceback (most recent call last):
...
BlobError: Already opened for reading.
Before we can write, we have to close the readers::
>>> f2.close()
>>> f3.close()
Now we can open it for writing again and e.g. append data::
>>> f4 = myblob.open("a")
>>> _ = f4.write(b"\nBlob is fine.")
We can't open a blob while it is open for writing:
>>> myblob.open("w")
Traceback (most recent call last):
...
BlobError: Already opened for writing.
>>> myblob.open("r")
Traceback (most recent call last):
...
BlobError: Already opened for writing.
>>> f4.close()
Now we can read it::
>>> f4a = myblob.open("r")
>>> f4a.read()
'Hi, Blob!\nBlob is fine.'
>>> f4a.close()
You shouldn't need to explicitly close a blob unless you hold a reference
to it via a name. If the first line in the following test kept a reference
around via a name, the second call to open it in a writable mode would fail
with a BlobError, but it doesn't::
>>> with myblob.open("r+") as fp: fp.read()
'Hi, Blob!\nBlob is fine.'
>>> f4b = myblob.open("a")
>>> f4b.close()
We can read lines out of the blob too::
>>> f5 = myblob.open("r")
>>> f5.readline()
'Hi, Blob!\n'
>>> f5.readline()
'Blob is fine.'
>>> f5.close()
We can seek to certain positions in a blob and read portions of it::
>>> f6 = myblob.open('r')
>>> _ = f6.seek(4)
>>> int(f6.tell())
4
>>> f6.read(5)
'Blob!'
>>> f6.close()
We can use the object returned by a blob open call as an iterable::
>>> f7 = myblob.open('r')
>>> for line in f7:
... print(line.decode())
Hi, Blob!
<BLANKLINE>
Blob is fine.
>>> f7.close()
We can truncate a blob::
>>> f8 = myblob.open('a')
>>> _ = f8.truncate(0)
>>> f8.close()
>>> f8 = myblob.open('r')
>>> f8.read()
''
>>> f8.close()
Blobs are always opened in binary mode::
>>> f9 = myblob.open("r")
>>> f9.mode
'rb'
>>> f9.close()
Blobs that have not been committed can be opened using any mode,
except for "c"::
>>> import six
>>> from ZODB.blob import BlobError, valid_modes
>>> for mode in valid_modes:
... try:
... f10 = Blob().open(mode)
... except BlobError:
... six.print_('open failed with mode "%s"' % mode)
... else:
... f10.close()
open failed with mode "c"
Some cleanup in this test is needed::
>>> import transaction
>>> transaction.get().abort()
Subclassing Blobs
-----------------
Blobs are not subclassable::
>>> class SubBlob(Blob):
... pass
>>> my_sub_blob = SubBlob()
Traceback (most recent call last):
...
TypeError: Blobs do not support subclassing.
Passing data to the blob constructor
------------------------------------
If you have a small amount of data, you can pass it to the blob
constructor. (This is a convenience, mostly for writing tests.)
>>> myblob = Blob(b'some data')
>>> with myblob.open() as fp: fp.read()
'some data'
You can’t perform that action at this time.