Яйца в пути перед переменной среды PYTHONPATH

Если у меня есть пакеты, установленные из easy_install, яйца добавляются к sys.path перед элементами в переменной PYTHONPATH.

Например, если у меня установлен пакет egg с именем foo, а также пакет с именем foo в текущем каталоге, а затем выполните следующее:

PYTHONPATH="." python
>>> import foo

Это будет использовать яичную версию foo вместо локального каталога. Проверка sys.path показывает, что яйца размещаются перед предметами из PYTHONPATH. Это кажется сломанным. Есть ли способ переопределить это поведение?


person jterrace    schedule 12.05.2011    source источник
comment
Вы уверены, что он не подберет пакет из текущего каталога? Обычно первая запись в sys.path всегда должна быть пустой строкой, т. е. сначала она будет искать в текущем каталоге.   -  person kynan    schedule 12.01.2013
comment
Нет, потому что загрузчик яиц добавляет свой путь, поэтому он оказывается перед текущим каталогом.   -  person jterrace    schedule 13.01.2013
comment
Он предшествует другим пакетам site, но первая запись в sys.path всегда '' при интерактивном запуске, см. документы. Для меня это так, что бы ни PYTHONPATH.   -  person kynan    schedule 13.01.2013


Ответы (3)


К сожалению, это делается с помощью жестко запрограммированного шаблона глубоко внутри setuptools/command/easy_install.py. Вы можете создать пропатченный setuptools с отредактированным шаблоном, но я не нашел простого способа расширить easy_install извне.

При каждом запуске easy_install будет заново создавать файл easy_install.pth. Вот быстрый скрипт, который вы можете запустить после easy_install, чтобы удалить верхний и нижний колонтитулы из easy_install.pth. Вы можете создать сценарий оболочки-оболочки для запуска сразу после easy_install:

#!/usr/bin/env python
import sys
path = sys.argv[1]
lines = open(path, 'rb').readlines()
if lines and 'import sys' in lines[0]:
    open(path, 'wb').write(''.join(lines[1:-1]) + '\n')

Пример:

% easy_install gdata
% PYTHONPATH=xyz python -c 'import sys; print sys.path[:2]'
['', '/Users/pat/virt/lib/python2.6/site-packages/gdata-2.0.14-py2.6.egg']

% ./fix_path ~/virt/lib/python2.6/site-packages/easy_install.pth
% PYTHONPATH=xyz python -c 'import sys; print sys.path[:2]'
['', '/Users/pat/xyz']

Для большего пояснения, вот формат easy-install.pth:

import sys; sys.__plen = len(sys.path)
./gdata-2.0.14-py2.6.egg
import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)

Две строки import sys являются причиной появления яиц в начале пути. Мой скрипт просто удаляет эти sys.path строки.

person samplebias    schedule 13.05.2011
comment
Это действительно раздражает, что сайт пользователя не имеет приоритета, когда пути/яйца добавляются в sys.path. На машине, где у меня нет sudo, я не нашел способа переопределить общесистемные установленные пакеты пакетами, установленными пользователем. Это выглядит как довольно серьезный недостаток в способе сборки sys.path. - person kynan; 12.01.2013
comment
У меня недостаточно представителей, чтобы прокомментировать ответ samplebias, но вот ссылка на отчет об ошибке, в котором приводится конкретный патч, предложенный samplebias для устранения этой проблемы в setuptools: bugs.launchpad.net/ubuntu/+source/distribute/+bug/821000 - person charlesreid1; 20.11.2013

Рассмотрите возможность использования параметра командной строки -S для подавления обработки *.pth:

python -c 'import sys; print("\n".join(sys.path))'
python -S -c 'import sys; print("\n".join(sys.path))'

https://docs.python.org/3/library/site.html#site.main

Вы также можете использовать -S с site.main(), чтобы отложить обработку *.pth до времени выполнения, скажем, чтобы захватить исходный sys.path для добавления:

export PYTHONPATH=$(
  PYTHONPATH='' \
  python -c 'import sys; \
    sys.path.extend(sys.argv[1:]); old=list(sys.path); \
    import site; site.main(); \
    [ old.append(p) for p in sys.path if p not in old ]; \
    sys.path=old; \
    print ":".join(sys.path)' \
  $EXTRA_PATH $ANOTHER_PATH)

python -S ... # using explicit PYTHONPATH
  • Начать с явного пустого PYTHONPATH
  • Добавить к sys.path явно с расширением
  • Импортируйте сайт и позвоните site.main()
  • Добавьте новые пути к старому пути, а затем установите его в sys.path.
  • Печатать с ":" для PYTHONPATH
  • python -S желателен для последующих запусков только с использованием $PYTHONPATH
  • python -S может быть или не быть желательным при настройке PYTHONPATH (в зависимости от того, нужно ли вам расширять sys.path перед расширением)
person bsb    schedule 17.08.2017

Я сделал что-то вроде следующего, чтобы добавить системный путь при запуске исполняемого файла Python верхнего уровня:

import sys
sys.path = ["<your python path>"] + sys.path

Часто "<your python path>" для меня включает использование атрибута __file__ для относительного поиска пути, который включает модуль верхнего уровня для моего проекта. Это не рекомендуется для использования в производстве яиц, хотя я, кажется, не возражаю против последствий. Может быть другая альтернатива __file__.

person nak    schedule 19.02.2013