-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
python: can not use imperatively installed packages as libraries #10597
Comments
Whether this is to be expected I am not sure, perhaps @domenkozar or @chaoflow can explain? I still find this confusing myself as well. Anyhow, I can recommend using nix-shell. E.g.
gives you an environment which has numpy and all its dependencies in it. You can then simply run
In this case scipy, and the Jupyter Notebook are installed along with all dependencies. |
You use an unsupported workflow, I believe. Please, use nix-shell & friends instead. (Nix+python people should know more particular details.) |
Well, I think this should be supported. That is inconvenient. Whenever I want to use packages such as Maybe hard code the path |
+1. I tried to implement it once: #792 |
Btw, I think it should be controlled by environment variables, not hardcoding. If, for instance, python picked up $NIX_PROFILES and appended ./lib/pythonVERSION/site-packages to each element, it'd be easy to have a pure / clean python by simply clearing $NIX_PROFILES. |
In general (as said before) I'm against this. But I do understand there is a need/expectation it works this way, so I'll think about it. The main problem is there is just one $PYTHONPATH so setting it for a profile might lead to weird side-effects. |
Is there any reason against this? Append the local profile path with python version in |
TL;DR: the general reason against this is that you add (impurely) things to scope, which isn't always a good thing. Would all python stuff would now magically "see" what you have in your profile? What would happen if it would now have multiple different versions of the same things in scope (e.g. built with a differently configured python)? On a standard distro all versions on a system are "kept consistent" but with nix we impose no such restrictions, and some packages don't handle well if you attempt to plug-in "incompatible versions". |
Yes, there is only one |
+1 Another user here who found this behavior unexpected :) But then I'm very new to NixOS, so it's not surprising that my expectations are somewhat "traditional". I (think I) understand the reasons not to modify On a vanilla instance of zsh under NixOS, (I realize fully well it's problematic -- I'm redefining As an aside, isn't there perhaps a configuration option when compiling python/perl that sets the path to search for libs? I'm pretty sure there is one for perl, python probably has something similar... Wouldn't that be a clean way to do this? |
To make matters worse, it looks like different python packages have more than one way of doing it (no pun on perl intended). See for instance >>> import flask
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/dvl/.nix-profile/lib/python2.7/site-packages/flask/__init__.py", line 19, in <module>
from jinja2 import Markup, escape
File "/nix/store/q8hxg7pvsnrax4jk141cbqx68m0jx33w-python2.7-Jinja2-2.7.3/lib/python2.7/site-packages/jinja2/__init__.py", line 33, in <module>
from jinja2.environment import Environment, Template
File "/nix/store/q8hxg7pvsnrax4jk141cbqx68m0jx33w-python2.7-Jinja2-2.7.3/lib/python2.7/site-packages/jinja2/environment.py", line 13, in <module>
from jinja2 import nodes
File "/nix/store/q8hxg7pvsnrax4jk141cbqx68m0jx33w-python2.7-Jinja2-2.7.3/lib/python2.7/site-packages/jinja2/nodes.py", line 18, in <module>
from jinja2.utils import Markup
File "/nix/store/q8hxg7pvsnrax4jk141cbqx68m0jx33w-python2.7-Jinja2-2.7.3/lib/python2.7/site-packages/jinja2/utils.py", line 520, in <module>
from markupsafe import Markup, escape, soft_unicode
ImportError: No module named markupsafe Unlike numpy (see OP), flask is reachable after installation, and even some of the dependencies which were fetched automatically (jinja2). Others (like markupsafe), however, are not, and have to be specified manually. Which is why Why This really should be made consistent somehow, if at all possible. I guess the problem is that this is entirely up to the author of the python package in question, and if I understand it correctly, there are several competing tools for generating nixpkgs from PyPI? To round the confusion off, when python is installed as a system package and flask via nix-env, flask is unreachable once again because the directories under Again, all of this works flawlessly with perl. System-installed packages are consistently symlinked under A similar solution for python would go a long way towards alleviating the concerns described in this thread, and would be consistent with the principle of least surprise. |
Installing python packages with |
I understand that (I've read the rest of the thread), I just agree with the OP and others above that current behavior is confusing from the perspective of an outside user (i.e. someone who is not a dev on NixOS) and addressing this (not necessarily be enabling this type of workflow, see below) would ease the transition for newcomers. The semantics of "installing" something is that afterwards, you're able to use it in the way it's intended to be used. In the case of an executable, this means running it; in the case of a library, this means accessing it as a resource. It's counterintuitive that one works, but the other doesn't (I guess because with bin directories, it's only a matter of setting up some symlinks and having a correct I guess what I'm saying is that if installing libraries with Please note that I wouldn't dream of arguing about the technical design decisions on a project I still know very little about (though I find it fascinating, extremely useful, and am trying to learn more). This is all about user experience design -- communicating the technical decisions to (new) users, who may have a specific set of (wrong) expectations, in the most frictionless way possible.
Well, originally, I was trying to pull in some python packages via But the same logic applies here, perhaps even more -- what's the purpose of installing a python library as a system package, if not to define an extended standard library of sorts, i.e. modules that one happens to use a lot? I've now effectively achieved this anyway by emending my Unfortunately, unlike with |
Yes, it takes effort and time to get used to Nix tooling. But you have to understand that supporting imperative installation of python packages brings a lot of problems. It's really hard to make it work reliably and I'd rather not support something than support it with lots of caveats and exceptions.
Coming from a traditional unix environment I understand the concern. But we don't install headers for C packages, so you're forced to use Nix tooling to build software. Same goes for Python, except the line between usage and development is very blurred.
We do offer alternatives, like using
I really recommend using
This is a documentation issue and I agree we should address it. |
At least
The same argument applies to bash. Why you support impurely
That is exactly what we want. (but not all python stuff, just the common packages and their dependency that we asked)
A sane person will not pull two same libraries into his profile. Maybe we can give a conflict warning/error message under such a abnormal case?
This does not mean that
I don't like to type In addition, according to my understanding, |
@zhou13 I also use Python a lot for modelling and such. While a bit off-topic, maybe my setup works for you. What I have is a Furthermore, there are some packages I develop and need and which are also included. Each of them has a release.nix file with buildPythonPackage, etc.
What also might be convenient for you is something like
in your I agree it is a bit inconvenient not to be able to access an interpreter directly with all the tools you need. Luckily only a couple of characters are needed :-) I guess the former (python.buildEnv) can also be used |
How does things like pip and easy_install factor into this discussion? |
It seems pretty clear to me that the OP wants something that the maintainers are not interested in implementing, so I don't see how this can be resolved without the issue opener providing some code. |
I think the solution to this would be to allow setting The builder for python packages can be extended to scan python imports and tell which package provides them. Test cases should probably not be installed so deps on tests wont be included. And then produce the propagated-user-env-pkgs metadata. Another option is to rename this file and patch python to process these. |
What some of you might be interested in is the following. Environment defined in separate
|
@FRidh thanks for sharing this. I believe this is currently the best/only option, but I would not count that method as imperative. Some time ago I opened a PR for adding runtime dependencies to matplotlib: #13939. This was rejected with the motivation that the right way to install packages was using the buildEnv function. I think this should be considered again, if people want to imperatively install python packages and submits patches that don't interfere other ways of installing other packages, can't those be accepted? |
@joelmo we have several methods for installing or building environments now, and there are still issues to be solved with those methods as well. Adding additional methods I fear will only make it more confusing and harder to maintain. |
A big issue for many is that #13939 was not a generic solution. A generic solution would be something like setting |
Actually why don't we patch .py files to use hard coded absolute imports? This would be more consistent with the RPATH approach of regular shared libraries and binaries. |
@knedlsepp Such approach definitely would make sense as well. I suppose with |
Note that in scripts we also add Python libraries to |
@FRidh I used your method to make the python layer (using anaconda mode) in Spacemacs work. It's easier than loading all "IDE" dependencies in every shell.nix for every Python project I'm working on. However it appears not all anaconda mode dependencies are available, but the layer no longer complains. The building of a custom python environment should be encouraged as the way to make things like this work. Although I wonder if this method is used for other languages like nodejs... etc. This does mean that for a proper dev environment you tend to have a user-profile language interpreter with minimal dependencies to make your IDE work, while having project specific interpreters inside a nix-shell. The downside is that usually layer/mode features that use the interpreter or compiler won't be using the project specific interpreter/compiler specified in the nix-shell, you just have to use a separate terminal to perform those actions, and you can't run everything inside emacs. FYI, with spacemacs, one can launch a terminal inside, and then run nix-shell inside there. For reference this is my # custom python environment with python packages embedded
# nixos isolates each language specific dependency, they are not automatically exposed to the interpreter
# note that this should not be used for development
# only for IDE integration and experiments
pythonEnv = with pkgs; buildEnv {
name = "pythonEnv";
paths = [
(with python27Packages; python.buildEnv.override {
extraLibs = [
setuptools
numpy
];
})
(with python35Packages; python.buildEnv.override {
extraLibs = [
setuptools
jedi
flake8
numpy
isort
yapf
pytest
];
})
];
}; |
In #25985 I propose using a The question would then be, how to enable this feature. There are I think two methods:
The suggestion
is not acceptable, as that would change the default. |
Option 3: Only look in |
The issue with env variables is that they leak. You may want to have it enabled for your Python "environment", but Python applications also become impure right away. Unless we explicitly clear this env var in our wrappers... |
Well, I want a global switch :-) If you don't then you don't have to enable it. |
Here's my (impure, heathen, infidel, sullied, etc) global switch, in export PYTHONPATH=$(find -L ~/.nix-profile -path "*/python*/site-packages" -type d | tr '\n' ':')$PYTHONPATH Notes:
|
Did anyone get |
@coretemp see https://gist.github.com/danbst/dd641c696f77f5465ef9c827fcbf1e2c, I am able to use
|
Looks interesting. If it is a general method, which it looks like, I would like to see it in the manual. |
@coretemp added a section to Wiki (https://wiki.nixos.org/wiki/Python#Emulating_virtualenv_with_nix-shell). I don't know whether others use this same technique, but it is definitely copypasted somewhere from internet. |
Additionally, |
I have worked around this by adding per-profile, version-specific I use Nix on Fedora. I am now able to import nix-installed usercustomize.py: nix_profiles = map(Path, os.environ.get("NIX_PROFILES", "").split())
python_version_majorminor = "{}.{}".format(
sys.version_info.major, sys.version_info.minor
)
site_packages_path = "lib/python{}/site-packages".format(python_version_majorminor)
profile_site_packages = filter(Path.exists,
map(lambda p: p / site_packages_path, nix_profiles)
)
sys.path.extend(map(str, profile_site_packages)) See usercustomize.py in my dotfiles for a full implementation. |
I marked this as stale due to inactivity. → More info |
nix-env -i python2.7 python2.7-numpy
python2.7
import numpy
I got
Is this expected?
The text was updated successfully, but these errors were encountered: