mirror of
https://github.com/yweber/lodel2.git
synced 2025-11-21 13:19:16 +01:00
193 lines
7.1 KiB
Python
193 lines
7.1 KiB
Python
#-*- coding: utf-8 -*-
|
||
|
||
import importlib
|
||
|
||
import EditorialModel
|
||
from EditorialModel.model import Model
|
||
from EditorialModel.fieldtypes.generic import GenericFieldType
|
||
|
||
## @brief This class is designed to generated the leobject API given an EditorialModel.model
|
||
# @note Contains only static methods
|
||
#
|
||
# The name is not good but i've no other ideas for the moment
|
||
class LeFactory(object):
|
||
|
||
output_file = 'dyn.py'
|
||
|
||
def __init__(LeFactory):raise NotImplementedError("Not designed (yet?) to be implemented")
|
||
|
||
## @brief Return a LeObject child class given its name
|
||
# @return a python class or False
|
||
@staticmethod
|
||
def leobj_from_name(name):
|
||
mod = importlib.import_module('leobject.'+LeFactory.output_file.split('.')[-1])
|
||
try:
|
||
res = getattr(mod, name)
|
||
except AttributeError:
|
||
return False
|
||
return res
|
||
|
||
## @brief Convert an EmType or EmClass name in a python class name
|
||
# @param name str : The name
|
||
# @return name.title()
|
||
@staticmethod
|
||
def name2classname(name):
|
||
if not isinstance(name, str):
|
||
raise AttributeError("Argument name should be a str and not a %s"%type(name))
|
||
return name.title()
|
||
|
||
## @brief Return a call to a FieldType constructor given an EmField
|
||
# @param emfield EmField : An EmField
|
||
# @return a string representing the python code to instanciate a EmFieldType
|
||
@staticmethod
|
||
def fieldtype_construct_from_field(emfield):
|
||
return '%s.EmFieldType(**%s)'%(
|
||
GenericFieldType.module_name(emfield.fieldtype),
|
||
repr(emfield._fieldtype_args),
|
||
)
|
||
|
||
## @brief Given a Model and an EmClass instances generate python code for corresponding LeClass
|
||
# @param model Model : A Model instance
|
||
# @param emclass EmClass : An EmClass instance from model
|
||
# @return A string representing the python code for the corresponding LeClass child class
|
||
@staticmethod
|
||
def emclass_pycode(model, emclass):
|
||
cls_fields = dict()
|
||
cls_linked_types = list()
|
||
for field in emclass.fields():
|
||
cls_fields[field.name] = LeFactory.fieldtype_construct_from_field(field)
|
||
fti = field.fieldtype_instance()
|
||
if fti.name == 'rel2type':
|
||
#relationnal field/fieldtype
|
||
cls_linked_types.append(LeFactory.name2classname(model.component(fti.rel_to_type_id).name))
|
||
cls_fieldgroup = dict()
|
||
for fieldgroup in emclass.fieldgroups():
|
||
cls_fieldgroup[fieldgroup.name] = list()
|
||
for field in fieldgroup.fields():
|
||
cls_fieldgroup[fieldgroup.name].append(field.name)
|
||
|
||
return """
|
||
#Initialisation of {name} class attributes
|
||
{name}._fieldtypes = {ftypes}
|
||
{name}._linked_types = {ltypes}
|
||
{name}._fieldgroups = {fgroups}
|
||
""".format(
|
||
name = LeFactory.name2classname(emclass.name),
|
||
ftypes = "{"+(','.join([ '\n\t%s:%s'%(repr(f),v) for f,v in cls_fields.items()]))+"\n}",
|
||
ltypes = "{"+(','.join(cls_linked_types))+'}',
|
||
fgroups = repr(cls_fieldgroup)
|
||
)
|
||
|
||
## @brief Given a Model and an EmType instances generate python code for corresponding LeType
|
||
# @param model Model : A Model instance
|
||
# @param emtype EmType : An EmType instance from model
|
||
# @return A string representing the python code for the corresponding LeType child class
|
||
@staticmethod
|
||
def emtype_pycode(model, emtype):
|
||
type_fields = list()
|
||
type_superiors = list()
|
||
for field in emtype.fields():
|
||
type_fields.append(field.name)
|
||
|
||
for nat, sup_l in emtype.superiors().items():
|
||
type_superiors.append('%s:[%s]'%(
|
||
repr(nat),
|
||
','.join([ LeFactory.name2classname(sup.name) for sup in sup_l])
|
||
))
|
||
|
||
return """
|
||
#Initialisation of {name} class attributes
|
||
{name}._fields = {fields}
|
||
{name}._superiors = {dsups}
|
||
{name}._leclass = {leclass}
|
||
""".format(
|
||
name = LeFactory.name2classname(emtype.name),
|
||
fields = repr(type_fields),
|
||
dsups = '{'+(','.join(type_superiors))+'}',
|
||
leclass = LeFactory.name2classname(emtype.em_class.name)
|
||
)
|
||
|
||
## @brief Generate python code containing the LeObject API
|
||
# @param backend_cls Backend : A model backend class
|
||
# @param backend_args dict : A dict representing arguments for backend_cls instanciation
|
||
# @param datasource_cls Datasource : A datasource class
|
||
# @param datasource_args dict : A dict representing arguments for datasource_cls instanciation
|
||
# @return A string representing python code
|
||
@staticmethod
|
||
def generate_python(backend_cls, backend_args, datasource_cls, datasource_args):
|
||
model = Model(backend=backend_cls(**backend_args))
|
||
|
||
result = ""
|
||
#result += "#-*- coding: utf-8 -*-\n"
|
||
#Putting import directives in result
|
||
result += """
|
||
|
||
from EditorialModel.model import Model
|
||
from leobject.leobject import _LeObject
|
||
from leobject.leclass import LeClass
|
||
from leobject.letype import LeType
|
||
import EditorialModel.fieldtypes
|
||
"""
|
||
|
||
result += """
|
||
import %s
|
||
import %s
|
||
"""%(backend_cls.__module__, datasource_cls.__module__)
|
||
|
||
#Generating the code for LeObject class
|
||
backend_constructor = '%s.%s(**%s)'%(backend_cls.__module__, backend_cls.__name__, repr(backend_args))
|
||
leobj_me_uid = dict()
|
||
for comp in model.components('EmType') + model.components('EmClass'):
|
||
leobj_me_uid[comp.uid] = LeFactory.name2classname(comp.name)
|
||
|
||
result += """
|
||
## @brief _LeObject concret clas
|
||
# @see leobject::leobject::_LeObject
|
||
class LeObject(_LeObject):
|
||
_model = Model(backend=%s)
|
||
_datasource = %s(**%s)
|
||
_me_uid = %s
|
||
|
||
"""%(backend_constructor, datasource_cls.__module__+'.'+datasource_cls.__name__, repr(datasource_args), repr(leobj_me_uid))
|
||
|
||
emclass_l = model.components(EditorialModel.classes.EmClass)
|
||
emtype_l = model.components(EditorialModel.types.EmType)
|
||
|
||
#LeClass child classes definition
|
||
for emclass in emclass_l:
|
||
result += """
|
||
## @brief EmClass {name} LeClass child class
|
||
# @see leobject::leclass::LeClass
|
||
class {name}(LeObject,LeClass):
|
||
_class_id = {uid}
|
||
""".format(
|
||
name = LeFactory.name2classname(emclass.name),
|
||
uid = emclass.uid
|
||
)
|
||
#LeType child classes definition
|
||
for emtype in emtype_l:
|
||
result += """
|
||
## @brief EmType {name} LeType child class
|
||
# @see leobject::letype::LeType
|
||
class {name}({leclass},LeType):
|
||
_type_id = {uid}
|
||
""".format(
|
||
name = LeFactory.name2classname(emtype.name),
|
||
leclass = LeFactory.name2classname(emtype.em_class.name),
|
||
uid = emtype.uid
|
||
)
|
||
|
||
#Set attributes of created LeClass and LeType child classes
|
||
for emclass in emclass_l:
|
||
result += LeFactory.emclass_pycode(model, emclass)
|
||
for emtype in emtype_l:
|
||
result += LeFactory.emtype_pycode(model, emtype)
|
||
|
||
#Populating LeObject._me_uid dict for a rapid fetch of LeType and LeClass given an EM uid
|
||
result += """
|
||
## @brief Dict for getting LeClass and LeType child classes given an EM uid
|
||
LeObject._me_uid = %s
|
||
"""%repr({ comp.uid:LeFactory.name2classname(comp.name) for comp in emclass_l + emtype_l })
|
||
|
||
return result
|
||
|