1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2025-11-30 08:36:53 +01:00

Implements handling of relation_name field in relation common fields

This commit is contained in:
Yann 2016-01-15 17:07:54 +01:00
commit 37edad7b1f
9 changed files with 55 additions and 38 deletions

View file

@ -112,8 +112,8 @@ class _LeCrud(object):
# @param name str : The name
# @return name.title()
@staticmethod
def name2rel2type(class_name, type_name):
cls_name = "Rel_%s2%s"%(_LeCrud.name2classname(class_name), _LeCrud.name2classname(type_name))
def name2rel2type(class_name, type_name, relation_name):
cls_name = "Rel%s%s%s"%(_LeCrud.name2classname(class_name), _LeCrud.name2classname(type_name), relation_name.title())
return cls_name
## @brief Given a dynamically generated class name return the corresponding python Class
@ -412,10 +412,9 @@ class _LeCrud(object):
def insert(cls, datas, classname=None):
callcls = cls if classname is None else cls.name2class(classname)
if not callcls:
raise LeApiErrors("Error when inserting",[ValueError("The class '%s' was not found"%classname)])
raise LeApiErrors("Error when inserting",{'error':ValueError("The class '%s' was not found"%classname)})
if not callcls.implements_letype() and not callcls.implements_lerelation():
raise ValueError("You can only insert relations and LeTypes objects but tying to insert a '%s'"%callcls.__name__)
insert_datas = callcls.prepare_datas(datas, complete = True, allow_internal = False)
return callcls._datasource.insert(callcls, **insert_datas)

View file

@ -76,7 +76,8 @@ class LeFactory(object):
for field in [ f for f in model.components('EmField') if f.fieldtype == 'rel2type']:
related = model.component(field.rel_to_type_id)
src = field.em_class
cls_name = _LeCrud.name2rel2type(src.name, related.name)
cls_name = _LeCrud.name2rel2type(src.name, related.name, field.name)
relation_name = field.name
attr_l = dict()
for attr in [ f for f in model.components('EmField') if f.rel_field_id == field.uid]:
@ -87,12 +88,14 @@ class {classname}(LeRel2Type):
_rel_attr_fieldtypes = {attr_dict}
_superior_cls = {supcls}
_subordinate_cls = {subcls}
_relation_name = {relation_name}
""".format(
classname = cls_name,
attr_dict = "{" + (','.join(['\n %s: %s' % (repr(f), v) for f,v in attr_l.items()])) + "\n}",
supcls = _LeCrud.name2classname(src.name),
subcls = _LeCrud.name2classname(related.name),
relation_name = repr(relation_name),
)
res_code += rel_code
return res_code
@ -104,11 +107,11 @@ class {classname}(LeRel2Type):
def emclass_pycode(self, model, emclass):
cls_fields = dict()
cls_linked_types = list() #Stores authorized LeObject for rel2type
cls_linked_types = dict() # Stores rel2type referenced by fieldname
#Populating linked_type attr
for rfield in [ f for f in emclass.fields() if f.fieldtype == 'rel2type']:
fti = rfield.fieldtype_instance()
cls_linked_types.append(_LeCrud.name2classname(model.component(fti.rel_to_type_id).name))
cls_linked_types[rfield.name] = _LeCrud.name2classname(model.component(fti.rel_to_type_id).name)
# Populating fieldtype attr
for field in emclass.fields(relational = False):
self.needed_fieldtypes |= set([field.fieldtype])
@ -123,8 +126,8 @@ class {classname}(LeRel2Type):
""".format(
name = _LeCrud.name2classname(emclass.name),
ftypes = "{" + (','.join(['\n %s: %s' % (repr(f), v) for f, v in cls_fields.items()])) + "\n}",
ltypes = "{" + (','.join(['\n %s: %s' % (repr(f), v) for f, v in cls_linked_types.items()])) + "\n}",
ltypes = "[" + (','.join(cls_linked_types))+"]",
classtype = repr(emclass.classtype)
)

View file

@ -163,6 +163,7 @@ class _LeHierarch(_LeRelation):
@classmethod
def insert(cls, datas):
# Checks if the relation exists
datas[EditorialModel.classtypes.relation_name] = None
res = cls.get(
[(cls._subordinate_field_name, '=', datas['subordinate']), ('nature', '=', datas['nature'])],
[ cls.uidname() ]
@ -201,8 +202,10 @@ class _LeRel2Type(_LeRelation):
## @brief Stores the LeClass child class used as superior
_superior_cls = None
## @biref Stores the LeType child class used as subordinate
## @brief Stores the LeType child class used as subordinate
_subordinate_cls = None
## @brief Stores the relation name for a rel2type
_relation_name = None
## @brief Delete current instance from DB
def delete(self):
@ -232,21 +235,31 @@ class _LeRel2Type(_LeRelation):
#Set the nature
if 'nature' not in datas:
datas['nature'] = None
if cls == cls.name2class('LeRel2Type') and classname is None:
# autodetect the rel2type child class
classname = relname(datas[self._superior_field_name], datas[self._subordinate_field_name])
if cls.__name__ == 'LeRel2Type' and classname is None:
if EditorialModel.classtypes.relation_name not in datas:
raise RuntimeError("Unable to autodetect rel2type. No relation_name given")
# autodetect the rel2type child class (BROKEN)
classname = relname(datas[self._superior_field_name], datas[self._subordinate_field_name], datas[EditorialModel.classtypes.relation_name])
else:
if classname != None:
ccls = cls.name2class(classname)
if ccls == False:
raise lecrud.LeApiErrors("Bad classname given")
relation_name = ccls._relation_name
else:
relation_name = cls._relation_name
datas[EditorialModel.classtypes.relation_name] = relation_name
return super().insert(datas, classname)
## @brief Given a superior and a subordinate, returns the classname of the give rel2type
# @param lesupclass LeClass : LeClass child class (not an instance) (can be a LeType or a LeClass child)
# @param lesubclass LeType : A LeType child class (not an instance)
# @return a name as string
@staticmethod
def relname(lesupclass, lesubclass):
@classmethod
def relname(cls, lesupclass, lesubclass, relation_name):
supname = lesupclass._leclass.__name__ if lesupclass.implements_letype() else lesupclass.__name__
subname = lesubclass.__name__
return "Rel_%s2%s" % (supname, subname)
return cls.name2rel2type(supname, subname, relation_name)
## @brief instanciate the relevant lodel object using a dict of datas
@classmethod
@ -254,7 +267,7 @@ class _LeRel2Type(_LeRelation):
le_object = cls.name2class('LeObject')
class_name = le_object._me_uid[datas['class_id']].__name__
type_name = le_object._me_uid[datas['type_id']].__name__
relation_classname = lecrud._LeCrud.name2rel2type(class_name, type_name)
relation_classname = lecrud._LeCrud.name2rel2type(class_name, type_name, EditorialModel.classtypes.relation_name)
del(datas['class_id'], datas['type_id'])

View file

@ -6,6 +6,7 @@
# @note LeObject will be generated by leapi.lefactory.LeFactory
import leapi
import EditorialModel.classtypes as lodel2const
from leapi.lecrud import _LeCrud, LeApiDataCheckError, LeApiQueryError
from leapi.leclass import _LeClass
from leapi.leobject import LeObjectError
@ -90,15 +91,17 @@ class _LeType(_LeClass):
# @note This methods asser that self is the superior and leo_tolink the subordinate
#
# @param leo_tolink LeObject : LeObject child instance to link with
# @param **datas : Relation attributes (if any)
# @param relation_name str : Name of the relation (the fieldname of the rel2type in the EmClass)
# @param datas dict : Relation attributes (if any)
# @return a relation id if success
def link_with(self, leo_tolink, datas):
def link_with(self, leo_tolink, relation_name, datas):
# Fetch rel2type leapi class
r2t = self.name2class('LeRel2Type')
class_name = r2t.relname(self, leo_tolink.__class__)
class_name = r2t.relname(self, leo_tolink.__class__, relation_name)
r2tcls = self.name2class(class_name)
if not r2tcls:
raise ValueError("No rel2type possible between a '%s' as superior and a '%s' as subordinate" % (self._leclass.__name__, leo_tolink.__class__.__name__))
datas['superior'] = self
datas['subordinate'] = leo_tolink
datas[lodel2const.relation_name] = relation_name
return r2tcls.insert(datas, class_name)

View file

@ -416,8 +416,8 @@ class LeCrudTestCase(TestCase):
r2t_lst = list()
for leo in leo_lst:
if leo.is_leclass() and hasattr(leo, '_linked_types'):
for relleo in leo._linked_types:
r2t_lst.append(LeRel2Type.relname(leo, relleo))
for relation_name, relleo in leo._linked_types.items():
r2t_lst.append(LeRel2Type.relname(leo, relleo, relation_name))
leo_lst = [cls.__name__ for cls in leo_lst]
# Begin test
@ -454,6 +454,6 @@ class LeCrudTestCase(TestCase):
def test_typeasserts(self):
""" Tests te implements_le* and is_le* methods """
from dyncode import LeObject, LeCrud, LeRelation, LeHierarch, LeRel2Type, Article, Textes, Rel_Textes2Personne
from dyncode import LeObject, LeCrud, LeRelation, LeHierarch, LeRel2Type, Article, Textes, RelTextesPersonneAuteur
self.assertTrue(LeObject.is_leobject())

View file

@ -68,7 +68,7 @@ class TestLeFactory(TestCase):
#Testing _linked_types attr
self.assertEqual(
set([ LeCrud.name2classname(lt.name) for lt in emclass.linked_types()]),
set([ t.__name__ for t in leclass._linked_types ])
set([ t.__name__ for t in leclass._linked_types.values() ])
)
#Testing fieldtypes

View file

@ -117,7 +117,6 @@ class LeHierarch(LeRelationTestCase):
self.assertEqual(len(cargs), 2)
cargs=cargs[1]
self.assertEqual(cargs['target_cls'], target, "%s != %s"%(cargs, eargs))
print("FUCK : ", cargs['field_list'])
self.assertEqual(set(cargs['field_list']), set(field_ds), "%s != %s"%(cargs, eargs))
self.assertEqual(cargs['filters'], filters_ds, "%s != %s"%(cargs, eargs))
self.assertEqual(cargs['rel_filters'], rfilters_ds, "%s != %s"%(cargs, eargs))
@ -219,7 +218,7 @@ class LeRel2TypeTestCase(LeRelationTestCase):
@patch('DataSource.dummy.leapidatasource.DummyDatasource.insert')
def test_insert(self, dsmock):
""" test LeHierach update method"""
from dyncode import LeObject, Article, Textes, Personne, Personnes, LeHierarch, LeRel2Type, Rel_Textes2Personne
from dyncode import LeObject, Article, Textes, Personne, Personnes, LeHierarch, LeRel2Type, RelTextesPersonneAuteur
queries = [
{
@ -245,7 +244,7 @@ class LeRel2TypeTestCase(LeRelationTestCase):
]
for query in queries:
Rel_Textes2Personne.insert(query)
RelTextesPersonneAuteur.insert(query)
eres = {
'nature': None,
@ -258,18 +257,19 @@ class LeRel2TypeTestCase(LeRelationTestCase):
if isinstance(eres[fname], int):
eres[fname] = LeObject(eres[fname])
dsmock.assert_called_once_with(Rel_Textes2Personne, **eres)
dsmock.assert_called_once_with(RelTextesPersonneAuteur, **eres)
dsmock.reset_mock()
LeRel2Type.insert(query, "Rel_Textes2Personne")
dsmock.assert_called_once_with(Rel_Textes2Personne, **eres)
query[EditorialModel.classtypes.relation_name] = 'auteur'
LeRel2Type.insert(query, "RelTextesPersonneAuteur")
dsmock.assert_called_once_with(RelTextesPersonneAuteur, **eres)
dsmock.reset_mock()
@patch('DataSource.dummy.leapidatasource.DummyDatasource.insert')
def test_insert_fails(self, dsmock):
""" test LeHierach update method"""
from dyncode import LeObject, Rubrique, Numero, Article, Textes, Personne, Personnes, LeHierarch, LeRel2Type, Rel_Textes2Personne
from dyncode import LeObject, Rubrique, Numero, Article, Textes, Personne, Personnes, LeHierarch, LeRel2Type, RelTextesPersonneAuteur
queries = [
{
@ -304,10 +304,10 @@ class LeRel2TypeTestCase(LeRelationTestCase):
self.fail("No exception raised")
except Exception as e:
if not isinstance(e, lecrud.LeApiErrors) and not isinstance(e, lecrud.LeApiDataCheckError):
self.fail("Bad exception raised : ", e)
self.fail("Bad exception raised : "+str(e))
try:
Rel_Textes2Personne.insert(query)
RelTextesPersonneAuteur.insert(query)
self.fail("No exception raised")
except Exception as e:
if not isinstance(e, lecrud.LeApiErrors) and not isinstance(e, lecrud.LeApiDataCheckError):