New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use hookwrapper with pytest_configure #2423

Closed
hdattada opened this Issue May 22, 2017 · 5 comments

Comments

Projects
None yet
2 participants
@hdattada

hdattada commented May 22, 2017

  • Include a detailed description of the bug or suggestion
    I am referring to https://docs.pytest.org/en/latest/writing_plugins.html for implementing my own plugin. I want the pytest_configure hook in my plugin to yield to all other plugins, so I am using @pytest.hookimpl(hookwrapper=True) . But I receive an error hook 'pytest_configure' historic incompatible to hookwrapper
  • pip list of the virtual environment you are using
pip (9.0.1)
py (1.4.33)
pycodestyle (2.3.1)
pycurl (7.43.0)
Pygments (2.2.0)
pypng (0.0.18)
pytest (3.0.7)
pytest-timeout (1.2.0)
pytest-xdist (1.16.0)
pytz (2017.2)
requests (2.14.2)
selenium (2.47.1)
setuptools (18.2)

  • pytest and operating system versions
    pytest-3.0.7
    15.6.0 Darwin Kernel Version 15.6.0
  • Minimal example if possible
@pytest.hookimpl(hookwrapper=True)
def pytest_configure(config, call):
    outcome = yield
@RonnyPfannschmidt

This comment has been minimized.

Member

RonnyPfannschmidt commented May 22, 2017

pytest_configure is a hook that needs a behavior that is inherently incompatible with hook-wrappers,
as such this is mainly a documentation issue

@hdattada

This comment has been minimized.

hdattada commented May 22, 2017

Thanks @RonnyPfannschmidt , prior to 2.8.0 we were able to use __multicall__ with pytest_configure is there an alternative solution to achieve such behavior with the latest version?

@RonnyPfannschmidt

This comment has been minimized.

Member

RonnyPfannschmidt commented May 22, 2017

@hdattada what did you use multicall for? given how the pytest_configure hook is used/reinvoked over time its simply not possible to do anything correct with that

so at best your code worked by sheer luck

if your desire is to wrap around configure that happens at the do_configure time of pytes,
your best option is to do at plugin register time register 2 plugin classes, one with a tryfirst and one with a trylast configure hook

i strongly suggest to outline your use-case and goal as i believe there could be a far more clean way to do this with current pytest

@hdattada

This comment has been minimized.

hdattada commented May 22, 2017

@RonnyPfannschmidt I am still new to this so excuse my naive understanding. I am taking over something that was developed earlier, from the information I have and from the little I understand it was used to wait for all other pytest_configure in multiple plugins to execute. I am also seeing an older release of pytest-xdist use this https://github.com/pytest-dev/pytest-xdist/blob/1.11/xdist/plugin.py#L62 . May be their usecase was a logical one or I am completely wrong. If my understanding is wrong, could you please explain what was __multicall__ used for earlier? So that I have a better idea of what this was used for.

I can give you an idea of my usecase/goal, (this will sound weird). We have a test framework that uses pytest-xdist to distribute tests to multiple targets. As part of this framework we have an internal implementation of retrying tests on failures. There is a limitation with pytest-xdist that expects atleast 2 test items in the node otherwise the tests are not executed https://github.com/pytest-dev/pytest-xdist/blob/master/xdist/remote.py#L60. Previously we bypassed this using a custom pytest plugin in pytest 2.6.4 to overwrite the hook in pytest-xdist. But since we upgraded to 3.0.7 we can no longer have the same functionality working. I believe the deprecation of __multicall__ could be a reason. Below is a snippet of the plugin:

import os
import sys
import types

# Overrides xdist.remote.SlaveInteractor.pytest_runloop()
# to support running one test at a time
def runtestloop(self, session):
    self.log("entering main loop")

    torun = []
    while 1:
        name, kwargs = self.channel.receive()
        self.log("received command", name, kwargs)
        if name == "runtests":
            torun.extend(kwargs['indices'])
        elif name == "runtests_all":
            torun.extend(range(len(session.items)))
        self.log("items to run:", torun)
        # only run if we have an item and a next item
        while torun:
            self.run_tests(torun)
        if name == "shutdown":
            if torun:
                self.run_tests(torun)
            break
    return True

# -------------------------------------------------------------------------
# distributed testing slave initialization
# -------------------------------------------------------------------------


def pytest_configure(config, __multicall__):
    __multicall__.execute()
    for plugin in config.pluginmanager.getplugins():
        if type(plugin).__name__ == "SlaveInteractor":
            plugin.pytest_runtestloop = types.MethodType(runtestloop, plugin)
            break
@RonnyPfannschmidt

This comment has been minimized.

Member

RonnyPfannschmidt commented May 22, 2017

you can implement that monkeypatch in a

def pytest_plugin_registered(plugin, manager):
    if type(plugin).__name__ == "SlaveInteractor":
            plugin.pytest_runtestloop = types.MethodType(runtestloop, plugin)

note that this kind of usage is explicitly unsupported for now - so it will likely break again in future

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