Skip to content
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 2.7 Full: sqlite3 module doesn't work in virtualenv #492

Closed
domenkozar opened this issue Apr 28, 2013 · 32 comments
Closed

Python 2.7 Full: sqlite3 module doesn't work in virtualenv #492

domenkozar opened this issue Apr 28, 2013 · 32 comments
Assignees
Labels
Milestone

Comments

@domenkozar
Copy link
Member

>>> import sqlite3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/nix/store/yzj6p5f7iyh247pwxrg97y3klm6d0cni-python-2.7.3/lib/python2.7/sqlite3/__init__.py", line 24, in <module>
    from dbapi2 import *
  File "/nix/store/yzj6p5f7iyh247pwxrg97y3klm6d0cni-python-2.7.3/lib/python2.7/sqlite3/dbapi2.py", line 27, in <module>
    from _sqlite3 import *
ImportError: No module named _sqlite3

@chaoflow @garbas can you reproduce?

@domenkozar
Copy link
Member Author

Seems like C compiled module doesn't get propagated.

@cillianderoiste
Copy link
Member

IIUC the typical python we use in nix is a wrapper which explicitly adds the paths to some c modules such as readline and sqlite3. virtualenv puts a copy of the unwrapped python into the virtualenv it creates, so it knows nothing about the python c modules.

One way to work with this is to install e.g. python27Packages.sqlite3 into a profile and add the site-packages path in that profile to your PYTHONPATH. From there you should be able to use the virtualenv as normal. I think it's handy to put all the c python modules in the nix profile and plain python stuff in the virtualenv. This is something like the setup described here: https://nixos.org/wiki/Using_Profiles_for_Development_Environments

@chaoflow has a more advanced setup which can be used to bootstrap and maintain a familiar python development environment: https://github.com/chaoflow/tpv.http/blob/master/Makefile

@domenkozar
Copy link
Member Author

What about providing virtualenv a python with all modules available?

@cillianderoiste
Copy link
Member

For example, patching virtualenv so that it copies the nix python wrapper instead of the python binary into the virtualenv? The problem with that is it would get garbage collected. If, instead we link to the current version of the wrapped python (e.g. /run/current-system/sw/bin/python) that will change with any update, also potentially breaking the virtualenv. IIUC this is always a problem with using virtualenv on nix without a dedicated profile (or similar). Any dependencies provided by nix may disappear after garbage collection, e.g. libxml for lxml which would break the virtualenv.

Maybe you have something else in mind?

I guess the motivation is to have virtualenv work on nix in the same way as it would on other distros. After upgrading a conventional distro don't you run into problems with virtualenv too? How does it work on gentoo? Maybe I'm imagining problems that don't exist :)

@peti
Copy link
Member

peti commented Jun 12, 2013

The problem with [virtualenv so that it copies the nix python wrapper instead of the python binary] is it would get garbage collected.

My understanding is that if the virtualenv derivation refers to pythonFull -- which it uses to copy that script into generated environments --, then pythonFull would not be garbage collected as long as someone references virtualenv.

Or am I missing something?

@cillianderoiste
Copy link
Member

Isn't pythonFull the wrapped version of python? So IIUC, you would install virtualenv, then use it to create a virtualenv, which would copy the wrapped python into venv/bin/python then you'd update your system and garbage collect. Nix wouldn't know about your copy of the wrapped python in venv/bin/python, right? So the wrapper would still have the old paths. I guess the best way to find out is to try it, but I don't see how it would work myself.

@peti
Copy link
Member

peti commented Jun 12, 2013

Okay, I see your point. I don't understand, though, how use of plain
python instead of python-wrapper alleviates that particular issue in any
way? If python is re-built, then a virtual environment generated with
the old version has a dangling reference, too, doesn't it?

@cillianderoiste
Copy link
Member

How about using myEnvFun to create your environment with pythonFull, you can also install virtualenv and use it in that environment https://nixos.org/wiki/Howto_develop_software_on_nixos?

@domenkozar
Copy link
Member Author

ln -s /nix/store/ppag7jq94mbq3wy1m4ah7z3jdhshgsma-python-sqlite3-2.7.5/lib/python2.7/site-packages/_sqlite3.so lib/python2.7/site-packages/ works, I'm still figuring out why it's not done

@domenkozar
Copy link
Member Author

@chaoflow @cillianderoiste what about putting following at the end of activate script:

export PYTHONPATH=/nix/store/c6463w4i2cg23sblknkqg3kr0k365yba-python2.7-virtualenv-1.10/lib/python2.7/site-packages:/nix/store/z7pci148ppkfkql275n00qvmf6brfszs-python-readline-2.7.5/lib/python2.7/site-packages:/nix/store/ppag7jq94mbq3wy1m4ah7z3jdhshgsma-python-sqlite3-2.7.5/lib/python2.7/site-packages:/nix/store/79pdp574ifsfpdw4dg5vhn1wwqqgqjqm-python-curses-2.7.5/lib/python2.7/site-packages:/nix/store/jphvspsmv66fx7m183ffzyblx3vqgdy7-python-recursive-pth-loader-1.0/lib/python2.7/site-packages:/nix/store/hhaf38aymksj1srybhr81xdd1l71sj60-python2.7-setuptools-0.9.8/lib/python2.7/site-packages```

@cillianderoiste
Copy link
Member

I think I'd prefer to add the paths to the current profile site-packages directory ~/.nix-profile/lib/python2.7/site-packages/ (including the recursivePthLoader) rather than the /nix/store paths, since that should survive more updates. We should also take care to the right thing inside a myEnv environment.

Perhaps we just need to add a default virtualenv.ini or otherwise specify extra-search-dir parameters (if that does what I think it does). https://pypi.python.org/pypi/virtualenv#environment-variables-and-configuration-files

@domenkozar
Copy link
Member Author

Yeah, let's put the symlinks from profile (no idea how to do that, but let's see).

extra-search-dir only tells virtualenv where to find setuptools/pip eggs (which we should use to achieve better purity), so that's not really an option.

From #pypa:

23:50 < iElectric> I'm still searching for a way to tell virtualenv about "extra packages"
23:51 < iElectric> the idea is to whitelist what system packages can it see
23:56 < dstufft> iElectric: don't think you can easily right now
23:56 < dstufft> without symlinking
23:57 < dstufft> I think Nick was working on something to enable that in the import lib Sig though

@brodul
Copy link
Contributor

brodul commented Oct 13, 2013

Tnx for the workaround. I run into this issue to.

@shlevy
Copy link
Member

shlevy commented Apr 5, 2014

@iElectric What's the status on this? IMO having references to store paths outside the store (other than (possibly indirect) gcroots) is generally a bad idea.

@domenkozar
Copy link
Member Author

Virtualenv is still broken when python updates. We need to fix this somehow.

@shlevy
Copy link
Member

shlevy commented Apr 5, 2014

Is it urgent enough that we should mark this for the 14.04 milestone?

@domenkozar
Copy link
Member Author

Since the problem exists from the very beginning, I don't think it's urgent.
On Apr 5, 2014 10:57 PM, "Shea Levy" [email protected] wrote:

Is it urgent enough that we should mark this for the 14.04 milestone?


Reply to this email directly or view it on GitHubhttps://github.com//issues/492#issuecomment-39651966
.

@cillianderoiste cillianderoiste self-assigned this Apr 16, 2014
@cillianderoiste
Copy link
Member

I noticed that the following works:

virtualenv py27; PYTHONHOME=/nix/store/v96gd7xfgr9llf3kj968wlppcmvfsqx8-python-2.7.6-wrapper py27/bin/python -c "import sqlite3"

I was thinking about patching the virtualenv generated site.py to add the relevant path(s) to sys.path. It's amazing, but the contents of site.py are actually inline, and compressed: https://github.com/pypa/virtualenv/blob/develop/virtualenv.py#L1847 so that could be tricky.

Perhaps modifying it after it gets written out https://github.com/pypa/virtualenv/blob/develop/virtualenv.py#L1193 (using python, patched into the virtualenv.py file via the nix expression) would work, but it's all a bit crazy. The code would need to get the path to the wrapper for the version of python specified e.g. virtualenv --python=python2.7 and then possibly add the corresponding lib/pythonX.X/site-packages to sys.path, and maybe also process the .pth files.

Maybe there's an easier way to tell it to do whatever python normally does with PYTHONHOME. Unless there are better ideas, I'll play around with that a bit.

@cillianderoiste
Copy link
Member

There's an easier way. We can get virtualenv to create a sitecustomize.py with:

import sys
sys.path.append("/nix/store/7j2sss6x13p7mxm3wwf7jhdjjj9k8vrq-python-2.7.6-wrapper/lib/python2.7/site-packages")

@domenkozar
Copy link
Member Author

It has to point to the profile, otherwise once the wrapper is gc, it will break again.

@cillianderoiste
Copy link
Member

I don't think there's any way around that though. I think the virtualenv needs to be recreated after garbage collection e.g.

$ virtualenv venv
$ ls -l venv/lib/*
total 468
lrwxrwxrwx 1 goibhniu users    81 Apr 17 18:44 _abcoll.py -> /nix/store/jr5gs24iyhmcd9zj3fd3r3i2x293fn4d-python-2.7.6/lib/python2.7/_abcoll.py
-r--r--r-- 1 goibhniu users 28144 Apr 17 18:44 _abcoll.pyc
lrwxrwxrwx 1 goibhniu users    77 Apr 17 18:44 abc.py -> /nix/store/jr5gs24iyhmcd9zj3fd3r3i2x293fn4d-python-2.7.6/lib/python2.7/abc.py
-r--r--r-- 1 goibhniu users  6484 Apr 17 18:44 abc.pyc
lrwxrwxrwx 1 goibhniu users    80 Apr 17 18:44 codecs.py -> /nix/store/jr5gs24iyhmcd9zj3fd3r3i2x293fn4d-python-2.7.6/lib/python2.7/codecs.py
...

I think the best we can do here is to make virtualenv provide the same modules provided by the wrapper by default.

EDIT: brevity

@cillianderoiste
Copy link
Member

This seems to work:

diff --git a/virtualenv.py b/virtualenv.py
index 0f5ae79..cfd19bd 100755
--- a/virtualenv.py
+++ b/virtualenv.py
@@ -1191,6 +1191,11 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear, sy
     site_filename_dst = change_prefix(site_filename, home_dir)
     site_dir = os.path.dirname(site_filename_dst)
     writefile(site_filename_dst, SITE_PY)
+    wrapper_path = join(prefix, "lib", py_version, "site-packages")
+    writefile(
+        join(site_dir, 'sitecustomize.py',),
+        "import sys; sys.path.append('%s')" % wrapper_path
+    )
     writefile(join(site_dir, 'orig-prefix.txt'), prefix)
     site_packages_filename = join(site_dir, 'no-global-site-packages.txt')
     if not site_packages:

@domenkozar
Copy link
Member Author

it's an improvement, so +1

@cillianderoiste
Copy link
Member

Cool! I'll do a bit more testing and if it looks OK (and there are no concerns) I'll push it tomorrow.

cillianderoiste added a commit that referenced this issue Apr 18, 2014
Note: simply calling `virtualenv .` will not produce a ./bin/python
which can import e.g. sqlite3, using `virtualenv --python=python2.7`
will, if python2.7 is python27Full (the wrapped python). I'm not sure
if this is a bug or a feature.
@cillianderoiste
Copy link
Member

I'll close this since I believe the initial issue is solved.

We could create a new ticket to tackle the issue of virtualenvs surviving garbage collection, but I'm not sure there is a nice way. At any rate, we should document the situation and encourage people to use nix instead of virtualenv where possible and otherwise to recreate their virtualenvs after garbage collection.

@domenkozar
Copy link
Member Author

Good job!

@copumpkin
Copy link
Member

I'm getting this with just nix-shell and straight nix python (with no virtualenv). Should I open a separate ticket?

let
  pkgs = import <nixpkgs> {};
in
{ stdenv ? pkgs.stdenv }:

with pkgs; stdenv.mkDerivation {
  name = "python-nix";
  version = "0.1.0.0";
  src = ./.;
  buildInputs = [ python nixops sqlite ];
}

results in an environment that can't import sqlite3 properly.

@copumpkin
Copy link
Member

Oh never mind, I needed pythonPackages.sqlite3

badmutex added a commit to badmutex/dotfiles that referenced this issue May 9, 2015
a virtualenv created useing `virtualenv venv` will not be able to import
modules such as sqlite3:

NixOS/nixpkgs#492

In order for virtualenv wrapped python to do so:

```
$ virtualenv --python=`which python2.7` venv
```
@jgeerds
Copy link
Member

jgeerds commented Mar 1, 2016

This also affects the tox test runner (which uses an unpatched version of virtualenv internally). This means that it is not possible to execute python2.7 tests for a django project/app because of the missing _sqlite3 module.

@domenkozar
Copy link
Member Author

I think we should include ncurses and sqlite by default. They're both very light and convenient.

@domenkozar domenkozar added this to the 16.03 milestone Mar 10, 2016
@domenkozar domenkozar reopened this Mar 10, 2016
@FRidh
Copy link
Member

FRidh commented Mar 13, 2016

@jgeerds could you show an example of how you use the tox test runner with Nix?

@FRidh
Copy link
Member

FRidh commented Oct 13, 2016

Since #19309 we don't have separate modules anymore except tkinter, which is like a 'normal' Python package: pythonPackages.tkinter.

@FRidh FRidh closed this as completed Oct 13, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

8 participants