#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
.. $Id$
"""
from __future__ import print_function, absolute_import, division
__docformat__ = "restructuredtext en"
logger = __import__('logging').getLogger(__name__)
import operator
from zope.annotation.interfaces import IAnnotations
[docs]
def alias(prop_name, doc=None):
"""
Returns a property that is a read/write alias for another attribute
of the object.
See :func:`dict_alias`.
"""
if doc is None:
doc = 'Alias for :attr:`' + prop_name + '`'
prop_name = str(prop_name) # native string
return property(lambda self: getattr(self, prop_name),
lambda self, nv: setattr(self, prop_name, nv),
doc=doc)
[docs]
def read_alias(prop_name, doc=None):
"""
Returns a property that is a read-only alias for another attribute
of the object.
See :func:`dict_read_alias`.
"""
if doc is None:
doc = 'Read-only alias for :attr:`' + prop_name + '`'
return property(lambda self: getattr(self, prop_name),
doc=doc)
[docs]
def dict_alias(key_name, doc=None):
"""
Returns a property that is a read/write alias for a value in the
instance's dictionary.
See :func:`alias` for a more general version; this is a speed or
access optimization.
"""
if doc is None:
doc = 'Alias for :attr:`' + key_name + '`'
key_name = str(key_name) # native string
return property(lambda self: self.__dict__[key_name],
lambda self, nv: operator.setitem(
self.__dict__, key_name, nv),
doc=doc)
[docs]
def dict_read_alias(key_name, doc=None):
"""
Returns a property that is a read-only alias for a value in the
instances dictionary.
See :func:`read_alias` for a more general version; this is a speed or
access optimization.
"""
if doc is None:
doc = 'Read-only alias for :attr:`' + key_name + '`'
return property(lambda self: self.__dict__[key_name],
doc=doc)
[docs]
class LazyOnClass(object):
"""
Like :class:`zope.cachedescriptors.property.Lazy`, but
when it caches, it caches on the class itself, not the instance,
thus sharing the value. Thus, the value should be immutable and
independent of any other state.
"""
def __init__(self, func):
self._func = func
self.klass_cache_name = '_v__LazyOnClass_' + self._func.__name__
def __get__(self, inst, klass):
if inst is None:
return self
# In order to let this be resetable, to keep access
# to this object and the original function, we
# use a different name
klass_cache_name = self.klass_cache_name
val = getattr(klass, klass_cache_name, self)
if val is self:
val = self._func(inst)
setattr(klass, klass_cache_name, val)
return val
[docs]
def annotation_alias(annotation_name, annotation_property=None, default=None,
delete=False, delete_quiet=True, doc=None):
"""
Returns a property that is a read/write alias for
a value stored as a :class:`zope.annotation.interface.IAnnotations`.
The object itself may be adaptable to an IAnnotations, or a property
of the object may be what is adaptable to the annotation. The later is intended
for use in adapters when the context object is what should be adapted.
:keyword bool delete: If ``True`` (not the default), then the property can be used
to delete the annotation.
:keyword bool delete_quiet: If ``True`` and `delete` is also True, then the property
will ignore key errors when deleting the annotation value.
:keyword str annotation_property: If set to a string, it is this property
of the object that will be adapted to IAnnotations. Most often this will
be ``context`` when used inside an adapter.
"""
if doc is None:
doc = 'Alias for annotation ' + annotation_name
if annotation_property:
def factory(self):
return IAnnotations(getattr(self, annotation_property))
else:
factory = IAnnotations
def fget(self):
# pylint:disable-next=too-many-function-args
return factory(self).get(annotation_name, default)
def fset(self, nv):
factory(self)[annotation_name] = nv
if delete:
def fdel(self):
try:
del factory(self)[annotation_name]
except KeyError:
if not delete_quiet:
raise
else:
fdel = None
return property(fget, fset, fdel, doc=doc)