2016-05-10 5 views
1

Заглядывая, как красиво обернуть перечисления в Python с помощью swig, я наткнулся на ответ this.Создание перечисления SWIG в последующем наблюдении на Python

Я пытаюсь создать перечислений так:

#ifndef PYTHON_ENUM 
#define PYTHON_ENUM(x) enum x 
#endif 

PYTHON_ENUM(TestName) { 
    foo=1, 
    bar=2 
}; 

PYTHON_ENUM(SomeOtherName) { 
    woof, 
    moo 
}; 

Я использую .i файл, как этот

%module test 
%{ 
#include "test.h" 
%} 

%typemap(constcode) int { 
    PyObject *val = PyInt_FromLong(($type)($value)); 
    SWIG_Python_SetConstant(d, "$1", val); 
    const char *name = "$typemap(enum_realname,$1_type)"; 
    PyObject *e = PyDict_GetItemString(d, name); 
    if (!e) PyDict_SetItemString(d, name, e = PyDict_New()); 
    PyDict_SetItemString(e, "$value", val); 
} 
#define PYTHON_ENUM(x) \ 
     %typemap(enum_realname) int "x"; \ 
     %pythoncode %{ \ 
     x = _test.x\ 
     %} \ 
     enum x 

%include "test.h" 

Проблема в том, что это бросает AttributeError: модуль «_test» не имеет атрибута 'TestName' Это связано с тем, что сгенерированный test.py определяет словарь TestName следующим образом:

TestName = _test.testEnum  # This should be in the last line 

_test.foo_swigconstant(_test) 
foo = _test.foo 

_test.bar_swigconstant(_test) 
bar = _test.bar 

В то время, когда вызывается TestName = _test.testEnum, _test не имеет члена testEnum и выдает исключение. После запуска либо foo_swigconstant(), либо bar_swigconstant() генерируется _test.testEnum, и TestName = _test.testEnum не подводит. Таким образом, эта строка должна идти после регистрации значений перечисления. Он работает, если я делаю это вручную, но я должен делать это каждый раз, когда SWIG запускает какую-то проблему. То же самое относится и к другому перечислению. Могу ли я изменить файл интерфейса для этого?

ответ

0

Я не вижу эту ошибку. Я компилирую и связываю этот пример следующим образом:

swig3.0 -c++ -python test.i 
g++ -c -fPIC test_wrap.cxx -I/usr/include/python2.7 
g++ -shared -g test_wrap.o -o _test.so 

Затем он работает точно так же, как предложил Флексо. Обратите внимание, что сгенерированные объекты test.py и _test.so находятся в одном каталоге. Я использую Python 2.7.6 и SWIG 3.0.7 под Debian.

Я пробовал то же самое с использованием VS2013 и SWIG 3.0.8. Случается, что typemap(constcode) генерирует функции woof_swigconstant и т. Д., А не вставляет const-код, который просто предоставляет статические словари. Вы пробовали это с помощью SWIG 3.0.7?

Я посмотрел немного больше на это. Использование SWIG 3.0.8 и VS2013. Сгенерированный код, например. запись в foo:

SWIGINTERN PyObject *foo_swigconstant(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { 
    PyObject *module; 
    PyObject *d; 
    if (!PyArg_ParseTuple(args,(char*)"O:swigconstant", &module)) return NULL; 
    d = PyModule_GetDict(module); 
    if (!d) return NULL; 
    { 
    PyObject *val = PyInt_FromLong((int)(foo)); 
    SWIG_Python_SetConstant(d, "foo", val); 
    const char *name = "TestName"; 
    PyObject *e = PyDict_GetItemString(d, name); 
    if (!e) PyDict_SetItemString(d, name, e = PyDict_New()); 
    PyDict_SetItemString(e, "foo", val); 
    } 
    return SWIG_Py_Void(); 
} 

Следовательно, генерируется запись функции. Использование SWIG 3.0.7 и Python 2.7.6 на Debian, я получаю следующее

{ 
    PyObject *val = PyInt_FromLong((int)(foo)); 
    SWIG_Python_SetConstant(d, "foo", val); 
    const char *name = "TestName"; 
    PyObject *e = PyDict_GetItemString(d, name); 
    if (!e) PyDict_SetItemString(d, name, e = PyDict_New()); 
    PyDict_SetItemString(e, "foo", val); 
    } 

вставляется сразу после SWIG_InstallConstants(d,swig_const_table);. Я считаю, что что-то изменилось с SWIG 3.0.7 до 3.0.8.

+0

Спасибо за ваш ответ. Я собираю его с VS2012 за то, что стоит, но я не делаю ничего по-другому. Дело в том, что в сгенерированном .py-файле порядок операций приводит к AttributeError. После того, как я играл с кодом, я обнаружил, что, переключая порядок операций, как я упоминал выше, исправляет проблему, но кажется довольно контрпродуктивным, чтобы отредактировать созданный файл py. Я работаю с python 3.5 и SWIG 3.0.7, если это имеет значение. –

+0

Хорошо. Я использую Python 2.7 и SWIG 3.0.7, и я получаю 'TestName = _test.TestName' перед' foo = _test.foo'. Я не получаю никаких записей '_test.bar_swigconstant (_test)'. Он отлично работает для меня. Странный. Вы помните опцию C++? –

+0

Пробовал его здесь, используя VS2013 и SWIG 3.0.8, и он не работает. Я буду сравнивать сгенерированные файлы C++ и .py. Ошибка в сгенерированном коде C++. –