views:

142

answers:

1

I am creating an IronPython engine more or less like so:

var engine = IronPython.Hosting.Python.CreateEngine();                
var scope = engine.CreateScope();

// my implementation of System.IO.Stream
var stream = new ScriptOutputStream(engine);
engine.Runtime.IO.SetOutput(stream, Encoding.UTF8);
engine.Runtime.IO.SetErrorOutput(stream, Encoding.UTF8);
engine.Runtime.IO.SetInput(stream, Encoding.UTF8);

var script = engine.CreateScriptSourceFromString(source, SourceCodeKind.Statements);
script.Execute(scope);

The variable source is a string with following contents (python statements):

import code
code.interact(None, None, 
        {
            '__name__' :  '__console__', 
            '__doc__'  :   None, 
        })

The stream is being hosted on a windows form. When that form closes, I want the interpreter to quit. Obviously, I tried closing the stream in the Read method:

    /// <summary>
    /// Read from the _inputBuffer, block until a new line has been entered...
    /// </summary>
    public override int Read(byte[] buffer, int offset, int count)
    {

        if (_gui.IsDisposed)
        {
            return 0; // msdn says this indicates the stream is closed
        }

        while (_completedLines.Count < 1)
        {
            // wait for user to complete a line
            Application.DoEvents();
            Thread.Sleep(10);
        }
        var line = _completedLines.Dequeue();
        return line.Read(buffer, offset, count);
    }

The member variable _completedLines holds a queue of MemoryStream objects representing lines the user has entered so far. _gui is a reference to the windows form - when it is disposed, I somehow want the IronPython engine to stop executing code.interact().

Returnin 0 from the Read method does not work (Read is just called again). Raising one of the exceptions from the documentation of Read does not work either: It does stop execution of the interpreter, but the IDE breaks inside the Read method :(

I have also tried returning ^Z (0x1a) and ^D (0x04) in Read's buffer, as these are used on the console to quit the interpreter, but that doesn't work at all...

+1  A: 

It took me a second look to figure out what you wanted, but this looks like a bug in IronPython. code.interact expects an EOFError to be raised from the raw_input builtin to signal that it's time for the loop to end, but IronPython doesn't do that - it just returns an empty string. This is IronPython issue #22140.

You could try throwing an EndOfStreamException, which converts to EOFError. That might be enough to trick it.

Jeff Hardy
I've tried engine.Runtime.Shutdown() - it doesn't work :( I'll try again, though...
Daren Thomas
I tried throwing SystemExitException - this still causes the IDE to break inside the custom stream class (unhandled user exception), even though the caller of the script.Excecute() *does* handle the error...
Daren Thomas
I rewrote my answer to better address your question - not sure it's the answer you want to hear, though.
Jeff Hardy
Thank you very much. This seems to work - i.e. it still breaks into the IDE, but when run standalone, IronPython seems to recognize the EndOfStreamException!
Daren Thomas