Skip to content

Bug with parameterized classes when running tests twice #683

Closed

Description

@pytestbot

Originally reported by: BitBucket: astrofrog, GitHub: astrofrog


If we consider the following example and place it in a file called test_double.py:

import pytest

class TestA(object):
    pass

@pytest.mark.parametrize(('model_class'), [1,2,3])
class TestB(TestA):
    def test_1(self, model_class):
        pass

We can then try and run this with:

py.test test_double.py test_double.py

This produces the following error:

========================================================= test session starts ==========================================================
platform darwin -- Python 3.4.2 -- py-1.4.23 -- pytest-2.6.1
plugins: cov, xdist
collected 3 items / 1 errors 

test_double.py ...

================================================================ ERRORS ================================================================
___________________________________________________ ERROR collecting test_double.py ____________________________________________________
../Library/Python/3.4/lib/python/site-packages/_pytest/runner.py:139: in __init__
    self.result = func()
../Library/Python/3.4/lib/python/site-packages/_pytest/main.py:438: in _memocollect
    return self._memoizedcall('_collected', lambda: list(self.collect()))
../Library/Python/3.4/lib/python/site-packages/_pytest/main.py:315: in _memoizedcall
    res = function()
../Library/Python/3.4/lib/python/site-packages/_pytest/main.py:438: in <lambda>
    return self._memoizedcall('_collected', lambda: list(self.collect()))
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:538: in collect
    return super(Instance, self).collect()
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:333: in collect
    res = self.makeitem(name, obj)
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:345: in makeitem
    collector=self, name=name, obj=obj)
../Library/Python/3.4/lib/python/site-packages/_pytest/main.py:166: in call_matching_hooks
    return hookmethod.pcall(plugins, **kwargs)
../Library/Python/3.4/lib/python/site-packages/_pytest/core.py:417: in pcall
    return self._docall(methods, kwargs)
../Library/Python/3.4/lib/python/site-packages/_pytest/core.py:424: in _docall
    res = mc.execute()
../Library/Python/3.4/lib/python/site-packages/_pytest/core.py:315: in execute
    res = method(**kwargs)
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:236: in pytest_pycollect_makeitem
    return list(collector._genfunctions(name, obj))
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:361: in _genfunctions
    gentesthook.pcall(plugins, metafunc=metafunc)
../Library/Python/3.4/lib/python/site-packages/_pytest/core.py:417: in pcall
    return self._docall(methods, kwargs)
../Library/Python/3.4/lib/python/site-packages/_pytest/core.py:424: in _docall
    res = mc.execute()
../Library/Python/3.4/lib/python/site-packages/_pytest/core.py:315: in execute
    res = method(**kwargs)
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:146: in pytest_generate_tests
    metafunc.parametrize(*marker.args, **marker.kwargs)
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:836: in parametrize
    param_index)
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:717: in setmulti
    self._checkargnotcontained(arg)
../Library/Python/3.4/lib/python/site-packages/_pytest/python.py:700: in _checkargnotcontained
    raise ValueError("duplicate %r" %(arg,))
E   ValueError: duplicate 'model_class'

We discovered this because when running Astropy tests twice in a row:

import astropy
astropy.test()
astropy.test()

the same error occurs.


Activity

  1. pytestbot commented on Feb 16, 2015

    @pytestbot
    ContributorAuthor

    Original comment by Erik Bray (BitBucket: embray, GitHub: embray):


    Just poking around at this a bit, what I found is that in PyCollector._genfunctions the routine transfer_markers, which copies markers on classes onto their methods, every time the tests are run.

    I wonder if it would be possible to somehow "undo" this after the test run, perhaps by copying the test method's original __dict__ and then restoring it afterwards.
    Another possibility might be to have a reverse of transfer_markers--it should be possible to unambiguously removing markers added to a test method from its class after it has been run.

  2. pytestbot commented on Feb 16, 2015

    @pytestbot
    ContributorAuthor

    Original comment by Erik Bray (BitBucket: embray, GitHub: embray):


    Or perhaps more simply transfer_markers could just check for duplicates in the first place.

  3. flub commented on Jul 26, 2015

    @flub
    Member

    Fix from @ojake merged, thanks

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: bugproblem that needs to be addressed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions