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.
The only supported way to fully reset Python environment with Python.NET is to restart the process.
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;
}
Related
Using Pybind11, I am able to call a C++ native function from my Python code.
My C++ programme has a long-running function that keeps on going until explicitly stopped and this function generates some output using std::cout. As this long-running function never returns due to its nature, I am trying to get the output of this C++ code in my Python code for further processing.
I am aware of this: https://pybind11.readthedocs.io/en/stable/advanced/pycpp/utilities.html#capturing-standard-output-from-ostream however I really do not see how to reflect the C++ generated output into my Python code.
Here is the code:
int myFunc()
{
...
for(;;) { // Can be only stopped if requested by user
std::cout << capturedEvent;
}
...
return 0;
}
namespace py = pybind11;
PYBIND11_MODULE(Handler, m) {
// Add a scoped redirect for your noisy code
m.def("myFunc", []() {
py::scoped_ostream_redirect stream(
std::cout, // std::ostream&
py::module_::import("sys").attr("stdout") // Python output
);
myFunc();
});
...
}
And Python:
from Handler import myFunc
from random import random
DATA = [(random() - 0.5) * 3 for _ in range(999999)]
def test(fn, name):
result = fn()
print('capturedEvent is {} {} \n\n'.format(result, name))
if __name__ == "__main__":
test(myFunc, '(PyBind11 C++ extension)')
I would like to retrieve, in realtime, the content of the C++ capturedEvent variable.
If there is another approach than capturing stdout, (maybe sharing a variable in realtime?) please, let me know, maybe my strategy is wrong.
Thank you.
Embedding Python in AHK(I have a code from AHK website), can't I put multiple python script in one Autohotkey script?
https://www.autohotkey.com/boards/viewtopic.php?t=7732
Python code is embeded with parenthesis, and it works fine. Like,
py =
(
some code
some code
)
Runpython(py) : works fine
Runpython()
{
some code
some code
}
Yes, codes above works fine. But what I am having trouble with is,
if I have more than one python codes like below, it seems like to return only the first python script no matter how.
py1 =
(
some code
some code
)
py2 =
(
some code
some code
)
Runpython(py1) ; returns py1 which is fine
Runpython(py2) ; still returns py1, which is the trouble I got.
Runpython()
{
some code
some code
}
Yes, it is like above. Hope I can run py2 as well as py1.
If you follow the link up there, there is a script far below which was completed by the user named XeroByte.
And I put that here in a shortened form to contain crutial parts only.
I wanted to run multiple python scripts. But everytime I tried to run the second script, the first one was run always.
I decided to take out each line until it works.
pyStr= ;python code
(
Some code works
Some code works
)
pyStr2= ;python code that I added
(
Some code don't work
Some code don't work
)
RunPython(pyStr:="", PyVer:="")
finalPyStr := (pyStr="") ? Selection() : pyStr ; if a string has been passed into this function then use that as the python code, otherwise use the currently selected text using my custom Selection() function
if(StrLen(finalPyStr) > 0){ ; Only do the following if there is some python code to run
DllCall("LoadLibrary", "Str", PythonDll)
DllCall(PythonDll "\Py_Initialize", "Cdecl")
DllCall(PythonDll "\PyRun_SimpleString", "AStr", finalPyStr)
DllCall(PythonDll "\Py_Finalize", "Cdecl")
}
return 1
}
Finally, I learned that DllCall(PythonDll "\Py_Finalize", "Cdecl") was the main problem. I don't know its use exactly, but it definitely blocked my second script to be run. So the final form is as follows.
pyStr= ;python code
(
Some code works
Some code works
)
pyStr2= ;python code that I added
(
Some code works
Some code works
)
RunPython(pyStr:="", PyVer:="")
finalPyStr := (pyStr="") ? Selection() : pyStr ; if a string has been passed into this function then use that as the python code, otherwise use the currently selected text using my custom Selection() function
if(StrLen(finalPyStr) > 0){ ; Only do the following if there is some python code to run
DllCall("LoadLibrary", "Str", PythonDll)
DllCall(PythonDll "\Py_Initialize", "Cdecl")
DllCall(PythonDll "\PyRun_SimpleString", "AStr", finalPyStr)
}
return 1
}
And my second code also works as first one.
This question has been asked a few times before, however the accepted answers suggest that the asker was looking to do something different to me.
I am trying to create an IPython widget that creates and runs a new cell. The purpose of this is to provide a similitude between the widget and the IPython cells.
For example: I would like to have a SelectorWidget that fills and runs the next cell with 'cell magic'.
But I am facing the problem that (please correct me if I am wrong) IPython does not keep an internal data-structure of cells.
It seems to me that the only way to modify a new cell is with:
In [1]: get_ipython().set_next_input('1')
In [2]: 1
I'd just like to be able to run that line automatically. But I don't think that's possible with set_next_input given it's just a hack on top of readline.
I can do what I want to do with:
display(Javacript('''
var code = IPython.notebook.insert_cell_at_bottom('code'))
code.execute()
'''))
But it just feels so incredibly wrong to be driving input that way as it depends on a web-browser to do something quite simple. And you're depending on an external event loop.
The equivalent to doing this on the command line would be starting a background thread/process/corountine that has access to the IPython prompt's stdin and that would accept tasks from the foreground thread to write to the forground thread's own stdin. It's possible to do but has the same problem as the Jupyter methodology because it's specific to the input mechanism of IPython.
Looking at the problem, I can't seem to find a fully synchronous method without JavaScript either.
I have found the run_cell and run_cell_magic work to avoid the JavaScript example but fail on producing the cell with the outputs.
The closest I could come to was:
from IPython import get_ipython
def make_cell_run_code(code):
ipython = get_ipython()
ipython.set_next_input(code)
ipython.run_cell(code)
code = "print('test')"
make_cell_run_code(code)
which avoids the JavaScript but still has cells out of sync.
With JavaScript, we can use negative indexing to ensure the same cell is excecuted.
from IPython.display import Javascript, display
def create_and_excecute_code_cell(code=''):
display(Javascript("""
var code = IPython.notebook.insert_cell_at_bottom('code');
code.set_text("{0}");
Jupyter.notebook.execute_cells([-1]);
""".format(code)))
create_and_excecute_code_cell("%time x=0")
Which I cribbed from here. Your JavaScript snippet didn't work for me.
Other avenues are to look deeper into IPython.core.interactiveshell.InteractiveShell
One possible but not portable solution is to monkey-patch the JavaScript that handles the set_next_input kernel message.
(function (){
IPython.CodeCell.prototype._handle_set_next_input = function (payload) {
var data = {
cell: this,
text: payload.text,
replace: payload.replace,
clear_output: payload.clear_output,
execute: payload.execute
};
this.events.trigger('set_next_input.Notebook', data);
};
var that = IPython.notebook;
// Out with the old, in with the new
that.events.unbind("set_next_input")
that.events.on('set_next_input.Notebook', function (event, data) {
if (data.replace) {
data.cell.set_text(data.text);
if (data.clear_output !== false) {
// default (undefined) is true to preserve prior behavior
data.cell.clear_output();
}
} else {
var index = that.find_cell_index(data.cell);
var new_cell = that.insert_cell_below('code',index);
new_cell.set_text(data.text);
}
if (data.execute && data.execute === true) {
new_cell.execute();
} else {
that.dirty = true;
}
});
})()
This can be then called in the notebook like so:
with open('run_next_cell_patch.js') as f:
# Monkey patch Jupyter with
# set_next_input(run=True) functionality
display(Javascript(f.read()))
from IPython import get_ipython
ip = get_ipython()
ip.payload_manager.write_payload(
dict(
source='set_next_input',
text='print(1)',
replace=False,
execute=True
)
)
That will create a new cell below with print(1) and it's output executed. This is a bit better than inserting JavaScript each time to take control of the input.
Problematically this only works on Jupyter notebook. Still looking for a solution for Jupyter Lab. On the plus side, I think this could be fairly simple to solve in the plain terminal.
I have successfully created a Python module that appears to work in isolation, but doesn't affect the program that is running it.
I have the following module:
BOOST_PYTHON_MODULE(mandala)
{
class_<state_mgr_t, state_mgr_t*, noncopyable>("states", no_init)
.def("push", &state_mgr_t::push)
.def("pop", &state_mgr_t::pop)
.def("count", &state_mgr_t::count);
scope().attr("states") = boost::python::object(boost::python::ptr(&states));
}
The states object is referencing a global value, states:
extern state_mgr_t states;
I can run the following script lines from within my program:
from mandala import states
states.count()
> 0
All of that is fine and whatnot, but I was expecting that running this python script would affect the actual state of the program that is running it. It appears as though Python is actually just dealing with it's own instance of states and not affecting the parent program.
Now I'm wondering if I've completely misunderstood what Boost.Python is capable of; I was expecting something similar to Lua, where I could modify the C++ program via scripts.
Is this not possible? Or am I doing something very wrong?
Thank you in advance!
If you are embedding Python into your C++ program, it should be possible to access the instance from your script. Obviously, I don't have your full code, but have you tried something like this?
PyImport_AppendInittab("mandala", &initmandala);
Py_Initialize();
try {
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
main_namespace.attr("states") = ptr(&states);
object ignored = exec("print states.count()", main_namespace);
} catch(const error_already_set&) {
PyErr_Print();
}
I'm designing a Unity3D game where the user can adjust gameplay by modifying a .py file.
I'm using Python Interpreter asset, which wraps IronPython.
I need to pass control between C# and the running Python instance. Here is a pseudocode example:
// From Unity, C# script...
bool MakeNoise( float vol ) {
//...
}
void Awake() {
m_pythonEngine = Python.CreateEngine();
m_scriptScope = m_pythonEngine.CreateScope();
}
bool NewRound( int n ) {
myPythonRuntime.InvokeFunction( "NewRoundPy", param: roundNumber = n );
return retVal;
}
And then, in the game while it is running, the user could enter in a textbox:
# Python
vol = 0.5
def NewRoundPy( roundNumber ):
theCSharpObject.MakeNoise( vol )
return True
Which would in turn invoke the MakeNoise function every time a new round starts.
Apologies for the clumsy hypothetical situation. The important thing is that I need to be able to transfer execution from one environment to the other, passsing data as I do so.
I'm aware of the code needed to run a Python script. But I want to invoke individual functions from the script. And the script has to stay running between such calls, so that variables set in one function/call are retaining their values the next time some function is called.
Is this possible? If so, how?
PS going Python -> C# seems to be fairly simple; IronPython .NET Integration documentation
PPS I will tidy up the question once I have some understanding of what's going on