CSV Replicator
==============

Overview
--------
A description of csv replicata here.


Interfaces
----------
import interfaces and classes ::

    >>> from zope.interface.verify import verifyClass
    >>> from zope.interface import implements
    >>> from Products.csvreplicata.handlers.base import CSVdefault
    >>> from Products.csvreplicata.handlers.file import CSVFile
    >>> from Products.csvreplicata.interfaces import ICSVDefault, ICSVFile

Verify implementation ::

    >>> verifyClass(ICSVDefault, CSVdefault)
    True
    >>> verifyClass(ICSVFile, CSVFile)
    True

Default handlers
----------------
Verify the default handlers provided for Archetypes fields::

    >>> self.portal.portal_csvreplicatatool.getHandlers() 
    {'Products.Archetypes.Field.DateTimeField':
     {'handler_class':
     <Products.csvreplicata.handlers.base.CSVDateTime object at ...,
     'file': False},
     'Products.Archetypes.Field.IntegerField':
     {'handler_class':
     <Products.csvreplicata.handlers.base.CSVInteger object at ...,
     'file': False},
     'default_handler':
     {'handler_class': <Products.csvreplicata.handlers.base.CSVdefault ...,
     'file': False},
     'Products.Archetypes.Field.FileField':
     {'handler_class':
     <Products.csvreplicata.handlers.file.CSVFile object ...,
     'file': True},
     'Products.Archetypes.Field.BooleanField':
     {'handler_class':
     <Products.csvreplicata.handlers.base.CSVBoolean object at ...,
     'file': False},
     'Products.Archetypes.Field.TextField':
     {'handler_class':
     <Products.csvreplicata.handlers.base.CSVText object at ...,
     'file': False},
     'Products.Archetypes.Field.LinesField':
     {'handler_class':
     <Products.csvreplicata.handlers.base.CSVLines object at ...,
     'file': False},
     'Products.Archetypes.Field.ImageField':
     {'handler_class':
     <Products.csvreplicata.handlers.file.CSVFile object at ...,
     'file': True},
     'Products.Archetypes.Field.FloatField':
     {'handler_class':
     <Products.csvreplicata.handlers.base.CSVFloat object at ...,
     'file': False},
     'plone.app.blob.subtypes.file.ExtensionBlobField':
     {'handler_class':
     <Products.csvreplicata.handlers.file.CSVFile object at ...,
     'file': True},
     'Products.Archetypes.Field.StringField':
     {'handler_class':
     <Products.csvreplicata.handlers.base.CSVString object at ...,
     'file': False},
     'Products.Archetypes.Field.ReferenceField': {'handler_class':
     <Products.csvreplicata.handlers.reference.CSVReference object at ...,
     'file': False}}


What happened with csvreplicata during import/export if MyField is not in tool's
handlers. replicator.py apllies default_handler on it:

{'default_handler':
 {'handler_class': base.CSVdefault(),'file': False}}


Provide a new handler
---------------------
A developper could write his proper widget for a new ATCT based type.
Of course he wants to provide it to the csvreplicata tool.

Then there are two cases:

 - his new field can be provided by an existing handler like CSVInt by example.
 
 - he wants to provide a new handler. ::
 
    >>> class MyCSV(CSVdefault) :
    ...     implements(ICSVDefault)
    ...
    ...     def get(self, obj, field, context=None):
    ...         pass
    ...          
    ...     def set(self, obj, field, value, context=None):
    ...         pass

    >>> verifyClass(ICSVDefault, MyCSV)
    True
 
 Ok now we could register a new handler to csvrplica tool and the way is the same in both cases.
 
 We have to set a new handler to the tool with the appropriated method. ::
 
    >>> self.portal.portal_csvreplicatatool.setHandler('Myproduct.Field.MyField',
    ... {'handler_class': MyCSV(), 'file': False})
    
    >>> 'Myproduct.Field.MyField' \
    ... in self.portal.portal_csvreplicatatool.getHandlers()
    True
    
 of course setHandler() permits to edit an existing handler too ! ::
 
    >>> class AnotherMyCSV(MyCSV) :
    ...     pass
 
    >>> self.portal.portal_csvreplicatatool.setHandler('Myproduct.Field.MyField',
    ... {'handler_class': AnotherMyCSV(), 'file': False})
    >>> self.portal.portal_csvreplicatatool.getHandlers()['Myproduct.Field.MyField']
    {'handler_class': <AnotherMyCSV object at ..., 'file': False}
 
 now we can aso delete this handler ::
 
    >>> self.portal.portal_csvreplicatatool.delHandler('Myproduct.Field.MyField')
    >>> 'Myproduct.Field.MyField' in self.portal.portal_csvreplicatatool.getHandlers()
    False


Export / Import
---------------

Export
______
here we export folders and documents ::

    >>> import re
    >>> self.setRoles(['Manager'])
    >>> id=self.folder.invokeFactory('Document', id='doc1', title="Document 1")
    >>> id=self.folder.invokeFactory('Document', id='doc2', title="Document 2")
    >>> id=self.folder.invokeFactory('Document', id='doc3',
    ... title="Document 'super' 3")
    >>> id=self.folder.invokeFactory('Document', id='doc4', title="Document 4")
    >>> id=self.folder.invokeFactory('Folder', id='sub1', title="Sous dossier 1")
    >>> id=self.folder.sub1.invokeFactory('Document', id='doc11',
    ... title="Document 1 du dossier 1")
    >>> self.portal.portal_csvreplicatatool.getEncoding()
    'UTF-8'
    >>> self.portal.portal_csvreplicatatool.getDelimiter()
    ';'
    >>> self.portal.portal_csvreplicatatool.getStringdelimiter()
    '"'
    >>> self.portal.portal_csvreplicatatool.replicabletypes = \
    ... {'Document':['default'], 'Folder':['default']}
    >>> from Products.csvreplicata.interfaces import Icsvreplicata
    >>> replicator = Icsvreplicata(self.folder)
    >>> re.sub(';\d{14}',';YYYYMMDDhhmmss',
    ... replicator.csvexport(exportable_content_types=['Document', 'Folder']))
    '"/plone/Members/test_user_1_";YYYYMMDDhhmmss\r\n"parent";"id";"type";"title";"description";"text"\r\n"Parent folder";"Identifier";"Content type";"Title";"label_description";"label_body_text"\r\n"";"doc1";"Document";"Document 1";"";""\r\n"";"doc2";"Document";"Document 2";"";""\r\n"";"doc3";"Document";"Document \'super\' 3";"";""\r\n"";"doc4";"Document";"Document 4";"";""\r\n"parent";"id";"type";"title";"description"\r\n"Parent folder";"Identifier";"Content type";"Title";"label_description"\r\n"";"sub1";"Folder";"Sous dossier 1";""\r\n'
    >>> re.sub(';\d{14}',';YYYYMMDDhhmmss',
    ... replicator.csvexport(depth=2, exportable_content_types=['Document', 'Folder']))
    '"/plone/Members/test_user_1_";YYYYMMDDhhmmss\r\n"parent";"id";"type";"title";"description";"text"\r\n"Parent folder";"Identifier";"Content type";"Title";"label_description";"label_body_text"\r\n"";"doc1";"Document";"Document 1";"";""\r\n"";"doc2";"Document";"Document 2";"";""\r\n"";"doc3";"Document";"Document \'super\' 3";"";""\r\n"";"doc4";"Document";"Document 4";"";""\r\n"parent";"id";"type";"title";"description"\r\n"Parent folder";"Identifier";"Content type";"Title";"label_description"\r\n"";"sub1";"Folder";"Sous dossier 1";""\r\n"parent";"id";"type";"title";"description";"text"\r\n"Parent folder";"Identifier";"Content type";"Title";"label_description";"label_body_text"\r\n"sub1";"doc11";"Document";"Document 1 du dossier 1";"";""\r\n'
    
import
______
see data in tests/test_file.csv ::

    >>> import os
    >>> from Globals import package_home
    >>> from Products.csvreplicata.tests import GLOBALS
    >>> path = os.path.join(package_home(GLOBALS), 'test_file.csv')
    >>> fd = open(path, 'rb')
    >>> replicator.csvimport(fd, datetimeformat='%d/%m/%Y')
    (1, 1, DateTime('2050/10/20 12:12:00 GMT+1'), [])
    >>> fd.close()
    >>> self.folder.doc1.Title()
    'Document 1 NEW'
    >>> self.folder.doc5
    <ATDocument at /plone/Members/test_user_1_/doc5>

    

