Posts: 13
Threads: 2
Joined: Jul 2022
Jul-30-2022, 05:12 AM
(This post was last modified: Jul-30-2022, 07:30 AM by Gribouillis.)
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?
Posts: 4,801
Threads: 77
Joined: Jan 2018
Jul-30-2022, 07:25 AM
(This post was last modified: Jul-30-2022, 07:25 AM by Gribouillis.)
(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__' .
Posts: 13
Threads: 2
Joined: Jul 2022
Jul-30-2022, 02:29 PM
(This post was last modified: Jul-30-2022, 03:39 PM by Gribouillis.)
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?
Gribouillis write Jul-30-2022, 03:39 PM:Please post all code, output and errors (it it's entirety) between their respective tags. Refer to BBCode help topic on how to post. Use the "Preview Post" button to make sure the code is presented as you expect before hitting the "Post Reply/Thread" button.
Posts: 4,801
Threads: 77
Joined: Jan 2018
Jul-30-2022, 04:01 PM
(This post was last modified: Jul-30-2022, 04:01 PM by Gribouillis.)
Here is a (quick and dirty) simple example in C created from the very high level embedding basic example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
int
main( int argc, char * argv[])
{
wchar_t * program = Py_DecodeLocale(argv[ 0 ], NULL);
const char * spamclass = R
";
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
1 2 3 4 5 |
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
|
Posts: 13
Threads: 2
Joined: Jul 2022
oh cool, thank you so much for the sample, I will use this to test my wrapper now.
this is really help fully.
Posts: 13
Threads: 2
Joined: Jul 2022
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
1 2 3 4 5 6 7 8 9 |
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
1 2 3 4 |
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?
Posts: 4,801
Threads: 77
Joined: Jan 2018
(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)
Posts: 13
Threads: 2
Joined: Jul 2022
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
int main() {
const char * spamclass = R
";
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 ;
}
|
Posts: 4,801
Threads: 77
Joined: Jan 2018
Jul-31-2022, 08:56 PM
(This post was last modified: Jul-31-2022, 08:59 PM by Gribouillis.)
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
using namespace std;
int main() {
const char * spamclass = R
";
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 ;
}
|
Posts: 13
Threads: 2
Joined: Jul 2022
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
|