That should be fine. My example was the simplest way possible to spin up a script, so I didn't bother with an explicit scope. But that doesn't change anything really. Also if you re-use the same engine many times, you only really need to wire up the custom output writer once - after initial engine creation.
You can also make the TextWriter slightly smarter and ensure that it only colorizes text that comes from the print function. There isn't a straightforward way to do that, but you can cheat and check the call stack. As long as your code is full-trust then this shouldn't be an issue. This version might be a little more suitable and complete after seeing your example. I still had to make some assumptions about how your Execute is being handled, but this should at least be fairly close: using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using IronPython.Compiler; using IronPython.Hosting; using IronPython.Runtime; using Microsoft.Scripting; using Microsoft.Scripting.Hosting; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { var scripting = new Scripting(); scripting.RunScript("22"); scripting.RunScript("print(23)"); Console.ReadKey(); } } internal class Scripting { private readonly ScriptEngine _engine; private readonly ScriptScope _scope; private readonly CompilerOptions _options; private readonly ConsoleWriter _green; private readonly PythonFile _stderr; private readonly PythonFile _stdin; private readonly PythonFile _stdout; public Scripting() { _engine = Python.CreateEngine(); var io = _engine.Runtime.IO; _green = new ConsoleWriter(io.OutputWriter, ConsoleColor.Green); io.SetOutput(io.OutputStream, _green); _scope = _engine.CreateScope(); _options = new PythonCompilerOptions(ModuleOptions.None); var sys = _engine.GetSysModule(); _stderr = sys.GetVariable<PythonFile>("stderr"); _stdin = sys.GetVariable<PythonFile>("stdin"); _stdout = sys.GetVariable<PythonFile>("stdout"); } public bool RunScript(string text) { var sctype = SourceCodeKind.InteractiveCode; var source = _engine.CreateScriptSourceFromString(text, sctype); try { source.Compile(_options); } catch { sctype = SourceCodeKind.Statements; source = _engine.CreateScriptSourceFromString(text, sctype); try { source.Compile(_options); } catch (Exception e) { var eo = _engine.GetService<ExceptionOperations>(); PrintLine(eo.FormatException(e)); return false; } } try { _green.IsEnabled = true; try { source.Execute(_scope); } finally { _green.IsEnabled = false; } } catch (Exception e) { if (e.Message.Contains("Thread was being aborted")) { _stderr.write("[Script stopped----------]\n"); } else { var eo = _engine.GetService<ExceptionOperations>(); PrintLine(eo.FormatException(e)); } return false; } if (_stderr != null) PrintLine("Ok"); return true; } void PrintLine(string msg) { _stdout.write(msg + Environment.NewLine); } } class ConsoleWriter : TextWriter { private readonly TextWriter _inner; public bool IsEnabled { get; set; } public ConsoleColor Color { get; set; } public ConsoleWriter(TextWriter inner, ConsoleColor color) { _inner = inner; Color = color; } public override void Write(string value) { var enabled = IsEnabled; if (enabled) { var stack = (new StackTrace()).GetFrames() ?? new StackFrame[0]; var indexed = stack.Select((f, ix) => new {mInfo = f.GetMethod(), ix}); var printFrameQuery = from frame in indexed where frame.mInfo.Name == "Print" && frame.mInfo.DeclaringType == typeof (IronPython.Runtime.Operations.PythonOps) select frame; var printFrame = printFrameQuery.FirstOrDefault(); if (printFrame != null) { var printFrameCallerIx = printFrame.ix + 1; var caller = stack[printFrameCallerIx].GetMethod(); var isHook = caller.DeclaringType == typeof (IronPython.Modules.SysModule) && caller.Name == "displayhookImpl"; // only apply color if this is a message being written by the print() function // but not if print() was called via internal sys displayhook - which should // leave only explicit print() calls enabled = !isHook; } } if (!enabled) { _inner.Write(value); return; } var original = Console.ForegroundColor; Console.ForegroundColor = Color; _inner.Write(value); Console.ForegroundColor = original; } public override Encoding Encoding { get { return _inner.Encoding; } } } } Keith Rome Senior Consultant and Architect MCPD-EAD, MCSD, MCDBA, MCTS-WPF, MCTS-TFS, MCTS-WSS Wintellect | 770.617.4016 | kr...@wintellect.com www.wintellect.com -----Original Message----- From: Doug Blank [mailto:doug.bl...@gmail.com] Sent: Thursday, September 20, 2012 6:44 AM To: Keith Rome Cc: ironpython-users@python.org Subject: Re: [Ironpython-users] Separating return values from printed values? On Thu, Sep 20, 2012 at 1:37 AM, Keith Rome <r...@wintellect.com> wrote: > This might give you what you need (hooking in via the runtime output writer, > which is where the print function routes to), it seems to work for my quick > test: > > using System; > using System.IO; > using System.Text; > using IronPython.Hosting; > > namespace ConsoleApplication3 > { > class Program > { > static void Main(string[] args) > { > RunScript("22"); > RunScript("print(23)"); > Console.ReadKey(); > } > > static void RunScript(string script) > { > var engine = Python.CreateEngine(); > var io = engine.Runtime.IO; > io.SetOutput(io.OutputStream, new GreenWriter(io.OutputWriter)); > var result = engine.Execute(script); > if (result != null) > Console.WriteLine(result); > } > } > > class GreenWriter : TextWriter > { > private readonly TextWriter _inner; > public GreenWriter(TextWriter inner) > { > _inner = inner; > } > public override void Write(string value) > { > var original = Console.ForegroundColor; > Console.ForegroundColor = ConsoleColor.Green; > _inner.Write(value); > Console.ForegroundColor = original; > } > public override Encoding Encoding > { > get { return _inner.Encoding; } > } > } > } > Thanks for the example! I guess we also have some other issues which may cause use to be unable to use that interface, or maybe our code is overly complicated? We: * use a shared scope, if available so other DLR languages can interoperate (manager.scope below) * compile the code, perhaps with options (for speed and feedback, I guess) * make a distinction between different SourceCodeKinds (for the compiler, I guess) * thus, we don't have a return value; the system automatically prints it (?) * we try/catch each step to give feedback to the student Here is our Execute: sctype = Microsoft.Scripting.SourceCodeKind.InteractiveCode; source = engine.CreateScriptSourceFromString(text, sctype); try { if (compiler_options != null) { source.Compile(compiler_options); } else { source.Compile(); } } catch { sctype = Microsoft.Scripting.SourceCodeKind.Statements; source = engine.CreateScriptSourceFromString(text, sctype); try { if (compiler_options != null) { source.Compile(compiler_options); } else { source.Compile(); } } catch (Exception e) { eo = engine.GetService<Microsoft.Scripting.Hosting.ExceptionOperations>(); PrintLine(eo.FormatException(e)); return false; } } try { if (manager != null && manager.UseSharedScope) source.Execute(manager.scope); else source.Execute(scope); } catch (Exception e) { if (e.Message.Contains("Thread was being aborted")) { manager.stderr.Print("[Script stopped----------]\n"); } else { eo = engine.GetService<Microsoft.Scripting.Hosting.ExceptionOperations>(); PrintLine(eo.FormatException(e)); } return false; } if (manager.stderr != null) PrintLine(Tag.Info, "Ok"); Is there a way using this interface, or is our code too much, and we could get by with less? -Doug > Keith Rome > Senior Consultant and Architect > MCPD-EAD, MCSD, MCDBA, MCTS-WPF, MCTS-TFS, MCTS-WSS Wintellect | > 770.617.4016 | kr...@wintellect.com www.wintellect.com > > -----Original Message----- > From: Ironpython-users > [mailto:ironpython-users-bounces+rome=wintellect....@python.org] On > Behalf Of Doug Blank > Sent: Thursday, September 20, 2012 12:43 AM > To: ironpython-users@python.org > Subject: [Ironpython-users] Separating return values from printed values? > > IronPython users, > > Interesting question: we have IronPython embedded in a nice little > educational GUI, and have the DLR output sent to our text output window where > we can control the font color, etc. > > In teaching CS, it is always hard to try to get across the difference between > a "return value" and a "displayed string". For example: > >>>> 22 > 22 >>>> print(23) > 23 >>>> function() > 22 > > where 22 is just a value, and 23 is a displayed string (a side-effect for you > functional types). These GUIs don't make it easy to see the difference. > > One thing we've thought about is making a distinction between them with > color, such that 22 might be blue, and 23 would be green. > > Can you think of an easy way to do that with IronPython and the DLR? > Anything we could tap into to send evaluations one way, and displayed values > another? > > Thanks for any suggestions, > > -Doug > _______________________________________________ > Ironpython-users mailing list > Ironpython-users@python.org > http://mail.python.org/mailman/listinfo/ironpython-users > > _______________________________________________ Ironpython-users mailing list Ironpython-users@python.org http://mail.python.org/mailman/listinfo/ironpython-users