Skip to content

Commit 562cecd

Browse files
authored
Add option ConsoleSupportLevel (#1730)
1 parent 8c0333b commit 562cecd

4 files changed

Lines changed: 59 additions & 25 deletions

File tree

Documentation/upgrading-from-ipy2.md

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,55 @@ System.StringSplitOptions["None"]
3131

3232
Similarly, `True` and `False` are also keywords in Python 3.
3333

34+
## Redirecting output
35+
36+
With IronPython 2, standard output was written to the runtime's `SharedIO.OutputWriter` (which was `Console.Out` by default). This is no longer the case with IronPython 3 where the standard output is a binary stream. The output is now written to runtime's `SharedIO.OutputStream`. Similarly, standard input and error are now using `SharedIO.InputStream` and `SharedIO.ErrorStream` respectively.
37+
38+
Because of this, using a `TextWriter` to capture output will no longer work. As a workaround, in order to use a `TextWriter` as the main method of redirection, one could wrap the writer inside a stream (for example, see [`TextStream`][TextStream]).
39+
40+
```c#
41+
// IronPython 2
42+
var engine = Python.CreateEngine();
43+
var textWriter = new MyTextWriter();
44+
// no longer works in IronPython 3!
45+
engine.Runtime.IO.RedirectToConsole();
46+
Console.SetOut(textWriter);
47+
```
48+
49+
```c#
50+
// IronPython 3
51+
var engine = Python.CreateEngine();
52+
var textWriter = new MyTextWriter();
53+
engine.Runtime.IO.SetOutput(new TextStream(textWriter), textWriter);
54+
```
55+
56+
Another way of achieving the redirection behavior similar to IronPython 2 is to set engine option `ConsoleSupportLevel` to `SupportLevel.Basic`. IronPython 3 still uses binary streams for standard input and output but **all three** standard streams are set to use `TextStream`, forwarding to the corresponding writers/reader.
57+
58+
```c#
59+
// IronPython 3
60+
var engine = Python.CreateEngine(new Dictionary<string, object> {
61+
{ "ConsoleSupportLevel", Microsoft.Scripting.Runtime.SharedIO.SupportLevel.Basic },
62+
});
63+
var textWriter = new MyTextWriter();
64+
// works again!
65+
engine.Runtime.IO.RedirectToConsole();
66+
Console.SetOut(textWriter);
67+
```
68+
69+
This method is particularly useful when embedding the IronPython 3 engine in a host that sets console's writers/reader before the engine is created and the host's code is not accessible to the user (for instance, scripting in [LINQPad]).
70+
71+
```c#
72+
// IronPython 3 in LINQPad
73+
var engine = Python.CreateEngine(new Dictionary<string, object> {
74+
{ "ConsoleSupportLevel", Microsoft.Scripting.Runtime.SharedIO.SupportLevel.Basic },
75+
});
76+
engine.Execute("print('abc')"); // shows output in the "Results" pane
77+
dynamic ans = engine.Execute("input()"); // pauses the script and asks for input at the bottom of the "Results" pane; terminate your input with Ctrl+Z, Enter
78+
```
79+
80+
[TextStream]: https://github.com/IronLanguages/dlr/blob/master/Src/Microsoft.Scripting/Utils/TextStream.cs
81+
[LINQPad]: https://www.linqpad.net/
82+
3483
## `int` Type
3584

3685
One of the major backward incompatible changes in Python 3 is [PEP 237 – Unifying Long Integers and Integers][PEP 0237]: Essentially, `long` renamed to `int`. That is, there is only one built-in integral type, named `int`; but it behaves mostly like the old `long` type. From the pure Python perspective this means that `int` should be used wherever previously `long` was used. More consideration has to be applied in interop cases with .NET.
@@ -206,27 +255,3 @@ IronPython's `range` is a generator that produces a sequence of `int` values. Th
206255

207256
[PEP 0237]: https://python.org/dev/peps/pep-0237
208257

209-
210-
## Redirecting output
211-
212-
With IronPython 2, standard output was written to the runtime's `SharedIO.OutputWriter` (which was `Console.Out` by default). This is no longer the case with IronPython 3 where the standard output is a binary stream. The output is now written to runtime's `SharedIO.OutputStream`. Similarly, standard input and error are now using `SharedIO.InputStream` and `SharedIO.ErrorStream` respectively.
213-
214-
Because of this, using a `TextWriter` to capture output will no longer work. As a workaround, in order to use a `TextWriter` as the main method of redirection, one could wrap the writer inside a stream (for example, see [TextStream][TextStream]).
215-
216-
IronPython 2
217-
```c#
218-
var engine = Python.CreateEngine();
219-
var textWriter = new MyTextWriter();
220-
// no longer works!
221-
engine.Runtime.IO.RedirectToConsole();
222-
Console.SetOut(textWriter);
223-
```
224-
225-
IronPython 3
226-
```c#
227-
var engine = Python.CreateEngine();
228-
var textWriter = new MyTextWriter();
229-
engine.Runtime.IO.SetOutput(new TextStream(textWriter), textWriter);
230-
```
231-
232-
[TextStream]: https://github.com/IronLanguages/main/blob/master/Runtime/Microsoft.Dynamic/Utils/TextStream.cs

Src/IronPython/Runtime/PythonContext.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,7 @@ internal void DelSystemStateValue(string name) {
18661866

18671867
private void SetStandardIO() {
18681868
SharedIO io = DomainManager.SharedIO;
1869+
io.ConsoleSupportLevel = PythonOptions.ConsoleSupportLevel;
18691870

18701871
var stdin = PythonIOModule.CreateConsole(this, io, ConsoleStreamType.Input, "<stdin>", out PythonIOModule.FileIO fstdin);
18711872
var stdout = PythonIOModule.CreateConsole(this, io, ConsoleStreamType.Output, "<stdout>", out PythonIOModule.FileIO fstdout);

Src/IronPython/Runtime/PythonOptions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Collections.ObjectModel;
8+
using System.Globalization;
89
using System.Text.RegularExpressions;
910

1011
using Microsoft.Scripting;
12+
using Microsoft.Scripting.Runtime;
1113

1214
namespace IronPython.Runtime {
1315

@@ -125,6 +127,11 @@ public sealed class PythonOptions : LanguageOptions {
125127

126128
public bool Quiet { get; }
127129

130+
/// <summary>
131+
/// On Basic level, console IO streams are emulated using console writer/reader.
132+
/// </summary>
133+
public SharedIO.SupportLevel ConsoleSupportLevel { get; }
134+
128135
internal bool NoImportLib { get; } // TODO: get rid of me when we no longer bootstrap importlib
129136

130137
public PythonOptions()
@@ -158,6 +165,7 @@ public PythonOptions(IDictionary<string, object> options)
158165
NoImportLib = GetOption(options, "NoImportLib", false);
159166
Isolated = GetOption(options, "Isolated", false);
160167
Utf8Mode = GetOption(options, "Utf8Mode", false);
168+
ConsoleSupportLevel = GetOption(options, "ConsoleSupportLevel", SharedIO.SupportLevel.Full);
161169
}
162170

163171
private static IDictionary<string, object> EnsureSearchPaths(IDictionary<string, object> options) {

0 commit comments

Comments
 (0)