Is there a way to PyImport_Import(PyModule) so that all it's functions or classes are run as directly vs as import?
Sample Python Code (main.py):
class TestClass:
- def print_hi(self, name):
print(f"print_hi {name})
if __name__ == '__main__'
- t = TestClass()
t.print_hi("test")
in c++ one can import the main.py with:
and created the class instance with:
- PyObject_callObject(pyTestClass)
How do one put the class instance behind the same guard as one can in python
if __name__ == '__main__'
Right now in all the module imported to c world is running as import, not direct.
Is there way to switch in c world?
(Jul-30-2022, 05:12 AM)Xeno Wrote: [ -> ]How do one put the class instance behind the same guard as one can in python
It is not clear what you want to do. In Python, the
if __name__ == '__main__'
only means that the following code must be executed only if the current module's name is
'__main__'
. There is no obstacle to do the same in C++, the code can check the current module's name.
Or perhaps you want to execute a Python files containing
if __name__ == '__main__'
sections and you want these sections to be executed, which won't work with an import statement. In that case, you could probably use
PyRun_File()
to run the file in a dictionary where
'__name__' --> '__main__'
.
[
attachment=1867]
I am mainly testing embedding python class in c++, just want to find a way to initilzie the python class that is behined
if __name__ == '__main__'
I am not sure how
PyRun_File() will help me here, can you show me know how to import a python class with it, and then call functions in the python class?
Here is a (quick and dirty) simple example in C created from the
very high level embedding basic example.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
wchar_t *program = Py_DecodeLocale(argv[0], NULL);
const char *spamclass = R""""(
class Spam:
def func(self):
if __name__ == '__main__':
print('called in __main__')
else:
print('called out of __main__')
)"""";
PyObject *mainmod, *Spam, *spam, *meth;
if (program == NULL) {
fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
exit(1);
}
Py_SetProgramName(program); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
PyRun_SimpleString(
spamclass
);
mainmod = PyImport_ImportModule("__main__");
Spam = PyObject_GetAttrString(mainmod, "Spam");
spam = PyObject_CallObject(Spam, NULL);
meth = PyObject_GetAttrString(spam, "func");
PyObject_CallObject(meth, NULL);
// printf("%p\n", spam);
if (Py_FinalizeEx() < 0) {
exit(120);
}
PyMem_RawFree(program);
return 0;
}
Here is the output
Output:
Today is Sat Jul 30 17:56:09 2022
called in __main__
and the makefile
foo.o: foo.c
gcc -c foo.c -I/usr/include/python3.8 -I/usr/include/python3.8 -Wno-unused-result -Wsign-compare -g -fdebug-prefix-map=/build/python3.8-uvizni/python3.8-3.8.10=. -specs=/usr/share/dpkg/no-pie-compile.specs -fstack-protector -Wformat -Werror=format-security -DNDEBUG -g -fwrapv -O3 -Wall -fPIE
a.out: foo.o
gcc foo.o -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -L/usr/lib -lcrypt -lpthread -ldl -lutil -lm -lm -lpython3.8
oh cool, thank you so much for the sample, I will use this to test my wrapper now.
this is really help fully.
I do have a follow up question on the return values
when I import __main__ and then do PyRun all is working good
but now it seems I can no long decode the python return value
class Spam:
def func(self):
if __name__ == '__main__':
print('called in __main__')
return "Completed"
else:
print('called out of __main__')
return "Skipped"
)"""";
I use to be able to decode the return values on the c++ side like this
PyObject* result= PyObject_CallObject(meth, NULL);
PyObject* repr = PyObject_Repr(result);
PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~I~");
cout << PyBytes_AS_STRING(str) << endl;
but now str object is NULL?
(Jul-31-2022, 07:26 AM)Xeno Wrote: [ -> ]but now str object is NULL?
Could you post complete C++ code to reproduce the issue? (preferably with makefile)
I was using the sample code as base and trying to return a string from the func.
mainly it seem to fail on:
str = PyUnicode_AsEncodedString(result, "utf-8", "~I~");
the returned str object is NULL
int main() {
const char* spamclass = R""""(
class Spam:
def func(self):
if __name__ == '__main__':
print('called in __main__')
return "Completed"
else:
print('called out of __main__')
return "Skipped"
)"""";
PyObject* mainmod, * Spam, * spam, * meth, * result, * repr, *str;
const char* s;
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
PyRun_SimpleString(
spamclass
);
mainmod = PyImport_ImportModule("__main__");
Spam = PyObject_GetAttrString(mainmod, "Spam");
spam = PyObject_CallObject(Spam, NULL);
meth = PyObject_GetAttrString(spam, "func");
result = PyObject_CallObject(meth, NULL);
if (!PyUnicode_CheckExact(result)) {
repr = PyObject_Repr(result);
str = PyUnicode_AsEncodedString(repr, "utf-8", "~I~");
s = PyBytes_AS_STRING(str);
cout << "response from python: " << s << endl;
}
else {
str = PyUnicode_AsEncodedString(result, "utf-8", "~I~");
s = PyBytes_AS_STRING(str);
cout << "response from python: " << s << endl;
}
if (Py_FinalizeEx() < 0) {
exit(120);
}
return 0;
}
It works for me. I could not reproduce the bug.
Output:
Today is Sun Jul 31 22:52:54 2022
called in __main__
response from python: Completed
Makefile:
Output:
# foo.o must come before the libraries when linking
a.out: foo.o
g++ foo.o -o a.out -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -L/usr/lib -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -lm
foo.o: foo.cpp
g++ foo.cpp -c -I/usr/include/python3.8 -I/usr/include/python3.8 -Wno-unused-result -Wsign-compare -g -fdebug-prefix-map=/build/python3.8-uvizni/python3.8-3.8.10=. -specs=/usr/share/dpkg/no-pie-compile.specs -fstack-protector -Wformat -Werror=format-security -DNDEBUG -g -fwrapv -O3 -Wall -fpie
clean:
rm -f a.out foo.o
Full C++ code
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include <iostream>
using namespace std;
int main() {
const char* spamclass = R""""(
class Spam:
def func(self):
if __name__ == '__main__':
print('called in __main__')
return "Completed"
else:
print('called out of __main__')
return "Skipped"
)"""";
PyObject* mainmod, * Spam, * spam, * meth, * result, * repr, *str;
const char* s;
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print('Today is', ctime(time()))\n");
PyRun_SimpleString(
spamclass
);
mainmod = PyImport_ImportModule("__main__");
Spam = PyObject_GetAttrString(mainmod, "Spam");
spam = PyObject_CallObject(Spam, NULL);
meth = PyObject_GetAttrString(spam, "func");
result = PyObject_CallObject(meth, NULL);
if (!PyUnicode_CheckExact(result)) {
repr = PyObject_Repr(result);
str = PyUnicode_AsEncodedString(repr, "utf-8", "~I~");
s = PyBytes_AS_STRING(str);
cout << "response from python: " << s << endl;
}
else {
str = PyUnicode_AsEncodedString(result, "utf-8", "~I~");
s = PyBytes_AS_STRING(str);
cout << "response from python: " << s << endl;
}
if (Py_FinalizeEx() < 0) {
exit(120);
}
return 0;
}
that is wired, the 2 diffrence I can see is
I am running this in vs2019, and running with python 3.10
is there anything linker wise i need to add in vc++?
this is the C++ options
/JMC /permissive- /ifcOutput "x64\Debug\" /GS /W3 /Zc:wchar_t /I"C:\Program Files\Python310\include" /ZI /Gm- /Od /sdl /Fd"x64\Debug\vc142.pdb" /Zc:inline /fp:precise /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /FC /Fa"x64\Debug\" /EHsc /nologo /Fo"x64\Debug\" /Fp"x64\Debug\cppTester.pch" /diagnostics:column
Linker options
/OUT:"C:\Users\WINSIM\PycharmProjects\testProject\cpp\cppTester\x64\Debug\cppTester.exe" /MANIFEST /NXCOMPAT /PDB:"C:\Users\WINSIM\PycharmProjects\testProject\cpp\cppTester\x64\Debug\cppTester.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /MACHINE:X64 /INCREMENTAL /PGD:"C:\Users\WINSIM\PycharmProjects\testProject\cpp\cppTester\x64\Debug\cppTester.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"x64\Debug\cppTester.exe.intermediate.manifest" /LTCGOUT:"x64\Debug\cppTester.iobj" /ERRORREPORT:PROMPT /ILK:"x64\Debug\cppTester.ilk" /NOLOGO /LIBPATH:"C:\Users\WINSIM\PycharmProjects\testProject\cpp\cppTester\x64\Debug" /LIBPATH:"C:\Program Files\Python310\libs" /TLBID:1