No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lefactory.py 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #-*- coding: utf-8 -*-
  2. import importlib
  3. import EditorialModel
  4. from EditorialModel.model import Model
  5. from EditorialModel.fieldtypes.generic import GenericFieldType
  6. ## @brief This class is designed to generated the leobject API given an EditorialModel.model
  7. # @note Contains only static methods
  8. #
  9. # The name is not good but i've no other ideas for the moment
  10. class LeFactory(object):
  11. output_file = 'dyn.py'
  12. def __init__(LeFactory):raise NotImplementedError("Not designed (yet?) to be implemented")
  13. ## @brief Return a LeObject child class given its name
  14. # @return a python class or False
  15. @staticmethod
  16. def leobj_from_name(name):
  17. mod = importlib.import_module('leobject.'+LeFactory.output_file.split('.')[-1])
  18. try:
  19. res = getattr(mod, name)
  20. except AttributeError:
  21. return False
  22. return res
  23. ## @brief Convert an EmType or EmClass name in a python class name
  24. # @param name str : The name
  25. # @return name.title()
  26. @staticmethod
  27. def name2classname(name):
  28. if not isinstance(name, str):
  29. raise AttributeError("Argument name should be a str and not a %s"%type(name))
  30. return name.title()
  31. ## @brief Return a call to a FieldType constructor given an EmField
  32. # @param emfield EmField : An EmField
  33. # @return a string representing the python code to instanciate a EmFieldType
  34. @staticmethod
  35. def fieldtype_construct_from_field(emfield):
  36. return '%s.EmFieldType(**%s)'%(
  37. GenericFieldType.module_name(emfield.fieldtype),
  38. repr(emfield._fieldtype_args),
  39. )
  40. ## @brief Given a Model and an EmClass instances generate python code for corresponding LeClass
  41. # @param model Model : A Model instance
  42. # @param emclass EmClass : An EmClass instance from model
  43. # @return A string representing the python code for the corresponding LeClass child class
  44. @staticmethod
  45. def emclass_pycode(model, emclass):
  46. cls_fields = dict()
  47. cls_linked_types = list()
  48. for field in emclass.fields():
  49. cls_fields[field.name] = LeFactory.fieldtype_construct_from_field(field)
  50. fti = field.fieldtype_instance()
  51. if fti.name == 'rel2type':
  52. #relationnal field/fieldtype
  53. cls_linked_types.append(LeFactory.name2classname(model.component(fti.rel_to_type_id).name))
  54. cls_fieldgroup = dict()
  55. for fieldgroup in emclass.fieldgroups():
  56. cls_fieldgroup[fieldgroup.name] = list()
  57. for field in fieldgroup.fields():
  58. cls_fieldgroup[fieldgroup.name].append(field.name)
  59. return """
  60. #Initialisation of {name} class attributes
  61. {name}._fieldtypes = {ftypes}
  62. {name}._linked_types = {ltypes}
  63. {name}._fieldgroups = {fgroups}
  64. """.format(
  65. name = LeFactory.name2classname(emclass.name),
  66. ftypes = "{"+(','.join([ '\n\t%s:%s'%(repr(f),v) for f,v in cls_fields.items()]))+"\n}",
  67. ltypes = "{"+(','.join(cls_linked_types))+'}',
  68. fgroups = repr(cls_fieldgroup)
  69. )
  70. ## @brief Given a Model and an EmType instances generate python code for corresponding LeType
  71. # @param model Model : A Model instance
  72. # @param emtype EmType : An EmType instance from model
  73. # @return A string representing the python code for the corresponding LeType child class
  74. @staticmethod
  75. def emtype_pycode(model, emtype):
  76. type_fields = list()
  77. type_superiors = list()
  78. for field in emtype.fields():
  79. type_fields.append(field.name)
  80. for nat, sup_l in emtype.superiors().items():
  81. type_superiors.append('%s:[%s]'%(
  82. repr(nat),
  83. ','.join([ LeFactory.name2classname(sup.name) for sup in sup_l])
  84. ))
  85. return """
  86. #Initialisation of {name} class attributes
  87. {name}._fields = {fields}
  88. {name}._superiors = {dsups}
  89. {name}._leclass = {leclass}
  90. """.format(
  91. name = LeFactory.name2classname(emtype.name),
  92. fields = repr(type_fields),
  93. dsups = '{'+(','.join(type_superiors))+'}',
  94. leclass = LeFactory.name2classname(emtype.em_class.name)
  95. )
  96. ## @brief Generate python code containing the LeObject API
  97. # @param backend_cls Backend : A model backend class
  98. # @param backend_args dict : A dict representing arguments for backend_cls instanciation
  99. # @param datasource_cls Datasource : A datasource class
  100. # @param datasource_args dict : A dict representing arguments for datasource_cls instanciation
  101. # @return A string representing python code
  102. @staticmethod
  103. def generate_python(backend_cls, backend_args, datasource_cls, datasource_args):
  104. model = Model(backend=backend_cls(**backend_args))
  105. result = ""
  106. #result += "#-*- coding: utf-8 -*-\n"
  107. #Putting import directives in result
  108. result += """
  109. from EditorialModel.model import Model
  110. from leobject.leobject import _LeObject
  111. from leobject.leclass import LeClass
  112. from leobject.letype import LeType
  113. import EditorialModel.fieldtypes
  114. """
  115. result += """
  116. import %s
  117. import %s
  118. """%(backend_cls.__module__, datasource_cls.__module__)
  119. #Generating the code for LeObject class
  120. backend_constructor = '%s.%s(**%s)'%(backend_cls.__module__, backend_cls.__name__, repr(backend_args))
  121. leobj_me_uid = dict()
  122. for comp in model.components('EmType') + model.components('EmClass'):
  123. leobj_me_uid[comp.uid] = LeFactory.name2classname(comp.name)
  124. result += """
  125. ## @brief _LeObject concret clas
  126. # @see leobject::leobject::_LeObject
  127. class LeObject(_LeObject):
  128. _model = Model(backend=%s)
  129. _datasource = %s(**%s)
  130. _me_uid = %s
  131. """%(backend_constructor, datasource_cls.__module__+'.'+datasource_cls.__name__, repr(datasource_args), repr(leobj_me_uid))
  132. emclass_l = model.components(EditorialModel.classes.EmClass)
  133. emtype_l = model.components(EditorialModel.types.EmType)
  134. #LeClass child classes definition
  135. for emclass in emclass_l:
  136. result += """
  137. ## @brief EmClass {name} LeClass child class
  138. # @see leobject::leclass::LeClass
  139. class {name}(LeObject,LeClass):
  140. _class_id = {uid}
  141. """.format(
  142. name = LeFactory.name2classname(emclass.name),
  143. uid = emclass.uid
  144. )
  145. #LeType child classes definition
  146. for emtype in emtype_l:
  147. result += """
  148. ## @brief EmType {name} LeType child class
  149. # @see leobject::letype::LeType
  150. class {name}({leclass},LeType):
  151. _type_id = {uid}
  152. """.format(
  153. name = LeFactory.name2classname(emtype.name),
  154. leclass = LeFactory.name2classname(emtype.em_class.name),
  155. uid = emtype.uid
  156. )
  157. #Set attributes of created LeClass and LeType child classes
  158. for emclass in emclass_l:
  159. result += LeFactory.emclass_pycode(model, emclass)
  160. for emtype in emtype_l:
  161. result += LeFactory.emtype_pycode(model, emtype)
  162. #Populating LeObject._me_uid dict for a rapid fetch of LeType and LeClass given an EM uid
  163. result += """
  164. ## @brief Dict for getting LeClass and LeType child classes given an EM uid
  165. LeObject._me_uid = %s
  166. """%repr({ comp.uid:LeFactory.name2classname(comp.name) for comp in emclass_l + emtype_l })
  167. return result