Search code examples
pythonc#python.net

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


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 sys\n"+ "from io import StringIO\n"+
        $"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.


Solution

  • 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;
        }