We use IronPython in our open source project. I have problem accesing the 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 the globals from the main script, but any module that is loaded will fail. How can it 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

edit: In response to @BendEg's answer
I tried this
scope.SetVariable("__import__", new Func<CodeContext, string, PythonDictionary, PythonDictionary, PythonTuple, object>(ResolveImport));
ImportDelegate is not defined so tried using a Func instead, the ResolveImport method never triggers and I get the same exception that the name is not defined
edit: I changed the scope creation to
var scope = Engine.GetBuiltinModule();
globals.ForEach(g => scope.SetVariable(g.Key, g.Value));
Now the import delegate triggers but it crashes on first line with global name 'mouse' is not defined, mouse is not used from the module. It seems its confused when I add my custom globals to the BuiltinModule
This is probably not the right answer, as still doesn't allow to share variables defined in the main IronPhyton script with the imported modules, however is a step forward.
This approach allows to set variables at the Engine level rather then the script level and they will be available in every imported module.
engine = Python.CreateEngine();
engine.Runtime.Globals.SetVariable("test_global", "This is a test global variable.");
then, within any IronPhyton script is possible to access it using an import:
import test_global
print(test_global)
Unlike ScriptScope, which makes them directly available, those Global variables need to be imported.
Original article
https://ludovic.chabant.com/devblog/2009/12/24/exposing-global-variables-in-ironpython/
Disclaimer
I added this answer as I've been struggling to find any material on this topic other then this SO Q&A, so I'm posting this possible workaround to help future troubled readers (like myself)
As far as i know, importing some module will create a new scope. So when creating an instance of PythonModule via from ... import ... they has it's own scope. In this new scope, your public variables are not available. Please correct me if i am wrong.
Workaround:
You could create some static class, which holdes the 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
maybe this is some thing you can use. You event don't need to set it as variable in the scope.
EDIT
Maybe this is working for you. In the code i override module importing and try to set the global vars:
First thing you need is, give IronPython some delegate, for module importing:
# 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 of ImportDelegate
delegate object ImportDelegate(CodeContext context, string moduleName, PythonDictionary globals, PythonDictionary locals, PythonTuple fromlist);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With