tags:

views:

184

answers:

2

I'm trying to convert some IronPython 1 code:

var ptype = this.engine.DefaultModule.Globals[ironPythonClassName];

I have a script that declares a class. I use a Python engine to execute the script.

How, in IronPython 2 do I get the names of the variables (including the class)?

+2  A: 

You have to execute the file in a Scope:

ScriptScope scope = engine.CreateScope();
CompiledCode code = engine.CreateScriptSourceFromFile(fullPath).Compile();
code.Execute(scope);

From the scope you can call GetVariable or GetVariable to get the variable value:

object c = scope.GetVariable(ironPythonClassName)
// or
int i = scope.GetVariable<int>(otherVar);

As far as I know, the DefaultModule is completely gone in IronPython 2.x.

For simplicity, there are also convenience methods on ScriptEngine:

ScriptScope scope = engine.ExecuteFile(fullPath);
names = scope.GetVariableNames()

This is easier for one-off script usage, but using the compiled code directly is better (faster) if you're repeatedly executing the same script.

Jeff Hardy
Thanks - I'm having trouble with the scripting documentation!Isn't there a default scope then for the engine? I'm thinking of ipy.exe - there is a default scope that dir() shows.I think I see the flexibility in that an engine can execute say, script A in scope A and script B in scope B.I was thinking an engine had a built-in scope, that I couldn't get to.
Hamish I E Gunn
More thoughts - an engine can have one script at a time, fair enough. However I can't get that script. There is a GetScript on engine but that wants a path (whatever that is).
Hamish I E Gunn
An engine can run multiple scripts just fine; by default they have their own scope, but you can provide one if they need to share.
Jeff Hardy
A: 

There is no need to create a new scope since the CompiledCode instance seems to be created with one.

ScriptEngine engine = Python.CreateEngine();
ScriptSource source = engine.CreateScriptSourceFromFile(fileName);
CompiledCode code = source.Compile();
ScriptScope scope = code.DefaultScope;
code.Execute();
var names = scope.GetVariableNames();


rant on

The scripting classes above are a bit of a nightmare - too much duplication of functionality and strange linkage between instances.

Why didn't MS use the well-known pattern of "an engine executes code compiled from a source, in a scope"?

So the model might be:

  • compile source to produce code (Compiler class)
  • provide or create a scope (Scope class)
  • bind code and scope and feed them to the engine to execute (Engine Class)

rant off

Hamish I E Gunn
If I were to hazard a guess (and hope Dino doesn't contradict me), it's because the DLR (which those classes are part of) supports multiple languages. Generally, the only language specific class you need is the engine, and everything is created from there. Other than the "compiler" being part of the engine, the code I posted above pretty much fits your model.
Jeff Hardy
I edited my answer to add a simpler method, it that's what you need.
Jeff Hardy
Yes. But my point is that there is a relationship between all these entities that is well understood. This should serve as a mental model for design. What we have is a mixture of classes performing operations "belonging" more naturally to other classes. The DLR document says "Our goal is to strike a balance between convenient execution methods on various objects and keeping redundancy across the types to a minimum. ". I think they have ended up confusing (me) for no good reason. Had they stuck to limiting methods to the classes they really belong to I'd be happer.
Hamish I E Gunn
With respect to multiple languages, what differs is:the engine (specific language operations, abstractions on the underlying operations), the source code (syntactic sugar). What is common is the underlying semantics of the architecture and the process by which we get from source to executed code.
Hamish I E Gunn