[Zope-dev] zope.filerepresentation

Martin Aspeli optilude+lists at gmail.com
Wed Sep 30 20:13:11 EDT 2009


Hanno Schlichting wrote:

> Is there any reason to invent a new API and not just use Python's file API?

I don't know. IReadFile and IWriteFile have been around for ever and are 
used by a number of things in Zope. They have read(), write() and 
size(). The first two are on file, the last one isn't. I'd like to be 
able to use this API as a base, since it's used for things like 
z3c.blobfile already, and is documented as the way to do this kind of 
thing in Philipp's book.

> So .name instead of getFilename, iterator per __iter__ and next?

Yeah, that's a better idea.

> I'm not sure about the different read/write methods on file-objects,
> but I think the standard ones do cover all the same use-cases.
 >
> The standard file implementation has no knowledge of its size, as this
> is sometimes impossible to get, when dealing with stream based
> file-like objects. Do we really need to have files to know their size?

Well, for the writeFile() stuff maybe we don't. Thinking through my use 
cases again, I can't see a need for passing the content type in, and 
encoding can be set if we support setting the '.encoding' property.

It's kind of important to be able to indicate the size and MIME type for 
a read operation, though. In this case, I want to be able to put that 
information into the Content-Type and Content-Length headers. The 
IStreamData stuff in Zope 2 also wants to know the length before it 
starts streaming.

In some cases, it may not be possible to know, in which case we can fall 
back on len(data), but in other cases, the length is known 
(plone.namedfile and z3c.blobfile keep track of it, for example), in 
which case having a way to ask the adapter means it can be done much 
more efficiently.

So, how about this:

class IReadFile(Interface):
     """Provide read access to file data
     """

     def read():
         """Return the file data as a str
         """

     def size():
         """Return the data length
         """

class ILargeReadFile(IReadFile):
     """Provide efficient read access to file data
     """

     def getContentType():
         """Get the content/MIME type of the file as a string in the form
         'major/minor'. Return None if this is not known or undefined.
         """

     name = schema.TextLine(title=u"Filename", readonly=True)
     encoding = schema.ASCIILine(title=u"Encoding", readonly=True)

     def __iter__():
         """Get an iterator"""

     def next():
         """See file"""

     def seek():
         """See file"""

     def tell():
         """See file"""

class IWriteFile(Interface):

     def write(data):
         """Update the file data
         """

class ILargeWriteFile(IWriteFile):

     def write(data):
         """Write a chunk of data
         """

     name = schema.TextLine(title=u"Filename", readonly=False)
     encoding = schema.ASCIILine(title=u"Encoding", readonly=False)

     def tell():
         """See file"""

     def close():
         """See file""

It may be worth supporting the rest of the functions (readlines, 
writelines, truncate, readline, isatty, fileno, flush) so that 
ILargeReadFile + ILargeWriteFile are equivalent to file.

I've also allowed here for the name and encoding to be set on an 
ILargeWriteFile, with the caveat that this has to be done before the 
writing.

In this approach, the caller is responsible for writing large streams in 
chunks and then calling close, i.e. the iterator isn't passed to the 
ILargeWriteFile. I think that's OK, though.

I've still got the content type as a method (maybe make it a read-only 
property?) that may return None. That could be in a separate adapter, 
but that feels like overkill to me. :)

Martin

-- 
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book



More information about the Zope-Dev mailing list