Python C API - Reload a module - python

I use Python 3.4 and Visual 2010.
I'm embedding Python using the C API to give the user some script capabilities in processing his data. I call python functions defined by the user from my C++ code. I call specific function like Apply() for example that the user has to define in a Python file.
Suppose the user has a file test.py where he has defined a function Apply() that process some data.
All I have to do is to import his module and get a "pointer" to his python function from the C++.
PySys_SetPath(file_info.absolutePath().toUtf8().data()));
m_module = PyImport_ImportModule(module_name.toUtf8().data());
if (m_module)
{
m_apply_function = PyObject_GetAttrString(m_module, "Apply");
m_main_dict = PyModule_GetDict(m_module);
}
So far, so good. But if the user modifies his script, the new version of his function is never taken into account. I have to reboot my program to make it work... I read somewhere that I need to reload the module and get new pointers on functions but the PyImport_ReloadModule returns NULL with "Import error".
// .... code ....
// Reload the module
m_module = PyImport_ReloadModule(m_module);
Any ideas ?
Best regards,
Poukill

The answer was found in the comments of my first post (thank you J.F Sebastian), the PySys_SetPath has to contain also the PYTHONPATH. In my case, that is the reason why the PyImport_ReloadModule was failing.
QString sys_path = file_info.absolutePath() + ";" + "C:\\Python34\\Lib";
PySys_SetPath(UTF8ToWide(sys_path.toUtf8().data()));
m_module = PyImport_ReloadModule(m_module); // Ok !

Related

What is the best way to execute simple user defined scripts in Python

I'm currently searching for some good ways how to support the execution of custom scripts in Python.
Let me present the "problem". I would like to execute some simple scripts on the data, that would accept a fixed number of arguments and return the transformed result.
Example:
function transform(input) {
if(input == 1)
return "YES"
return "NO"
}
These scripts could be defined dynamically by the user. I have solved a similar problem some years ago in .NET by using Lua scripts and executing them dynamically and filling the data into the function using the String.format. So for example the script that user-defined looked like that:
function transform(input) {
//function logic
return transformedInput
}
return transform({0});
And the script was executed like this:
var result = Lua.run(String.format("aboveFunction", 0));
(I have simplified the function, since the original also had some helper functions for string operations, ... but this is not relevant to the question.)
I also looked into using Lua script in Python, but there doesn't seem to be any packages that have been maintained lately. If I have missed some package that is currently worked on, or someone has some better ideas on how to solve the described problem I will be very gratefull for all sugesstions :)
So I ended up with using the lupa package for executing Lua scripts in my application.
So for example, I have prepared the following Lua function:
function(input)
if input == 1 then
return "{'turn': 'ON'}"
end
return "{'turn': 'OFF'}"
end
Which is the executed in the following Python code:
from lupa import LuaRuntime
lua = LuaRuntime(unpack_returned_tuples=True)
lua_func = lua.eval("""
function(input)
if input == 1 then
return "{'turn': 'ON'}"
end
return "{'turn': 'OFF'}"
end
""")
print(lua_func(1))
This is currently enough for my use case. I have not however tried to write some helper functions for the main function.

Passing a variable from Excel to Python with XLwings

I am trying write a simple user defined function in Python that I pass a value to from Excel via Xlwings. I ran across some examples with an Add-in that you need to import user defined functions, but that seems overly complex.
Why isn't my example working?
VBA:
Function Hello(name As String) As String
RunPython ("import Test; Test.sayhi(name)")
End Function
Python (Test.py):
from xlwings import Workbook, Range
def sayhi(name):
wb = Workbook.caller()
return 'Hello {}'.format(name)
Error:
NameError: name 'name' is not defined
Make sure you're supplying the argument correctly:
RunPython ("import Test; Test.sayhi('" & name & "')")
The text inside RunPython() should be a valid python script. So the comment from "Tim Williams" is a quick solution. You just need to be careful to avoid ' character inside the name variable to break the python script.
If you need to write UDF (User Defined Function) a lot, or need to pass in value to get the output and then handle the result via VBA, try use ExcelPython instead of Xlwings.
Note, ExcelPython and Xlwings can work together, you can have both without conflict.
I think it's better you play the example to understand the difference. My understanding is limited to my knowledge, which might not be correct.
To summarize the difference:
ExcelPython needs a installer to be installed, it is good in UDF, which helps if you want to pass arguments in and out, and the function is cached in memory, so later call will be very quick.
Xlwings is simpler by just add the VBA module, no installer needed. It trigger Python in the background each time to run the script (each call starts a new process), in the script you can manipulate (read/write) Excel via COM.
I have the same question in the beginning, but later I find out using VBA in Excel side (intellisense) plus ExcelPython on UDF (simply process and return the data back) is a nice combination, so I think ExcelPython is only what I need.
As mentioned earlier, the 2 components have no conflict, you can have both. If the 2 author agree too, it is a good idea to combine them.

JMeter - Run a python script before calling each HTTP request sampler

I am new to Jmeter. My HTTP request sampler call looks like this
Path= /image/**image_id**/list/
Header = "Key" : "Key_Value"
Key value is generated by calling a python script which uses the image_id to generate a unique key.
Before each sampler I wanted to generate the key using python script which will be passed as a header to the next HTTP Request sampler.
I know I have to used some kind of preprocessor to do that. Can anyone help me do it using a preprocessor in jmeter.
I believe that Beanshell PreProcessor is what you're looking for.
Example Beanshell code will look as follows:
import java.io.BufferedReader;
import java.io.InputStreamReader;
Runtime r = Runtime.getRuntime();
Process p = r.exec("/usr/bin/python /path/to/your/script.py");
p.waitFor();
BufferedReader b = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
StringBuilder response = new StringBuilder();
while ((line = b.readLine()) != null) {
response.append(line);
}
b.close();
vars.put("ID",response.toString());
The code above will execute Python script and put it's response into ID variable.
You will be able to refer it in your HTTP Request as
/image/${ID}/list/
See How to use BeanShell: JMeter's favorite built-in component guide for more information on Beanshell scripting in Apache JMeter and a kind of Beanshell cookbook.
You can also put your request under Transaction Controller to exclude PreProcessor execution time from load report.
A possible solution posted by Eugene Kazakov here:
JSR223 sampler has good possibility to write and execute some code,
just put jython.jar into /lib directory, choose in "Language" pop-up
menu jython and write your code in this sampler.
Sadly there is a bug in Jython, but there are some suggestion on the page.
More here.
You can use a BSF PreProcessor.
First download the Jython Library and save to your jmeter's lib directory.
On your HTTP sampler add a BSF PreProcessor, choose as language Jython and perform your needed magic to obtain the id, as an example I used this one:
import random
randImageString = ""
for i in range(16):
randImageString = randImageString + chr(random.randint(ord('A'),ord('Z')))
vars.put("randimage", randImageString)
Note the vars.put("randimage",randImageString") which will insert the variable available later to jmeter.
Now on your test you can use ${randimage} when you need it:
Now every Request will be different changing with the value put to randimage on the Python Script.

Python C API - Call C function from embedded python (callback)

I have a .cpp file loading python file and calling a function. I have a logger class in the .cpp and I want to use it from .py file.
Example:
# python-file.py
def FunctionCalledFromC_API():
log("some string")
log("some error", error)
log("some debug info", debug)
# etc...
And the .cpp
// cpp-file.cpp
// Load python file, do stuff...
PyObject *args = PyTuple_New(0);
PyObject_CallObject(pFunctionCalledFromC_API, args);
Py_DECREF(args);
I want that the log("some string") function of the .py file calls my logger.log(...) function from the C++ application.
As Markku K. suggested, I made all my app a DLL and I'll try soon.
That's what I'll do (for people with the same question):
Make my app a single DLL
Make an executable to run it (obvious)
Make a Python file containing the functions (example: logger.log()). That functions should call the DLL's equivalent functions.
Do "trial&error" until it works ;)
EDIT:
After a lot of "trial&error", I've found a way to do it!
Using boost::python to expose my API and the standard Python API to load the .py file I made this work!
But I'll have to start the application with a python file importing the shared object and calling the main function :(
Anyway, Thanks Markku K. for your help!

Calling Python code from Gnome Shell extension

I was looking for some time, but still can't find any documented way to call python functions from GnomeShell extension code. Is there any possibility to do that?
You can do it like this :)
const Util = imports.misc.util;
let python_script = '/path/to/python/script';
Util.spawnCommandLine("python " + python_script);
I don't know how to directly call a python function from Gnomeshell, but there is an alternative way. As gnomeshell is programmed with Javascript you could use a python to javascript compiler to translate the python functions you need.

Categories

Resources