Metadata-Version: 1.0
Name: dolmen.file
Version: 0.6
Summary: A Zope3/Grok File Representation package.
Home-page: UNKNOWN
Author: Souheil Chelfouh
Author-email: trollfot@gmail.com
License: GPL
Description: ===========
        dolmen.file
        ===========
        
        ``dolmen.file`` allows you to manage and store files within the ZODB.
        It takes the core functionalities of ``zope.app.file``, and simplifies
        them, using Grok for views and adapters registrations.
        
        Compatibility
        =============
        
        In order to make sure that our `File` implementation is complete and
        functional, we test it against the original ``zope.app.file`` tests::
        
            >>> from dolmen.file import NamedFile, INamedFile, FileChunk
        
        Let's test the constructor::
        
            >>> file = NamedFile()
            >>> file.contentType
            ''
            >>> file.data
            ''
        
            >>> file = NamedFile('Foobar')
            >>> file.contentType
            ''
            >>> file.data
            'Foobar'
        
            >>> file = NamedFile('Foobar', 'text/plain')
            >>> file.contentType
            'text/plain'
            >>> file.data
            'Foobar'
        
            >>> file = NamedFile(data='Foobar', contentType='text/plain')
            >>> file.contentType
            'text/plain'
            >>> file.data
            'Foobar'
        
        Let's test the mutators::
        
            >>> file = NamedFile()
            >>> 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 = NamedFile()
        
            Insert as string:
        
            >>> file.data = 'Foobar'*60000
            >>> file.size
            360000
            >>> file.data == 'Foobar'*60000
            True
        
        Insert data as FileChunk::
        
            >>> fc = FileChunk('Foobar'*4000)
            >>> file.data = fc
            >>> file.size
            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.size
            600000
            >>> file.data == 'Foobar'*100000
            True
        
        Last, but not least, verify the interface implementation::
        
            >>> from zope.interface.verify import verifyClass
            >>> INamedFile.implementedBy(NamedFile)
            True
            >>> verifyClass(INamedFile, NamedFile)
            True
        
        
        Naming
        ======
        
        When no name is provided, the fallback is a simple empty unicode
        string::
        
            >>> file = NamedFile('Foobar')
            >>> file.contentType
            ''
            >>> file.data
            'Foobar'
            >>> file.filename
            u''
        
        To specifiy a filename, we can give it to the constructor::
            
            >>> file = NamedFile('Foobar', filename='foobar.txt')
            >>> file.data
            'Foobar'
            >>> file.filename
            u'foobar.txt'
        
        The filename can be both unicode or simple string::
        
            >>> file = NamedFile('Foobar', filename=u'foobar.txt')
            >>> file.data
            'Foobar'
            >>> file.filename
            u'foobar.txt'
        
        The filename provided had an extension : 'txt'. This extension is used
        by the NamedFile, while instanciated, to try and guess the mimetype of
        the data::
        
            >>> file.contentType
            'text/plain'
        
            The filename can be set later, but this won't trigger the mime
            type guess::
            
            >>> file.filename = u"something.zip"
            >>> file.filename
            u'something.zip'
            >>> file.contentType
            'text/plain'
        
        
        Size
        ====
        
        To represent the size of the stored data, ``dolmen.file`` uses a
        normalized adaptation, based on ``zope.size`` definitions::
        
          >>> from zope.size import ISized
          >>> sized = ISized(file)
          >>> sized
          <dolmen.file.size.Sized object at ...>
          >>> sized.sizeForSorting()
          ('byte', 6)
          >>> sized.sizeForDisplay()
          u'1 KB'
        
        
        Access
        ======
        
        In order to access our file, ``dolmen.file`` provides a view called
        `file_publish` that sets the proper headers and returns the
        data. Let's set up a simple environment to test that behavior::
        
            >>> from zope.component.hooks import getSite
            >>> from zope.component import getMultiAdapter
            >>> from zope.publisher.browser import TestRequest
        
            >>> root = getSite()
            >>> root['myfile'] = NamedFile('Foobar', filename='foobar.txt')
            >>> myfile = root['myfile']
        
            The `file_publish` view will adapt a INamedFile and a request and,
            when called, will return the data.
        
            >>> request = TestRequest()
            >>> view = getMultiAdapter((myfile, request), name='file_publish')
            >>> view
            <dolmen.file.access.FilePublisher object at ...>
        
        
        In the update of the view, the headers are set properly, using the
        info of the file::
        
            >>> 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 '6'
            Content-Type 'text/plain'
            Content-Disposition 'attachment; filename="foobar.txt"'
            >>> view.render()
            'Foobar'
        
        
        Field, download and security
        ============================
        
        In a site, the file object is rarely accessed directly. Often, it's
        just a part of a more complex object. For that matter, we have three
        dedicated components: the field, the property and the traverser.
        
        
        Field and Property
        ------------------
        
        A property is provided to allow a transparent use of a INamedFile component.
        
        Working exemple
        ~~~~~~~~~~~~~~~
        
            >>> from persistent import Persistent
            >>> from dolmen.file import FileProperty, FileField
            >>> from zope.interface import Interface, implements
        
            >>> class IContent(Interface):
            ...     binary = FileField(title=u"Binary data")
        
            >>> class MyContent(Persistent):
            ...     implements(IContent)
            ...     binary = FileProperty(IContent['binary'])
        
            >>> root['mammoth'] = MyContent()
            >>> manfred = root['mammoth']
            >>> manfred.binary = FileChunk('Foobar')
            >>> manfred.binary
            <dolmen.file.file.NamedFile object at ...>
        
            >>> manfred.binary.data
            'Foobar'
        
        Custom factory
        ~~~~~~~~~~~~~~
        
            >>> class MyFile(NamedFile):
            ...     """My own file type.
            ...     """
        
            >>> class CustomContent(object):
            ...     implements(IContent)
            ...     binary = FileProperty(IContent['binary'], factory=MyFile)
        
            >>> custom = CustomContent()
            >>> custom.binary = FileChunk('Foobar')
            >>> custom.binary
            <MyFile object at ...>
        
        Error
        ~~~~~
         
            >>> class MyFalseFile(object):
            ...     """My own file type.
            ...     """
        
            >>> class FaultyContent(object):
            ...     implements(IContent)
            ...     binary = FileProperty(IContent['binary'], factory=MyFalseFile)
            Traceback (most recent call last):
            ...
            ValueError: Provided factory is not a valid INamedFile
        
        Fields
        ~~~~~~
        
        There are two fields provided by `dolmen.file`: the FileField and the
        ImageField. They are just logical separation but have a common base::  
        
            >>> from dolmen.file import IImageField, IFileField, ImageField
            >>> IImageField.extends(IFileField)
            True
            >>> isinstance(ImageField(), FileField)
            True
        
        
        Traversal
        ---------
        
        The traverser will take care of both the fetching and the security
        checking, while accessing your data. The basic permission used to
        check the availability of the data, is `zope.View`.
        
        Here, we set up two principals to test this. 'jason' is a logged in
        member with no rights while 'judith' has the `zope.View` permission
        granted::
        
            >>> import zope.security.management as security  
            >>> from zope.traversing.interfaces import ITraversable
            >>> from zope.security.testing import Principal, Participation
        
            >>> judith = Principal('zope.judith', 'Judith')
            >>> jason = Principal('zope.jason', 'Jason')
        
        We create the interaction and try to traverse to our binary data::
        
            >>> security.newInteraction(Participation(jason))
            >>> traverser = getMultiAdapter(
            ...              (manfred, request), ITraversable, 'download')
            >>> traverser
            <dolmen.file.access.DownloadTraverser object at ...>
            >>> traverser.traverse('binary')
            Traceback (most recent call last):
            ...
            Unauthorized: binary
            >>> security.endInteraction()
        
        It fails. An Unauthorized Error is raised. We now try with Judith::
        
            >>> security.newInteraction(Participation(judith))
            >>> traverser.traverse('binary')
            <dolmen.file.access.FilePublisher object at ...>
        
        Our data is returned, wrapped in a `FilePublisher` view, ready to be
        rendered (see the Access section, for more information).
        
        What if we traverse to an unknown field ? Let's try::
        
            >>> traverser.traverse('zorglub')
            Traceback (most recent call last):
            ...
            NotFound: Object: <MyContent object at ...>, name: 'zorglub'
        
        
        Everything is fine : a NotFound error has been raised. If we try to
        access a file that is not an INamedFile, we get another error::
        
            >>> traverser.traverse('__name__')
            Traceback (most recent call last):
            ...
            LocationError: '__name__ is not a valid INamedFile'
        
        We gracefully end our tests::
        
            >>> security.endInteraction()
        
        Enjoy !
        
        
        Changelog
        =========
        
        0.6 (2010-11-17)
        ------------------
        
        * Tested for Grok 1.2.
        
        * ``zope.testing`` dependency has been removed.
        
        * The INamedFile factory is now pluggable, in the file property. Tests
          have been added to fix that behavior.
        
        
        0.5.1 (2010-02-28)
        ------------------
        
        * Added an `ISized` adapter for `INamedFile` objects. Added tests
          accordingly.
        
        
        0.5.0 (2010-02-28)
        ------------------
        
        * Updated code base to be fully pep8 compatible.
        
        * `zope.app` dependencies have been entirely dropped. 
        
        * ``dolmen.file`` is no longer a layer above ``zope.app.file``. It
          nows integrates the few features it needed from ``zope.app.file``.
        
        
        0.4.0 (2009-11-18)
        ------------------
        
        * Release compatible with ZTK 1.0dev versions. Pinned down the version
          of zope.traversing in the setup.py. It now runs on Python 2.6 !
        
        
        0.3.2 (2009-10-23)
        ------------------
        
        * Corrected a bug on the clean_filename util function, that would fail
          on unicode values. Added a test to fix that behavior.
        
        
        0.3.1 (2009-10-23)
        ------------------
        
        * Removed the __parent__ attribution in the property. If you relied on
          this, you now have to take care of the location proxying yourself.
        
        
        0.3.0 (2009-10-23)
        ------------------
        
        * Changed the filename cleaning method, now exposed in the public
          API. We now use a compiled regexp to get the name.
        
        
        0.2.0 (2009-10-21)
        ------------------
        
        * Added an image field with the corresponding interface. This was
          previously part of ``dolmen.imaging``. The ImageField component is a
          simple subclass of the default FileField.
        
        
        0.1.0 (2009-10-16)
        ------------------
        
        * Initial release
        
Keywords: Grok Zope3 file download
Platform: UNKNOWN
Classifier: Environment :: Web Environment
Classifier: Framework :: Zope3
Classifier: Intended Audience :: Other Audience
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
