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