Skip to content

[MRG] Refactor test_disk.py as per pytest design.#446

Merged
lesteve merged 8 commits intojoblib:masterfrom
kdexd:pytestify-test-disk
Dec 9, 2016
Merged

[MRG] Refactor test_disk.py as per pytest design.#446
lesteve merged 8 commits intojoblib:masterfrom
kdexd:pytestify-test-disk

Conversation

@kdexd
Copy link
Copy Markdown

@kdexd kdexd commented Dec 7, 2016

Third Phase PR on #411 (Succeeding PR #441)

This PR deals with refactor of tests in test_disk.py to adopt the pytest flavor.

  • assert_raises now derived from pytest because it removes two redundant layers from traceback. In a deliberately created failure, pytest.raises only highlights the last two lines in this traceback as opposed to unittests traceback (the complete one)...
/usr/lib/python3.5/unittest/case.py:727: in assertRaises
    return context.handle('assertRaises', args, kwargs)
/usr/lib/python3.5/unittest/case.py:176: in handle
    callable_obj(*args, **kwargs)
joblib/disk.py:53: in mkdirp
    os.makedirs(d)
  • Test cases have been separated out and parametrized using a decorator.

@kdexd
Copy link
Copy Markdown
Author

kdexd commented Dec 7, 2016

conftest.py will grow over time, probably we may end up emptying up joblib/test/common.py as well, if need be..

@kdexd kdexd changed the title Refactor test_disk.py as per pytest design. [MRG] Refactor test_disk.py as per pytest design. Dec 7, 2016
@kdexd
Copy link
Copy Markdown
Author

kdexd commented Dec 8, 2016

@lesteve Please review this code whenever you feel convenient 😄

('1.4M', int(1.4 * 1024 ** 2), None),
('120M', 120 * 1024 ** 2, None),
('53K', 53 * 1024, None),
('fooG', None, ValueError)])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Put the exception in a separate test function this way test_mem_str_to_bytes can be simpler.

assert_equal = _dummy.assertEqual
assert_not_equal = _dummy.assertNotEqual
assert_raises = _dummy.assertRaises
assert_raises = pytest.raises
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think I said somewhere else that I would have a different name to make it clear that it is not the stldlib assert_raises, maybe pytest_assert_raises.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there an advantage of using pytest.raises in the tests affected by this PR?

For the record, my personal preference is to always use assert_raises_regex in order to check the error message. I have seen cases where the test pass but the exception is raised for a completely different reason.

pytest has some way with a context manager of checking the error message by the way.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

pytest has some way with a context manager of checking the error message by the way.

Yeah quite convenient, have a look

from joblib.testing import fixture


@fixture(scope='function')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Just checking we don't actually need to write a fixture, provided we use tmpdir as the test function arguments and tmpdir.strpath in the test function body right?

Maybe this solution would have my preference.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Sure, I was fine the either way, although at one point I thought tmpdir.strpath would be a bit clumsy everywhere.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think what this is is me, as a new pytest user, being a bit wary about pytest magic ... Leave it like this is fine.

mkdirp(os.path.join(tmpdir_path, 'ham'))
mkdirp(os.path.join(tmpdir_path, 'ham'))
mkdirp(os.path.join(tmpdir_path, 'spam', 'spam'))
@parametrize(['text', 'exception', 'exc_substr'],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You don't need the parametrize here anymore, right?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I mean you are parametrizing over one item so there is no need to parametrize and you can use local variables into a standard test function.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Please refer this thread Coincidentially we wrote our comments at the same moment 😄

def test_memstr_to_bytes_exception(text, exception, exc_substr):
with pytest_assert_raises(exception) as excinfo:
memstr_to_bytes(text)
assert exc_substr in str(excinfo.value)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The "pytest" way of assert_raises_regex. Also there's just one test case but it looks better this way in my opinion.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

You don't need the parametrize here anymore, right?

@lesteve I was writing this comment simultaneously, well in variable names exception, text and exc_substr make the test body very generic. I chose to write it this way because of the way the method just above this was written in a similar manner. No objections in modifying it though, shall I ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Also, looking at the code of memstr_to_bytes it looks like the ValueError can be raised both by a prior KeyError as well as a ValueError. Maybe a good time to test it properly by corresponding two test cases ? Or is it not that significant ?

def test_memstr_to_bytes_exception(text, exception, exc_substr):
with pytest_assert_raises(exception) as excinfo:
memstr_to_bytes(text)
assert exc_substr in str(excinfo.value)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You can use excinfo.match(r'.* 123 .*') according to http://doc.pytest.org/en/latest/assert.html. It is general a good idea to make sure that the value the user provided is given in the error message. Here you could check 'Invalid literal for size.*fooG'.

@kdexd kdexd force-pushed the pytestify-test-disk branch from dfad634 to 991e36d Compare December 8, 2016 16:34
@kdexd kdexd force-pushed the pytestify-test-disk branch from 991e36d to d3cae30 Compare December 8, 2016 16:35

@parametrize(['text', 'exception', 'regex'],
[('fooG', ValueError, r'Invalid literal for size.*fooG.*'),
('1.4N', ValueError, r'Invalid literal for size.*1.4N.*')])
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

    try:
        size = int(units[text[-1]] * float(text[:-1]))
    except (KeyError, ValueError):
        raise ValueError(
            "Invalid literal for size give: %s (type %s) should be "
            "alike '10G', '500M', '50K'." % (text, type(text)))

So to test this block of memstr_to_bytes I added one more test case. First case causes ValueError before landing in except block while second causes KeyError.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Just a nitpick from my side...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I can tell you were just looking for an excuse to keep the parametrize ;-).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Haha you got me xD anyways jokes apart, I can revert back if you wish..

@kdexd
Copy link
Copy Markdown
Author

kdexd commented Dec 9, 2016

@lesteve The failing job on Travis CI uses pytest==2.7.2 and raises an AttributeError that ExceptionInfo has no attribute named match because that feature was introduced in pytest==3.0.0 as per their CHANGELOG. I guess there's one solution, pin pytest to one version in both packaging as well as testing.

@lesteve
Copy link
Copy Markdown
Member

lesteve commented Dec 9, 2016

@lesteve The failing job on Travis CI uses pytest==2.7.2 and raises an AttributeError that ExceptionInfo has no attribute named match because that feature was introduced in pytest==3.0.0 as per their CHANGELOG.

The reason for that is that conda has some dependency constraints that are not up-to-date for python 3.3. Pytest 3 works perfectly well with python 3.3 AFAIK. I am going to install pytest via pip and that should fix this problem.

to make sure we have a pytest version >=3 even on Python 3.3
@lesteve
Copy link
Copy Markdown
Member

lesteve commented Dec 9, 2016

Side note we will probably drop support for Python 3.3 in the not too distant future.

@kdexd
Copy link
Copy Markdown
Author

kdexd commented Dec 9, 2016

The reason for that is that conda has some dependency constraints that are not up-to-date for python 3.3. Pytest 3 works perfectly well with python 3.3 AFAIK.

Yes you are correct, pytest works fine with python 3.3. I was puzzled by the fact that always pytest==2.7.2 was installed by default in that particular job. Never hit me that I might have been conda...

I am going to install pytest via pip and that should fix this problem.

Yeah that fixed it, great ! Thanks for the help 😄

@lesteve lesteve merged commit d3b5388 into joblib:master Dec 9, 2016
@lesteve
Copy link
Copy Markdown
Member

lesteve commented Dec 9, 2016

OK merging this one, thanks a lot!

Feel free to reintroduce the tmpdir_path fixture in conftest.py in your next PR.

@kdexd kdexd deleted the pytestify-test-disk branch December 9, 2016 16:52
@kdexd
Copy link
Copy Markdown
Author

kdexd commented Dec 9, 2016

Great, thanks for the continuous review feedbacks ! As usual, next PR on the way...

@GaelVaroquaux
Copy link
Copy Markdown
Member

GaelVaroquaux commented Dec 9, 2016 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants