Freeing script variables from modules

We are using IronPython in our open source project. I have a problem with variables added to the script scope like

private ScriptScope CreateScope(IDictionary<string, object> globals)
{
    globals.Add("starting", true);
    globals.Add("stopping", false);

    var scope = Engine.CreateScope(globals);
    scope.ImportModule("math");
    return scope;
}

      

https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.Core/ScriptEngine/Python/PythonScriptEngine.cs#L267

I can use globals from the main script, but any loaded module will fail. How can this be fixed?

update: given this module mymodule.py

if starting: #starting is defined on the scope
   ...

      

From the main script executed using this code

void RunLoop(string script, ScriptScope scope)
{
    ExecuteSafe(() =>
    {
        var compiled = Engine.CreateScriptSourceFromString(script).Compile();

        while (!stopRequested)
        {
            usedPlugins.ForEach(p => p.DoBeforeNextExecute());
            CatchThreadAbortedException(() => compiled.Execute(scope));
            scope.SetVariable("starting", false);
            threadTimingFactory.Get().Wait();
        }
        scope.SetVariable("stopping", true);
        CatchThreadAbortedException(() => compiled.Execute(scope));
    });
}

      

https://github.com/AndersMalmgren/FreePIE/blob/master/FreePIE.Core/ScriptEngine/Python/PythonScriptEngine.cs#L163

from mymodule import * #this will load the moduel and it fails with

      

enter image description here

edit: In response to @ BendEg's answer

I tried this

scope.SetVariable("__import__", new Func<CodeContext, string, PythonDictionary, PythonDictionary, PythonTuple, object>(ResolveImport));

      

ImportDelegate

is undefined so tried to use Func instead, ResolveImport method never gets run and I get the same exception name is undefined

edit: I changed the creation of the area to

var scope = Engine.GetBuiltinModule();
globals.ForEach(g => scope.SetVariable(g.Key, g.Value));

      

Now the import delegate starts, but the first line fails with global name 'mouse' is not defined

, mouse is not used from the module. It seems to be confusing when I add my custom globals toBuiltinModule

+3


source to share


1 answer


As far as I know, importing some module will create a new scope. So when instantiated PythonModule

through from ... import ...

it has its own scope. In this new scope, your public variables are not available. Please correct me if I am wrong.

Workaround:

You can create some static class that stores values. Than you can be sure, you always have them. For example:

namespace someNS
{
    public static class SomeClass
    {
        public static bool Start { get; set; }
    }
}

      

And than in your IP code:

from someNS import SomeClass

# Now you can access the member
yourVal = SomeClass.Start

      

Perhaps this is what you can use. You don't need to specify it as a variable in scope.

EDIT



Maybe it works for you. In the module, I override the import module and try to set the global vars:

The first thing you need is to provide the IronPython delegate with some delegate to import the module:

# Scope should be your default scope
scope.SetVariable("__import__", new ImportDelegate(ResolveImport));

      

Then override the import function:

private object ResolveImport(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple fromlist)
{
    // Do default import but set module
    var builtin = IronPython.Modules.Builtin.__import__(context, moduleName, globals, locals, fromlist, 0);
    context.ModuleContext.Module.__setattr__(context, "some_global", "Hello World");
    return builtin;
}

      

EDIT



Definition ImportDelegate

delegate object ImportDelegate(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple fromlist);

      

+1


source







All Articles