1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2026-03-17 08:42:01 +01:00

Implements relation stuff + a lot of fixes in tests and in leo fieldtypes validation stack

This commit is contained in:
Yann 2015-12-03 17:41:59 +01:00
commit 67dbe5c097
6 changed files with 90 additions and 90 deletions

View file

@ -3,7 +3,7 @@
import leapi.letype as letype
import leapi.leclass as leclass
from .generic import GenericFieldType
from .generic import GenericFieldType, FieldTypeError
class EmFieldType(GenericFieldType):
@ -24,13 +24,30 @@ class EmFieldType(GenericFieldType):
return (value, None)
## @brief If field value is an integer, returns a partially instanciated LeObject (only with an ID)
# @todo what should we do if the get fails ? Raise ?
def construct_data(self, lec, fname, datas):
if isinstance(datas[fname], str):
# Cast to int
try:
datas[fname] = int(datas[fname])
except ValueError as e:
raise e # Raise Here !?
if datas[fname].is_leobject():
# Its an object not populated (we dont now its type)
datas[fname] = datas[fname].lodel_id #Optimize here giving only class_id and type_id to populate ?
if isinstance(datas[fname], int):
leobject = lec.name2class('LeObject')
return leobject(datas[fname])
else:
return datas[fname]
# Get instance with id
resget = lec.name2class('LeObject').get(['lodel_id = %d' % datas[fname]])
if resget is None or len(resget) != 1:
# Bad filter or bad id... raise ?
raise Exception("BAAAAAD")
return datas[fname]
## @brief checks datas consistency
# @param lec LeCrud : A LeCrud child instance
# @param fname str : concerned field name
# @param datas dict : Datas of lec
# @return True if ok else an Exception instance
def check_data_consistency(self, lec, fname, datas):
if self.superior:
return self.check_sup_consistency(lec, fname, datas)
@ -38,7 +55,14 @@ class EmFieldType(GenericFieldType):
return self.check_sub_consistency(lec, fname, datas)
def check_sup_consistency(self, lec, fname, datas):
if lec.implements_lerel2type():
# Checking consistency for a rel2type relation
lesup = datas['lesup']
lesub = datas['lesub']
if lesub.__class__ not in lesup._linked_types:
return FieldTypeError("Rel2type not authorized between %s and %s"%(lesup, lesub))
pass
def check_sub_consistency(self, lec, fname, datas):
pass

View file

@ -272,7 +272,9 @@ class _LeCrud(object):
@classmethod
def insert(cls, datas, classname = None):
callcls = cls if classname is None else cls.name2class(classname)
if not callcls.is_letype() and not callcls.implements_lerelation():
if not callcls:
raise LeApiErrors("Error when inserting",[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)
@ -303,6 +305,7 @@ class _LeCrud(object):
## @brief Build a filter to select an object with a specific ID
# @warning assert that the uid is not composed with multiple fieldtypes
# @return A filter of the form tuple(UID, '=', self.UID)
# @todo This method should not be private
def _id_filter(self):
id_name = self.uidname()
return ( id_name, '=', getattr(self, id_name) )

View file

@ -55,38 +55,19 @@ class _LeRelation(lecrud._LeCrud):
# @return prepared and checked filters
@classmethod
def _prepare_filters(cls, filters_l):
filters = list()
res = list()
rel = list()
for filter_item in filters_l:
if isinstance(filter_item, tuple):
filters.append(filter_item)
else:
filter_item_data = filter_item.split(" ")
if len(filter_item_data) == 3:
if filter_item_data[0] in cls._lesub_fieldtype.keys():
filter_item_data[2] = cls._lesub_fieldtype[filter_item_data[0]].construct_data(
cls,
filter_item_data[0],
{filter_item_data[0]: int(filter_item_data[2])}
)
elif filter_item_data[0] in cls._lesup_fieldtype.keys():
filter_item_data[2] = cls._lesup_fieldtype[filter_item_data[0]].construct_data(
cls,
filter_item_data[0],
{filter_item_data[0]: int(filter_item_data[2])}
)
filters.append(tuple(filter_item_data))
for field, operator, value in filters:
if field.startswith('superior') or field.startswith('subordinate'):
rel.append((field, operator, value))
else:
res.append((field, operator, value))
return (res, rel)
filters, rel_filters = super()._prepare_filters(filters_l)
res_filters = list()
for field, op, value in filters:
if field in ['lesup', 'lesub']:
if isinstance(value, str):
try:
value = int(value)
except ValueError as e:
raise LeApiDataCheckError("Wrong value given for '%s'"%field)
if isinstance(value, int):
value = cls.name2class('LeObject')(value)
res_filters.append( (field, op, value) )
return res_filters, rel_filters
@classmethod
## @brief deletes a relation between two objects
@ -115,12 +96,18 @@ class _LeRel2Type(_LeRelation):
## @brief Delete current instance from DB
def delete(self):
lecrud._LeCrud._delete(self)
## @brief Implements insert for rel2type
# @todo checks when autodetecing the rel2type class
@classmethod
def insert(cls, datas, classname):
def insert(cls, datas, classname = None):
#Set the nature
if 'nature' not in datas:
datas['nature'] = None
cls.name2class('LeCrud').insert(datas, classname)
if cls == cls.name2class('LeRel2Type') and classname is None:
# autodetect the rel2type child class
classname = relname(datas['lesup'], datas['lesub'])
super().insert(datas, classname)
## @brief Given a superior and a subordinate, returns the classname of the give rel2type
# @param lesupclass LeClass : LeClass child class (can be a LeType or a LeClass child)

View file

@ -11,7 +11,7 @@
# @note LeObject will be generated by leapi.lefactory.LeFactory
import leapi
from leapi.lecrud import _LeCrud, LeApiDataCheckError
from leapi.lecrud import _LeCrud, LeApiDataCheckError, LeApiQueryError
from leapi.leclass import _LeClass
from leapi.leobject import LeObjectError
@ -82,8 +82,11 @@ class _LeType(_LeClass):
rel_filters = []
fdatas = self._datasource.select(self.__class__, field_list, filters, rel_filters)
for fname, fdats in fdatas[0].items():
setattr(self, name, value)
if fdatas is None or len(fdatas) == 0:
raise LeApiQueryError("Error when trying to populate an object. For type %s id : %d"% (self.__class__.__name__, self.lodel_id))
for fname, fval in fdatas[0].items():
setattr(self, fname, fval)
## @brief Get a fieldname:value dict
# @return A dict with field name as key and the field value as value

View file

@ -5,6 +5,7 @@
import unittest
from unittest import TestCase
from unittest.mock import patch
from collections import OrderedDict
import EditorialModel
import DataSource.dummy
@ -129,16 +130,18 @@ class LeHierarch(LeRelationTestCase):
queries = [
(
{
'lesup': Rubrique(7),
'lesub': Numero(42),
'lesup': Rubrique(7, class_id = Rubrique._class_id, type_id = Rubrique._type_id),
'lesub': Numero(42, class_id = Numero._class_id, type_id = Numero._type_id),
'nature': 'parent',
},
{
'lesup': Rubrique(7),
'lesub': Numero(42),
'nature': 'parent',
}
},
),
]
""" # Those tests are not good
(
{
'lesup': 7,
@ -176,6 +179,7 @@ class LeHierarch(LeRelationTestCase):
}
)
]
"""
for query, equery in queries:
LeHierarch.insert(query)
dsmock.assert_called_once_with(LeHierarch, **equery)
@ -207,7 +211,6 @@ class LeHierarch(LeRelationTestCase):
class LeRel2TypeTestCase(LeRelationTestCase):
@unittest.skip("Wait for implmentation (mainly implements nature = none for non hierarch)")
@patch('DataSource.dummy.leapidatasource.DummyDatasource.insert')
def test_insert(self, dsmock):
""" test LeHierach update method"""
@ -224,20 +227,14 @@ class LeRel2TypeTestCase(LeRelationTestCase):
'lesub': Personne(24),
'adresse': None,
},
{
'lesup': 42,
'lesub': Personne(24),
'adresse': None,
},
{
'lesup': Article(42),
'lesub': Personnes(24),
'lesub': Personne(24),
'adresse': "bar",
},
{
'lesup': Textes(42),
'lesub': Personnes(24),
'lesub': Personne(24),
'adresse': "foo",
},
]
@ -246,7 +243,7 @@ class LeRel2TypeTestCase(LeRelationTestCase):
Rel_Textes2Personne.insert(query)
eres = {'nature': None}
eres.uopdate(query)
eres.update(query)
for fname in ('lesup', 'lesub'):
if isinstance(eres[fname], int):
eres[fname] = LeObject(eres[fname])
@ -254,12 +251,11 @@ class LeRel2TypeTestCase(LeRelationTestCase):
dsmock.assert_called_once_with(Rel_Textes2Personne, **eres)
dsmock.reset_mock()
LeRel2Type.insert(query, "Rel_textes2personne")
LeRel2Type.insert(query, "Rel_Textes2Personne")
dsmock.assert_called_once_with(Rel_Textes2Personne, **eres)
dsmock.reset_mock()
@unittest.skip("Wait implementation to unskip")
@patch('DataSource.dummy.leapidatasource.DummyDatasource.insert')
def test_insert_fails(self, dsmock):
""" test LeHierach update method"""
@ -276,7 +272,7 @@ class LeRel2TypeTestCase(LeRelationTestCase):
},
{
'lesup': Rubrique(42),
'lesub': LeObject(24),
'lesub': Rubrique(24),
'adresse': None,
},
{
@ -285,38 +281,24 @@ class LeRel2TypeTestCase(LeRelationTestCase):
'adresse': 'foo',
},
{
'lesup': 42,
'lesub': 24,
},
{
'lesup': 42,
'lesub': 24,
'adresse': None,
'nature': "parent",
},
{
'lesup': 42,
'lesub': 24,
'adresse': None,
'nature': None,
},
{
'lesup': 42,
'lesub': 24,
'adresse': None,
'foofield': None,
},
{
'lesup': 42,
'lesub': 24,
'id_relation': 1337,
'adresse': None,
'lesup': Article(42),
'lesub': Numero(24),
'adresse': 'foo',
},
]
for query in queries:
with self.assertRaises(lecrud.LeApiQueryError):
try:
LeRel2Type.insert(query, 'Rel_textes2personne')
with self.assertRaises(lecrud.LeApiQueryError):
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)
try:
Rel_Textes2Personne.insert(query)
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)

View file

@ -72,8 +72,9 @@ class LeTypeMockDsTestCase(TestCase):
num = Numero(1, type_id = Numero._type_id)
missing_fields = [f for f in Numero._fields if not (f in ['lodel_id', 'type_id'])]
num.populate()
dsmock.assert_called_once_with(Numero, missing_fields, [('lodel_id','=',1)],[])
with self.assertRaises(leapi.lecrud.LeApiQueryError):
num.populate()
dsmock.assert_called_once_with(Numero, missing_fields, [('lodel_id','=',1)],[])
@patch('DataSource.dummy.leapidatasource.DummyDatasource.update')
def test_update(self, dsmock):