I want to simply pass the value of a variable to the c++ application.

I am trying this code:


	/* Import the Python script */
	pModule = PyImport_ImportModule("test1");
	if (pModule != nullptr) {
		res = PyModule_AddStringConstant(pModule, "__file__", "");
		if (res == 0) {
			pLocal = PyModule_GetDict(pModule);
			if (pLocal != nullptr) {
				/* Define my function in the newly created module */
				pValue = PyRun_String(
					"def executed(dun):\n\treturn dun\n",
					Py_file_input,
					pGlobal,
					pLocal
				);
				/* pValue would be null if the Python syntax is wrong, for example */
				if (pValue == NULL) {
					if (PyErr_Occurred()) {
						PyErr_Print();
					}
				}
				else {
					/* Get a pointer to the function just defined
					Retrieve an attribute named attr_name from object o.
					Returns the attribute value on success, or NULL on failure */
					pFunc = PyObject_GetAttrString(pModule, "executed");
					/* Double check we have actually found it and it is callable
					Return 1 if the object is callable and 0 otherwise */
					if (!pFunc || !PyCallable_Check(pFunc)) {
						if (PyErr_Occurred()) {
							PyErr_Print();
						}
						return 2;
					}

					/* Build a tuple to hold arguments 
					Return a new tuple object of size len, or NULL */
					pArgs = PyTuple_New(1);
					if (pArgs != nullptr) {
						int val = 0;
						/* Parse the input argument as an integer */
						if (!PyArg_ParseTuple(pArgs, "i", &val)) {
							return NULL;
						}

						/* Return Py_True or Py_False, depending on the value */
						pValue = PyBool_FromLong(val);
						if (pValue != nullptr) {
							tup = PyTuple_SetItem(pArgs, 0, pValue);
							if (tup == 0) {
								// success
							}
							else {
								// failed
							}

							/* Call function */
							pValue = PyObject_CallObject(pFunc, pArgs);
						}
					}
				}
			}
		}
	}

However, PyArg_ParseTuple does not succeed.

Am I going about this correctly?

My python code looks like this:

dun = False
pix = PIL.ImageGrab.grab()
x, y = pyautogui.position()
r, g, b = pix.getpixel((x, y))
dun = True

I want to get the boolean value.

1 Like

What do you think this piece of code is doing?

Are you just copy pasting LLM output without understanding the underlying functions?

1 Like

I am going to move this to Python Help, as it doesn’t seem to be relevant to Core Development in any way.

When a Python function is called, the arguments are passed in a tuple. PyArg_ParseTuple is used to fetch the values from that tuple.

What your code is doing is creating a new tuple of size 1, and then using PyArg_ParseTuple to fetch a value (an int) from it, but, of course, there’s no value, because you’ve only just created the tuple and haven’t yet filled in the value!

1 Like

I thought it was creating the tuple to hold the value that would be extracted from from the function.

However, you are right. I don’t know what I am doing. I have the documentation, but they give so little information. I’m finding it difficult to follow.

I didn’t even find information on the format for PyArg_ParseTuple.

I’d appreciate any help by those who understand. Even if it’s just to push me in the right direction, because I accomplished quite a lot thus far.

I’m just stuck at this point, which is why I came to the Python Help Forums., looking for help.

I did not understand that, since the vale came from later down.

For example,

pValue = PyLong_FromLong(4);
tup = PyTuple_SetItem(pArgs, 0, pValue);
/* Call my function, passing it the number four */
pValue = PyObject_CallObject(pFunc, pArgs);

I understood that the value… in this case (4) was inserted in the tuple, in order to call the function with it.

The result was correct. 20

pValue = PyRun_String(
	"def blah(x):\n\ty = x * 5\n\treturn y\n",
	Py_file_input,
	pGlobal,
	pLocal
);

I’m confused.

How would you correct my code, to achieve my aim?

I’d probably use Py_BuildValue to create the tuple of the arguments, something like this:

/* Create the tuple of the arguments. */
int val = 0;
pArgs = Py_BuildValue("(i)", val);
if (pArgs != nullptr) {
    /* Call the function. */
    pResult = PyObject_CallObject(pFunc, pArgs);
}

The docs for Py_BuildValue are here: Parsing arguments and building values — Python 3.14.0 documentation.

The docs describe the format strings of PyArg_ParseTuple here: Parsing arguments and building values — Python 3.14.0 documentation.

Incidentally, your code has a lot of indentation, which makes it harder to follow. It’s neater to go to an error handler. (Normally, using goto is a bad idea, but, in C, it’s usually the best solution for error handling.)

Also, it’s simpler if you discard objects you no longer need as soon as possible so that you have fewer to track.

Something like this:

/* Create the tuple of the arguments. */
int val = 0;
pArgs = Py_BuildValue("(i)", val);
if (pArgs == nullptr)
    goto error;

/* Call the function. */
pResult = PyObject_CallObject(pFunc, pArgs);
/* The arguments aren't needed after this point; dispose of them now. */
Py_DECREF(pArgs);
if (pResult == nullptr)
    goto error;

Thank you for the example, and the tips.

I’ll try to implement them.

Using Py_BuildValue doesn’t return an error. However, it seems (correct me please if I am wrong) what I am doing here is inserting a value, and then extracting it…. which isn’t what I am trying to accomplish.

Sorry if I gave that impression.

Can I explain from the beginning…

I am running my script with this code:

pyResult = PyRun_String(
    "import subprocess\nsubprocess.Popen('cmd /k python script.py', shell=True)",
    Py_file_input,
    pMainDict,
    pLocalDict
);

The script just does this:

dun = False
pix = PIL.ImageGrab.grab()
x, y = pyautogui.position()
r, g, b = pix.getpixel((x, y))
dun = True

The boolean is to indicate the script completed, because it’s being executed in a loop, and it gets left behind if I don’t wait till it’s done (dun).

I use a while loop to check if dun is True.

Would you mind at all just showing me the code that extracts the value of the boolean ‘dun’, so that the c++ application knows the script finished executing?

I’d really appreciate that very much.

Trust me when I say, I’ve really been working hard and spent weeks getting to this point.

Thank you for your help.

The variable dun exists entirely within script.py when it’s running.

Nothing outside the script has access to it, and its value isn’t returned anywhere - it’s purely local to that script.

What you have there is a script that’s run by another instance of Python, which is run by cmd, which is run by a subprocess, which is run by Python, which is run by C++.

That’s a lot of levels between dun and C++!

The simplest way of detecting when script.py is done might be to have it create a file when it’s finished and then wait for that to appear.

Thanks, I did that, but since it has to create the file over and over, and delete the file repeatedly, I think that is having a toll on the application,

It slows down to a point of stopping, and sometimes crashes.

This is the reason I was trying another method.

I would run the script from pyRun if it did not skew the coordinates, but when I import PIL, it throws the coordinates off.

I can’t figure why that happens.

Suppose I executed the script this way:

pyResult = PyRun_String(
    "pix = PIL.ImageGrab.grab()\nx, y = pyautogui.position()\nr, g, b = pix.getpixel((x, y))\ndun = True",
    Py_file_input,
    pMainDict,
    pLocalDict
);

Can you show me how I would extract the value of ‘dun’.

It does not have to be a boolean, It can be an integer - dun = 1.

I could accept that as a solution to this.

Thanks.

You could look for it in pMainDict or pLocalDict, but it’s pointless in that example because you’ll know that it’s True when the Python code finishes and PyRun_String returns.

1 Like

So, does that mean using the dictionary, I can tell when it does become true, if it starts false, like this:

"dun = False\npix = PIL.ImageGrab.grab()\nx, y = pyautogui.position()\nr, g, b = pix.getpixel((x, y))\ndun = True"

Can you show me an example, please.