Commit 2c2fb087 authored by Sylvain Thénault's avatar Sylvain Thénault
Browse files

Backed out changeset 3f6dfc312760

parent 3f6dfc312760
......@@ -168,7 +168,7 @@ class WorkflowableMixIn(object):
@property
def state(self):
try:
return self.related('in_state', entities=True)[0].get_value('name')
return self.in_state[0].name
except IndexError:
self.warning('entity %s has no state', self)
return None
......@@ -259,10 +259,10 @@ class EmailableMixIn(object):
__implements__ = (IEmailable,)
def get_email(self):
emails = self.related('primary_email', 'subject', entities=True) or \
self.related('use_email', 'subject', entities=True)
if emails:
return emails[0].get_value('address')
if getattr(self, 'primary_email', None):
return self.primary_email[0].address
if getattr(self, 'use_email', None):
return self.use_email[0].address
return None
@classmethod
......@@ -283,8 +283,7 @@ class EmailableMixIn(object):
NOTE: the dictionary keys should match the list returned by the
`allowed_massmail_keys` method.
"""
return dict( (attr, self.cwgetattr(attr))
for attr in self.allowed_massmail_keys() )
return dict( (attr, getattr(self, attr)) for attr in self.allowed_massmail_keys() )
......
......@@ -44,7 +44,7 @@ class CWUser(AnyEntity):
try:
return self._groups
except AttributeError:
self._groups = set(g.cwdb.name for g in self.cwdb.in_group)
self._groups = set(g.name for g in self.in_group)
return self._groups
@property
......@@ -52,8 +52,7 @@ class CWUser(AnyEntity):
try:
return self._properties
except AttributeError:
self._properties = dict((p.cwdb.pkey, p.cwdb.value)
for p in self.cwdb.reverse_for_user)
self._properties = dict((p.pkey, p.value) for p in self.reverse_for_user)
return self._properties
def property_value(self, key):
......@@ -64,8 +63,7 @@ class CWUser(AnyEntity):
except KeyError:
pass
except ValueError:
self.warning('incorrect value for property %s of user %s', key,
self.cwdb.login)
self.warning('incorrect value for eproperty %s of user %s', key, self.login)
return self.vreg.property_value(key)
def matching_groups(self, groups):
......@@ -124,17 +122,16 @@ class CWUser(AnyEntity):
def name(self):
"""construct a name using firstname / surname or login if not defined"""
surname = self.get_value('surname')
firstname = self.get_value('firstname')
if firstname and surname:
if self.firstname and self.surname:
return self.req._('%(firstname)s %(surname)s') % {
'firstname': firstname, 'surname' : surname}
if firstname or surname:
return surname or firstname
return self.get_value('login')
'firstname': self.firstname, 'surname' : self.surname}
if self.firstname:
return self.firstname
return self.login
def dc_title(self):
return self.get_value('login')
return self.login
dc_long_title = name
......
......@@ -132,20 +132,14 @@ class _metaentity(type):
return super(_metaentity, mcs).__new__(mcs, name, bases, classdict)
_CWDB_CLASSES = {}
def cwdb___init__(self, entity):
self.entity = entity
class Entity(AppObject, dict):
"""an entity instance has e_schema automagically set on the class.
"""an entity instance has e_schema automagically set on
the class and instances has access to their issuing cursor.
Also its special cwdb attribute provides access to persistent attributes and
relation using properties which are set for each attribute and relation
according to entity's type schema.
Beware that among attributes, 'eid' is *NEITHER* stored in the dict
containment (which acts as a cache for other attributes dynamically fetched)
A property is set for each attribute and relation on each entity's type
class. Becare that among attributes, 'eid' is *NEITHER* stored in the
dict containment (which acts as a cache for other attributes dynamically
fetched)
:type e_schema: `cubicweb.schema.EntitySchema`
:ivar e_schema: the entity's schema
......@@ -183,30 +177,24 @@ class Entity(AppObject, dict):
etype = cls.id
assert etype != 'Any', etype
cls.e_schema = eschema = cls.schema.eschema(etype)
cwdbclsdict = {'__init__': cwdb___init__}
for rschema, _ in eschema.attribute_definitions():
rtype = rschema.type
if rtype == 'eid':
if rschema.type == 'eid':
continue
setattr(cls, rtype, DeprecatedAttribute(rtype))
cwdbclsdict[rtype] = Attribute(rtype)
setattr(cls, rschema.type, Attribute(rschema.type))
mixins = []
for rschema, _, role in eschema.relation_definitions():
if (rschema, role) in MI_REL_TRIGGERS:
mixin = MI_REL_TRIGGERS[(rschema, role)]
for rschema, _, x in eschema.relation_definitions():
if (rschema, x) in MI_REL_TRIGGERS:
mixin = MI_REL_TRIGGERS[(rschema, x)]
if not (issubclass(cls, mixin) or mixin in mixins): # already mixed ?
mixins.append(mixin)
for iface in getattr(mixin, '__implements__', ()):
if not interface.implements(cls, iface):
interface.extend(cls, iface)
rtype = rschema.type
if role == 'object':
attr = 'reverse_%s' % rtype
if x == 'subject':
setattr(cls, rschema.type, SubjectRelation(rschema))
else:
attr = rtype
setattr(cls, attr, DeprecatedRelation(rtype, role))
cwdbclsdict[attr] = Relation(rtype, role)
_CWDB_CLASSES[etype] = type(etype + 'CWDB', (object,), cwdbclsdict)
attr = 'reverse_%s' % rschema.type
setattr(cls, attr, ObjectRelation(rschema))
if mixins:
cls.__bases__ = tuple(mixins + [p for p in cls.__bases__ if not p is object])
cls.debug('plugged %s mixins on %s', mixins, etype)
......@@ -311,8 +299,6 @@ class Entity(AppObject, dict):
else:
self.eid = None
self._is_saved = True
if self.id != 'Any':
self.cwdb = _CWDB_CLASSES[self.id](self)
def __repr__(self):
return '<Entity %s %s %s at %s>' % (
......@@ -324,15 +310,6 @@ class Entity(AppObject, dict):
def __hash__(self):
return id(self)
def cwgetattr(self, attr, default=_marker):
"""return attribute from either self.cwdb or self"""
try:
return getattr(self.cwdb, attr)
except AttributeError:
if default is _marker:
return getattr(self, attr)
return getattr(self, attr, default)
def pre_add_hook(self):
"""hook called by the repository before doing anything to add the entity
(before_add entity hooks have not been called yet). This give the
......@@ -415,7 +392,7 @@ class Entity(AppObject, dict):
etype = str(self.e_schema)
path = etype.lower()
if mainattr != 'eid':
value = getattr(self.cwdb, mainattr)
value = getattr(self, mainattr)
if value is None or unicode(value) == u'':
mainattr = 'eid'
path += '/eid'
......@@ -436,7 +413,7 @@ class Entity(AppObject, dict):
def attr_metadata(self, attr, metadata):
"""return a metadata for an attribute (None if unspecified)"""
value = self.cwgetattr('%s_%s' % (attr, metadata), None)
value = getattr(self, '%s_%s' % (attr, metadata), None)
if value is None and metadata == 'encoding':
value = self.vreg.property_value('ui.encoding')
return value
......@@ -448,17 +425,14 @@ class Entity(AppObject, dict):
"""
attr = str(attr)
if value is _marker:
value = self.cwgetattr(attr)
value = getattr(self, attr)
if isinstance(value, basestring):
value = value.strip()
if value is None or value == '': # don't use "not", 0 is an acceptable value
return u''
if attrtype is None:
attrtype = self.e_schema.destination(attr)
try:
props = self.e_schema.rproperties(attr)
except KeyError:
props = {}
props = self.e_schema.rproperties(attr)
if attrtype == 'String':
# internalinalized *and* formatted string such as schema
# description...
......@@ -499,20 +473,13 @@ class Entity(AppObject, dict):
assert self.has_eid()
execute = self.req.execute
for rschema in self.e_schema.subject_relations():
# skip final, meta or composite relation
if rschema.is_final() or rschema.meta or self.e_schema.subjrproperty(rschema, 'composite'):
if rschema.is_final() or rschema.meta:
continue
# skip relation with card in ?1 else we either change the copied
# object (inlined relation) or inserting some inconsistency
if self.e_schema.subjrproperty(rschema, 'cardinality')[1] in '?1':
# skip already defined relations
if getattr(self, rschema.type):
continue
# skip if we're told to do so
if rschema.type in self.skip_copy_for:
continue
# skip already defined relations
if self.related(rschema.type, 'subject'):
continue
# special case for in_state
if rschema.type == 'in_state':
# if the workflow is defining an initial state (XXX AND we are
# not in the managers group? not done to be more consistent)
......@@ -520,26 +487,32 @@ class Entity(AppObject, dict):
if execute('Any S WHERE S state_of ET, ET initial_state S,'
'ET name %(etype)s', {'etype': str(self.e_schema)}):
continue
# skip composite relation
if self.e_schema.subjrproperty(rschema, 'composite'):
continue
# skip relation with card in ?1 else we either change the copied
# object (inlined relation) or inserting some inconsistency
if self.e_schema.subjrproperty(rschema, 'cardinality')[1] in '?1':
continue
rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % (
rschema, rschema)
rschema.type, rschema.type)
execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y'))
self.clear_related_cache(rschema.type, 'subject')
for rschema in self.e_schema.object_relations():
# skip meta or composite
if rschema.meta or self.e_schema.objrproperty(rschema, 'composite'):
if rschema.meta:
continue
# skip already defined relations
if getattr(self, 'reverse_%s' % rschema.type):
continue
# skip composite relation
if self.e_schema.objrproperty(rschema, 'composite'):
continue
# skip relation with card in ?1 else we either change the copied
# object (inlined relation) or inserting some inconsistency
if self.e_schema.objrproperty(rschema, 'cardinality')[0] in '?1':
continue
# skip if we're told to do so
if rschema.type in self.skip_copy_for:
continue
# skip already defined relations
if self.related(rschema.type, 'object'):
continue
rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % (
rschema, rschema)
rschema.type, rschema.type)
execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y'))
self.clear_related_cache(rschema.type, 'object')
......@@ -904,9 +877,9 @@ class Entity(AppObject, dict):
yielded = False
for rschema, target in containers:
if target == 'object':
targets = self.related(rschema.type, 'subject', entities=True)
targets = getattr(self, rschema.type)
else:
targets = self.related(rschema.type, 'object', entities=True)
targets = getattr(self, 'reverse_%s' % rschema)
for entity in targets:
if entity.eid in _done:
continue
......@@ -942,73 +915,61 @@ class Entity(AppObject, dict):
words += tokenize(value)
for rschema, role in self.e_schema.fulltext_relations():
for entity in self.related(rschema.type, role, entities=True):
words += entity.get_words()
if role == 'subject':
for entity in getattr(self, rschema.type):
words += entity.get_words()
else: # if role == 'object':
for entity in getattr(self, 'reverse_%s' % rschema.type):
words += entity.get_words()
return words
# attribute and relation descriptors ##########################################
class Attribute(object):
"""descriptor that controls schema attribute access"""
def __init__(self, rtype):
assert rtype != 'eid'
self._rtype = rtype
def __get__(self, cwdbobj, eclass):
if cwdbobj is None:
return self
return cwdbobj.entity.get_value(self._rtype)
def __set__(self, eobj, value):
raise NotImplementedError
class Relation(Attribute):
"""descriptor that controls schema relation access"""
def __init__(self, rtype, role):
super(Relation, self).__init__(rtype)
self._role = role
def __get__(self, cwdbobj, eclass):
if cwdbobj is None:
raise AttributeError('%s cannot be only be accessed from instances'
% self._rtype)
return cwdbobj.entity.related(self._rtype, self._role, entities=True)
class DeprecatedAttribute(Attribute):
"""descriptor that controls schema attribute access"""
def __init__(self, attrname):
assert attrname != 'eid'
self._attrname = attrname
def __get__(self, eobj, eclass):
rtype = self._rtype
warn('entity.%s is deprecated, use entity.cwdb.%s' % (rtype, rtype),
DeprecationWarning, stacklevel=2)
if eobj is None:
return self
return eobj.get_value(self._rtype)
return eobj.get_value(self._attrname)
def __set__(self, eobj, value):
# XXX bw compat
# would be better to generate UPDATE queries than the current behaviour
eobj.warning("deprecated usage, don't use 'entity.attr = val' notation)")
eobj[self._rtype] = value
eobj[self._attrname] = value
class DeprecatedRelation(Relation):
class Relation(object):
"""descriptor that controls schema relation access"""
_role = None # for pylint
def __init__(self, rschema):
self._rschema = rschema
self._rtype = rschema.type
def __get__(self, eobj, eclass):
rtype = self._rtype
warn('entity.[reverse_]%s is deprecated, use entity.cwdb.[reverse_]%s'
% (rtype, rtype), DeprecationWarning, stacklevel=2)
if eobj is None:
raise AttributeError('%s cannot be only be accessed from instances'
% self._rtype)
return eobj.related(rtype, self._role, entities=True)
return eobj.related(self._rtype, self._role, entities=True)
def __set__(self, eobj, value):
raise NotImplementedError
class SubjectRelation(Relation):
"""descriptor that controls schema relation access"""
_role = 'subject'
class ObjectRelation(Relation):
"""descriptor that controls schema relation access"""
_role = 'object'
from logging import getLogger
from cubicweb import set_log_methods
......
......@@ -67,7 +67,7 @@ class SetCreatorOp(PreCommitOperation):
if self.entity.eid in session.transaction_data.get('pendingeids', ()):
# entity have been created and deleted in the same transaction
return
if not self.entity.related('created_by'):
if not self.entity.created_by:
session.add_relation(self.entity.eid, 'created_by', session.user.eid)
......
......@@ -687,7 +687,7 @@ class Repository(object):
if props is not None:
self.set_session_props(sessionid, props)
user = session.user
return user.eid, user.cwdb.login, user.groups, user.properties
return user.eid, user.login, user.groups, user.properties
def set_session_props(self, sessionid, props):
"""this method should be used by client to:
......
......@@ -48,7 +48,7 @@ class Session(RequestSessionMixIn):
def __init__(self, user, repo, cnxprops=None, _id=None):
super(Session, self).__init__(repo.vreg)
self.id = _id or make_uid(user.cwdb.login.encode('UTF8'))
self.id = _id or make_uid(user.login.encode('UTF8'))
cnxprops = cnxprops or ConnectionProperties('inmemory')
self.user = user
self.repo = repo
......
......@@ -117,7 +117,7 @@ class ResultSetTC(CubicWebTC):
rs.req = self.request()
rs.vreg = self.vreg
def test_filter(entity):
return entity.cwdb.login != 'nico'
return entity.login != 'nico'
rs2 = rs.filtered_rset(test_filter)
self.assertEquals(len(rs2), 2)
......@@ -271,11 +271,11 @@ class ResultSetTC(CubicWebTC):
self.assertEquals(pprelcachedict(e._related_cache),
[('created_by_subject', [5])])
# first level of recursion
u = e.cwdb.created_by[0]
u = e.created_by[0]
self.assertEquals(u['login'], 'admin')
self.assertRaises(KeyError, u.__getitem__, 'firstname')
# second level of recursion
s = u.cwdb.in_state[0]
s = u.in_state[0]
self.assertEquals(s['name'], 'activated')
self.assertRaises(KeyError, s.__getitem__, 'description')
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment