Extending via C++, adding a module throws exception

All other Source.Python topics and issues.
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Extending via C++, adding a module throws exception

Postby Chrisber » Thu Oct 30, 2014 1:39 am

Hello,

I'm trying to extend SP with a C++ addon. The following exception is thrown:

Code: Select all

sp load pbtest
[SP] Loading plugin 'pbtest'...

[SP] Caught an Exception:
Traceback (most recent call last):
  File '..\addons\source-python\packages\source-python\plugins\manager.py', line 72, in __missing__
    instance = self.instance(plugin_name, self.base_import)
  File '..\addons\source-python\packages\source-python\plugins\instance.py', line 82, in __init__
    self._plugin = import_module(import_name)
  File '..\addons\source-python\plugins\pbtest\pbtest.py', line 1, in <module>
    from pawnbridge import numargs

ImportError: 'pawnbridge' is not a built-in module

I really don't know why this happens. In my opinion, I followed everything described on https://docs.python.org/3/extending/embedding.html#extending-embedded-python
The module is definitely loaded. When I don't load my C++ stuff, the normal 'no module named blah' error appears.

The necessary code is:

Code: Select all

static int numargs 0;

static 
PyObjectemb_numargs(PyObject *selfPyObject *args)
{
    if (!
PyArg_ParseTuple(args":numargs"))
        return 
NULL;
    return 
PyLong_FromLong(numargs);
}

static 
PyMethodDef PawnBridgeMethods[] = {
        { 
"numargs"emb_numargsMETH_VARARGS,
        
"Return the number of arguments received by the process." },
        { 
NULLNULL0NULL }
};

static 
PyModuleDef PawnBridgeModule = {
    
PyModuleDef_HEAD_INIT"pawnbridge"NULL, -1PawnBridgeMethods,
    
NULLNULLNULLNULL
};

static 
PyObjectPyInit_emb(void)
{
    return 
PyModule_Create(&PawnBridgeModule);
}

bool PawnBridge::SDK_OnLoad(char *errorsize_t maxlengthbool late)
{
    
numargs 42;
    
PyImport_AppendInittab("pawnbridge", &PyInit_emb);
    
Py_Initialize();
    return 
true;


I'm thankful for help.
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Postby L'In20Cible » Thu Oct 30, 2014 2:22 am

My guess is that the exception is throw by the following line:

Syntax: Select all

PyImport_AppendInittab("pawnbridge", &PyInit_emb);

Most likely since you declare your module as "emb":

Syntax: Select all

static PyObject* PyInit_emb(void)

Rename the function to PyInit_pawnbridge and it should works just fine.
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 3:07 am

This does not change anything. Of course it does not, since this is only the internal symbol name. Python doesn't care about them. Thanks anyway :-)
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 12:21 pm

Your statement makes sense if considering the following sentence (same link as yours):
and should be the only non-static item defined in the module file:

Code: Select all

PyMODINIT_FUNC
PyInit_spam(void)
{
    return PyModule_Create(&spammodule);
}


This is ok, since PyMODINIT_FUNC translates to an exporting function. Problem is, it is still not working.
I also tried using boost.python and compiled against 3.4, but it still doesn't work. Visual Studio still wants to link against the static version (libboost_python-vc120-mt-s-1_55.lib) but I set BOOST_ALL_DYN_LINK in the compiler options...
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 1:26 pm

I think the problem is that you are trying to initialize another Python interpreter.

Syntax: Select all

PyImport_AppendInittab("pawnbridge", &PyInit_emb);
Py_Initialize();
I have updated an old Python 2 extension to test extending Python 3. Here is all I did to get it working. https://code.google.com/p/symdump/source/detail?r=3
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 1:32 pm

Hi,

this is out of the official documentation where they are saying "extending an embedded python". As for Python 2, you had to call the Py_Initialize() from extending libraries too. Even removing it, it does not change anything. Your code sample looks nearly the same as the code above. I am confused.

I'll try to use boost.python.

Edit: worked. My code is:

Code: Select all

char const* greet()
{
   return "hello, world";
}

BOOST_PYTHON_MODULE(pawnbridge)
{
   using namespace boost: :p ython;
   def("greet", greet);
}
Do you have an idea how to initialize the module? I'm very new to boost.python.
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 1:34 pm

What happens when you remove the line L'In20Cible pointed out?[python]PyImport_AppendInittab("pawnbridge", &PyInit_emb);[/python]
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 1:36 pm

This should already initialize the module.
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 1:38 pm

Nothing happens if I remove that line.
Well, it does not initialize it. It now says "no module named pawnbridge". I'm unsure whether it's possible to extend a given boost.python instance with another library.
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 1:43 pm

Where did you place the extension and how does your import line looks like?
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 1:48 pm

This is a SourceMod extension. It is loaded after Source.Python is loaded.

Testscript is (from boost.python now). It is under plugins/pbtest/pbtest.py.

Code: Select all

import pawnbridge
from core import echo_console

@Event
def game_start(game_event):
    echo_console('This is a test: {:s}'.format(pawnbridge.greet()))
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 2:06 pm

Well, that complicates things. :D

Is your extension on the search path?
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 2:18 pm

In co-work with your-name-here, I debugged a little bit. This is what comes out:
The attachment 30.10.2014 15_15_47.jpg is no longer available
(bigger: http://img.unsuspicious.de/c5c33.png)
You see that this is definitely the same python instance running. Guess, it doesn't work either. :confused:
Attachments
30.10.2014 15_15_47.jpg
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 2:40 pm

That's good news! Can you import modules of Source.Python (_events, _memory, etc.)? https://docs.python.org/3.4/c-api/import.html#c.PyImport_ImportModule
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 3:01 pm

Yes, works: http://img.r4nz.de/d2565.png
I guess the way is right that it doesn't lookup my dll for PyInit_pawnbridge, but adding it to sys.path doesn't seem the solution.
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 3:21 pm

Have you tried to call PyInit_pawnbridge manually? You can also try to add a module like we do in Source.Python. https://github.com/Source-Python-Dev-Team/Source.Python/blob/master/src/core/modules/export_main.cpp#L74
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 3:32 pm

User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 3:39 pm

Yes, that's why you need to call your initialization function.
def() is the function which can be used to expose C++ functions and callable objects as Python functions in the current scope.
Chrisber
Junior Member
Posts: 21
Joined: Thu Jul 19, 2012 10:25 pm

Postby Chrisber » Thu Oct 30, 2014 3:40 pm

I call the init func. It doesn't work.
I also tried:

Code: Select all

   std::wstring x = Py_GetPath();
   x += L";D:\\C++\\Source\\SrcDS\\games\\css\\cstrike\\addons\\sourcemod\\extensions";
   Py_SetPath(x.c_str());

But it has no effect :/
User avatar
Ayuto
Project Leader
Posts: 2195
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Postby Ayuto » Thu Oct 30, 2014 3:44 pm

Could you please post the current code?

Return to “General Discussion”

Who is online

Users browsing this forum: No registered users and 151 guests