Skip to content

Calling a deleate from a Unity Coroutine #1471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mespino-cityzenith opened this issue Jun 15, 2021 · 2 comments
Closed

Calling a deleate from a Unity Coroutine #1471

mespino-cityzenith opened this issue Jun 15, 2021 · 2 comments

Comments

@mespino-cityzenith
Copy link

Environment

  • Pythonnet version:3.0.0.0
  • Python version:3.9
  • Operating System: Windows 10, 64 bits
  • .NET Runtime: Mono, .Net Standard 2.0
  • Unity: 2020.3.11

Details

  • Describe what you were trying to get done.

    I trying to create a plugin architecture with pythonnet that allows async callbacks (for example, to wait a server response)

    I have been able to pass a delegate from python to c#. Then, the c# code calls the delegate, which points to python again. This is working just fine.
    The problem is when I try to do this, through a unity co-routine. When I try that, I get the a PyScopeException: object is not a module (see traceback section)
    In summary;
    Python -> delegate -> c# -> callback-> python. Working fine
    Python -> delegate -> c# -> Unity coroutine -> callback-> python. PyScopeException: object is not a module

  • What commands did you run to trigger this issue? If you can provide a
    Minimal, Complete, and Verifiable example
    this will help us understand the issue.

This code reproduces exactly the issue.

Event.issue.mp4
using Python.Runtime;
using System;
using System.Collections;
using UnityEngine;

public class EventTest : MonoBehaviour
{
    public enum Mode
    {
        SimpleCallback,
        CoroutineCallback
    }

    public Mode mode = Mode.CoroutineCallback;

    void Start()
    {
        Test();
    }

    private void Test()
    {
        PythonEngine.Initialize(mode:ShutdownMode.Soft);
        using (Py.GIL())
        {
            PyScope scope = Py.CreateScope();
            SetupLogger(scope);
            scope.Set("callbackTest", this.ToPython());

            var code = string.Empty;
            if (mode == Mode.SimpleCallback)
            {
                code = GetCodeForSimpleCallback();//Working
            }
            else
            {
                code = GetCodeForCoroutineCallback();//not working, PyScopeException: object is not a module
            }

            var pyCompile = PythonEngine.Compile(code);
            scope.Execute(pyCompile);
        }

        PythonEngine.Shutdown(mode: ShutdownMode.Soft);
    }

    private string GetCodeForSimpleCallback()
    {
        string code =
@"
from System import Action

def PrintText(text):
    print(text)

callback = Action[str](PrintText)
callbackTest.Test(callback)
";

        return code;
    }

    private string GetCodeForCoroutineCallback()
    {
        string code =
@"
from System import Action

def PrintText(text):
    print(text)

callback = Action[str](PrintText)
callbackTest.TestCallbackWithCoroutine(callback)
";

        return code;
    }

    public void Test(Action<string> func)
    {
        func("Test");
    }

    public void TestCallbackWithCoroutine(Action<string> func)
    {
        StartCoroutine(ICallback(func));
    }

    private IEnumerator ICallback(Action<string> func)
    {
        yield return new WaitForSeconds(1f);
        func("Test Coroutine Callback");
    }


    #region miscellaneous

    private void SetupLogger(PyScope scope)
    {
        scope.Set("Logger", this.ToPython());

        string loggerSrc = 
            "import sys\n" 
            + "sys.stdout = Logger\n";
        scope.Exec(loggerSrc);
    }

    public void write(string line)
    {
        Debug.Log(line);
    }
    #endregion
}
  • If there was a crash, please include the traceback here.

PyScopeException: object is not a module
Python.Runtime.PyScope..ctor (System.IntPtr ptr, Python.Runtime.PyScopeManager manager) (at C:/Users/mespino/Workspace/Cityzenith/Pythonnet/src/runtime/pyscope.cs:61)
Python.Runtime.PyScope..ctor (Python.Runtime.NewReference& reference, Python.Runtime.PyScopeManager manager) (at C:/Users/mespino/Workspace/Cityzenith/Pythonnet/src/runtime/pyscope.cs:48)
Python.Runtime.PyModule..ctor (Python.Runtime.NewReference& reference) (at C:/Users/mespino/Workspace/Cityzenith/Pythonnet/src/runtime/pymodule.cs:7)
Python.Runtime.PyModule.Import (System.String name) (at C:/Users/mespino/Workspace/Cityzenith/Pythonnet/src/runtime/pymodule.cs:19)
Python.Runtime.PythonException..ctor () (at C:/Users/mespino/Workspace/Cityzenith/Pythonnet/src/runtime/pythonexception.cs:51)
Python.Runtime.Dispatcher.TrueDispatch (System.Object[] args) (at C:/Users/mespino/Workspace/Cityzenith/Pythonnet/src/runtime/delegatemanager.cs:299)
Python.Runtime.Dispatcher.Dispatch (System.Object[] args) (at C:/Users/mespino/Workspace/Cityzenith/Pythonnet/src/runtime/delegatemanager.cs:269)
__System_Action`1/[/[System_String/, mscorlib/, Version=4_0_0_0/, Culture=neutral/, PublicKeyToken=b77a5c561934e089/]/]Dispatcher.Invoke (System.String ) (at <16ca6f0fe1de48349722972d141afb2e>:0)
EventTest+d__8.MoveNext () (at Assets/Event/EventTest.cs:92)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at <127e81e1cb3441cc97d26b1910daae77>:0)

    print('TODO')
@mespino-cityzenith
Copy link
Author

I was closing the engine before the execution could finish

This code works:

using Python.Runtime;
using System;
using System.Collections;
using UnityEngine;

public class EventTest : MonoBehaviour
{
    public enum Mode
    {
        SimpleCallback,
        CoroutineCallback
    }

    public Mode mode = Mode.CoroutineCallback;

    private void OnEnable()
    {
        PythonEngine.Initialize(mode: ShutdownMode.Soft);
    }

    private void OnDisable()
    {
        PythonEngine.Shutdown(mode: ShutdownMode.Soft);
    }

    void Start()
    {
        Test();
    }

    private void Test()
    {
        using (Py.GIL())
        {
            PyScope scope = Py.CreateScope();
            SetupLogger(scope);
            scope.Set("callbackTest", this.ToPython());

            var code = string.Empty;
            if (mode == Mode.SimpleCallback)
            {
                code = GetCodeForSimpleCallback();//Working
            }
            else
            {
                code = GetCodeForCoroutineCallback();//not working, PyScopeException: object is not a module
            }

            var pyCompile = PythonEngine.Compile(code);
            scope.Execute(pyCompile);
        }

    }

    private string GetCodeForSimpleCallback()
    {
        string code =
@"
from System import Action

def PrintText(text):
    print(text)

callback = Action[str](PrintText)
callbackTest.Test(callback)
";

        return code;
    }

    private string GetCodeForCoroutineCallback()
    {
        string code =
@"
from System import Action

def PrintText(text):
    print(text)

callback = Action[str](PrintText)
callbackTest.TestCallbackWithCoroutine(callback)
";

        return code;
    }

    public void Test(Action<string> func)
    {
        func("Test");
    }

    public void TestCallbackWithCoroutine(Action<string> func)
    {
        StartCoroutine(ICallback(func));
    }

    private IEnumerator ICallback(Action<string> func)
    {
        yield return new WaitForSeconds(10f);
        func("Test Coroutine Callback");
    }


    #region miscellaneous

    private void SetupLogger(PyScope scope)
    {
        scope.Set("Logger", this.ToPython());

        string loggerSrc = 
            "import sys\n" 
            + "sys.stdout = Logger\n";
        scope.Exec(loggerSrc);
    }

    public void write(string line)
    {
        Debug.Log(line);
    }
    #endregion
}

@lostmsu
Copy link
Member

lostmsu commented Aug 25, 2021

This looks like it might have been caused by #1489

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants