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.

leobject.py 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. #-*- coding: utf-8 -*-
  2. ## @package leobject API to access lodel datas
  3. #
  4. # This package contains abstract classes leapi.leclass.LeClass , leapi.letype.LeType, leapi.leapi._LeObject.
  5. # Those abstract classes are designed to be mother classes of dynamically generated classes ( see leapi.lefactory.LeFactory )
  6. ## @package leapi.leobject
  7. # @brief Abstract class designed to be implemented by LeObject
  8. #
  9. # @note LeObject will be generated by leapi.lefactory.LeFactory
  10. import re
  11. import copy
  12. import warnings
  13. import leapi
  14. from leapi.lecrud import _LeCrud, REL_SUP, REL_SUB
  15. from leapi.lefactory import LeFactory
  16. import EditorialModel
  17. from EditorialModel.types import EmType
  18. ## @brief Main class to handle objects defined by the types of an Editorial Model
  19. class _LeObject(_LeCrud):
  20. ## @brief maps em uid with LeType or LeClass keys are uid values are LeObject childs classes
  21. # @todo check if this attribute shouldn't be in _LeCrud
  22. _me_uid = dict()
  23. ## @brief Stores the fields name associated with fieldtype of the fields that are common to every LeObject
  24. _leo_fieldtypes = dict()
  25. ## @brief Instanciate a partial LeObject with a lodel_id
  26. # @note use the get_instance method to fetch datas and instanciate a concret LeObject
  27. def __init__(self, lodel_id):
  28. #Warning ! Handles only single pk
  29. uid_fname, uid_ft = list(self._uid_fieldtype.items())[0]
  30. new_id, err = uid_ft.check_data_value(lodel_id)
  31. if not (err is None):
  32. raise err
  33. setattr(self, uid_fname, lodel_id)
  34. ## @return Corresponding populated LeObject
  35. def get_instance(self):
  36. uid_fname = self.uidname()
  37. qfilter = '{uid_fname} = {uid}'.format(uid_fname = uid_fname, uid = getattr(self, uid_fname))
  38. return leobject.get([qfilter])[0]
  39. ## @return True if the LeObject is partially instanciated
  40. def is_partial(self):
  41. return not hasattr(self, '_classtype')
  42. ## @brief Check if a LeObject is the relation tree Root
  43. # @todo implementation
  44. def is_root(self):
  45. return False
  46. ## @brief Dirty & quick comparison implementation
  47. def __cmp__(self, other):
  48. return 0 if self == other else 1
  49. ## @brief Dirty & quick equality implementation
  50. # @todo check class
  51. def __eq__(self, other):
  52. uid_fname = self.uidname()
  53. if not hasattr(other, uid_fname):
  54. return False
  55. return getattr(self, uid_fname) == getattr(other, uid_fname)
  56. ## @brief Quick str cast method implementation
  57. def __str__(self):
  58. return "<%s lodel_id=%d>"%(self.__class__, getattr(self, self.uidname()))
  59. def __repr__(self):
  60. return self.__str__()
  61. ## @brief Given a ME uid return the corresponding LeClass or LeType class
  62. # @return a LeType or LeClass child class
  63. # @throw KeyError if no corresponding child classes
  64. # @todo check if this method shouldn't be in _LeCrud
  65. @classmethod
  66. def uid2leobj(cls, uid):
  67. uid = int(uid)
  68. if uid not in cls._me_uid:
  69. raise KeyError("No LeType or LeClass child classes with uid '%d'"%uid)
  70. return cls._me_uid[uid]
  71. @classmethod
  72. def fieldtypes(cls):
  73. if cls._fieldtypes_all is None:
  74. cls._fieldtypes_all = dict()
  75. cls._fieldtypes_all.update(cls._uid_fieldtype)
  76. cls._fieldtypes_all.update(cls._leo_fieldtypes)
  77. return cls._fieldtypes_all
  78. @classmethod
  79. def typefilter(cls):
  80. if hasattr(cls, '_type_id'):
  81. return ('type_id','=', cls._type_id)
  82. elif hasattr(cls, '_class_id'):
  83. return ('class_id', '=', cls._class_id)
  84. else:
  85. raise ValueError("Cannot generate a typefilter with %s class"%cls.__name__)
  86. ## @brief Delete LeObjects from db given filters and a classname
  87. # @note if no classname given, take the caller class
  88. # @param filters list :
  89. # @param classname None|str : the classname or None
  90. # @return number of deleted LeObjects
  91. # @see leapi.lecrud._LeCrud.delete()
  92. @classmethod
  93. def delete(cls, filters, classname = None):
  94. ccls = cls if classname is None else cls.name2class(classname)
  95. new_filters = copy.copy(filters)
  96. new_filters.append(ccls.typefilter())
  97. return _LeCrud.delete(ccls, new_filters)
  98. ## @brief Check that a relational field is valid
  99. # @param field str : a relational field
  100. # @return a nature
  101. @staticmethod
  102. def _prepare_relational_fields(field):
  103. spl = field.split('.')
  104. if len(spl) != 2:
  105. return ValueError("The relationalfield '%s' is not valid"%field)
  106. nature = spl[-1]
  107. if nature not in EditorialModel.classtypes.EmNature.getall():
  108. return ValueError("'%s' is not a valid nature in the field %s"%(nature, field))
  109. if spl[0] == 'superior':
  110. return (REL_SUP, nature)
  111. elif spl[0] == 'subordinate':
  112. return (REL_SUB, nature)
  113. else:
  114. return ValueError("Invalid preffix for relationnal field : '%s'"%spl[0])
  115. ## @brief Class designed to represent the hierarchy roots
  116. # @see _LeObject.get_root() _LeObject.is_root()
  117. class LeRoot(object):
  118. pass
  119. class LeObjectError(Exception):
  120. pass
  121. class LeObjectQueryError(LeObjectError):
  122. pass