Permalink
Browse files

This adds support for export/import of dexterity types as json files …

…in combination with quintagroup.transmogrifier trunk. It now uses the IFromUnicode and IToUnicode converters defined in plone.supermodel.
  • Loading branch information...
1 parent b3ba982 commit 32594001d0da48850eddbf4a7f26bd0fcf5e45ab @lrowe lrowe committed Jan 25, 2011
View
@@ -0,0 +1,30 @@
+[transmogrifier]
+pipeline =
+ sitewalker
+ manifestexporter
+ content
+ serializer
+ writer
+ EXPORTING
+
+[sitewalker]
+blueprint = quintagroup.transmogrifier.sitewalker
+
+[manifestexporter]
+blueprint = quintagroup.transmogrifier.manifestexporter
+
+[content]
+blueprint = transmogrify.dexterity.schemareader
+
+[serializer]
+blueprint = transmogrify.dexterity.serializer
+
+[writer]
+blueprint = quintagroup.transmogrifier.writer
+prefix = structure
+
+[EXPORTING]
+blueprint = quintagroup.transmogrifier.logger
+keys =
+ _type
+ _path
View
@@ -0,0 +1,32 @@
+[transmogrifier]
+pipeline =
+ reader
+ manifestimporter
+ constructor
+ deserializer
+ schemaupdater
+ IMPORTING
+
+[reader]
+blueprint = quintagroup.transmogrifier.reader
+prefix = structure
+.objects.xml = manifest
+_content.json = content
+
+[manifestimporter]
+blueprint = quintagroup.transmogrifier.manifestimporter
+
+[constructor]
+blueprint = collective.transmogrifier.sections.constructor
+
+[deserializer]
+blueprint = transmogrify.dexterity.deserializer
+
+[schemaupdater]
+blueprint = transmogrify.dexterity.schemaupdater
+
+[IMPORTING]
+blueprint = quintagroup.transmogrifier.logger
+keys =
+ _type
+ _path
View
@@ -7,6 +7,7 @@
tests_require = [
'plone.app.testing',
'plone.app.dexterity',
+ 'plone.namedfile[blobs]',
]
setup(name='transmogrify.dexterity',
version=version,
@@ -29,16 +30,19 @@
include_package_data=True,
zip_safe=False,
install_requires=[
- 'z3c.form',
- 'plone.namedfile',
- 'plone.dexterity',
+ 'setuptools',
'collective.transmogrifier',
- 'setuptools',
- # -*- Extra requirements: -*-
- ],
+ 'plone.app.textfield',
+ 'plone.dexterity',
+ 'plone.namedfile',
+ 'plone.supermodel',
+ 'plone.uuid',
+ 'z3c.form',
+ ],
tests_require=tests_require,
extras_require=dict(tests=tests_require),
entry_points="""
- # -*- Entry points: -*-
- """,
+ [z3c.autoinclude.plugin]
+ target = plone
+ """,
)
@@ -1,5 +1,6 @@
<configure
xmlns="http://namespaces.zope.org/zope"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
i18n_domain="transmogrify.dexterity">
<include package="collective.transmogrifier" file="meta.zcml" />
@@ -9,4 +10,37 @@
name="transmogrify.dexterity.schemaupdater"
/>
+<utility
+ component=".schemareader.DexterityReaderSection"
+ name="transmogrify.dexterity.schemareader"
+ />
+
+<utility
+ component=".serializer.SerializerSection"
+ name="transmogrify.dexterity.serializer"
+ />
+
+<utility
+ component=".serializer.DeserializerSection"
+ name="transmogrify.dexterity.deserializer"
+ />
+
+<adapter factory=".converters.NamedFileSerializer" />
+<adapter factory=".converters.NamedFileDeserializer" />
+<adapter factory=".converters.NamedImageDeserializer" />
+
+<configure zcml:condition="installed z3c.blobfile">
+ <adapter factory=".converters.NamedBlobFileDeserializer" />
+ <adapter factory=".converters.NamedBlobImageDeserializer" />
+</configure>
+
+<adapter factory=".converters.RichTextSerializer" />
+<adapter factory=".converters.RichTextDeserializer" />
+
+<adapter factory=".converters.CollectionSerializer" />
+<adapter factory=".converters.CollectionDeserializer" />
+
+<adapter factory=".converters.DefaultSerializer" />
+<adapter factory=".converters.DefaultDeserializer" />
+
</configure>
@@ -0,0 +1,213 @@
+import mimetypes
+
+from plone.app.textfield.interfaces import IRichText
+from plone.app.textfield.value import RichTextValue
+from plone.app.textfield.utils import getSiteEncoding
+
+from plone import namedfile
+from plone.namedfile import interfaces as nfi
+from plone.supermodel.interfaces import IToUnicode
+
+from zope.component import adapts
+from zope.interface import implements
+from zope.schema.interfaces import ICollection, IField, IFromUnicode
+
+from interfaces import ISerializer, IDeserializer
+
+
+class NamedFileSerializer:
+ implements(ISerializer)
+ adapts(nfi.INamedField)
+
+ def __init__(self, field):
+ self.field = field
+
+ def __call__(self, value, filestore, extra=None):
+ if extra is None:
+ extra = ''
+ else:
+ extra = '_%s' % extra
+ fieldname = self.field.__name__
+ name = '_field_%s%s_%s' % (fieldname, extra, value.filename)
+ filestore[name] = dict(data=value.read(), name=name, contenttype=value.contenttype)
+ return dict(file=name, filename=value.filename, contenttype=value.contenttype)
+
+
+class BaseNamedFileDeserializer:
+ implements(IDeserializer)
+ _type = None
+
+ def __init__(self, field):
+ self.field = field
+
+ def __call__(self, value, filestore, item):
+ if isinstance(value, dict):
+ filename = value.get('filename', None)
+ contenttype = value.get('contenttype', '')
+ file = value.get('file', None)
+ if file is not None:
+ data = filestore[file]['data']
+ else:
+ data = value['data']
+ elif isinstance(value, str):
+ data = value
+ filename = item.get('_filename', None)
+ contenttype = ''
+ else:
+ raise ValueError('Unable to convert to named file')
+ if isinstance(filename, str):
+ filename = filename.decode('utf-8')
+ instance = self._type(
+ data=data,
+ filename=filename,
+ contentType=contenttype,
+ )
+ return instance
+
+
+class NamedFileDeserializer(BaseNamedFileDeserializer):
+ adapts(nfi.INamedFileField)
+ _type = namedfile.NamedFile
+
+
+class NamedImageDeserializer(BaseNamedFileDeserializer):
+ adapts(nfi.INamedImageField)
+ _type = namedfile.NamedImage
+
+
+if namedfile.HAVE_BLOBS:
+
+ class NamedBlobFileDeserializer(BaseNamedFileDeserializer):
+ adapts(nfi.INamedBlobFileField)
+ _type = namedfile.NamedBlobFile
+
+
+ class NamedBlobImageDeserializer(BaseNamedFileDeserializer):
+ adapts(nfi.INamedBlobImageField)
+ _type = namedfile.NamedBlobImage
+
+
+class RichTextSerializer:
+ implements(ISerializer)
+ adapts(IRichText)
+
+ def __init__(self, field):
+ self.field = field
+
+ def __call__(self, value, filestore, extra=None):
+ if extra is None:
+ extra = ''
+ else:
+ extra = '_%s' % extra
+ extension = mimetypes.guess_extension(value.mimeType) or ''
+ fieldname = self.field.__name__
+ name = '_field_%s%s%s' % (fieldname, extra, extension)
+ filestore[name] = dict(data=value.raw_encoded, name=name, contenttype=value.mimeType)
+ return dict(file=name, contenttype=value.mimeType, encoding=value.encoding)
+
+
+class RichTextDeserializer:
+ implements(IDeserializer)
+ adapts(IRichText)
+ _type = RichTextValue
+
+ def __init__(self, field):
+ self.field = field
+
+ def __call__(self, value, filestore, item):
+ if isinstance(value, dict):
+ encoding = value.get('encoding', None)
+ contenttype = value.get('contenttype', None)
+ file = value.get('file', None)
+ if file is not None:
+ data = filestore[file]['data']
+ else:
+ data = value['data']
+ elif isinstance(value, str):
+ data = value
+ encoding = None
+ contenttype = Non
+ else:
+ raise ValueError('Unable to convert to named file')
+ if encoding is None:
+ encoding = getSiteEncoding()
+ if contenttype is None:
+ conenttype = self.field.default_mime_type
+ instance = self._type(
+ raw=data,
+ mimeType=contenttype,
+ outputMimeType=self.field.output_mime_type,
+ encoding=encoding,
+ )
+ return instance
+
+
+class CollectionSerializer:
+ implements(ISerializer)
+ adapts(ICollection)
+
+ def __init__(self, field):
+ self.field = field
+
+ def __call__(self, value, filestore, extra=None):
+ field = self.field
+ if field.value_type is not None:
+ serializer = ISerializer(self.field.value_type)
+ else:
+ serializer = DefaultSerializer()
+ return [serializer(v, filestore, str(i)) for i, v in enumerate(value)]
+
+
+class CollectionDeserializer:
+ implements(IDeserializer)
+ adapts(ICollection)
+
+ def __init__(self, field):
+ self.field = field
+
+ def __call__(self, value, filestore, item):
+ field = self.field
+ if isinstance(value, basestring):
+ value = [v for v in (v.strip() for v in value.split(';')) if v]
+ if field.value_type is not None:
+ deserializer = IDeserializer(self.field.value_type)
+ else:
+ deserializer = DefaultDeserializer()
+ value = [deserializer(v, filestore, item) for v in value]
+ value = field._type(value)
+ return value
+
+
+class DefaultSerializer:
+ implements(ISerializer)
+ adapts(IField)
+
+ def __init__(self, field=None):
+ self.field = field
+
+ def __call__(self, value, filestore, extra=None):
+ BASIC_TYPES = (unicode, int, long, float, bool, type(None))
+ if type(value) in BASIC_TYPES:
+ pass
+ elif self.field is not None:
+ value = IToUnicode(self.field).toUnicode(value)
+ else:
+ raise ValueError('Unable to serialize field value')
+ return value
+
+
+class DefaultDeserializer:
+ implements(IDeserializer)
+ adapts(IField)
+
+ def __init__(self, field):
+ self.field = field
+
+ def __call__(self, value, filestore, item):
+ field = self.field
+ if field is not None:
+ if isinstance(value, str):
+ value = value.decode('utf-8')
+ if isinstance(value, unicode):
+ value = IFromUnicode(field).fromUnicode(value)
+ return value
@@ -0,0 +1,10 @@
+from zope.interface import Interface
+
+class ISerializer(Interface):
+ def __call__(value, filestore, extra=None):
+ """Convert to a serializable reprentation"""
+
+
+class IDeserializer(Interface):
+ def __call__(value, filestore, item):
+ """Convert to a field value"""
Oops, something went wrong.

0 comments on commit 3259400

Please sign in to comment.