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

TST: Added scipy import warning unit test to test_distances.py. #1141

Merged
merged 6 commits into from
Jan 1, 2017

Conversation

tylerjereddy
Copy link
Member

A small PR with draft code to test for scipy related import exception handling in MDAnalysis/analysis/distances.py as per the uncovered lines.

It is particularly tricky to deal with this stuff because scipy is a sort of pseudo-dependency. I don't think we'll even get coverage credit because I think the full test build has scipy and python doesn't support module unloading / hiding, etc., unless you have a really creative idea.

So, actually I think this mostly increases coverage of a minimal build (where scipy is absent and the Exception will actually be triggered at the module level & then caught / a warning issued), which I suppose is also still important, but probably not accounted for in the coverage badge.

@orbeckst
Copy link
Member

@richardjgowers did something creative with mock somewhere to test missing modules... can't just quite remember what it was, perhaps ncdf. That might be a way to test scipy missing even in full build.

@tylerjereddy
Copy link
Member Author

Alright, I'll wait for him to comment. If I'm not mistaken, Python 3.3 onward has unittest.mock, but it is not in the standard library for Python 2, which is why I didn't go that route. But I agree that mocking is really powerful for tests if we can start using it at some point.

@orbeckst
Copy link
Member

orbeckst commented Dec 29, 2016 via email

with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
import MDAnalysis.analysis.distances
assert w == []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do like checking that we don't warn when not necessary though!


class TestImportWarnings(TestCase):

def test_no_exception_scipy_module_level(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can wrap this with the PR I put up, so it always issue a warning. Then split the else: branch of this if into a separate test that only runs when the scipy module is present.

@tylerjereddy
Copy link
Member Author

The new decorator from @richardjgowers has been merged in. I'll now refactor my tests a bit accordingly. Hopefully by later today.

@richardjgowers
Copy link
Member

The new failing test looks like we're not allowed relative imports in the testsuite, I don't remember why this is, but I think @mnmelo might. It might have been that they stop coverage reporting working?

@tylerjereddy
Copy link
Member Author

I banned relative imports in the testsuite a while ago in #189. The reason for doing this was fairly idiosyncratic, but presumably I can fix the relate import(s) without too much hassle here?

@richardjgowers
Copy link
Member

richardjgowers commented Dec 30, 2016 via email

@tylerjereddy
Copy link
Member Author

tylerjereddy commented Dec 30, 2016

Even with the new decorator, it still doesn't work in my hands. I have to conda remove scipy on my machine to get the test to pass. Specifically, your decorator will only raise an ImportError if used in this manner:

@block_import('scipy')
def test_stuff(self):
  import scipy # this is properly blocked   

But it won't work if another module is importing scipy, which is what I want to test:

@block_import('scipy')
def test_stuff(self):
  import MDAnalysis.analysis.distances # this can still import scipy from my machine install   

@richardjgowers
Copy link
Member

I'm fairly happy the decorator is working, I just think the scipy import is happening before the test - the first time the module is imported elsewhere in the testing process. I think all future imports of the module are using a cached? version of the module, so the scipy import try/except block is happening only once.

The below test will pass/fail depending on if analysis.distances is imported at the top of the module. I'm not sure if there's a way to either a) clear the cache of imported modules and make the entire module setup run again, OR b) define that the import test must run before all others. b) seems fragile because the tests should all be state independent really..

from numpy.testing import assert_warns
import warnings

from MDAnalysisTests.util import block_import

# Comment / uncomment this line
from MDAnalysis.analysis import distances as d

class TestImportWarn(object):
    @block_import('scipy')
    def test_warning(self):
        warnings.simplefilter('always')

        def do_this():
            import MDAnalysis.analysis.distances as d
            return d

        assert_warns(ImportWarning, do_this)

@tylerjereddy
Copy link
Member Author

This solves the issue:

198     def setUp(self):                                                            
199         sys.modules.pop('MDAnalysis.analysis.distances', None)  

All tests pass on my machine using the above setUp so I've pushed the adjustment. If Travis is also happy with that, I'll aim to cover the other import warning in this module so we can bring its coverage up to 100 %. Thanks for the insight -- I think you'll agree this was a bit tricky.

@tylerjereddy
Copy link
Member Author

Ok, that worked, so I've now added in one more test to bring the coverage up to 100 % for MDAnalysis.analysis.distances, assuming Travis is happy with this new test to cover the contact_matrix exception.

@richardjgowers
Copy link
Member

Awesome, I didn't know it was that simple to fix. Looking good now

@richardjgowers richardjgowers merged commit 6e51830 into develop Jan 1, 2017
@tylerjereddy tylerjereddy deleted the warning_check_distances branch January 1, 2017 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants