Почему происходит сбой Python/C API на PyRun_SimpleFile?

Я экспериментировал с внедрением различных языков сценариев в приложение C++, в настоящее время я пробую Stackless Python 3.1. Я пробовал несколько учебных пособий и примеров, которые я могу найти, чтобы попытаться запустить простой скрипт из приложения.

Py_Initialize();

FILE* PythonScriptFile = fopen("Python Scripts/Test.py", "r");
if(PythonScriptFile)
{
    PyRun_SimpleFile(PythonScriptFile, "Python Scripts/Test.py");
    fclose(PythonScriptFile);
}

Py_Finalize();

По какой-то странной причине выполнение этого фрагмента кода приводит к нарушению прав доступа по адресу:

    PyRun_SimpleFile(PythonScriptFile, "Python Scripts/Test.py");

Я искал в Интернете других с похожей проблемой и нашел только одну. Их единственным решением был обходной путь, который кажется возможным только в более старой версии Python: создание объекта файла python и возвращение FILE* из этого объекта файла Python в PyRun_SimpleFile, Однако такие вызовы функций недоступны, API-интерфейс Python 3.1 создает файловые объекты из файлового дескриптора и возвращает файловые дескрипторы, но PyRun_SimpleFile функция по-прежнему требует FILE*,

Я в растерянности относительно того, как запускать любые сценарии из файла, если не считать загрузки всего файла в память вручную и запуска его в виде гигантской строки, что, конечно, не является практическим решением.

Что дает? Как я могу выполнить эту задачу, если в API есть внутренняя ошибка?

Обновление: мне удалось собрать Stackless Python 3.1 из исходного кода, и все же сбой остается полностью неизменным, несмотря на использование той же самой библиотеки времени выполнения C. И мой проект, и исходник Stackless Python 3.1 созданы с использованием компилятора Visual Studio 2010 C++ и среды выполнения C. Я больше не догадываюсь о том, что может решить эту проблему, за исключением модификации Python для использования имени файла, а не ФАЙЛА *. Еще один ужасный обходной путь.

7 ответов

Это работает для меня на Python 3:

 PyObject *obj = Py_BuildValue("s", "test.py");
 FILE *file = _Py_fopen_obj(obj, "r+");
 if(file != NULL) {
     PyRun_SimpleFile(file, "test.py");
 }

Надеюсь, это будет полезно.

Я получил похожий сбой и сделал следующее:

   PyObject* PyFileObject = PyFile_FromString("test.py", "r");
   PyRun_SimpleFileEx(PyFile_AsFile(PyFileObject), "test.py", 1);

Обратите внимание, что это было в Python 2.7, хотя. Я не знаю, изменился ли API в 3.x.

Ваш код работает правильно на моей установленной версии Python 2.6. Я также собрал 3.1.2 без стека из исходного кода, и он работал правильно. Это было с g++ 4.4.3 на Ubuntu 10.04. Если вы работаете в Windows, вы можете проверить, что и стек без стека, и ваш код созданы для одной и той же среды выполнения C.

Это звучит как проблема несовпадающих API. Если ваш код и среда выполнения Python были скомпилированы с использованием разных компиляторов или даже разных опций компилятора, то доступ к FILE* может привести к нарушению прав доступа. Можете ли вы еще раз проверить, правильно ли вы создали свой C-код?

Вы упоминаете, что встраиваете Python в свое приложение C++. Имейте в виду, что Python - это C-код, скомпилированный как C-код. Возможно, это источник проблемы?

Приведенный ниже код выполнит модуль test.py. Python будет искать модуль в наборе путей. Таким образом, путь должен быть обработан в первую очередь.

Py_Initialize();

string path = "Python Scripts/";

//Set the path
PyRun_SimpleString("import sys");
string str = "sys.path.append('" + path + "')";
PyRun_SimpleString(str.c_str());

//Dont use test.py as it actually searches sub module test>>py
PyObject * moduleName = PyUnicode_FromString("test");
PyObject * pluginModule = PyImport_Import(moduleName);

if (pluginModule == nullptr)
{
    PyErr_Print();
    return "";
}

//Do the executions here

//clean up
Py_DECREF(moduleName);
Py_DECREF(pluginModule);
Py_DECREF(transformFunc);
Py_DECREF(result);

Py_Finalize();

Если вы построили свой тест с VC 2010, у вас наверняка возникнут проблемы - VC9 (VS 2008) и VC10 (VS 2010) имеют взаимно несовместимые библиотеки поддержки DLL, которые обычно требуются (реализуйте printf, файловый ввод-вывод и тому подобное). Вы не можете смешивать их, если они включают стандартные библиотеки, что делает сборка Python.

У вас всегда есть возможность использовать gcc (например, Cygwin или mingw) или загрузить Visual Studio 2008 Express, что должно хорошо работать для экспериментов по внедрению Python. Я использовал оба со стандартной сборкой Python 2.7.6.

А как насчет этого решения:

Py_SetProgramName(argv[0]);
Py_Initialize();
PyRun_SimpleString("execfile(\"ex30.py\")");
Py_Finalize();

куда ex30.py это имя скрипта Python, который я запускаю.

Другие вопросы по тегам