@@ -190,12 +190,17 @@ def load_functions(filepath: t.Optional[str] = None) -> t.Optional[types.ModuleT
190
190
191
191
mod_name , file_ext = os .path .splitext (os .path .split (filepath )[- 1 ])
192
192
193
+ logger .info (f"Loading functions module { mod_name } from { filepath } " )
194
+
193
195
if file_ext .lower () == ".py" :
194
196
py_mod = imp .load_source (mod_name , filepath )
195
197
196
198
elif file_ext .lower () == ".pyc" :
197
199
py_mod = imp .load_compiled (mod_name , filepath )
198
200
201
+ elif file_ext .lower () in [".js" , ".javascript" ]:
202
+ py_mod = load_source_js (mod_name , filepath )
203
+
199
204
else :
200
205
raise ValueError ("'{}' does not have the .py or .pyc extension" .format (filepath ))
201
206
@@ -251,3 +256,28 @@ def load_file(path: t.Union[str, Path], retry_tries=None, retry_interval=0.075,
251
256
except : # pragma: nocover
252
257
pass
253
258
return reader
259
+
260
+
261
+ def module_factory (name , variables ):
262
+ """
263
+ Create a synthetic Python module object.
264
+
265
+ Derived from:
266
+ https://www.oreilly.com/library/view/python-cookbook/0596001673/ch15s03.html
267
+ """
268
+ module = imp .new_module (name )
269
+ module .__dict__ .update (variables )
270
+ module .__file__ = "<synthesized>"
271
+ return module
272
+
273
+
274
+ def load_source_js (mod_name , filepath ):
275
+ """
276
+ Load a JavaScript module, and import its exported symbols into a synthetic Python module.
277
+ """
278
+ import javascript
279
+
280
+ js_code = load_file (filepath , retry_tries = 0 ).read ().decode ("utf-8" )
281
+ module = {}
282
+ javascript .eval_js (js_code )
283
+ return module_factory (mod_name , module ["exports" ])
0 commit comments