2

Sorry in advance if this is a dumb question. I'm new to Python in general (not new to other languages at all) and new to IronPython in particular.

I'm trying to run a Python project via my C# project. I'm including all the relevant Python sources as embedded resources (which I read into a Dictionary<string,string> where the key is the name of the module and the value is the content of the file.

I've implemented a class quite similar to the one suggested in this reply to "Custom IronPython import resolution", like so:

public class PythonInstance
{
    private ScriptEngine engine;
    private ScriptScope scope;
    private ScriptSource source;
    private CompiledCode compiled;
    private object pythonClass;
    private delegate object ImportDelegate(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple tuple);
    private Dictionary<string, string> importModulesCode = new Dictionary<string, string>();

    public PythonInstance(string code, Dictionary<string,string> modulesCode, string className = "PyClass")
    {
        this.importModulesCode.Clear();
        foreach(KeyValuePair<string,string> module in modulesCode)
            this.importModulesCode.Add(module.Key, module.Value);

        //creating engine and stuff
        this.engine = Python.CreateEngine();
        this.scope = Python.GetBuiltinModule(engine);//engine.CreateScope();

        this.scope.SetVariable("__import__", new ImportDelegate(this.ImportModuleFromResources));

        //loading and compiling code
        this.source = this.engine.CreateScriptSourceFromString(code, SourceCodeKind.Statements);
        this.compiled = this.source.Compile();

        //now executing this code (the code should contain a class)
        this.compiled.Execute(this.scope);

        //now creating an object that could be used to access the stuff inside a python script
        this.pythonClass = this.engine.Operations.Invoke(this.scope.GetVariable(className));
    }

    public void SetVariable(string variable, dynamic value)
    {
        this.scope.SetVariable(variable, value);
    }

    public dynamic GetVariable(string variable)
    {
        return this.scope.GetVariable(variable);
    }

    public void CallMethod(string method, params dynamic[] arguments)
    {
        this.engine.Operations.InvokeMember(this.pythonClass, method, arguments);
    }

    public dynamic CallFunction(string method, params dynamic[] arguments)
    {
        return this.engine.Operations.InvokeMember(this.pythonClass, method, arguments);
    }

    protected object ImportModuleFromResources(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple tuple)
    {
        if ((this.importModulesCode.Keys.Contains(moduleName)) && (!string.IsNullOrWhiteSpace(this.importModulesCode[moduleName])))
        {
            string rawScript = this.importModulesCode[moduleName];
            this.engine.Execute(rawScript, this.scope);
            Scope ret = HostingHelpers.GetScope(this.scope);
            this.scope.SetVariable(moduleName, ret);
            return ret;
        }
        else
        {   // fall back on the built-in method
            return Builtin.__import__(context, moduleName);
        }
    }
}

Now this seems to work fine. Just that I'm getting a stack overflow exception when I try to run the Python code, since the references seem to be recursive.

My main pyw file contains the following header:

import os, sys, getopt, __builtin__
from pyglossary.glossary import confPath, VERSION

The first import is of the os module, which I've taken out of the IronPython Lib, so my ImportModuleFromResources method uses the first if block and the reference gets resolved.

The next iteration tries to import sys (using the else block and the built-in module import), then errno (again the else block and the built-in module import) -> nt (built-in import again) -> nt (again..) -> ntpath (yep..) -> then going back to os again, and continues in an infinite recursion to go through the modules again... (resulting in a stack overflow, of course).

Since I'm no Python expert, and I am not aware of IronPython's standard library modules and how they refer to each other, I'm sure I'm doing something very basic wrong, but not sure which reference I need to take out, manipulate one of my included Lib files (unlikely, I think), or improve my ImportModuleFromResources method in order to avoid a recursive reference..

Help would be greatly appreciated. Thank you!

Community
  • 1
  • 1
alrotem
  • 92
  • 1
  • 7

1 Answers1

0

I have done it the same way like Einar Egilsson has sugested in Custom IronPython import resolution => Use a PlatformAdaptationLayer

In this way, ironpython uses its own mechanisms to search for modules and only uses your code when a module can't be found.

Community
  • 1
  • 1
Traummaennlein
  • 474
  • 5
  • 12