Reset environment/scope between multiple function calls in Python.Net

Question:

I want to execute the same Python function several times and I want each execution to be completely isolated from the previous one.
But the problem is that the first execution of the method changes a global variable and when I execute the method the second time the global variable has the value left by the first execution.

I want that from one call to another the environment is reset and is like the first time.

var1=1

def Met(n) :
    global var1

    if n!=1 : var1=n
    print(f"Py: {var1}")
    
    return var1
    
if __name__ == "__main__":
    args = sys.argv
    globals()[args[1]](*args[2:])

If I execute it from command line:

python .Test1.py Met 2
python .Test1.py Met 1

The output is (correct):

Py: 2
Py: 1

What I want, OK.

But if I run it from Pythonet I get:

Py: 2
Py: 2

Incorrect!

That is, the second call, the value of var1 is the value of first call.

The code (simplifying):

public string Met2(int n) {
    dynamic txtResul="X";

     using ( Py.GIL() ) { 
        using (var scope=gbl.NewScope() ) { //Witout this, it doesn't work too
            dynamic f=Py.Import(NOM_FICH_Py);
            txtResul=f.Met(n);
        }
    }        

    return txtResul.ToString();
}

I have tried initialising with and without this:

    PythonEngine.Initialize();
    gbl = Py.CreateScope(nombre);
    pyPtr=PythonEngine.BeginAllowThreads();

I have also tried to finalize everything and run it, with and without this:

public void Fin() {
    PythonEngine.EndAllowThreads(pyPtr);
    PythonEngine.Shutdown();
}

I have also tried running each function call as a separate script:

using (Py.GIL()) {
    dynamic sys = Py.Import("sys");
    string script ="import sysn"+ "from io import StringIOn"+
        $"from {NOM_FICH_Py} import {funcion.Split('(')[0]}n"+
        "sys.stdout=StringIO()n"+ "sys.stdout.flush()n"+
        "sys.stderr=StringIO()n"+ "sys.stderr.flush()n"+
        funcion;
    var scope = Py.CreateScope(); 
    var vars=scope.Variables();
    scope.Exec(script, new PyDict());
    salida=sys.stdout.getvalue();
    scope.Dispose();
}

I use Python 3.10 and Python .Net 3.0.0-rc 4 and Python.Net 3.0.0-preview2022-03-03 (in other computer) and I cann’t get the ‘reset’ as I executed it like command line.

Thanks in advance.

Extra question, is there any wiki/documentacion to read the detail of functions like CreateScope, NewScope, Exec…? In https://github.com/pythonnet/pythonnet/wiki I haven’t found the function’s detail.

Asked By: Enrique

||

Answers:

The only supported way to fully reset Python environment with Python.NET is to restart the process.

Answered By: LOST

At the end, the only posible solution it’s to exectue like a script in cmd.
It’s not the best solution (it’s not posible to debug) but it’s the only one I know.

    public string ExecCmd(string funcion, string args) {
        Process p = new Process();
        p.StartInfo=new ProcessStartInfo(PYTHON_EXE, $"{NombreFichApp} {funcion} {args}") {
            RedirectStandardOutput=true,
            UseShellExecute=false,
            CreateNoWindow=true
        };

        p.Start();
        string salida = p.StandardOutput.ReadToEnd();
        p.WaitForExit();

        return salida;
    }
Answered By: Enrique

Try enclosing your code with another using block for PythonEngine, you can also use PythonEngine.Shutdown and then reinitialise it every time a method call is made

    using(var pyEngine=new PythonEngine())
{
using ( Py.GIL() ) { 
        using (var scope=gbl.NewScope() ) { //Witout this, it doesn't work too
            dynamic f=Py.Import(NOM_FICH_Py);
            txtResul=f.Met(n);
        }
    }  
}   
Answered By: Shiva Rama Krishnan
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.