|
@@ -2,6 +2,7 @@
|
2
|
2
|
|
3
|
3
|
import importlib
|
4
|
4
|
import copy
|
|
5
|
+import os.path
|
5
|
6
|
|
6
|
7
|
import EditorialModel
|
7
|
8
|
from EditorialModel.model import Model
|
|
@@ -17,27 +18,11 @@ class LeFactory(object):
|
17
|
18
|
output_file = 'dyn.py'
|
18
|
19
|
modname = None
|
19
|
20
|
|
20
|
|
- def __init__(self):
|
21
|
|
- raise NotImplementedError("Not designed (yet?) to be implemented")
|
22
|
21
|
|
23
|
|
- ## @brief Return a LeObject child class given its name
|
24
|
|
- # @return a python class or False
|
25
|
|
- @staticmethod
|
26
|
|
- def leobj_from_name(name):
|
27
|
|
- if LeFactory.modname is None:
|
28
|
|
- modname = 'leapi.' + LeFactory.output_file.split('.')[0]
|
29
|
|
- else:
|
30
|
|
- modname = LeFactory.modname
|
31
|
|
- mod = importlib.import_module(modname)
|
32
|
|
- try:
|
33
|
|
- res = getattr(mod, name)
|
34
|
|
- except AttributeError:
|
35
|
|
- return False
|
36
|
|
- return res
|
37
|
|
-
|
38
|
|
- @classmethod
|
39
|
|
- def leobject(cls):
|
40
|
|
- return cls.leobj_from_name('LeObject')
|
|
22
|
+ def __init__(self, code_filename = 'leapi/dyn.py'):
|
|
23
|
+ self._code_filename = code_filename
|
|
24
|
+ self._dyn_file = os.path.basename(code_filename)
|
|
25
|
+ self._modname = os.path.dirname(code_filename).strip('/').replace('/', '.') #Warning Windaube compatibility
|
41
|
26
|
|
42
|
27
|
## @brief Convert an EmType or EmClass name in a python class name
|
43
|
28
|
# @param name str : The name
|
|
@@ -57,13 +42,19 @@ class LeFactory(object):
|
57
|
42
|
GenericFieldType.module_name(emfield.fieldtype),
|
58
|
43
|
repr(emfield._fieldtype_args),
|
59
|
44
|
)
|
|
45
|
+
|
|
46
|
+ ## @brief Write generated code to a file
|
|
47
|
+ # @todo better options/params for file creation
|
|
48
|
+ def create_pyfile(self, model, datasource_cls, datasource_args):
|
|
49
|
+ with open(self._code_filename, "w+") as dynfp:
|
|
50
|
+ dynfp.write(self.generate_python(model, datasource_cls, datasource_args))
|
60
|
51
|
|
61
|
52
|
## @brief Given a Model and an EmClass instances generate python code for corresponding LeClass
|
62
|
53
|
# @param model Model : A Model instance
|
63
|
54
|
# @param emclass EmClass : An EmClass instance from model
|
64
|
55
|
# @return A string representing the python code for the corresponding LeClass child class
|
65
|
|
- @staticmethod
|
66
|
|
- def emclass_pycode(model, emclass):
|
|
56
|
+ def emclass_pycode(self, model, emclass):
|
|
57
|
+
|
67
|
58
|
cls_fields = dict()
|
68
|
59
|
cls_linked_types = dict() #keys are LeType classnames and values are tuples (attr_fieldname, attr_fieldtype)
|
69
|
60
|
#Populating linked_type attr
|
|
@@ -74,6 +65,7 @@ class LeFactory(object):
|
74
|
65
|
]
|
75
|
66
|
# Populating fieldtype attr
|
76
|
67
|
for field in emclass.fields(relational = False):
|
|
68
|
+ self.needed_fieldtypes |= set([field.fieldtype])
|
77
|
69
|
cls_fields[field.name] = LeFactory.fieldtype_construct_from_field(field)
|
78
|
70
|
fti = field.fieldtype_instance()
|
79
|
71
|
|
|
@@ -102,8 +94,7 @@ class LeFactory(object):
|
102
|
94
|
# @param model Model : A Model instance
|
103
|
95
|
# @param emtype EmType : An EmType instance from model
|
104
|
96
|
# @return A string representing the python code for the corresponding LeType child class
|
105
|
|
- @staticmethod
|
106
|
|
- def emtype_pycode(model, emtype):
|
|
97
|
+ def emtype_pycode(self, model, emtype):
|
107
|
98
|
type_fields = list()
|
108
|
99
|
type_superiors = list()
|
109
|
100
|
for field in emtype.fields(relational=False):
|
|
@@ -128,37 +119,37 @@ class LeFactory(object):
|
128
|
119
|
)
|
129
|
120
|
|
130
|
121
|
## @brief Generate python code containing the LeObject API
|
131
|
|
- # @param backend_cls Backend : A model backend class
|
132
|
|
- # @param backend_args dict : A dict representing arguments for backend_cls instanciation
|
|
122
|
+ # @param model EditorialModel.model.Model : An editorial model instance
|
133
|
123
|
# @param datasource_cls Datasource : A datasource class
|
134
|
124
|
# @param datasource_args dict : A dict representing arguments for datasource_cls instanciation
|
135
|
125
|
# @return A string representing python code
|
136
|
|
- @staticmethod
|
137
|
|
- def generate_python(backend_cls, backend_args, datasource_cls, datasource_args):
|
138
|
|
- model = Model(backend=backend_cls(**backend_args))
|
|
126
|
+ def generate_python(self, model, datasource_cls, datasource_args):
|
|
127
|
+ self.needed_fieldtypes = set() #Stores the list of fieldtypes that will be used by generated code
|
|
128
|
+
|
|
129
|
+ model = model
|
139
|
130
|
|
140
|
131
|
result = ""
|
141
|
132
|
#result += "#-*- coding: utf-8 -*-\n"
|
142
|
133
|
#Putting import directives in result
|
143
|
|
- result += """## @author LeFactory
|
|
134
|
+ heading = """## @author LeFactory
|
|
135
|
+
|
|
136
|
+import EditorialModel
|
|
137
|
+from EditorialModel import fieldtypes
|
|
138
|
+from EditorialModel.fieldtypes import {needed_fieldtypes_list}
|
144
|
139
|
|
145
|
140
|
import leapi
|
146
|
141
|
import leapi.lecrud
|
147
|
142
|
import leapi.leobject
|
148
|
143
|
from leapi.leclass import LeClass
|
149
|
144
|
from leapi.letype import LeType
|
150
|
|
-import EditorialModel.fieldtypes
|
151
|
|
-from EditorialModel.fieldtypes import *
|
152
|
145
|
"""
|
153
|
146
|
|
154
|
147
|
result += """
|
155
|
148
|
import %s
|
156
|
|
-import %s
|
157
|
149
|
|
158
|
|
-""" % (backend_cls.__module__, datasource_cls.__module__)
|
|
150
|
+""" % (datasource_cls.__module__)
|
159
|
151
|
|
160
|
152
|
#Generating the code for LeObject class
|
161
|
|
- backend_constructor = '%s.%s(**%s)' % (backend_cls.__module__, backend_cls.__name__, repr(backend_args))
|
162
|
153
|
leobj_me_uid = dict()
|
163
|
154
|
for comp in model.components('EmType') + model.components('EmClass'):
|
164
|
155
|
leobj_me_uid[comp.uid] = LeFactory.name2classname(comp.name)
|
|
@@ -169,6 +160,7 @@ import %s
|
169
|
160
|
for fname, ftargs in EditorialModel.classtypes.common_fields.items():
|
170
|
161
|
ftargs = copy.copy(ftargs)
|
171
|
162
|
fieldtype = ftargs['fieldtype']
|
|
163
|
+ self.needed_fieldtypes |= set([fieldtype])
|
172
|
164
|
del(ftargs['fieldtype'])
|
173
|
165
|
|
174
|
166
|
constructor = '{ftname}.EmFieldType(**{ftargs})'.format(
|
|
@@ -237,9 +229,9 @@ class {name}(LeType, {leclass}):
|
237
|
229
|
|
238
|
230
|
#Set attributes of created LeClass and LeType child classes
|
239
|
231
|
for emclass in emclass_l:
|
240
|
|
- result += LeFactory.emclass_pycode(model, emclass)
|
|
232
|
+ result += self.emclass_pycode(model, emclass)
|
241
|
233
|
for emtype in emtype_l:
|
242
|
|
- result += LeFactory.emtype_pycode(model, emtype)
|
|
234
|
+ result += self.emtype_pycode(model, emtype)
|
243
|
235
|
|
244
|
236
|
#Populating LeObject._me_uid dict for a rapid fetch of LeType and LeClass given an EM uid
|
245
|
237
|
me_uid = {comp.uid: LeFactory.name2classname(comp.name) for comp in emclass_l + emtype_l}
|
|
@@ -247,4 +239,9 @@ class {name}(LeType, {leclass}):
|
247
|
239
|
## @brief Dict for getting LeClass and LeType child classes given an EM uid
|
248
|
240
|
LeObject._me_uid = %s""" % "{" + (', '.join(['%s: %s' % (k, v) for k, v in me_uid.items()])) + "}"
|
249
|
241
|
result += "\n"
|
|
242
|
+
|
|
243
|
+ heading = heading.format(needed_fieldtypes_list = ', '.join(self.needed_fieldtypes))
|
|
244
|
+ result = heading + result
|
|
245
|
+
|
|
246
|
+ del(self.needed_fieldtypes)
|
250
|
247
|
return result
|