Source code for pyams_i18n.property

#
# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
# 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.
#

__docformat__ = 'restructuredtext'


# import standard library

# import interfaces
from pyams_file.interfaces import DELETED_FILE, IFile, IFileInfo, IFileFieldContainer
from zope.schema.interfaces import IField

# import packages
from pyams_file.file import FileFactory
from pyams_file.property import FILE_CONTAINER_ATTRIBUTES
from pyams_utils.adapter import get_annotation_adapter
from pyramid.threadlocal import get_current_registry
from z3c.form.interfaces import NOT_CHANGED
from zope.interface import alsoProvides
from zope.lifecycleevent import ObjectCreatedEvent, ObjectRemovedEvent, ObjectAddedEvent
from zope.location import locate


_marker = object()


[docs]class I18nFileProperty(object): """I18n property class used to handle files""" def __init__(self, field, name=None, klass=None, **args): if not IField.providedBy(field): raise ValueError("Provided field must implement IField interface...") if name is None: name = field.__name__ self.__field = field self.__name = name self.__klass = klass self.__args = args def __get__(self, instance, klass): if instance is None: return self value = instance.__dict__.get(self.__name, _marker) if value is _marker: field = self.__field.bind(instance) value = getattr(field, 'default', _marker) if value is _marker: raise AttributeError(self.__name) return value def __set__(self, instance, value): registry = get_current_registry() for lang in value: lang_value = value[lang] if (lang_value is DELETED_FILE) or (lang_value is NOT_CHANGED): continue elif lang_value is not None: filename = None # file upload data converter returns a tuple containing # filename and buffered IO stream extracted from FieldStorage... if isinstance(lang_value, tuple): filename, lang_value = lang_value # initialize file through factory if not IFile.providedBy(lang_value): factory = self.__klass or FileFactory file = factory(lang_value, **self.__args) registry.notify(ObjectCreatedEvent(file)) if not file.get_size(): lang_value.seek(0) # because factory may read until end of file... file.data = lang_value lang_value = file if filename is not None: info = IFileInfo(lang_value) if info is not None: info.filename = filename value[lang] = lang_value field = self.__field.bind(instance) field.validate(value) if field.readonly and instance.__dict__.has_key(self.__name): raise ValueError(self.__name, "Field is readonly") old_value = instance.__dict__.get(self.__name, _marker) if old_value != value: # check for previous value if old_value is _marker: old_value = {} for lang in value: new_lang_value = value.get(lang) if new_lang_value is NOT_CHANGED: continue old_lang_value = old_value.get(lang, _marker) if (old_lang_value is not _marker) and (old_lang_value is not None): registry.notify(ObjectRemovedEvent(old_lang_value)) if new_lang_value is DELETED_FILE: if self.__name in instance.__dict__: del old_value[lang] else: # set name of new value name = '++i18n++{0}:{1}'.format(self.__name, lang) if new_lang_value is not None: locate(new_lang_value, instance, name) old_value[lang] = new_lang_value # store file attributes of instance if not IFileFieldContainer.providedBy(instance): alsoProvides(instance, IFileFieldContainer) attributes = get_annotation_adapter(instance, FILE_CONTAINER_ATTRIBUTES, set, notify=False, locate=False) attributes.add('{0}::{1}'.format(self.__name, lang)) registry.notify(ObjectAddedEvent(new_lang_value, instance, name)) instance.__dict__[self.__name] = old_value