Яйца в пути до переменной окружения PYTHONPATH

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

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

PYTHONPATH="." python
>>> import foo

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

Ответы

Ответ 1

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

Каждый раз, когда выполняется easy_install, он восстанавливает файл easy_install.pth. Вот быстрый script, который вы можете запустить после easy_install, чтобы удалить верхний и нижний колонтитулы из easy_install.pth. Вы можете создать оболочку оболочки script, чтобы запустить ее сразу после 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 являются виновниками, вызывающими появление яиц в начале пути. Мой script просто удаляет те строки sys.path -munging.

Ответ 2

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

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

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

Ответ 3

Рассмотрите возможность использования опции командной строки -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 до продолжения)