Sorting sys.path: first virtualenv, then /usr

纵然是瞬间 提交于 2019-12-23 12:24:28

问题


Why does sys.path contain /usr/... before directories from my virtualenv?

I create the virtualenv with --system-site-packages

The sys.path looks like this at the moment:

/home/my-virtualenv/src/foo
/usr/lib/python2.7/site-packages        <--- /usr paths should be below 
/usr/lib64/python2.7/site-packages
/home/my-virtualenv/lib/python27.zip
/home/my-virtualenv/lib64/python2.7
/home/my-virtualenv/lib64/python2.7/plat-linux2
/home/my-virtualenv/lib64/python2.7/lib-tk
/home/my-virtualenv/lib64/python2.7/lib-old
/home/my-virtualenv/lib64/python2.7/lib-dynload
/usr/lib64/python2.7
/usr/lib/python2.7
/usr/lib64/python2.7/lib-tk
/home/my-virtualenv/lib/python2.7/site-packages

I want all paths outside my virtualenv (/usr...) to be below the paths of the virtualenv.

Otherwise crazy things happen: I install a package with pip. Pip tells me that the new version is installed (pip freeze | grep -i ...) but the import does use the one from /usr/lib/python2.7/site-packages

I can't use --no-site-packages in my context.

Is there a way to sort sys.path?

Why I use system-site-packages

There seems to be no straight forward way to make single libraries from the global site-packages available in the virtualenv. See this question: make some modules from global site-packages available in virtualenv

There are packages like python-gtk which are very hard to install in a virtualenv.


回答1:


Edit, after discussion:

"I want all paths outside my virtualenv (/usr...) to be below the paths of the virtualenv. [...] It needs to be sorted."

Then, just sort your sys.path before the first import happens. Given a certain path prefix corresponding to the location of your virtalenv, this approach likely is sufficient:

sys.path = sorted(sys.path, key=lambda x: x.startswith(prefix), reverse=True)

sorted()'s sorting behavior is stable: the original order is preserved for items with same sort key. Here, only two sort keys are used: True and False. You need to come up with a reliable way to set your prefix (You might want to hard-code it, or determine it based on the current working directory, I am sure you find a way).

Original answer (still valid, in general):

You did not want to elaborate on your requirements and application scenario too much, so I provide a more general answer: you may need to overthink your approach, and maybe not expect virtualenv to entirely solve your problem.

In certain situations, virtualenv is just not the perfect solution. It is a compromise, and one side of this compromise is exhaustively described in this article: https://pythonrants.wordpress.com/2013/12/06/why-i-hate-virtualenv-and-pip/

In many scenarios virtualenv serves a splendid purpose and does its job very fine! It helped me a lot, for sure, especially for development purposes. In other scenarios, it is either not a complete solution or even a bad solution.

So, there are a few different options now that I see:

  1. Use virtualenv, but take control over those things that you need to have changed. For instance, modify sys.path from within your package before doing a certain import. While some might consider this "not clean", it for sure is a very quick way to efficiently and reliably control directory search order. sys.path.insert(1, foo) is actually used by many packages and test environments. It not uncommon at all. This approach may provide you with a working solution after just one minute of work. Give it a try!
  2. If you think that virtualenv in your case does not behave as documented or clearly shows buggy behavior, then please report you findings to the project. They will surely appreciate your concise feedback.
  3. If you think that virtualenv does not provide the level of isolation or control that you need in your application case, you might want to look at other options, such as Docker or Vagrant, or fully-features virtual machines.



回答2:


You can simply prepend desired path before module imports. Kinda hacky, but should solve your problem

import sys
sys.path.insert(1, '/home/my-virtualenv/lib/python2.7/site-packages')

import lalala



回答3:


If you're using interactive shell you can set PYTHONSTARTUP, or also set a few bash aliases to modify your PYTHONPATH in the ways that you prefer. You can also modify the activate files activate.csh, activate_this.py in the bin directory of your virtualenv; or the site.py file as another response mentioned.

pip + virtualenv is - as it has been pointed out not a very friendly combo for system-wide packages, i.e. there is no default flag for say use system numpy or package x,y when building an environment. Although as has been suggested in comments I would also recommend building with --no-site-packages and then importing specifically what you need from /usr/lib




回答4:


Below straight solution resolve your problem:

1- Open my-virtualenv/lib/python2.7/site.py file for edit.

2- Append below lines of sort algorithm(or any code that resolve your problem) at the end of this file(without first line indent):

prefix = __file__.rsplit(os.sep, 3)[0]

Below code line Suggested by @Jan-Philip Gehrcke:

sys.path = sorted(sys.path, key=lambda x: x.startswith(prefix), reverse=True)

3- Run your program and enjoy

This solution helping you to sort the sys.path list without adding annoying lines to body of your program.

Note: The site module is automatically imported during initialization. The automatic import can be suppressed using the interpreter’s -S option.




回答5:


A easy way I found to solve this problem was just to add your virtualenv site-packages folder to the $VIRTUAL_ENV/lib/python2.7/site-packages/_virtualenv_path_extensions.pth file or just enter in shell after activate the environment:

$ add2virtualenv $VIRTUAL_ENV/lib/python2.7/site-packages

this would force to appear the folder before your systems folders as I notice it does for the others paths added.

I believe this is not the cleanest solution, but indeed virtualenv strangely order the paths.

Another observation is when I start ipython the sys.path appears in a reasonable order, but when inside the python interpreter doesn', not sure why tho.



来源:https://stackoverflow.com/questions/28239484/sorting-sys-path-first-virtualenv-then-usr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!