How to do an "early return" of an import under Nose?

751 Views Asked by At

I'm curating a large number of unit tests for a large Python project. We use nose to do our test discovery and execution. I have some test files that really shouldn't be run in certain conditions. For instance, maybe I have a test module that should never be run on Windows (only on Mac and Linux).

Here are some solutions I have used:

  1. Mark test methods or classes with conditions using Nose's excellent attrib plugin.
  2. Use unittest.skipIf() on test methods or classes
  3. Use nose's pattern exclusions to skip files with windows in the name, for instance.

My complaint about 1 & 2 is that these force me to import the module, which is at least a waste of time and could possibly cause errors if there are platform dependent imports. I don't like #3 because I feel like it is brittle, and not easily apparent when reading the test case that it will be skipped. All three seem to depend excessively on the interaction between the test and the test runner, I'd like something that is just in the test.

I would like to do something like the following at the top of the test module:

"""This module should not be run on Windows"""
import platform
if platform.system() == 'Windows':
    <stop reading this module.  nothing to see here>

# do the tests.

How can I tell Python or Nose to stop reading the module, but that there is no error? I guess I am looking for the import equivalent of an early return.

3

There are 3 best solutions below

0
On BEST ANSWER

Under Nose and unittest, the SkipTest exception is treated specially - it's not a failure. Thus, the following code will stop execution, and no error will be reported to the unittest runner:

import unittest
import platform
if platform.system() == 'Windows':
  raise unittest.case.SkipTest("The rest of this code will not be run on Windows.")
0
On

The ability to return early from the execution of a module has been proposed before but it received some negative votes and the feature was not added to the language.

You can read the mailing list thread, but generally it was not felt that the problem of having to indent large parts of a module by an extra level was not a good enough reason to add this "return" feature. Some said that almost all code in modules should be inside functions and classes anyway, leaving almost no module-level code that would be subject to this problem.

2
On

You can raise ImportError there with that message. The caller will likely exit with an uncaught exception explaining showing that error, but it can catch the ImportError if necessary.