@@ -190,12 +190,17 @@ def load_functions(filepath: t.Optional[str] = None) -> t.Optional[types.ModuleT
190190
191191 mod_name , file_ext = os .path .splitext (os .path .split (filepath )[- 1 ])
192192
193+ logger .info (f"Loading functions module { mod_name } from { filepath } " )
194+
193195 if file_ext .lower () == ".py" :
194196 py_mod = imp .load_source (mod_name , filepath )
195197
196198 elif file_ext .lower () == ".pyc" :
197199 py_mod = imp .load_compiled (mod_name , filepath )
198200
201+ elif file_ext .lower () in [".js" , ".javascript" ]:
202+ py_mod = load_source_js (mod_name , filepath )
203+
199204 else :
200205 raise ValueError ("'{}' does not have the .py or .pyc extension" .format (filepath ))
201206
@@ -251,3 +256,28 @@ def load_file(path: t.Union[str, Path], retry_tries=None, retry_interval=0.075,
251256 except : # pragma: nocover
252257 pass
253258 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