IronPython dependencies for scripts stored as strings

I have a C # application that stores python script files (* .py) as strings. I download them using:

scriptEngine.CreateScriptSourceFromString(code); 

But now I have several script files with dependencies between them (import). To handle the dependencies, I could save all the lines back to the files in the folder and load the script that I want to execute using:

 scriptEngine.CreateScriptSourceFromFile(filePath); 

but this will make all script files visible. Is there a way to achieve this in memory, so that the script files are not first saved to disk, but loaded from strings directly?

TL; DR: an example of how this might look:

myutils.py:

 def SomeMethod(p): print ('SomeMethod(p=%s)' % p) 

script1.py:

 import myutils; if __name__ == '__main__': myutils.SomeMethod('script1') 

script2.py:

 import myutils; if __name__ == '__main__': myutils.SomeMethod('script2') 

My application has scripts stored as strings. something like

 Dictionary<string, string> filePathToContent = new Dictionary<string, string>(); filePathToContent["myutils.py"] = "..."; // The script file content. filePathToContent["script1.py"] = "..."; // The script file content. filePathToContent["script2.py"] = "..."; // The script file content. 

I want to call script1.py without having to save the scripts in a folder first. Note: the code is just a simplified example of what I have.

+2
c # ironpython
source share
2 answers

There are several approaches to custom import processing in IronPython and Python in general. Most concepts are defined in PEP 0302 (New Imported Hooks).

Two python mechanisms that can solve the requirements are meta_path and path_hooks . Both can be implemented in Python or (in the case of IronPython) C # /. NET Given that the question of placing IronPython from C # implementing the import infrastructure might work anyway.

Using meta_path

IronPython comes with ResourceMetaPathImporter , which allows you to have a ZIP archive containing your scripts as an embedded resource. Assuming that such an archive is called scripts.zip contained in the current executable assembly, the required configuration might look like this:

 var engine = Python.CreateEngine(); var sysScope = engine.GetSysModule(); List metaPath = sysScope.GetVariable("meta_path"); var importer = new ResourceMetaPathImporter(Assembly.GetExecutingAssembly(), "scripts.zip"); metaPath.Add(importer); sysScope.SetVariable("meta_path", metaPath); 

This approach works well if the builds and scripts are known, and the ZIP package does not interfere with the development process.

Using path_hooks

Path hooks contain a chain of importers that are requested for all elements in sys.path to determine if they can handle the given path. The importer is similar to zipimport.cs , but it is responsible for the embedded resources in the DLL / EXE libraries instead of the ZIP archives. This can provide a more general approach that processes additional files by simply adding the DLL to the path.

Using PlatformAdaptationLayer

A third approach works by providing the PlatformAdaptationLayer , which is part of Microsoft.Scripting / IronPython. This answer shows a complete working example of an adaptive platform level that resolves the embedded resources of a predefined assembly and package namespace.

General note: Related question / discussion on github .

+3
source share

You can create different scripts as one function each and call these functions based on arguments

 ScriptScope scope = scriptEngine.CreateScope(); scope.SetVariable("language", "en"); scriptEngine.Execute(scope); 

and python (stupid example I know):

 def doEnStuff(): print "english" def doEsStuff(): print "espagna" if language == "en" doEnStuff() 
0
source share

All Articles