pytest-datadir icon indicating copy to clipboard operation
pytest-datadir copied to clipboard

test_method_dir?

Open panicoenlaxbox opened this issue 4 years ago • 4 comments

Thank you very much for the plugin Have you considered including a test_method_dir (or a similar name) to be able to have files only for one method (instead of the whole module)? I don't think it's a good idea to copy all the files in a module when I only want the files for one method. The directory for the method would be inside the module directory. In the example, it would be test_hello \ test_a_method, so I could inject what is common to the module or what is necessary only for the method. If you give the OK, I could try to do it myself and do a PR. Thanks.

panicoenlaxbox avatar Nov 11 '21 13:11 panicoenlaxbox

I have written this in my project:

@pytest.fixture()
def test_shared_dir(request: FixtureRequest, tmp_path: Path):
    original_path = Path(request.fspath.dirname)
    if original_path.name != "tests":
        while original_path.parent.name != "tests":
            original_path = original_path.parent
    original_path = original_path / "data"
    copy_tree(str(original_path), str(tmp_path))
    return tmp_path


@pytest.fixture()
def test_case_dir(request: FixtureRequest, tmp_path: Path):
    original_path = Path(request.fspath.dirname) / request.fspath.purebasename
    copy_tree(str(original_path), str(tmp_path))
    test_method_dir = Path(tmp_path) / request.node.name
    if test_method_dir.exists():
        shutil.rmtree(str(test_method_dir))
    return tmp_path


@pytest.fixture()
def test_method_dir(request: FixtureRequest, tmp_path: Path):
    original_path = Path(request.fspath.dirname) / request.fspath.purebasename / request.node.name
    copy_tree(str(original_path), str(tmp_path))
    return tmp_path

image

Because test_case_dir removes a specific folder for the current test, the order is relevant when you use these fixtures in your test, you should inject them in the following order test_shared_dir, test_case_dir and test_method_dir.

Also, if I have a file with the same name in each of them, the last will win, for me, it has sense, because always it will be more concrete, more specific.

Regards.

panicoenlaxbox avatar Nov 12 '21 13:11 panicoenlaxbox

Hi @panicoenlaxbox,

Thanks for writing.

An alternative way I can think of would be to provide a separate fixture, which would copy files as needed:

def test_foo(data_files) -> None:
    fn = data_files.get("foo.txt")  # this copies just "foo.txt" to a temporary folder, and return the filename as Path

But your approach works well too.

As for adding this to pytest-datadir I'm particularly -0.5 as I never had the need for it and would prefer to keep this plugin simple, but others might have think differently.

nicoddemus avatar Nov 12 '21 13:11 nicoddemus

Hi @panicoenlaxbox

Thank you very much for writing this down and engaging with contributing.

I agree with @nicoddemus because historically I haven't seen use cases where it would require a further breakdown for data for individual test functions.

Copying those temporary files these days should not present an overhead in your test execution, since superfast SSDs nowadays are present in our development and CI machines.

However, I appreciate some cases where it may be better to avoid copying large files even temporarily.

@nicoddemus - do you think it's possible to make the fixture to return an instance of a subclass of pathlib.Path which overrides __truediv__ to only copy the file that is being accessed? Like a lazy copy on-demand, instead of copying the entire structure? This would satisfy that need, right?

gabrielcnr avatar Nov 12 '21 13:11 gabrielcnr

@nicoddemus - do you think it's possible to make the fixture to return an instance of a subclass of pathlib.Path which overrides truediv to only copy the file that is being accessed? Like a lazy copy on-demand, instead of copying the entire structure? This would satisfy that need, right?

It is possible, but I would advise against it, feels too magical... plus you will need to override some other methods too (say joinpath). Better be explicit and provide a different fixture for that use case.

nicoddemus avatar Nov 12 '21 14:11 nicoddemus