dlr icon indicating copy to clipboard operation
dlr copied to clipboard

Strange iterator behavior with async code

Open gmkado opened this issue 11 months ago • 0 comments

I'm getting a weird error when trying to run a modified version of Scenario_ExecuteFile_Push. Here is my code:

public static class Scenarios {
    static async Task Main() {
        await Scenario_ExecuteFile_Push();
    }

    public class MyHostObjectModel {
        public Func<IEnumerable<string>> GetUserCommands = default!;
    }
    
    private static ScriptRuntime CreateScriptRuntime()
    {
        var setup = new ScriptRuntimeSetup();
        setup.LanguageSetups.Add(IronPython.Hosting.Python.CreateLanguageSetup(null));
        var runtime = new ScriptRuntime(setup);
        return runtime;
    }

    public static async Task Scenario_ExecuteFile_Push() {
        var hostOm = new MyHostObjectModel();
        var runtime = CreateScriptRuntime();

        runtime.Globals.SetVariable("App", hostOm);
        runtime.ExecuteFile("register_user_commands.py");
        
        foreach (var str in hostOm.GetUserCommands())
        {
            // await Task.Delay(100);
            Console.WriteLine(str);
        }
    }
}

Here is my register_user_commands.py:

import App

def fun():
  yield 'does'
  yield 'this'
  yield 'work'

App.GetUserCommands = fun

Without the Task.Delay, (aka when run synchronously) this prints to the console:

does
this
work

But with the Task.Delay uncommented I get:

does
this
work
Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
   at System.Collections.Generic.List`1.RemoveAt(Int32 index)
   at Microsoft.Scripting.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.LightLambda.Run1[T0,TRet](T0 arg0)
   at IronPython.Runtime.PythonGenerator.GetNext()
   at IronPython.Runtime.PythonGenerator.MoveNextWorker()
   at IronPython.Runtime.PythonGenerator.System.Collections.IEnumerator.MoveNext()
   at IronPython.Runtime.IEnumeratorOfTWrapper`1.MoveNext()
   at dlr_playground.Scenarios.Scenario_ExecuteFile_Push() in [...]Program.cs:line 39
   at dlr_playground.Scenarios.Main() in [...]Program.cs:line 17
   at dlr_playground.Scenarios.<Main>()

gmkado avatar Jan 22 '25 09:01 gmkado