Как предварять путь к sys.path в Python?

Описание проблемы:

Используя pip, я обновил до последней версии запросов (версия 2.7.0, с pip show requests давая местоположение /usr/local/lib/python2.7/dist-packages). Когда я import requests и распечатать requests.__version__ в интерактивной командной строке я вижу версию 2.2.1. Оказывается, что Python использует предустановленную версию запросов Ubuntu (requests.__file__ является /usr/lib/python2.7/dist-packages/requests/__init__.pyc - нет /user/local/lib/...).

Из моего исследования, этот факт вызван изменениями Ubuntu в пути поиска Python (я запускаю Ubuntu 14.04) путем добавления пути к пакету Python в Ubuntu (для моей машины это происходит в usr/local/lib/python2.7/dist-packages/easy-install.pth). В моем случае это вызывает apt-get версия запросов, которая предварительно упакована с Ubuntu, для использования, а не версия pip, которую я хочу использовать.

Что я ищу:

Я хочу глобально добавить путь к каталогу установки pip к пути поиска Python (sys.path), до пути к установочному каталогу Python в Ubuntu. Поскольку запросы (и многие другие пакеты) используются во многих моих скриптах Python, я не хочу вручную изменять путь поиска для каждого файла на моем компьютере.

Неудовлетворительное решение 1: использование virtualenv

Использование virtualenv приведет к ненужным изменениям в моей машине, поскольку мне придется переустанавливать каждый пакет, существующий в глобальном масштабе. Я только хочу обновить пакеты Ubuntu до пакетов pip.

Неудовлетворительное решение 2. Изменение easy-install.pth

поскольку easy-install.pth перезаписывается каждый раз easy-install используется, мои изменения в easy-install.pth будет удален, если будет установлен новый пакет. Эта проблема затрудняет обслуживание пакетов на моей машине.

Неудовлетворительно (но лучший из тех, что у меня есть) Решение 3: Добавление отдельного файла.pth

В той же директории, что и easy-install.pth, я добавил zzz.pth с содержанием:

import sys; sys.__plen = len(sys.path)
/usr/lib/python2.7/dist-packages/test_dir
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)

Этот файл читается site.py когда Python запускается. Так как его имя файла приходит после easy-install.pth буквально, это потребляется site.py после этого. Взятые вместе, первая и последняя строки файла предваряют путь к sys.path (эти строки были взяты из easy-install.pth).

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

PYTHONPATHs следуют по путям Ubuntu

Другой ответ на переполнение стека не сработал для меня. мой PYTHONPATH пути идут после путей в easy-install.pth, который использует тот же код, который я упоминаю в "Неудовлетворительное решение 3", чтобы предвосхитить его пути.

Заранее спасибо!

8 ответов

Это не рекомендуется *, но из вашего скрипта Python вы можете сделать

>>> import sys
>>> b = sys.path
>>> sys.path = ['/home/anand/'] + b
>>> print(sys.path)
['/home/anand/', '', '/usr/local/lib/python2.7/dist-packages/_pdbpp_path_hack', '/usr/local/lib/python2.7/dist-packages/goose-0.0.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/jieba-0.33-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/cssselect-0.9.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nanoservice-0.1.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nanomsg-1.0a2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/msgpack_python-0.4.2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/DecisionTree-2.2.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/nudepy-0.2-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/wsgilog-0.3-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/distribute-0.7.3-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/PIL-1.1.7-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/MySQL_python-1.2.5-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/munkres-1.0.7-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/parsedatetime-1.4-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/argparse-1.3.0-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/tusker-0.1-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/SQLAlchemy-1.0.3-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/numpy-1.9.2-py2.7-linux-x86_64.egg', '/usr/local/lib/python2.7/dist-packages/turkic-0.2.5-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/scikits.bootstrap-0.3.2-py2.7.egg', '/usr/local/lib/python2.7/dist-packages/pyvision-0.1-py2.7-linux-x86_64.egg', '/home/anand/playspace/languages/python_pkgs/ets', '/usr/local/lib/python2.7/dist-packages/Scrapy-1.1.0dev1-py2.7.egg', '/usr/lib/python2.7/dist-packages', '/home/anand/playspace', '/home/anand/workspace/pyvision/src', '/home/anand/playspace/yapf', '/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/local/lib/python2.7/dist-packages/Orange/orng', '/usr/local/lib/python2.7/dist-packages/PIL', '/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/wx-3.0-gtk2']
>>>

После этого ваши импорты будут смотреть на предварительно подготовленный путь, прежде чем искать в другом месте.

  • - Для жесткого кодирования пути и невозможности запуска скрипта где-либо еще.

Вам не нужно возиться с путём pip, Python фактически обрабатывает его автоматически, по моему опыту. Похоже, у вас установлены два питона. Если вы введете:

which pip
which python

какие пути вы видите? Если они не находятся в одной папке / bin, то это ваша проблема. Я предполагаю, что у питона, на котором вы работаете (возможно, оригинального системного), нет установленного собственного пипа. Возможно, вам просто нужно убедиться, что путь к питону, который вы хотите запустить, должен находиться перед /usr/ bin в вашем.bashrc или.zshrc

Если это правильно, то вы должны увидеть, что:

which easy_install

использует тот же путь, что и используемая вами установка на python, может быть, в /usr/ local / bin. Тогда просто запустите:

easy_install pip

И начните устанавливать правильные пакеты для питона, который вы используете.

Ответ на прямой вопрос

Вы можете создать каталог с именем sitecustomize в вашем site-packages каталог. Мы превратим это в sitecustomize модуль, как описано здесь (Python 2 здесь). В частности:

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

в sitecustomize каталог создать файл с именем __init__.py и добавьте манипуляции, которые вы хотите выполнить там. Очень простой пример:

import sys
sys.path = ['/your/path/to/pip/install'] + sys.path

В твоем случае я думаю your/path... было бы /usr/local/lib/python2.7/dist-packages, Возможно, вы захотите сделать что-то более сложное, но это грубо sys.path и запускается всякий раз, когда запускается python (например, запускает интерпретатор в командной строке или запускает скрипт python из файла).

Предостережение

Я не большой сторонник этого - это немного тупой способ делать то, что вы хотите. Но вы конкретно говорите, что с помощью virtualenv это нежелательно для вас, и вы хотите внести изменения "глобально", и я думаю, что это будет делать то, что вы хотите.

Мысли по основной проблеме

Я думаю, что ответ @ Fivetentaylor находится на правильном пути здесь - кажется, вы используете pip от одной установки с python исполняемый для другого. Маскировка этого путаницей с путём может очень запутать очень быстро. Я определенно гарантирую, что у вас есть отдельный pip за каждую установку python и вы используете это. Это должно держать структуру каталогов для отдельных установок отдельно. В противном случае вы заставляете одну установку использовать пакеты из разных каталогов установки. Нет проблем технически, но запутанно с точки зрения логистики.

Использование virtualenv приведет к ненужным изменениям в моей машине, поскольку мне придется переустанавливать каждый пакет, существующий в глобальном масштабе. Я только хочу обновить пакеты Ubuntu до пакетов pip.

Нет, вы можете использовать --system-site-packages,

редактировать

# make your new virtualenv
user@darkstar:~$ mkvirtualenv --system-site-packages max
(max)user@darkstar:~$ python
>>> pprint(sys.path)
['',
 '/home/user/.virtualenvs/max/lib64/python27.zip',
 '/home/user/.virtualenvs/max/lib64/python2.7',
 '/home/user/.virtualenvs/max/lib64/python2.7/plat-linux2',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-tk',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-old',
 '/home/user/.virtualenvs/max/lib64/python2.7/lib-dynload',
 '/usr/lib64/python2.7',
 '/usr/lib/python2.7',
 '/usr/lib64/python2.7/lib-tk',
 '/home/user/.virtualenvs/max/lib/python2.7/site-packages',
 '/usr/lib64/python2.7/site-packages/google_api_python_client-1.2-py2.7.egg',
 '/usr/lib64/python2.7/site-packages',
 '/usr/lib64/python2.7/site-packages/PIL',
 '/usr/lib64/python2.7/site-packages/gtk-2.0',
 '/usr/lib64/python2.7/site-packages/IPython/extensions']

Как видите, путь этого virtualenv включает системный путь. Чтобы проверить, работает ли он, я установил пакет для всей системы после создания virtualenv.

root@darkstar:~: pip install igraph
Collecting igraph
  Downloading igraph-0.1.8-py2.py3-none-any.whl (119kB)
    100% |████████████████████████████████| 122kB 1.7MB/s
Collecting ipython (from igraph)
  Downloading ipython-3.2.1-py2-none-any.whl (3.4MB)
    100% |████████████████████████████████| 3.4MB 203kB/s 
Installing collected packages: ipython, igraph
Successfully installed igraph-0.1.8 ipython-3.2.1
root@darkstar:~: python -c 'print __import__("igraph")'
<module 'igraph' from '/usr/lib64/python2.7/site-packages/igraph/__init__.pyc'>

(max)user@darkstar:max$ python -c 'print __import__("igraph")'
<module 'igraph' from '/usr/lib64/python2.7/site-packages/igraph/__init__.pyc'>

Очевидно, что то, что установлено внутри virtualenv, имеет приоритет над общесистемными библиотеками.

Я верю, что ответить на ваши потребности.

Что ж, альтернативы, представленные другими, очень приемлемы и могут быть даже лучше. Однако, если вы намереваетесь использовать sys.path() Кстати, тогда просто относитесь к нему как к списку и используйте метод вставки.

import sys
sys.path.insert(0, "path_to_pip") 
from subprocess import call
call("sudo pip install requests") 

Я бы сделал это с sitecustomize как описано в site.py Docs. Этот файл импортируется после начальной sys.path настроен, и вы можете использовать его для изменения sys.path произвольно по мере необходимости.

Я использовал его в качестве системного администратора для включения пользовательских версий релизов, и он отлично справляется со своей задачей.

https://docs.python.org/2/library/site.html

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

Глядя на site.py, я вижу, что существует определенный порядок разрешения пути, который вызывает файлы конфигурации при разрешении каталогов пакетов сайта.

Я думаю, что это дает вам три варианта, которые я вижу:

  1. Используйте virtualenv --system-site-packages согласно ответу @bufh.
  2. Используйте pip user installs для установки пакетов, которые вам нужны по пути перед стандартными пакетами сайта.
  3. Используйте sitecustomize, чтобы переписать ваш sys.path (например, чтобы сначала поместить ваши локальные каталоги).

Хотя ответ bufh решит вашу проблему сейчас, вы, вероятно, обнаружите, что будет какой-то другой пакет, в котором вы не хотите использовать версию, предоставленную Ubuntu. Вот почему вы хотите использовать virtualenvs для управления версиями пакетов (а не пытаться переопределить системные версии).

Как вы заметили, порядок sys.path устанавливает порядок обнаружения пакетов python. Это означает, что изменение sys.path влияет на то, как скрипты python находят свои импорты, как написанные вами скрипты, так и предоставленные Ubuntu. Учитывая, что скрипты python используются в программах Ubuntu, можно "интересным образом" "сломать" Ubuntu, изменив, какую версию пакетов Python используют программы Ubuntu (что является причиной существования dist-пакетов).

Чтобы избежать этого, был создан virtualenv, который эффективно позволяет использовать различные наборы пакетов. Теперь есть множество утилит, которые облегчают использование и управление virtualenvs. Вероятно, наиболее интересным для вас является pipsi, который создает virtualenv для каждого сценария и не требует его активации.

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