pytest-dev / pytest

The pytest framework makes it easy to write small tests, yet scales to support complex functional testing
https://pytest.org
MIT License
11.98k stars 2.66k forks source link

pytest_load_initial_conftests not called for conftest plugins (arg manipulation) #5024

Open hameerabbasi opened 5 years ago

hameerabbasi commented 5 years ago

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 commented 5 years ago

Here's a minimum verifiable example.

pytest_test.zip

blueyed commented 5 years ago

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.

hameerabbasi commented 5 years ago

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.

blueyed commented 5 years ago

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.

nicoddemus commented 5 years ago

@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.

hameerabbasi commented 5 years ago

@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 commented 5 years ago

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

devincunningham commented 4 years ago

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 😄

shareefj commented 1 year ago

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.

RonnyPfannschmidt commented 1 year ago

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

nicoddemus commented 1 year ago

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.

RonnyPfannschmidt commented 1 year ago

@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

nicoddemus commented 1 year ago

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.

RonnyPfannschmidt commented 1 year ago

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

xaver-k commented 5 months ago

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)