LINUX.ORG.RU

sys.path разный у интерпретатора и при Py_Initialize()

 


2

3

Такая беда чайника у меня. Пришлось разбираться с Питоном.

Окружение: Linux Mint, python 2.7.

Надо сделать embedded python приложение. Проблема: sys.path отличается при запуске интерпретатора и при загрузке из C программы. Python code:

import sys
print sys.path

Если вызов из программы, то получается так:

['/usr/lib/python2.7/', 
'/usr/lib/python2.7/plat-x86_64-linux-gnu', 
'/usr/lib/python2.7/lib-tk', 
'/usr/lib/python2.7/lib-old', 
'/usr/lib/python2.7/lib-dynload']

Если вызов интерпертатором python filename.py (я заменил точкой название текущей директории, чтобы скрыть юзернэйм):

['.', 
'/usr/lib/python2.7', 
'/usr/lib/python2.7/plat-x86_64-linux-gnu', 
'/usr/lib/python2.7/lib-tk', 
'/usr/lib/python2.7/lib-old', 
'/usr/lib/python2.7/lib-dynload', 
'/usr/local/lib/python2.7/dist-packages', 
'/usr/lib/python2.7/dist-packages', 
'/usr/lib/python2.7/dist-packages/PILcompat', 
'/usr/lib/python2.7/dist-packages/gst-0.10', 
'/usr/lib/python2.7/dist-packages/gtk-2.0', 
'/usr/lib/pymodules/python2.7', 
'/usr/lib/python2.7/dist-packages/ubuntu-sso-client', 
'/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode']

Как сделать так, чтобы они не отличались? Что пробовал: import site (не лечит проблему вообще никак).

★★★

На вскидку, что говорит комманда env на счёт питоновских путей окружения (типа PYTHONPATH)? Нет ли какого-нить virtenv?

true_admin ★★★★★
()
#!/bin/bash

python - <<EOF
print '***from script***'
import sys
print '>'+'\n>'.join(sys.path)
EOF

gcc -I/usr/include/python2.7 -lpython2.7 \
  -x c -o a.out - <<EOF
#include <Python.h>
int main(int argc, char *argv[]) {
  Py_SetProgramName(argv[0]);
  Py_Initialize();
  PyRun_SimpleString(
    "print '***from c***'\\n"
    "import sys\\n"
    "print '>'+'\\\\n>'.join(sys.path)\\n");
  Py_Finalize();
  return 0;
}
EOF

./a.out
$ ./run.sh
***from script***
>
>/usr/lib/python2.7
>/usr/lib/python2.7/plat-i386-linux-gnu
>/usr/lib/python2.7/lib-tk
>/usr/lib/python2.7/lib-old
>/usr/lib/python2.7/lib-dynload
>/usr/local/lib/python2.7/dist-packages
>/usr/lib/python2.7/dist-packages
>/usr/lib/python2.7/dist-packages/PILcompat
>/usr/lib/python2.7/dist-packages/gst-0.10
>/usr/lib/python2.7/dist-packages/gtk-2.0
>/usr/lib/pymodules/python2.7
***from c***
>/usr/lib/python2.7
>/usr/lib/python2.7/plat-i386-linux-gnu
>/usr/lib/python2.7/lib-tk
>/usr/lib/python2.7/lib-old
>/usr/lib/python2.7/lib-dynload
>/usr/local/lib/python2.7/dist-packages
>/usr/lib/python2.7/dist-packages
>/usr/lib/python2.7/dist-packages/PILcompat
>/usr/lib/python2.7/dist-packages/gst-0.10
>/usr/lib/python2.7/dist-packages/gtk-2.0
>/usr/lib/pymodules/python2.7
anonymous
()
Ответ на: комментарий от anonymous

Спасибо! Но к сожалению не получилось. То есть PyRun_SimpleString все делает правильно. Но когда я использую PyImport_Import то окружение не читается. Я, видимо, что-то делаю не так. Но что я никак не пойму.

atoku ★★★
() автор топика
Ответ на: комментарий от atoku

После адского греппинга сырцов питона и дебиановского debsrc (говнокодище ппц!) я понял твою проблему: у тебя embeeded-версия автоматом не включает /usr/lib/python2.7/site.py . Судя по гуглу, проблема не только у тебя. Так что можешь либо сделать import site, либо погуглить отчего такая фигня (сорри, я затрахался разбирать дебиановскую помойку).

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

Спасибо. Видимо так и есть. На MacOSX все подключилось. Надо посмотреть как подгрузить правильный site.py

atoku ★★★
() автор топика
Ответ на: комментарий от anonymous

Вот простой код на С++, который я нарезал из того что есть. Я добавляю текущую директорию к пути. Это можно тоже убрать.

#include <iostream>
using namespace std;

#include <assert.h>

extern "C" {
#include <Python.h>
}


//---------------------------------------------------------------------
static string remove_file_extension( const string& filename ) 
{
    size_t lastdot = filename.find_last_of( "." );
    if ( lastdot == std::string::npos ) 
      return filename;

    return filename.substr( 0, lastdot ); 
}

//--------------------------------------------------------------------
int main( int argc, char* argv[] )
{
  PyObject *pModule;
  PyObject *pDict;
  PyObject *pName;

  // Initialize the Python Interpreter
  Py_Initialize();

  // Adding the current path to python path
  string python_path = string( Py_GetPath() );
  python_path = ".:" + python_path;
  char* pc = strdup( python_path.c_str() ); 
  PySys_SetPath( pc );
  free( pc );

  // Printing the path
  cout << python_path << endl;

  Py_Finalize();

  return 0;
}

Вывод программы получается такой (порезал на строки для удобства):

.:/usr/lib/python2.7/:/usr/lib/python2.7/plat-x86_64-linux-gnu:
/usr/lib/python2.7/lib-tk:/usr/lib/python2.7/lib-old:
/usr/lib/python2.7/lib-dynload

Теперь вот питонов код

import sys
print sys.path

Вывод такой (разбил на строки для удобства):

['.', 
'/usr/lib/python2.7', 
'/usr/lib/python2.7/plat-x86_64-linux-gnu', 
'/usr/lib/python2.7/lib-tk', 
'/usr/lib/python2.7/lib-old', 
'/usr/lib/python2.7/lib-dynload', 
'/usr/local/lib/python2.7/dist-packages', 
'/usr/lib/python2.7/dist-packages', 
'/usr/lib/python2.7/dist-packages/PILcompat', 
'/usr/lib/python2.7/dist-packages/gst-0.10', 
'/usr/lib/python2.7/dist-packages/gtk-2.0', 
'/usr/lib/pymodules/python2.7', 
'/usr/lib/python2.7/dist-packages/ubuntu-sso-client',
 '/usr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode']

Как видим, что списки разные. Последний список включает первый.

Еще раз спасибо за помощь!

atoku ★★★
() автор топика
Ответ на: комментарий от atoku

судя по коду так и должно быть.

  • getpath.c, 459: calculate_path: собирает пути для Py_GetPath() (и 3-х других интерфейсных функций этого файла), вызывается один раз при вызове любой из интерфейсных функций. Ищет пути смотря на такой список входных данных: PYTHONPATH, Py_GETENV("PYTHONPATH"), Py_GetPythonHome(), getenv("PATH"), Py_GetProgramName(). О site.py тут не нет ничего, как нет и загрузки модулей питона. По сути просто объединение найденных строк. Зато есть одна переменная: Py_FrozenFlag.
  • pythonrun.c, 426: Py_InitializeEx: Тут происходит вызов Py_GetPath() и запись его с помощью функции PySys_SetPath в переменную sys.path.
  • pythonrun.c, 481-482: Py_InitializeEx: И только тут происходит инициализация модулей из site.py. И здесь уже стоит обратить внимание на переменную Py_NoSizeFlag.
anonymous
()
Ответ на: комментарий от anonymous

Я попытался установить Py_NoSiteFlag перед вызовом Py_Initialize. Однако, это не помогло. Как правильно сказал true_admin, не все site.py подгружаются. Видимо, проблема в том, где ищутся site.py и какой из них выбирается initsite. Я пытаюсь с этим разобраться - но пока без особого успеха.

atoku ★★★
() автор топика
Ответ на: комментарий от atoku

в Py_GetPath не собираются никогда пути до загружаемых модулей, это не эквивалент sys.path. я только это хотел сказать. сходи по ссылке первой в том сообщении, там код который собирает путь для Py_GetPath.

anonymous
()
Ответ на: комментарий от atoku

дак, тебе нужно получить sys.path? импортируешь модуль sys, запрашиваешь у него атрибут по имени path, разбираешь список по элементам и уносишь к себе.

anonymous
()
Ответ на: комментарий от anonymous

Не работает. Вот что я делаю (кусок кода):

 // Getting sys.path
  PyObject *pXMname;
  pXMname = PyString_FromString( "sys" );

  PyObject *pXM;
  pXM = PyImport_Import( pXMname );

  PyObject *pXMdict;
  pXMdict = PyModule_GetDict( pXM );
  
  PyObject *pXMpath;
  pXMpath = PyDict_GetItemString( pXMdict, "path" );

  // Print every element of the list  
  size_t nl = PyList_Size( pXMpath );
  for ( size_t i = 0; i < nl; ++i )
    {
      PyObject *px;
      px = PyList_GetItem( pXMpath, i );

      const char* tmp = PyString_AsString( px );
      cout << tmp << endl;
    }

Как и ожидалось, никакой разницы нет. На самом деле Py_GetPath() возвращает тоже самое у меня. Извини, что-то не так в твоих рассуждениях. Да и не должно быть так сложно. Видимо, что-то в настройках моего дистрибутива (Linux Mint).

atoku ★★★
() автор топика
Ответ на: комментарий от atoku

давай начнем с начала. этот код возвращает правильный результат?

если не собирается то попробуй переставить -lpython2.7 самым последним аргументом gcc

anonymous
()
Ответ на: комментарий от atoku

а такой код не работает?

#!/bin/bash

gcc -I/usr/include/python2.7 \
  -x c -o a.out - -lpython2.7 <<EOF
#include <Python.h>
int main(int argc, char *argv[]) {
  Py_SetProgramName(argv[0]);
  Py_Initialize();
  // Getting sys.path
  PyObject *pXMname;
  pXMname = PyString_FromString( "sys" );

  PyObject *pXM;
  pXM = PyImport_Import( pXMname );

  PyObject *pXMdict;
  pXMdict = PyModule_GetDict( pXM );

  PyObject *pXMpath;
  pXMpath = PyDict_GetItemString( pXMdict, "path" );

  // Print every element of the list
  size_t i,nl = PyList_Size( pXMpath );
  for ( i = 0; i < nl; ++i )
    {
      PyObject *px;
      px = PyList_GetItem( pXMpath, i );

      const char* tmp = PyString_AsString( px );
      printf("+%s\n", tmp);
    }

  PyRun_SimpleString(
    "print '***from c***'\\n"
    "import sys\\n"
    "print '>'+'\\\\n>'.join(sys.path)\\n");


  Py_Finalize();
  return 0;
}
EOF

./a.out

anonymous
()
Ответ на: комментарий от anonymous

Извини, что заняло так долго. Да, вижу, что распечатано одно и то же. Хм... Не понимаю.

atoku ★★★
() автор топика
Ответ на: комментарий от anonymous

А может это быть разница между gcc, g++ или С и С++? -- исправлено: нет, разницы нет. Странно, что все теперь работает. Спасибо за помощь. Буду собирать путь через импорт sys.

atoku ★★★
() автор топика
Последнее исправление: atoku (всего исправлений: 1)
Ответ на: комментарий от anonymous

Спасибо еще раз. Все проверю завтра и тогда отмечу как все разрешилось и тогда поставлю галочку, что проблема решена.

atoku ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.