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.

model.py 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #-*- coding:utf-8 -*-
  2. import hashlib
  3. import importlib
  4. from lodel.utils.mlstring import MlString
  5. from lodel.logger import logger
  6. from lodel.settings import Settings
  7. from lodel.settings.utils import SettingsError
  8. from lodel.editorial_model.exceptions import *
  9. from lodel.editorial_model.components import EmClass, EmField, EmGroup
  10. ##@brief Describe an editorial model
  11. class EditorialModel(object):
  12. ##@brief Create a new editorial model
  13. # @param name MlString|str|dict : the editorial model name
  14. # @param description MlString|str|dict : the editorial model description
  15. def __init__(self, name, description = None):
  16. self.name = MlString(name)
  17. self.description = MlString(description)
  18. ##@brief Stores all groups indexed by id
  19. self.__groups = dict()
  20. ##@brief Stores all classes indexed by id
  21. self.__classes = dict()
  22. ## @brief Stores all activated groups indexed by id
  23. self.__active_groups = dict()
  24. ## @brief Stores all activated classes indexed by id
  25. self.__active_classes = dict()
  26. ##@brief EmClass accessor
  27. #@param uid None | str : give this argument to get a specific EmClass
  28. #@return if uid is given returns an EmClass else returns an EmClass
  29. # iterator
  30. #@todo use Settings.editorialmodel.groups to determine wich classes should
  31. # be returned
  32. def classes(self, uid = None):
  33. try:
  34. return self.__elt_getter( self.__active_classes,
  35. uid)
  36. except KeyError:
  37. raise EditorialModelException("EmClass not found : '%s'" % uid)
  38. ##@brief EmGroup getter
  39. # @param uid None | str : give this argument to get a specific EmGroup
  40. # @return if uid is given returns an EmGroup else returns an EmGroup iterator
  41. def groups(self, uid = None):
  42. try:
  43. return self.__elt_getter( self.__active_groups,
  44. uid)
  45. except KeyError:
  46. raise EditorialModelException("EmGroup not found : '%s'" % uid)
  47. ##@brief Private getter for __groups or __classes
  48. # @see classes() groups()
  49. def __elt_getter(self, elts, uid):
  50. return list(elts.values()) if uid is None else elts[uid]
  51. ##@brief Update the EditorialModel.__active_groups and
  52. #EditorialModel.__active_classes attibutes
  53. def __set_actives(self):
  54. if Settings.editorialmodel.editormode:
  55. # all groups & classes actives because we are in editor mode
  56. self.__active_groups = self.__groups
  57. self.__active_classes = self.__classes
  58. else:
  59. #determine groups first
  60. self.__active_groups = dict()
  61. for agrp in Settings.editorialmodel.groups:
  62. if agrp not in self.__groups:
  63. raise SettingsError('Invalid group found in settings : %s' % agrp)
  64. grp = self.__groups[agrp]
  65. self.__active_groups[grp.uid] = grp
  66. for acls in grp.components():
  67. self.__active_classes[acls.uid] = acls
  68. ##@brief EmField getter
  69. # @param uid str : An EmField uid represented by "CLASSUID.FIELDUID"
  70. # @return Fals or an EmField instance
  71. #
  72. # @todo delete it, useless...
  73. def field(self, uid = None):
  74. spl = uid.split('.')
  75. if len(spl) != 2:
  76. raise ValueError("Malformed EmField identifier : '%s'" % uid)
  77. cls_uid = spl[0]
  78. field_uid = spl[1]
  79. try:
  80. emclass = self.classes(cls_uid)
  81. except KeyError:
  82. return False
  83. try:
  84. return emclass.fields(field_uid)
  85. except KeyError:
  86. pass
  87. return False
  88. ##@brief Add a class to the editorial model
  89. # @param emclass EmClass : the EmClass instance to add
  90. # @return emclass
  91. def add_class(self, emclass):
  92. self.raise_if_ro()
  93. if not isinstance(emclass, EmClass):
  94. raise ValueError("<class EmClass> expected but got %s " % type(emclass))
  95. if emclass.uid in self.classes():
  96. raise EditorialModelException('Duplicated uid "%s"' % emclass.uid)
  97. self.__classes[emclass.uid] = emclass
  98. return emclass
  99. ##@brief Add a group to the editorial model
  100. # @param emgroup EmGroup : the EmGroup instance to add
  101. # @return emgroup
  102. def add_group(self, emgroup):
  103. self.raise_if_ro()
  104. if not isinstance(emgroup, EmGroup):
  105. raise ValueError("<class EmGroup> expected but got %s" % type(emgroup))
  106. if emgroup.uid in self.groups():
  107. raise EditorialModelException('Duplicated uid "%s"' % emgroup.uid)
  108. self.__groups[emgroup.uid] = emgroup
  109. return emgroup
  110. ##@brief Add a new EmClass to the editorial model
  111. #@param uid str : EmClass uid
  112. #@param **kwargs : EmClass constructor options (
  113. # see @ref lodel.editorial_model.component.EmClass.__init__() )
  114. def new_class(self, uid, **kwargs):
  115. self.raise_if_ro()
  116. return self.add_class(EmClass(uid, **kwargs))
  117. ##@brief Add a new EmGroup to the editorial model
  118. #@param uid str : EmGroup uid
  119. #@param *kwargs : EmGroup constructor keywords arguments (
  120. # see @ref lodel.editorial_model.component.EmGroup.__init__() )
  121. def new_group(self, uid, **kwargs):
  122. self.raise_if_ro()
  123. return self.add_group(EmGroup(uid, **kwargs))
  124. ##@brief Save a model
  125. # @param translator module : The translator module to use
  126. # @param **translator_args
  127. def save(self, translator, **translator_kwargs):
  128. self.raise_if_ro()
  129. if isinstance(translator, str):
  130. translator = self.translator_from_name(translator)
  131. return translator.save(self, **translator_kwargs)
  132. ##@brief Raise an error if lodel is not in EM edition mode
  133. @staticmethod
  134. def raise_if_ro():
  135. if not Settings.editorialmodel.editormode:
  136. raise EditorialModelError("Lodel in not in EM editor mode. The EM is in read only state")
  137. ##@brief Load a model
  138. # @param translator module : The translator module to use
  139. # @param **translator_args
  140. @classmethod
  141. def load(cls, translator, **translator_kwargs):
  142. if isinstance(translator, str):
  143. translator = cls.translator_from_name(translator)
  144. return translator.load(**translator_kwargs)
  145. ##@brief Return a translator module given a translator name
  146. # @param translator_name str : The translator name
  147. # @return the translator python module
  148. # @throw NameError if the translator does not exists
  149. @staticmethod
  150. def translator_from_name(translator_name):
  151. pkg_name = 'lodel.editorial_model.translator.%s' % translator_name
  152. try:
  153. mod = importlib.import_module(pkg_name)
  154. except ImportError:
  155. raise NameError("No translator named %s")
  156. return mod
  157. ##@brief Lodel hash
  158. def d_hash(self):
  159. payload = "%s%s" % (
  160. self.name,
  161. 'NODESC' if self.description is None else self.description.d_hash()
  162. )
  163. for guid in sorted(self.__groups):
  164. payload += str(self.__groups[guid].d_hash())
  165. for cuid in sorted(self.__classes):
  166. payload += str(self.__classes[cuid].d_hash())
  167. return int.from_bytes(
  168. hashlib.md5(bytes(payload, 'utf-8')).digest(),
  169. byteorder='big'
  170. )