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.

randomem.py 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. #-*- coding: utf-8 -*-
  2. ## @package EditorialModel.randomem
  3. #
  4. # Provide methods for random EM generation
  5. import random
  6. from EditorialModel.backend.dummy_backend import EmBackendDummy
  7. from EditorialModel.model import Model
  8. from EditorialModel.fieldgroups import EmFieldGroup
  9. from EditorialModel.fields import EmField
  10. from EditorialModel.types import EmType
  11. from EditorialModel.classtypes import EmClassType
  12. from Lodel.utils.mlstring import MlString
  13. class RandomEm(object):
  14. ## @brief Instanciate a class allowing to generate random EM
  15. # @see RandomEm::random_em()
  16. def __init__(self, backend=None, **kwargs):
  17. self.backend = backend
  18. self.kwargs = kwargs
  19. ## @brief Return a random EM
  20. # @return A random EM
  21. def gen(self):
  22. return self.random_em(self.backend, **self.kwargs)
  23. @classmethod
  24. ## @brief Generate a random editorial model
  25. #
  26. # The random generator can be tuned with integer parameters
  27. # that represent probability or maximum numbers of items.
  28. # The probability (chances) works like 1/x chances to append
  29. # with x the tunable parameter
  30. # Tunable generator parameters :
  31. # - classtype : Chances for a classtype to be empty (default 0)
  32. # - nclass : Maximum number of classes per classtypes (default 5)
  33. # - nofg : Chances for a classe to have no fieldgroup associated to it (default 10)
  34. # - notype : Chances for a classe to have no type associated to it (default 5)
  35. # - seltype : Chances for a type to select an optionnal field (default 2)
  36. # - ntypesuperiors : Chances for a type to link with a superiors (default 3)
  37. # - nofields : Chances for a fieldgroup to be empty (default 10)
  38. # - nfields : Maximum number of field per fieldgroups (default 8)
  39. # - rfields : Maximum number of relation_to_type attributes fields (default 5)
  40. # - optfield : Chances for a field to be optionnal (default 2)
  41. # @param backend : A backend to use with the new EM
  42. # @param **kwargs dict : Provide tunable generation parameter
  43. # @param cls
  44. # @return A randomly generate EM
  45. def random_em(cls, backend=None, **kwargs):
  46. ed_mod = Model(EmBackendDummy if backend is None else backend)
  47. chances = {
  48. 'classtype': 0, # a class in classtype
  49. 'nclass': 5, # max number of classes per classtype
  50. 'nofg': 10, # no fieldgroup in a class
  51. 'nfg': 5, # max number of fieldgroups per classes
  52. 'notype': 10, # no types in a class
  53. 'ntype': 8, # max number of types in a class
  54. 'seltype': 2, # chances to select an optional field
  55. 'ntypesuperiors': 2, # chances to link with a superior
  56. 'nofields': 10, # no fields in a fieldgroup
  57. 'nfields': 8, # max number of fields per fieldgroups
  58. 'nr2tfields': 1, # max number of rel2type fields per fieldgroups
  59. 'rfields': 5, # max number of attributes relation fields
  60. 'optfield': 2, # chances to be optionnal
  61. }
  62. for name, value in kwargs.items():
  63. if name not in chances:
  64. #warning
  65. pass
  66. else:
  67. chances[name] = value
  68. #classes creation
  69. for classtype in EmClassType.getall():
  70. if random.randint(0, chances['classtype']) == 0:
  71. for _ in range(random.randint(1, chances['nclass'])):
  72. cdats = cls._rnd_component_datas()
  73. cdats['classtype'] = classtype['name']
  74. ed_mod.create_component('EmClass', cdats)
  75. for emclass in ed_mod.classes():
  76. #fieldgroups creation
  77. if random.randint(0, chances['nofg']) != 0:
  78. for _ in range(random.randint(1, chances['nfg'])):
  79. fgdats = cls._rnd_component_datas()
  80. fgdats['class_id'] = emclass.uid
  81. ed_mod.create_component('EmFieldGroup', fgdats)
  82. #types creation
  83. if random.randint(0, chances['notype']) != 0:
  84. for _ in range(random.randint(1, chances['ntype'])):
  85. tdats = cls._rnd_component_datas()
  86. tdats['class_id'] = emclass.uid
  87. ed_mod.create_component('EmType', tdats)
  88. #random type hierarchy
  89. for emtype in ed_mod.components(EmType):
  90. possible = emtype.possible_superiors()
  91. for nat in possible:
  92. if len(possible[nat]) > 0 and random.randint(0, chances['ntypesuperiors']) == 0:
  93. random.shuffle(possible[nat])
  94. for i in range(random.randint(1, len(possible[nat]))):
  95. emtype.add_superior(possible[nat][i], nat)
  96. #fields creation
  97. ft_l = [ ftname for ftname in EmField.fieldtypes_list() if ftname != 'pk' and ftname != 'rel2type']
  98. for emfg in ed_mod.components(EmFieldGroup):
  99. if random.randint(0, chances['nofields']) != 0:
  100. for _ in range(random.randint(1, chances['nfields'])):
  101. field_type = ft_l[random.randint(0, len(ft_l) - 1)]
  102. fdats = cls._rnd_component_datas()
  103. fdats['fieldtype'] = field_type
  104. fdats['fieldgroup_id'] = emfg.uid
  105. if random.randint(0, chances['optfield']) == 0:
  106. fdats['optional'] = True
  107. ed_mod.create_component('EmField', fdats)
  108. #rel2type creation (in case none where created before
  109. for emfg in ed_mod.components(EmFieldGroup):
  110. for _ in range(random.randint(0, chances['nr2tfields'])):
  111. field_type = 'rel2type'
  112. fdats = cls._rnd_component_datas()
  113. fdats['fieldtype'] = field_type
  114. fdats['fieldgroup_id'] = emfg.uid
  115. emtypes = ed_mod.components(EmType)
  116. fdats['rel_to_type_id'] = emtypes[random.randint(0, len(emtypes) - 1)].uid
  117. if random.randint(0, chances['optfield']) == 0:
  118. fdats['optional'] = True
  119. ed_mod.create_component('EmField', fdats)
  120. #relationnal fields creation
  121. ft_l = [field_type for field_type in EmField.fieldtypes_list() if field_type != 'rel2type' and field_type != 'pk']
  122. for emrelf in [f for f in ed_mod.components(EmField) if f.fieldtype == 'rel2type']:
  123. for _ in range(0, chances['rfields']):
  124. field_type = ft_l[random.randint(0, len(ft_l) - 1)]
  125. fdats = cls._rnd_component_datas()
  126. fdats['rel_field_id'] = emrelf.uid
  127. fdats['fieldtype'] = field_type
  128. fdats['fieldgroup_id'] = emrelf.fieldgroup_id
  129. if random.randint(0, chances['optfield']) == 0:
  130. fdats['optional'] = True
  131. ed_mod.create_component('EmField', fdats)
  132. #selection optionnal fields
  133. for emtype in ed_mod.components(EmType):
  134. selectable = [field for fieldgroup in emtype.fieldgroups() for field in fieldgroup.fields() if field.optional]
  135. for field in selectable:
  136. if random.randint(0, chances['seltype']) == 0:
  137. emtype.select_field(field)
  138. return ed_mod
  139. @staticmethod
  140. ## @brief Generate a random string
  141. # @warning dirty cache trick with globals()
  142. # @return a randomly selected string
  143. def _rnd_str(words_src='/usr/share/dict/words'):
  144. if '_words' not in globals() or globals()['_words_fname'] != words_src:
  145. globals()['_words_fname'] = words_src
  146. with open(words_src, 'r') as fpw:
  147. globals()['_words'] = [l.strip() for l in fpw]
  148. words = globals()['_words']
  149. return words[random.randint(0, len(words) - 1)]
  150. @classmethod
  151. ## @brief Generate a random MlString
  152. # @param nlng : Number of langs in the MlString
  153. # @return a random MlString with nlng translations
  154. # @todo use a dict to generated langages
  155. def _rnd_mlstr(cls, nlng):
  156. ret = MlString()
  157. for _ in range(nlng):
  158. ret.set(cls._rnd_str(), cls._rnd_str())
  159. return ret
  160. @classmethod
  161. ## @brief returns randomly generated datas for an EmComponent
  162. # @return a dict with name, string and help_text
  163. def _rnd_component_datas(cls):
  164. mlstr_nlang = 2
  165. ret = dict()
  166. ret['name'] = cls._rnd_str()
  167. ret['string'] = cls._rnd_mlstr(mlstr_nlang)
  168. ret['help_text'] = cls._rnd_mlstr(mlstr_nlang)
  169. return ret