nose-devs / nose

nose is nicer testing for python
http://readthedocs.org/docs/nose/en/latest/
1.36k stars 395 forks source link

nosetest does not honour virtual environments #973

Closed raffienficiaud closed 8 years ago

raffienficiaud commented 8 years ago

Suppose I just installed a virtualenv and some packages inside it

virtualenv myenv
. myenv/bin/activate
pip install nose 
pip install chumpy

and I have a test_case.py that looks like

import chumpy
import unittest

class TestKinematicTree(unittest.TestCase):
    pass

when I run nosetests test_case.py (from the virtualenv) I have

======================================================================
ERROR: Failure: ImportError (No module named chumpy)                  
----------------------------------------------------------------------

However, if I do

python -c "import nose; nose.main()"

it works without any problem (it works without any problem with python -m unittest discover ... as well). I tried with several nosetests options without any success. Any hint?

Thanks!

jszakmeister commented 8 years ago

Are you certain that you are running the one from the virtualenv? I do this all the time without any issue.

raffienficiaud commented 8 years ago

Yes, I am sure. I am running Ubuntu LTS 14.04, nose is installed on the system but I create an empty virtual environment:

$> cd sandbox/
$> virtualenv test_nose
$> . test_nose/bin/activate
$> pip install chumpy
$> pip install nose
$> pip list
argparse (1.2.1)
chumpy (0.66)
nose (1.3.7)
numpy (1.10.1)
pip (1.5.4)
scipy (0.16.1)
setuptools (2.2)
wsgiref (0.1.2)

$> mkdir test_test
$> touch test_test/__init__.py
$> vim test_test/test_1.py
$> more test_test/test_1.py
import unittest
import chumpy

class Test1(unittest.TestCase):
    def test1(self):
        self.assertTrue(True)

$> nosetests -w test_test/
E
======================================================================
ERROR: Failure: ImportError (No module named chumpy)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/nose/loader.py", line 411, in loadTestsFromName
    addr.filename, addr.module)
  File "/usr/lib/python2.7/dist-packages/nose/importer.py", line 47, in importFromPath
    return self.importFromDir(dir_path, fqname)
  File "/usr/lib/python2.7/dist-packages/nose/importer.py", line 94, in importFromDir
    mod = load_module(part_fqname, fh, filename, desc)
  File "/media/renficiaud/linux-data/Code/sandbox/toto/test_1.py", line 2, in <module>
    import chumpy
ImportError: No module named chumpy

$> python -m nose -v -w test_test/ 
test1 (toto.test_1.Test1) ... ok

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

$> which nosetests
/.../sandbox/test_nose/bin/nosetests
$> more `which nosetests`
#!/.../sandbox/test_nose/bin/python

# -*- coding: utf-8 -*-
import re
import sys

from nose import run_exit

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(run_exit())
jszakmeister commented 8 years ago

Hmmm... If I replace chumpy with pyserial, and try to import the serial package, it all works fine. So it seems like there's something going on with the chumpy import.

jszakmeister commented 8 years ago

I'm pretty sure something else is going on here (unrelated to Nose). I don't usually do this (I don't like installing random things on my machine), but I installed chumpy under a virtualenv and had zero issues running the test case you gave above.

raffienficiaud commented 8 years ago

How can I debug more?

jszakmeister commented 8 years ago

Can you import chumpy in your virtualenv? I'd start there. Beyond that, I'm not sure where to proceed, and unfortunately, don't have time to debug non-related issues. I'm sorry. :-(

raffienficiaud commented 8 years ago

yes I can import chumpy. Once I am inside python, everything is working well (eg. python -m nose xxx works as expected). The problem happens with nosetests only.

raffienficiaud commented 8 years ago

Also please note that it is working ok on OSX, but I tried on several LTS 14.04 instances and I hit the same issue (even in docker instance).

raffienficiaud commented 8 years ago

The problem comes from tmux apparently, seems related to https://github.com/sstephenson/rbenv/issues/369. Sorry for the noise.

jszakmeister commented 8 years ago

Once I am inside python, everything is working well (eg. python -m nose xxx works as expected). The problem happens with nosetests only.

Right... Hrmph.

Also please note that it is working ok on OSX, but I tried on several LTS 14.04 instances and I hit the same issue (even in docker instance).

I actually tested it in an Ubuntu 14.04.3 VM and it worked for me.

jszakmeister commented 8 years ago

The problem comes from tmux apparently, seems related to sstephenson/rbenv#369. Sorry for the noise.

Oh my, yeah, that makes perfect sense. That stinks, but I'm glad you noticed it. Thanks for reporting back!

raffienficiaud commented 8 years ago

For the record, it is a bash issue that caches commands. In that case, which nosetests points (deterministically) to the right executable, while bash cached the system installed one. Using hash -r clears the cache (see http://unix.stackexchange.com/questions/5609/how-do-i-clear-bashs-cache-of-paths-to-executables).

I did not know about the cache behaviour of bash.

raffienficiaud commented 8 years ago

Wait... that also means that, if I use virtualenv --system-site-packages myenv, I point to the system installed nose, in which nosetests has a shebang pointing to the system installed python...

Out of curiosity, why not promoting the use of the following syntax: python -m nose [options]. I find it quite convenient and apparently less error prone, and it just looks like the one that I use for unit tests with the official python package.

Do you want me to drop a line in the documentation about this issue?

jszakmeister commented 8 years ago

Wow, that's usually disabled by default on many distros and monkeying with the PATH usually resets the cache, so I'm surprised it bit you like this with using virtualenv. :-(

jszakmeister commented 8 years ago

Out of curiosity, why not promoting the use of the following syntax: python -m nose [options].

The ability to do that isn't present in all the Python versions currently supported by Nose.

Do you want me to drop a line in the documentation about this issue?

shrug On the one hand, I think most setups are more sane and would have behaved better. On the other hand, it obviously took you some time to track it down. If it can be short and informative, perhaps adding something to the "Installation and Quick Start" section on the main page would be good. The down side is that not everyone uses bash--I use both bash and zsh, depending on the environment--and you would not use hash -r under zsh, you'd use rehash. I don't want it to become directions for how to clear the hash on every shell. So, if it can be phrased appropriately, with bash as an example, then I think it could be useful. Otherwise, I'm kind of -0 on the idea (neutral, but leaning towards "no").

raffienficiaud commented 8 years ago

I meant a line on the python -m nose [options] syntax, not this weird behaviour of bash. But if this is something you do not want to promote (which I understand), it's fine :)

Please note however that the nosetests shebang is overriding the one of the environment (so in a virtualenv created with --system-site-packages, it points to the wrong python binary). A colleague told me that using /usr/bin/env python instead would do the trick.

Thanks a lot for your support.

jszakmeister commented 8 years ago

I meant a line on the python -m nose [options] syntax, not this weird behavior of bash. But if this is something you do not want to promote (which I understand), it's fine :)

You're right, I don't necessarily want to advocate the python -m nose syntax, in the sense that it's the preferred way of running nose--it's not. It would be okay to show it as an alternate way though, without giving preference to it--except may to say it's useful when using virtualenv with the --system-site-packages method to ensure you're running the correct version of Nose.

Please note however that the nosetests shebang is overriding the one of the environment (so in a virtualenv created with --system-site-packages, it points to the wrong python binary). A colleague told me that using /usr/bin/env python instead would do the trick.

That is done by setuptools at install time, and it's the correct thing to do. Using /usr/bin/env python just moves the problem, and makes the situation considerably worse. What version of Python is it? 2 or 3? Is it one from a virtualenv? If so, what if nose is not installed? Now you have an import error for Nose, or you're simply trying to execute it with the wrong version of Python.

You'd also hate for system-level Python scripts to default to that behavior, since many required packages may not be installed in your virtualenv. That would wreak all kinds of havoc.