pytest icon indicating copy to clipboard operation
pytest copied to clipboard

pytest_load_initial_conftests not called for conftest plugins (arg manipulation)

Open hameerabbasi opened this issue 6 years ago • 15 comments

Hi! I'm trying to find a way to use doctests, but not for Windows. It seems that there's a way to do this at: https://docs.pytest.org/en/latest/example/simple.html#dynamically-adding-command-line-options

I tried the following minimal example but it did not work:

import platform

def pytest_load_initial_conftests(args):
    if platform.system() != 'Windows':
        args[:] = args + ['--doctest-modules']

Is there something I'm missing here?

hameerabbasi avatar Apr 02 '19 10:04 hameerabbasi

Here's a minimum verifiable example.

pytest_test.zip

hameerabbasi avatar Apr 03 '19 08:04 hameerabbasi

Sorry for not looking into the zip, but I think you cannot use it from a conftest (IIRC you mentioned this on IRC). You could use pytest_cmdline_preparse, but that is deprecated - see https://github.com/blueyed/pytest/blob/983883af16897b6c9868d3a23383646329cccaf9/testing/test_config.py#L679-L687.

Or use a real plugin, which you can add using -p in addopts.

blueyed avatar Apr 03 '19 10:04 blueyed

The documentation states "dynamically adding command line options"... That's more or less exactly what I'm doing, right? It even states, in the comment:

# content of conftest.py

I may be missing something, but it seems that either the documentation is out of date or there's an actual bug.

hameerabbasi avatar Apr 03 '19 10:04 hameerabbasi

Yes, it might be a bug. Maybe the hook needs to be called after conftests are handled (historic)?

But I also think there should be a distinct/clear hook for manipulating args, i.e. it might make sense to undeprecate pytest_cmdline_preparse.

blueyed avatar Apr 03 '19 11:04 blueyed

@hameerabbasi can you check if pytest_cmdline_preparse works for you? If it does, we might investigate why it is deprecated, as well as investigate the reason why your initial attempt with pytest_load_initial_conftests did not work.

nicoddemus avatar Apr 03 '19 11:04 nicoddemus

@nicoddemus pytest_cmdline_preparse worked for me. Here's the updated ZIP. pytest_test.zip

Edit: I also tried moving conftest.py out from tests into . and that did not work either.

hameerabbasi avatar Apr 03 '19 12:04 hameerabbasi

I'd be willing to make a PR here, if it's a simple change to the docs. 😄

hameerabbasi avatar Apr 08 '19 16:04 hameerabbasi

Yes, it might be a bug. Maybe the hook needs to be called after conftests are handled (historic)?

But I also think there should be a distinct/clear hook for manipulating args, i.e. it might make sense to undeprecate pytest_cmdline_preparse.

I'm curious if there's been any movement on this. I use arg manipulation with pytest_cmdline_preparse in most my test cases, but I've noticed that it has not worked since version 5.2.4. At least, I see no way of accessing manipulated args from within a fixture that calls request.config.getoption.

Neither does pytest_load_initial_conftests seem to have any effect within the root conftest.py, as per the documentation. Is there a workaround somewhere in the documentation that I'm missing? Would love to get this working again 😄

devincunningham avatar Apr 28 '20 00:04 devincunningham

I'll also add my vote for this not to be deprecated. Seems like it has been replaced with something that doesn't offer the same functionality.

shareefj avatar Jul 19 '23 13:07 shareefj

@nicoddemus I believe with the new code for explicit testpaths consideration we can close this off as reasonably replaced

RonnyPfannschmidt avatar Jul 19 '23 13:07 RonnyPfannschmidt

Can you elaborate @RonnyPfannschmidt?

I understand the gist of this issue ended up being to not deprecate pytest_cmdline_preparse anymore, as the suggested alternative of using pytest_load_initial_conftests does not account for all cases.

nicoddemus avatar Jul 27 '23 12:07 nicoddemus

@nicoddemus my understanding was that with early conftests loading its now valid to configure objects in the configuration instead of mungeing the cli args

Based on that I believe we can complete the removal of the Hook given that changing the configuration is usable

RonnyPfannschmidt avatar Jul 27 '23 13:07 RonnyPfannschmidt

Thanks, but I'm not fully convinced: I have used the hook in the past to change the arguments of other plugins before processed being processed by pytest; while it is possible to change the config object using pytest_load_initial_conftests hook, this might not be clean because the objects/configuration might be part of the other plugin's private API.

I was not even in the project when pytest_cmdline_preparse got deprecated, but I would guess that it was deprecated because it was thought that the introduction of pytest_load_initial_conftests would cover all the uses cases covered by pytest_cmdline_preparse, so it made the deprecation reasonable -- however in the wild new use cases appeared which should make us reconsider the deprecation.

I'm also weighting in that decision because pytest_cmdline_preparse is not really a maintenance burden, is just a call during pytest startup.

nicoddemus avatar Jul 27 '23 13:07 nicoddemus

Among other things it's broken in xdist, messes with early init and contributes to the general madness of config initialisation , unfortunately I won't be able to work on the topic soonish but I want to avoid calling the deprecation off

RonnyPfannschmidt avatar Jul 27 '23 13:07 RonnyPfannschmidt

For everyone being directed here by googling, what we migrated to at $DAYJOB for modifying plugin behavior after the removal of pytest_cmdline_preparse in pytest 8 is to use pytest_configure() and overwrite the parse configuration options. As an example, we disable pytest-xdist if a debugger is attached with something along the lines of:

# in conftest.py

import sys
from pytest import Config

def _is_debugger_attached() -> bool:
    return sys.gettrace() is not None


def _disable_pytest_xdist_parallel_running(config: Config) -> None:
    setattr(config.option, "dist", "no")


@pytest.hookimpl(tryfirst=True)
def pytest_configure(config: Config):
    # disable parallel test-running for some run conditions
    if "xdist" in sys.modules:  # pytest-xdist plugin is installed
        if _is_debugger_attached():
            print("Detected attached debugger or other tracing, disabling parallel test execution via pytest-xdist.")
            _disable_pytest_xdist_parallel_running(config)

xaver-k avatar Apr 26 '24 06:04 xaver-k