Giter Club home page Giter Club logo

pytest-timeout's Introduction

pytest-timeout

python version anaconda ci pre-commit

Warning

Please read this README carefully and only use this plugin if you understand the consequences. This plugin is designed to catch excessively long test durations like deadlocked or hanging tests, it is not designed for precise timings or performance regressions. Remember your test suite should aim to be fast, with timeouts being a last resort, not an expected failure mode.

This plugin will time each test and terminate it when it takes too long. Termination may or may not be graceful, please see below, but when aborting it will show a stack dump of all thread running at the time. This is useful when running tests under a continuous integration server or simply if you don't know why the test suite hangs.

Note

While by default on POSIX systems pytest will continue to execute the tests after a test has timed out this is not always possible. Often the only sure way to interrupt a hanging test is by terminating the entire process. As this is a hard termination (os._exit()) it will result in no teardown, JUnit XML output etc. But the plugin will ensure you will have the debugging output on stderr nevertheless, which is the most important part at this stage. See below for detailed information on the timeout methods and their side-effects.

The pytest-timeout plugin has been tested on Python 3.6 and higher, including PyPy3. See tox.ini for currently tested versions.

Usage

Install is as simple as e.g.:

pip install pytest-timeout

Now you can run the test suite while setting a timeout in seconds, any individual test which takes longer than the given duration will be terminated:

pytest --timeout=300

Furthermore you can also use a decorator to set the timeout for an individual test. If combined with the --timeout flag this will override the timeout for this individual test:

@pytest.mark.timeout(60)
def test_foo():
    pass

By default the plugin will not time out any tests, you must specify a valid timeout for the plugin to interrupt long-running tests. A timeout is always specified as a number of seconds, and can be defined in a number of ways, from low to high priority:

  1. You can set a global timeout in the pytest configuration file using the timeout option. E.g.:

    [pytest]
    timeout = 300
  2. The PYTEST_TIMEOUT environment variable sets a global timeout overriding a possible value in the configuration file.
  3. The --timeout command line option sets a global timeout overriding both the environment variable and configuration option.
  4. Using the timeout marker on test items you can specify timeouts on a per-item basis:

    @pytest.mark.timeout(300)
    def test_foo():
        pass

Setting a timeout to 0 seconds disables the timeout, so if you have a global timeout set you can still disable the timeout by using the mark.

Timeout Methods

Interrupting tests which hang is not always as simple and can be platform dependent. Furthermore some methods of terminating a test might conflict with the code under test itself. The pytest-timeout plugin tries to pick the most suitable method based on your platform, but occasionally you may need to specify a specific timeout method explicitly.

If a timeout method does not work your safest bet is to use the thread method.

thread

This is the surest and most portable method. It is also the default on systems not supporting the signal method. For each test item the pytest-timeout plugin starts a timer thread which will terminate the whole process after the specified timeout. When a test item finishes this timer thread is cancelled and the test run continues.

The downsides of this method are that there is a relatively large overhead for running each test and that test runs are not completed. This means that other pytest features, like e.g. JUnit XML output or fixture teardown, will not function normally. The second issue might be alleviated by using the --boxed option of the pytest-xdist plugin.

The benefit of this method is that it will always work. Furthermore it will still provide you debugging information by printing the stacks of all the threads in the application to stderr.

signal

If the system supports the SIGALRM signal the signal method will be used by default. This method schedules an alarm when the test item starts and cancels the alarm when the test finishes. If the alarm expires during the test the signal handler will dump the stack of any other threads running to stderr and use pytest.fail() to interrupt the test.

The benefit of this method is that the pytest process is not terminated and the test run can complete normally.

The main issue to look out for with this method is that it may interfere with the code under test. If the code under test uses SIGALRM itself things will go wrong and you will have to choose the thread method.

Specifying the Timeout Method

The timeout method can be specified by using the timeout_method option in the pytest configuration file, the --timeout_method command line parameter or the timeout marker. Simply set their value to the string thread or signal to override the default method. On a marker this is done using the method keyword:

@pytest.mark.timeout(method="thread")
def test_foo():
    pass

The timeout Marker API

The full signature of the timeout marker is:

pytest.mark.timeout(timeout=0, method=DEFAULT_METHOD)

You can use either positional or keyword arguments for both the timeout and the method. Neither needs to be present.

See the marker api documentation and examples for the various ways markers can be applied to test items.

Timeouts in Fixture Teardown

The plugin will happily terminate timeouts in the finalisers of fixtures. The timeout specified applies to the entire process of setting up fixtures, running the tests and finalising the fixtures. However when a timeout occurs in a fixture finaliser and the test suite continues, i.e. the signal method is used, it must be realised that subsequent fixtures which need to be finalised might not have been executed, which could result in a broken test-suite anyway. In case of doubt the thread method which terminates the entire process might result in clearer output.

Avoiding timeouts in Fixtures

The timeout applies to the entire test including any fixtures which may need to be setup or torn down for the test (the exact affected fixtures depends on which scope they are and whether other tests will still use the same fixture). If the timeouts really are too short to include fixture durations, firstly make the timeouts larger ;). If this really isn't an option a timeout_func_only boolean setting exists which can be set in the pytest ini configuration file, as documented in pytest --help.

For the decorated function, a decorator will override timeout_func_only = true in the pytest ini file to the default value. If you need to keep this option for a decorated test, you must specify the option explicitly again:

@pytest.mark.timeout(60, func_only=True)
def test_foo():
    pass

Debugger Detection

This plugin tries to avoid triggering the timeout when a debugger is detected. This is mostly a convenience so you do not need to remember to disable the timeout when interactively debugging.

The way this plugin detects whether or not a debugging session is active is by checking if a trace function is set and if one is, it check to see if the module it belongs to is present in a set of known debugging frameworks modules OR if pytest itself drops you into a pdb session using --pdb or similar.

This functionality can be disabled with the --disable-debugger-detection flag or the corresponding timeout_disable_debugger_detection ini setting / environment variable.

Extending pytest-timeout with plugins

pytest-timeout provides two hooks that can be used for extending the tool. These hooks are used for setting the timeout timer and cancelling it if the timeout is not reached.

For example, pytest-asyncio can provide asyncio-specific code that generates better traceback and points on timed out await instead of the running loop iteration.

See pytest hooks documentation for more info regarding to use custom hooks.

pytest_timeout_set_timer

@pytest.hookspec(firstresult=True)
def pytest_timeout_set_timer(item, settings):
    """Called at timeout setup.

    'item' is a pytest node to setup timeout for.

    'settings' is Settings namedtuple (described below).

    Can be overridden by plugins for alternative timeout implementation strategies.
    """

Settings

When pytest_timeout_set_timer is called, settings argument is passed.

The argument has Settings namedtuple type with the following fields:

Attribute Index Value
timeout 0 timeout in seconds or None for no timeout
method 1 Method mechanism, 'signal' and 'thread' are supported by default
func_only 2
Apply timeout to test function only if True,

wrap all test function and its fixtures otherwise

pytest_timeout_cancel_timer

@pytest.hookspec(firstresult=True)
def pytest_timeout_cancel_timer(item):
    """Called at timeout teardown.

    'item' is a pytest node which was used for timeout setup.

    Can be overridden by plugins for alternative timeout implementation strategies.
    """

is_debugging

When the timeout occurs, user can open the debugger session. In this case, the timeout should be discarded. A custom hook can check this case by calling is_debugging() function:

import pytest
import pytest_timeout


def on_timeout():
    if pytest_timeout.is_debugging():
        return
    pytest.fail("+++ Timeout +++")

Session Timeout

The above mentioned timeouts are all per test function. The "per test function" timeouts will stop an individual test from taking too long. We may also want to limit the time of the entire set of tests running in one session. A session all of the tests that will be run with one invokation of pytest.

A session timeout is set with --session-timeout and is in seconds.

The following example shows a session timeout of 10 minutes (600 seconds):

pytest --session-timeout=600

You can also set the session timeout the pytest configuration file using the session_timeout option:

[pytest]
session_timeout = 600

Cooperative timeouts

Session timeouts are cooperative timeouts. pytest-timeout checks the session time at the end of each test function, and stops further tests from running if the session timeout is exceeded. The session will results in a test failure if this occurs.

In particular this means if a test does not finish of itself, it will only be interrupted if there is also a function timeout set. A session timeout is not enough to ensure that a test-suite is guaranteed to finish.

Combining session and function timeouts

It works fine to combine both session and function timeouts. In fact when using a session timeout it is recommended to also provide a function timeout.

For example, to limit test functions to 5 seconds and the full session to 100 seconds:

pytest --timeout=5 --session-timeout=100

Changelog

2.3.1

  • Fixup some build errors, mostly README syntax which stopped twine from uploading.

2.3.0

  • Fix debugger detection for recent VSCode, this compiles pydevd using cython which is now correctly detected. Thanks Adrian Gielniewski.
  • Switched to using Pytest's TerminalReporter instead of writing directly to sys.{stdout,stderr}. This change also switches all output from sys.stderr to sys.stdout. Thanks Pedro Algarvio.
  • Pytest 7.0.0 is now the minimum supported version. Thanks Pedro Algarvio.
  • Add --session-timeout option and session_timeout setting. Thanks Brian Okken.

2.2.0

  • Add --timeout-disable-debugger-detection flag, thanks Michael Peters

2.1.0

  • Get terminal width from shutil instead of deprecated py, thanks Andrew Svetlov.
  • Add an API for extending pytest-timeout functionality with third-party plugins, thanks Andrew Svetlov.

2.0.2

  • Fix debugger detection on OSX, thanks Alexander Pacha.

2.0.1

  • Fix Python 2 removal, thanks Nicusor Picatureanu.

2.0.0

  • Increase pytest requirement to >=5.0.0. Thanks Dominic Davis-Foster.
  • Use thread timeout method when plugin is not called from main thread to avoid crash.
  • Fix pycharm debugger detection so timeouts are not triggered during debugger usage.
  • Dropped support for Python 2, minimum pytest version supported is 5.0.0.

1.4.2

  • Fix compatibility when run with pytest pre-releases, thanks Bruno Oliveira,
  • Fix detection of third-party debuggers, thanks Bruno Oliveira.

1.4.1

  • Fix coverage compatibility which was broken by 1.4.0.

1.4.0

  • Better detection of when we are debugging, thanks Mattwmaster58.

1.3.4

  • Give the threads a name to help debugging, thanks Thomas Grainger.
  • Changed location to https://github.com/pytest-dev/pytest-timeout because bitbucket is dropping mercurial support. Thanks Thomas Grainger and Bruno Oliveira.

1.3.3

  • Fix support for pytest >= 3.10.

1.3.2

  • This changelog was omitted for the 1.3.2 release and was added afterwards. Apologies for the confusion.
  • Fix pytest 3.7.3 compatibility. The capture API had changed slightly and this needed fixing. Thanks Bruno Oliveira for the contribution.

1.3.1

  • Fix deprecation warning on Python 3.6. Thanks Mickaël Schoentgen
  • Create a valid tag for the release. Somehow this didn't happen for 1.3.0, that tag points to a non-existing commit.

1.3.0

  • Make it possible to only run the timeout timer on the test function and not the whole fixture setup + test + teardown duration. Thanks Pedro Algarvio for the work!
  • Use the new pytest marker API, Thanks Pedro Algarvio for the work!

1.2.1

  • Fix for pytest 3.3, thanks Bruno Oliveira.
  • Update supported python versions:
    • Add CPython 3.6.
    • Drop CPyhon 2.6 (as did pytest 3.3)
    • Drop CPyhon 3.3
    • Drop CPyhon 3.4

1.2.0

  • Allow using floats as timeout instead of only integers, thanks Tom Myers.

1.1.0

  • Report (default) timeout duration in header, thanks Holger Krekel.

1.0.0

  • Bump version to 1.0 to commit to semantic versioning.
  • Fix issue #12: Now compatible with pytest 2.8, thanks Holger Krekel.
  • No longer test with pexpect on py26 as it is no longer supported
  • Require pytest 2.8 and use new hookimpl decorator

0.5

  • Timeouts will no longer be triggered when inside an interactive pdb session started by pytest.set_trace() / pdb.set_trace().
  • Add pypy3 environment to tox.ini.
  • Transfer repository to pytest-dev team account.

0.4

  • Support timeouts happening in (session scoped) finalizers.
  • Change command line option --timeout_method into --timeout-method for consistency with pytest

0.3

  • Added the PYTEST_TIMEOUT environment variable as a way of specifying the timeout (closes issue #2).
  • More flexible marker argument parsing: you can now specify the method using a positional argument.
  • The plugin is now enabled by default. There is no longer a need to specify timeout=0 in the configuration file or on the command line simply so that a marker would work.

0.2

  • Add a marker to modify the timeout delay using a @pytest.timeout(N) syntax, thanks to Laurant Brack for the initial code.
  • Allow the timeout marker to select the timeout method using the method keyword argument.
  • Rename the --nosigalrm option to --method=thread to future proof support for eventlet and gevent. Thanks to Ronny Pfannschmidt for the hint.
  • Add timeout and timeout_method items to the configuration file so you can enable and configure the plugin using the ini file. Thanks to Holger Krekel and Ronny Pfannschmidt for the hints.
  • Tested (and fixed) for python 2.6, 2.7 and 3.2.

pytest-timeout's People

Contributors

altendky avatar asottile avatar asvetlov avatar bobotig avatar ferguzz avatar flub avatar graingert avatar h4iku avatar hpk42 avatar hugovk avatar jacobschaer avatar jmennius avatar kianmeng avatar loader-bsd avatar mattwmaster58 avatar mgorny avatar michaeljpeters avatar monkey-debugger avatar nicoddemus avatar nicusor97 avatar okken avatar pkoch avatar pre-commit-ci[bot] avatar s0undt3ch avatar sobolevn avatar swt2c avatar thedrow avatar wosc avatar xoviat avatar youssefelmasry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pytest-timeout's Issues

Test failures with pytest 5.2.2

Original report by Felix Yan (Bitbucket: felixonmars, GitHub: felixonmars).


Not sure which exact version did the problem occur:

============================= test session starts ==============================
platform linux -- Python 3.8.0, pytest-5.2.2, py-1.8.0, pluggy-0.13.0
rootdir: /build/python-pytest-timeout/src/pytest-timeout, inifile: tox.ini
plugins: timeout-1.3.3
collected 35 items

test_pytest_timeout.py ....F.F.F.F..F.F.F.F...............               [100%]

=================================== FAILURES ===================================
________________________ test_fix_setup[function-meth0] ________________________

meth = MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
scope = 'function'
testdir = <Testdir local('/tmp/pytest-of-builduser/pytest-0/test_fix_setup0')>

    @pytest.mark.parametrize('meth', [have_sigalrm('signal'), 'thread'])
    @pytest.mark.parametrize('scope', ['function', 'class', 'module', 'session'])
    def test_fix_setup(meth, scope, testdir):
        testdir.makepyfile("""
            import time, pytest
    
            class TestFoo:
    
                @pytest.fixture(scope='{scope}')
                def fix(self):
                    time.sleep(2)
    
                def test_foo(self, fix):
                    pass
        """.format(scope=scope))
        result = testdir.runpytest('--timeout=1',
                                   '--timeout-method={0}'.format(meth))
        assert result.ret > 0
>       assert 'Timeout' in result.stdout.str() + result.stderr.str()
E       assert 'Timeout' in ('' + 'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n')
E        +  where '' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb52f8430>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb52f8430>> = <_pytest.pytester.LineMatcher object at 0x7fcfb52f8430>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb52f8430> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stdout
E        +  and   'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb52f85e0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb52f85e0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb52f85e0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb52f85e0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stderr

/build/python-pytest-timeout/src/pytest-timeout/test_pytest_timeout.py:114: AssertionError
----------------------------- Captured stdout call -----------------------------
running: /usr/bin/python -mpytest --basetemp=/tmp/pytest-of-builduser/pytest-0/test_fix_setup0/runpytest-0 --timeout=1 --timeout-method=MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
     in: /tmp/pytest-of-builduser/pytest-0/test_fix_setup0
----------------------------- Captured stderr call -----------------------------
ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]
pytest.py: error: argument --timeout-method: invalid choice: "MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))" (choose from 'signal', 'thread')

_________________________ test_fix_setup[class-meth0] __________________________

meth = MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
scope = 'class'
testdir = <Testdir local('/tmp/pytest-of-builduser/pytest-0/test_fix_setup2')>

    @pytest.mark.parametrize('meth', [have_sigalrm('signal'), 'thread'])
    @pytest.mark.parametrize('scope', ['function', 'class', 'module', 'session'])
    def test_fix_setup(meth, scope, testdir):
        testdir.makepyfile("""
            import time, pytest
    
            class TestFoo:
    
                @pytest.fixture(scope='{scope}')
                def fix(self):
                    time.sleep(2)
    
                def test_foo(self, fix):
                    pass
        """.format(scope=scope))
        result = testdir.runpytest('--timeout=1',
                                   '--timeout-method={0}'.format(meth))
        assert result.ret > 0
>       assert 'Timeout' in result.stdout.str() + result.stderr.str()
E       assert 'Timeout' in ('' + 'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n')
E        +  where '' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb52f89d0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb52f89d0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb52f89d0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb52f89d0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.25s>.stdout
E        +  and   'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb52f8f10>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb52f8f10>> = <_pytest.pytester.LineMatcher object at 0x7fcfb52f8f10>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb52f8f10> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.25s>.stderr

/build/python-pytest-timeout/src/pytest-timeout/test_pytest_timeout.py:114: AssertionError
----------------------------- Captured stdout call -----------------------------
running: /usr/bin/python -mpytest --basetemp=/tmp/pytest-of-builduser/pytest-0/test_fix_setup2/runpytest-0 --timeout=1 --timeout-method=MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
     in: /tmp/pytest-of-builduser/pytest-0/test_fix_setup2
----------------------------- Captured stderr call -----------------------------
ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]
pytest.py: error: argument --timeout-method: invalid choice: "MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))" (choose from 'signal', 'thread')

_________________________ test_fix_setup[module-meth0] _________________________

meth = MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
scope = 'module'
testdir = <Testdir local('/tmp/pytest-of-builduser/pytest-0/test_fix_setup4')>

    @pytest.mark.parametrize('meth', [have_sigalrm('signal'), 'thread'])
    @pytest.mark.parametrize('scope', ['function', 'class', 'module', 'session'])
    def test_fix_setup(meth, scope, testdir):
        testdir.makepyfile("""
            import time, pytest
    
            class TestFoo:
    
                @pytest.fixture(scope='{scope}')
                def fix(self):
                    time.sleep(2)
    
                def test_foo(self, fix):
                    pass
        """.format(scope=scope))
        result = testdir.runpytest('--timeout=1',
                                   '--timeout-method={0}'.format(meth))
        assert result.ret > 0
>       assert 'Timeout' in result.stdout.str() + result.stderr.str()
E       assert 'Timeout' in ('' + 'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n')
E        +  where '' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb5264160>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb5264160>> = <_pytest.pytester.LineMatcher object at 0x7fcfb5264160>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb5264160> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.25s>.stdout
E        +  and   'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb5264100>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb5264100>> = <_pytest.pytester.LineMatcher object at 0x7fcfb5264100>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb5264100> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.25s>.stderr

/build/python-pytest-timeout/src/pytest-timeout/test_pytest_timeout.py:114: AssertionError
----------------------------- Captured stdout call -----------------------------
running: /usr/bin/python -mpytest --basetemp=/tmp/pytest-of-builduser/pytest-0/test_fix_setup4/runpytest-0 --timeout=1 --timeout-method=MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
     in: /tmp/pytest-of-builduser/pytest-0/test_fix_setup4
----------------------------- Captured stderr call -----------------------------
ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]
pytest.py: error: argument --timeout-method: invalid choice: "MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))" (choose from 'signal', 'thread')

________________________ test_fix_setup[session-meth0] _________________________

meth = MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
scope = 'session'
testdir = <Testdir local('/tmp/pytest-of-builduser/pytest-0/test_fix_setup6')>

    @pytest.mark.parametrize('meth', [have_sigalrm('signal'), 'thread'])
    @pytest.mark.parametrize('scope', ['function', 'class', 'module', 'session'])
    def test_fix_setup(meth, scope, testdir):
        testdir.makepyfile("""
            import time, pytest
    
            class TestFoo:
    
                @pytest.fixture(scope='{scope}')
                def fix(self):
                    time.sleep(2)
    
                def test_foo(self, fix):
                    pass
        """.format(scope=scope))
        result = testdir.runpytest('--timeout=1',
                                   '--timeout-method={0}'.format(meth))
        assert result.ret > 0
>       assert 'Timeout' in result.stdout.str() + result.stderr.str()
E       assert 'Timeout' in ('' + 'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n')
E        +  where '' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a6ca0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a6ca0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb53a6ca0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb53a6ca0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.25s>.stdout
E        +  and   'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a6610>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a6610>> = <_pytest.pytester.LineMatcher object at 0x7fcfb53a6610>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb53a6610> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.25s>.stderr

/build/python-pytest-timeout/src/pytest-timeout/test_pytest_timeout.py:114: AssertionError
----------------------------- Captured stdout call -----------------------------
running: /usr/bin/python -mpytest --basetemp=/tmp/pytest-of-builduser/pytest-0/test_fix_setup6/runpytest-0 --timeout=1 --timeout-method=MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
     in: /tmp/pytest-of-builduser/pytest-0/test_fix_setup6
----------------------------- Captured stderr call -----------------------------
ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]
pytest.py: error: argument --timeout-method: invalid choice: "MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))" (choose from 'signal', 'thread')

______________________ test_fix_finalizer[function-meth0] ______________________

meth = MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
scope = 'function'
testdir = <Testdir local('/tmp/pytest-of-builduser/pytest-0/test_fix_finalizer0')>

    @pytest.mark.parametrize('meth', [have_sigalrm('signal'), 'thread'])
    @pytest.mark.parametrize('scope', ['function', 'class', 'module', 'session'])
    def test_fix_finalizer(meth, scope, testdir):
        testdir.makepyfile("""
            import time, pytest
    
            class TestFoo:
    
                @pytest.fixture
                def fix(self, request):
                    print('fix setup')
                    def fin():
                        print('fix finaliser')
                        time.sleep(2)
                    request.addfinalizer(fin)
    
                def test_foo(self, fix):
                    pass
        """)
        result = testdir.runpytest('--timeout=1', '-s',
                                   '--timeout-method={0}'.format(meth))
        assert result.ret > 0
>       assert 'Timeout' in result.stdout.str() + result.stderr.str()
E       assert 'Timeout' in ('' + 'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n')
E        +  where '' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a2df0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a2df0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb53a2df0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb53a2df0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stdout
E        +  and   'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53981c0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53981c0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb53981c0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb53981c0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stderr

/build/python-pytest-timeout/src/pytest-timeout/test_pytest_timeout.py:158: AssertionError
----------------------------- Captured stdout call -----------------------------
running: /usr/bin/python -mpytest --basetemp=/tmp/pytest-of-builduser/pytest-0/test_fix_finalizer0/runpytest-0 --timeout=1 -s --timeout-method=MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
     in: /tmp/pytest-of-builduser/pytest-0/test_fix_finalizer0
----------------------------- Captured stderr call -----------------------------
ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]
pytest.py: error: argument --timeout-method: invalid choice: "MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))" (choose from 'signal', 'thread')

_______________________ test_fix_finalizer[class-meth0] ________________________

meth = MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
scope = 'class'
testdir = <Testdir local('/tmp/pytest-of-builduser/pytest-0/test_fix_finalizer2')>

    @pytest.mark.parametrize('meth', [have_sigalrm('signal'), 'thread'])
    @pytest.mark.parametrize('scope', ['function', 'class', 'module', 'session'])
    def test_fix_finalizer(meth, scope, testdir):
        testdir.makepyfile("""
            import time, pytest
    
            class TestFoo:
    
                @pytest.fixture
                def fix(self, request):
                    print('fix setup')
                    def fin():
                        print('fix finaliser')
                        time.sleep(2)
                    request.addfinalizer(fin)
    
                def test_foo(self, fix):
                    pass
        """)
        result = testdir.runpytest('--timeout=1', '-s',
                                   '--timeout-method={0}'.format(meth))
        assert result.ret > 0
>       assert 'Timeout' in result.stdout.str() + result.stderr.str()
E       assert 'Timeout' in ('' + 'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n')
E        +  where '' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a98b0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a98b0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb53a98b0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb53a98b0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stdout
E        +  and   'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a91f0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53a91f0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb53a91f0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb53a91f0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stderr

/build/python-pytest-timeout/src/pytest-timeout/test_pytest_timeout.py:158: AssertionError
----------------------------- Captured stdout call -----------------------------
running: /usr/bin/python -mpytest --basetemp=/tmp/pytest-of-builduser/pytest-0/test_fix_finalizer2/runpytest-0 --timeout=1 -s --timeout-method=MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
     in: /tmp/pytest-of-builduser/pytest-0/test_fix_finalizer2
----------------------------- Captured stderr call -----------------------------
ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]
pytest.py: error: argument --timeout-method: invalid choice: "MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))" (choose from 'signal', 'thread')

_______________________ test_fix_finalizer[module-meth0] _______________________

meth = MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
scope = 'module'
testdir = <Testdir local('/tmp/pytest-of-builduser/pytest-0/test_fix_finalizer4')>

    @pytest.mark.parametrize('meth', [have_sigalrm('signal'), 'thread'])
    @pytest.mark.parametrize('scope', ['function', 'class', 'module', 'session'])
    def test_fix_finalizer(meth, scope, testdir):
        testdir.makepyfile("""
            import time, pytest
    
            class TestFoo:
    
                @pytest.fixture
                def fix(self, request):
                    print('fix setup')
                    def fin():
                        print('fix finaliser')
                        time.sleep(2)
                    request.addfinalizer(fin)
    
                def test_foo(self, fix):
                    pass
        """)
        result = testdir.runpytest('--timeout=1', '-s',
                                   '--timeout-method={0}'.format(meth))
        assert result.ret > 0
>       assert 'Timeout' in result.stdout.str() + result.stderr.str()
E       assert 'Timeout' in ('' + 'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n')
E        +  where '' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb5381400>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb5381400>> = <_pytest.pytester.LineMatcher object at 0x7fcfb5381400>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb5381400> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stdout
E        +  and   'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53819a0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53819a0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb53819a0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb53819a0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stderr

/build/python-pytest-timeout/src/pytest-timeout/test_pytest_timeout.py:158: AssertionError
----------------------------- Captured stdout call -----------------------------
running: /usr/bin/python -mpytest --basetemp=/tmp/pytest-of-builduser/pytest-0/test_fix_finalizer4/runpytest-0 --timeout=1 -s --timeout-method=MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
     in: /tmp/pytest-of-builduser/pytest-0/test_fix_finalizer4
----------------------------- Captured stderr call -----------------------------
ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]
pytest.py: error: argument --timeout-method: invalid choice: "MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))" (choose from 'signal', 'thread')

______________________ test_fix_finalizer[session-meth0] _______________________

meth = MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
scope = 'session'
testdir = <Testdir local('/tmp/pytest-of-builduser/pytest-0/test_fix_finalizer6')>

    @pytest.mark.parametrize('meth', [have_sigalrm('signal'), 'thread'])
    @pytest.mark.parametrize('scope', ['function', 'class', 'module', 'session'])
    def test_fix_finalizer(meth, scope, testdir):
        testdir.makepyfile("""
            import time, pytest
    
            class TestFoo:
    
                @pytest.fixture
                def fix(self, request):
                    print('fix setup')
                    def fin():
                        print('fix finaliser')
                        time.sleep(2)
                    request.addfinalizer(fin)
    
                def test_foo(self, fix):
                    pass
        """)
        result = testdir.runpytest('--timeout=1', '-s',
                                   '--timeout-method={0}'.format(meth))
        assert result.ret > 0
>       assert 'Timeout' in result.stdout.str() + result.stderr.str()
E       assert 'Timeout' in ('' + 'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n')
E        +  where '' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53982e0>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb53982e0>> = <_pytest.pytester.LineMatcher object at 0x7fcfb53982e0>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb53982e0> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stdout
E        +  and   'ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]\npytest.py: error: argument --timeout-method: inv... args=(False, \'signal\'), kwargs={\'reason\': \'OS does not have SIGALRM\'}))" (choose from \'signal\', \'thread\')\n' = <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb5398790>>()
E        +    where <bound method LineMatcher.str of <_pytest.pytester.LineMatcher object at 0x7fcfb5398790>> = <_pytest.pytester.LineMatcher object at 0x7fcfb5398790>.str
E        +      where <_pytest.pytester.LineMatcher object at 0x7fcfb5398790> = <RunResult ret=4 len(stdout.lines)=0 len(stderr.lines)=3 duration=0.24s>.stderr

/build/python-pytest-timeout/src/pytest-timeout/test_pytest_timeout.py:158: AssertionError
----------------------------- Captured stdout call -----------------------------
running: /usr/bin/python -mpytest --basetemp=/tmp/pytest-of-builduser/pytest-0/test_fix_finalizer6/runpytest-0 --timeout=1 -s --timeout-method=MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))
     in: /tmp/pytest-of-builduser/pytest-0/test_fix_finalizer6
----------------------------- Captured stderr call -----------------------------
ERROR: usage: pytest.py [options] [file_or_dir] [file_or_dir] [...]
pytest.py: error: argument --timeout-method: invalid choice: "MarkDecorator(mark=Mark(name='skipif', args=(False, 'signal'), kwargs={'reason': 'OS does not have SIGALRM'}))" (choose from 'signal', 'thread')

=========================== short test summary info ============================
FAILED test_pytest_timeout.py::test_fix_setup[function-meth0] - assert 'Timeo...
FAILED test_pytest_timeout.py::test_fix_setup[class-meth0] - assert 'Timeout'...
FAILED test_pytest_timeout.py::test_fix_setup[module-meth0] - assert 'Timeout...
FAILED test_pytest_timeout.py::test_fix_setup[session-meth0] - assert 'Timeou...
FAILED test_pytest_timeout.py::test_fix_finalizer[function-meth0] - assert 'T...
FAILED test_pytest_timeout.py::test_fix_finalizer[class-meth0] - assert 'Time...
FAILED test_pytest_timeout.py::test_fix_finalizer[module-meth0] - assert 'Tim...
FAILED test_pytest_timeout.py::test_fix_finalizer[session-meth0] - assert 'Ti...
======================== 8 failed, 27 passed in 38.44s =========================

Mention func_only option in README

Original report by Anonymous.


Please mention the (very useful) func_only option in the README.

Currently, it's almost impossible to find without reading the code or searching for the issue / PR that implemented it.

Use thread.interrupt_main()

Original report by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


When using the thread method pytest-timeout should try to use the thread.interrupt_main() call when a timeout occurs. The benefit is that this would allow py.test to keep running and carry on with the next test instead of simply stopping completely.

The current "thread" method behaviour should be kept available as well since it is the very safe backup option.

New hook called right before timeout occurs

Original report by Bruno Oliveira (Bitbucket: nicoddemus, GitHub: nicoddemus).


It would be nice if pytest-timeout supplied a hook that is called right before a timeout occurs:

def pytest_about_to_timeout(config):
    """Called when a timeout is reached and the test suite is about to be aborted.
    """

It could be called as the first thing in dump_stacks.

What do you think @flub? If you like the idea I could work on a PR.

Process hangs after timeout on Windows?

Original report by Florian Bruhin (Bitbucket: The-Compiler, GitHub: The-Compiler).


So I played with pytest-timeout again, but it seems like it's never finishing my build on AppVeyor after a timeout occured:

https://ci.appveyor.com/project/The-Compiler/qutebrowser/build/timeout-2017/job/i0w9743s7p55kuyr

I see the tox lines after the timeout:

___________________________________ summary ___________________________________
ERROR:   py34: commands failed

But AppVeyor never marks the build as finished. So maybe the timeout thread is not finished cleanly in the background or something?

pytest-timeout's tests fail on pypy3 Windows

From #45:

2019-11-20T10:47:29.4376002Z GLOB sdist-make: D:\a\pytest-timeout\pytest-timeout\setup.py
2019-11-20T10:47:31.0354032Z pypy3 create: D:\a\pytest-timeout\pytest-timeout\.tox\pypy3
2019-11-20T10:47:50.7392632Z pypy3 installdeps: pytest, pexpect
2019-11-20T10:47:59.3280264Z pypy3 inst: D:\a\pytest-timeout\pytest-timeout\.tox\.tmp\package\1\pytest-timeout-1.3.3.zip
2019-11-20T10:48:05.7915309Z pypy3 installed: atomicwrites==1.3.0,attrs==19.3.0,cffi==1.12.0,colorama==0.4.1,greenlet==0.4.13,importlib-metadata==0.23,more-itertools==7.2.0,packaging==19.2,pathlib2==2.3.5,pexpect==4.7.0,pluggy==0.13.0,ptyprocess==0.6.0,py==1.8.0,pyparsing==2.4.5,pytest==5.3.0,pytest-timeout==1.3.3,readline==6.2.4.1,six==1.13.0,wcwidth==0.1.7,zipp==0.6.0
2019-11-20T10:48:05.7925096Z pypy3 run-test-pre: PYTHONHASHSEED='281'
2019-11-20T10:48:05.7928537Z pypy3 run-test: commands[0] | py.test
2019-11-20T10:48:07.3011721Z INTERNALERROR> Traceback (most recent call last):
2019-11-20T10:48:07.3012233Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\_pytest\main.py", line 192, in wrap_session
2019-11-20T10:48:07.3012455Z INTERNALERROR>     config._do_configure()
2019-11-20T10:48:07.3012747Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\_pytest\config\__init__.py", line 726, in _do_configure
2019-11-20T10:48:07.3012939Z INTERNALERROR>     self.hook.pytest_configure.call_historic(kwargs=dict(config=self))
2019-11-20T10:48:07.3013133Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\hooks.py", line 308, in call_historic
2019-11-20T10:48:07.3013359Z INTERNALERROR>     res = self._hookexec(self, self.get_hookimpls(), kwargs)
2019-11-20T10:48:07.3013543Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\manager.py", line 92, in _hookexec
2019-11-20T10:48:07.3013723Z INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
2019-11-20T10:48:07.3014005Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\manager.py", line 86, in <lambda>
2019-11-20T10:48:07.3014196Z INTERNALERROR>     firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
2019-11-20T10:48:07.3014387Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 208, in _multicall
2019-11-20T10:48:07.3014586Z INTERNALERROR>     return outcome.get_result()
2019-11-20T10:48:07.3014746Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 80, in get_result
2019-11-20T10:48:07.3014928Z INTERNALERROR>     raise ex[1].with_traceback(ex[2])
2019-11-20T10:48:07.3015317Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 187, in _multicall
2019-11-20T10:48:07.3015494Z INTERNALERROR>     res = hook_impl.function(*args)
2019-11-20T10:48:07.3015679Z INTERNALERROR>   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\_pytest\faulthandler.py", line 21, in pytest_configure
2019-11-20T10:48:07.3015879Z INTERNALERROR>     if faulthandler.is_enabled():
2019-11-20T10:48:07.3016034Z INTERNALERROR> AttributeError: module 'faulthandler' has no attribute 'is_enabled'
2019-11-20T10:48:07.3048062Z Traceback (most recent call last):
2019-11-20T10:48:07.3050004Z   File "c:\hostedtoolcache\windows\pypy\3.5.3\x86\lib-python\3\runpy.py", line 193, in _run_module_as_main
2019-11-20T10:48:07.3050379Z     "__main__", mod_spec)
2019-11-20T10:48:07.3050646Z   File "c:\hostedtoolcache\windows\pypy\3.5.3\x86\lib-python\3\runpy.py", line 85, in _run_code
2019-11-20T10:48:07.3052110Z     exec(code, run_globals)
2019-11-20T10:48:07.3052656Z   File "D:\a\pytest-timeout\pytest-timeout\.tox\pypy3\bin\py.test.EXE\__main__.py", line 7, in <module>
2019-11-20T10:48:07.3053586Z     sys.exit(main())
2019-11-20T10:48:07.3054237Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\_pytest\config\__init__.py", line 92, in main
2019-11-20T10:48:07.3054452Z     config=config
2019-11-20T10:48:07.3054710Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\hooks.py", line 286, in __call__
2019-11-20T10:48:07.3054892Z     return self._hookexec(self, self.get_hookimpls(), kwargs)
2019-11-20T10:48:07.3055118Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\manager.py", line 92, in _hookexec
2019-11-20T10:48:07.3055337Z     return self._inner_hookexec(hook, methods, kwargs)
2019-11-20T10:48:07.3057362Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\manager.py", line 86, in <lambda>
2019-11-20T10:48:07.3057656Z     firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
2019-11-20T10:48:07.3057957Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 208, in _multicall
2019-11-20T10:48:07.3058200Z     return outcome.get_result()
2019-11-20T10:48:07.3058480Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 80, in get_result
2019-11-20T10:48:07.3058719Z     raise ex[1].with_traceback(ex[2])
2019-11-20T10:48:07.3058995Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 187, in _multicall
2019-11-20T10:48:07.3059234Z     res = hook_impl.function(*args)
2019-11-20T10:48:07.3060361Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\_pytest\main.py", line 233, in pytest_cmdline_main
2019-11-20T10:48:07.3061092Z     return wrap_session(config, _main)
2019-11-20T10:48:07.3062439Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\_pytest\main.py", line 228, in wrap_session
2019-11-20T10:48:07.3062687Z     config._ensure_unconfigure()
2019-11-20T10:48:07.3062920Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\_pytest\config\__init__.py", line 731, in _ensure_unconfigure
2019-11-20T10:48:07.3063090Z     self.hook.pytest_unconfigure(config=self)
2019-11-20T10:48:07.3063295Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\hooks.py", line 286, in __call__
2019-11-20T10:48:07.3063480Z     return self._hookexec(self, self.get_hookimpls(), kwargs)
2019-11-20T10:48:07.3063687Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\manager.py", line 92, in _hookexec
2019-11-20T10:48:07.3063867Z     return self._inner_hookexec(hook, methods, kwargs)
2019-11-20T10:48:07.3064072Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\manager.py", line 86, in <lambda>
2019-11-20T10:48:07.3064260Z     firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
2019-11-20T10:48:07.3064631Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 208, in _multicall
2019-11-20T10:48:07.3064793Z     return outcome.get_result()
2019-11-20T10:48:07.3065038Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 80, in get_result
2019-11-20T10:48:07.3065277Z     raise ex[1].with_traceback(ex[2])
2019-11-20T10:48:07.3065488Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\pluggy\callers.py", line 187, in _multicall
2019-11-20T10:48:07.3065641Z     res = hook_impl.function(*args)
2019-11-20T10:48:07.3065856Z   File "d:\a\pytest-timeout\pytest-timeout\.tox\pypy3\site-packages\_pytest\faulthandler.py", line 42, in pytest_unconfigure

pytest 3.8.0 deprecation warnings

Original report by Anonymous.


 149s] =============================== warnings summary ===============================
[  149s] tester/test_pytest_timeout.py:96: RemovedInPytest4Warning: Applying marks directly to parameters is deprecated, please use pytest.param(..., marks=...) instead.
[  149s] For more details, see: https://docs.pytest.org/en/latest/parametrize.html
[  149s] 
[  149s] tester/test_pytest_timeout.py:136: RemovedInPytest4Warning: Applying marks directly to parameters is deprecated, please use pytest.param(..., marks=...) instead.
[  149s] For more details, see: https://docs.pytest.org/en/latest/parametrize.html
[  149s] 
[  149s] -- Docs: https://docs.pytest.org/en/latest/warnings.html

UnicodeEncodeError when printing standard output

Original report by Bruno Oliveira (Bitbucket: nicoddemus, GitHub: nicoddemus).


Hi Floris,

When a test timeouts, it may fail to print the captured standard output if the output contains non-ascii characters:

# encoding: UTF-8
import time
import pytest

@pytest.mark.timeout(1)
def test_foo():    
    print '¯\_(ツ)_/¯'
    time.sleep(2)

Executing this test, it gives this error:

============================= test session starts =============================
platform win32 -- Python 2.7.7 -- py-1.4.26 -- pytest-2.6.4
plugins: timeout, localserver, xdist, cov, mock
collected 1 items

test_foo.py
+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Captured stdout ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Traceback (most recent call last):
  File "D:\Shared\dist\12.0-all\pytest_timeout-0.3\lib\site-packages\pytest_timeout.py", line 251, in timeout_timer
    write(stdout)
  File "D:\Shared\dist\12.0-all\pytest_timeout-0.3\lib\site-packages\pytest_timeout.py", line 304, in write
    stream.write(text)
  File "D:\Shared\dist\12.0-win64\python-2.7.X\lib\encodings\cp437.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_map)
UnicodeEncodeError: 'charmap' codec can't encode character u'\xaf' in position 0: character maps to <undefined>

This happens in version 0.3 and 0.5.

timeout does not seem to work anymore with pytest-3.3 on Windows

Original report by Bruno Oliveira (Bitbucket: nicoddemus, GitHub: nicoddemus).


Howdy!

Consider this test file:

import pytest
import time

@pytest.mark.timeout(1)
def test():
    time.sleep(3)

This works as expected in pytest-3.2 on Windows:

============================= test session starts =============================
platform win32 -- Python 2.7.12, pytest-3.2.5, py-1.5.2, pluggy-0.4.0
PyQt5 5.5.1 -- Qt runtime 5.5.1 -- Qt compiled 5.5.1
session-tmp-dir: W:\ws\Souring\Projects\etk\coilib50\tmp\tmp-6
rootdir: W:\ws\Souring\Projects\etk\coilib50, inifile: pytest.ini
plugins: llvmpipe-gl-0.0.0, cov-2.5.1, cpp-0.4.4, forked-0.2, localserver-0.3.6, mock-1.6.2, qt-2.1.0, timeout-1.2.0, xdist-1.20.1
collected 1 item

test_foo.py
+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++

~~~~~~~~~~~~~~~~~~~~~~~~~~ Stack of MainThread (1116) ~~~~~~~~~~~~~~~~~~~~~~~~~~
  File "w:\ws\Souring\envs\souring20-py27\Scripts\pytest-script.py", line 5, in <module>
    sys.exit(py.test.main())
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\config.py", line 58, in main
    return config.hook.pytest_cmdline_main(config=config)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 745, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 339, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 334, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 614, in execute
    res = hook_impl.function(*args)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\main.py", line 140, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\main.py", line 111, in wrap_session
    session.exitstatus = doit(config, session) or 0
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\main.py", line 147, in _main
    config.hook.pytest_runtestloop(session=session)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 745, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 339, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 334, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 614, in execute
    res = hook_impl.function(*args)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\main.py", line 170, in pytest_runtestloop
    item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 745, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 339, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 334, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 613, in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 248, in _wrapped_call
    call_outcome = _CallOutcome(func)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 265, in __init__
    self.result = func()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 613, in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 248, in _wrapped_call
    call_outcome = _CallOutcome(func)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 265, in __init__
    self.result = func()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 613, in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 248, in _wrapped_call
    call_outcome = _CallOutcome(func)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 265, in __init__
    self.result = func()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 614, in execute
    res = hook_impl.function(*args)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\runner.py", line 63, in pytest_runtest_protocol
    runtestprotocol(item, nextitem=nextitem)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\runner.py", line 77, in runtestprotocol
    reports.append(call_and_report(item, "call", log))
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\runner.py", line 157, in call_and_report
    call = call_runtest_hook(item, when, **kwds)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\runner.py", line 177, in call_runtest_hook
    return CallInfo(lambda: ihook(item=item, **kwds), when=when)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\runner.py", line 191, in __init__
    self.result = func()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\runner.py", line 177, in <lambda>
    return CallInfo(lambda: ihook(item=item, **kwds), when=when)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 745, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 339, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 334, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 613, in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 248, in _wrapped_call
    call_outcome = _CallOutcome(func)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 265, in __init__
    self.result = func()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 613, in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 248, in _wrapped_call
    call_outcome = _CallOutcome(func)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 265, in __init__
    self.result = func()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 614, in execute
    res = hook_impl.function(*args)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\runner.py", line 107, in pytest_runtest_call
    item.runtest()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\python.py", line 1169, in runtest
    self.ihook.pytest_pyfunc_call(pyfuncitem=self)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 745, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 339, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 334, in <lambda>
    _MultiCall(methods, kwargs, hook.spec_opts).execute()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 613, in execute
    return _wrapped_call(hook_impl.function(*args), self.execute)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 248, in _wrapped_call
    call_outcome = _CallOutcome(func)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 265, in __init__
    self.result = func()
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\vendored_packages\pluggy.py", line 614, in execute
    res = hook_impl.function(*args)
  File "w:\ws\Souring\envs\souring20-py27\lib\site-packages\_pytest\python.py", line 143, in pytest_pyfunc_call
    testfunction(**testargs)
  File "W:\ws\Souring\Projects\etk\coilib50\source\python\coilib50\unittest_tools\_tests\test_foo.py", line 6, in test
    time.sleep(3)

+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++

But it quits without any message on pytest-3.3:

============================= test session starts =============================
platform win32 -- Python 2.7.12, pytest-3.3.0, py-1.5.2, pluggy-0.6.0
PyQt5 5.5.1 -- Qt runtime 5.5.1 -- Qt compiled 5.5.1
session-tmp-dir: W:\ws\Souring\Projects\etk\coilib50\tmp\tmp-7
rootdir: W:\ws\Souring\Projects\etk\coilib50, inifile: pytest.ini
plugins: llvmpipe-gl-0.0.0, cov-2.5.1, cpp-0.4.4, forked-0.2, localserver-0.3.6, mock-1.6.2, qt-2.1.0, timeout-1.2.0, xdist-1.20.1
collected 1 item

test_foo.py
(souring20-py27) w:\ws\Souring\Projects\souring\souring20 (fb-ETK-SSRL-pytest33)
λ echo %errorlevel%
1

On Linux things seem to be working as expected.

timeout works differently in windows than it does in mac or linux

Original report by Noam Mendelssohn (Bitbucket: [Noam Mendelssohn](https://bitbucket.org/Noam Mendelssohn), ).


Hey guys
So, running timeout works great on our mac machines:

On mac, a timeout failure will continue with out destructors and fail correctly:

============================= test session starts ==============================
platform darwin -- Python 3.6.3, pytest-3.6.0, py-1.5.4, pluggy-0.6.0
rootdir: /Users/noammendelssohn/QAtest/qa-automation/tests, inifile:
plugins: testinfra-1.10.1, timeout-1.3.1collected 2 items

pr_unit_tests.py F
pr_unit_tests.py:72 (TestTimeout.test_timeout_fail)
self = <tests.pr_unit_tests.TestTimeout object at 0x10ac46ef0>

    def test_timeout_fail(self):
        """
            expected to fail
            :return:
            """
>       time.sleep(6)
E       Failed: Timeout >5.0s

pr_unit_tests.py:78: Failed
.                                                      [100%]

=================================== FAILURES ===================================
________________________ TestTimeout.test_timeout_fail _________________________

self = <tests.pr_unit_tests.TestTimeout object at 0x10ac46ef0>

    def test_timeout_fail(self):
        """
            expected to fail
            :return:
            """
>       time.sleep(6)
E       Failed: Timeout >5.0s

pr_unit_tests.py:78: Failed
====================== 1 failed, 1 passed in 8.44 seconds ======================
Process finished with exit code 0

This is as expected.

In windows, the test fails and just breaks the entire thread, not calling our destructors and basically failing things in a non graceful way:


~~~~~~~~~~~~~~~~~~~~~~~~~ Stack of MainThread (13808) ~~~~~~~~~~~~~~~~~~~~~~~~~~
  File "C:\Program Files\JetBrains\PyCharm Community Edition 2018.1\helpers\pycharm\_jb_pytest_runner.py", line 31, in <module>
    pytest.main(args, plugins_to_load)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\config.py", line 61, in main
    return config.hook.pytest_cmdline_main(config=config)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\main.py", line 138, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\main.py", line 107, in wrap_session
    session.exitstatus = doit(config, session) or 0
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\main.py", line 145, in _main
    config.hook.pytest_runtestloop(session=session)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\main.py", line 168, in pytest_runtestloop
    item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\runner.py", line 62, in pytest_runtest_protocol
    runtestprotocol(item, nextitem=nextitem)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\runner.py", line 79, in runtestprotocol
    reports.append(call_and_report(item, "call", log))
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\runner.py", line 159, in call_and_report
    call = call_runtest_hook(item, when, **kwds)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\runner.py", line 180, in call_runtest_hook
    treat_keyboard_interrupt_as_exception=item.config.getvalue("usepdb"))
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\runner.py", line 194, in __init__
    self.result = func()
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\runner.py", line 179, in <lambda>
    return CallInfo(lambda: ihook(item=item, **kwds), when=when,
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\runner.py", line 110, in pytest_runtest_call
    item.runtest()
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\python.py", line 1206, in runtest
    self.ihook.pytest_pyfunc_call(pyfuncitem=self)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "C:\spectron_sample\daqri_scan\venv\lib\site-packages\_pytest\python.py", line 152, in pytest_pyfunc_call
    testfunction(**testargs)
  File "C:\qa-automation246\tests\scan_tests\test_desktop.py", line 202, in test_timeout_fail
    time.sleep(6)

+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++

Process finished with exit code 1

Test example to recreate issue below.

Just run on mac and windows and see how it behaves differently.

This is required for test failures to : collect logs, take screenshots, clean up resources, etc. Please feel free to comment for any further clarifications etc. (demo code only of course, tis not our tests :) )

#!python

@pytest.mark.timeout(5)
class TestTimeout:
    def test_timeout_fail(self):
        """
        expected to fail
        :return:
        """
        time.sleep(6)
        assert True
    # can be used for methods
    # @pytest.mark.timeout(7)

    def test_timeout_pass(self):
        """
        expected to pass
        :return:
        """
        time.sleep(3)
        assert True

pytest-timeout does not work correctly with python2.7

Original report by Alexander Petrov (Bitbucket: alvipet, ).


Hi,

My bag is the same as https://bitbucket.org/pytest-dev/pytest-timeout/issues/21/timeout-does-not-seem-to-work-anymore-with

I have the next stack trace:

#!python

+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++

~~~~~~~~~~~~~~~~~~~~~~~~ Stack of MainThread (2897892) ~~~~~~~~~~~~~~~~~~~~~~~~~
  File "d:\python27\Lib\runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "d:\python27\Lib\runpy.py", line 72, in _run_code
    exec code in run_globals
  File "d:\data\jenkins\venv\Scripts\pytest.exe\__main__.py", line 9, in <module>
    sys.exit(main())
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\config.py", line 59, in main
    return config.hook.pytest_cmdline_main(config=config)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\main.py", line 134, in pytest_cmdline_main
    return wrap_session(config, _main)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\main.py", line 103, in wrap_session
    session.exitstatus = doit(config, session) or 0
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\main.py", line 141, in _main
    config.hook.pytest_runtestloop(session=session)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\main.py", line 164, in pytest_runtestloop
    item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\runner.py", line 62, in pytest_runtest_protocol
    runtestprotocol(item, nextitem=nextitem)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\runner.py", line 76, in runtestprotocol
    reports.append(call_and_report(item, "call", log))
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\runner.py", line 155, in call_and_report
    call = call_runtest_hook(item, when, **kwds)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\runner.py", line 175, in call_runtest_hook
    return CallInfo(lambda: ihook(item=item, **kwds), when=when)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\runner.py", line 189, in __init__
    self.result = func()
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\runner.py", line 175, in <lambda>
    return CallInfo(lambda: ihook(item=item, **kwds), when=when)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\runner.py", line 106, in pytest_runtest_call
    item.runtest()
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\python.py", line 1171, in runtest
    self.ihook.pytest_pyfunc_call(pyfuncitem=self)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 617, in __call__
    return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 222, in _hookexec
    return self._inner_hookexec(hook, methods, kwargs)
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\__init__.py", line 216, in <lambda>
    firstresult=hook.spec_opts.get('firstresult'),
  File "d:\data\jenkins\venv\lib\site-packages\pluggy\callers.py", line 180, in _multicall
    res = hook_impl.function(*args)
  File "d:\data\jenkins\venv\lib\site-packages\_pytest\python.py", line 147, in pytest_pyfunc_call
    testfunction(**testargs)
  File "D:\data\jenkins\tmp\test_1.py", line 6, in test
    time.sleep(5)

+++++++++++++++++++++++++++++++++++ Timeout ++++++++++++++++++++++++++++++++++++

Detect when the fail exception was caught in the test

Original report by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


Sometimes a test can catch the pytest.fail.Exception itself which makes it look like the test was fine while it did really time out.

One improvement is to use an exception which is a subclass of BaseException instead. Then in the pytest_runtest_call hook catch this exception and change it to a pytest.fail.Exception.

Another improvement is to mark the test item as timed out in the signal handler. Then e.g. pytest_runtest_call call can detect when the test cheated and caught the exception, after which it can fail it anyway with an appropriate message.

improvement: make pytest-timeout failure message customizable

Original report by Anonymous.


i was trying to customize the pytest-timeout failure message one of this days and notice there is no extension point (hook or argument) that allows me to do that. digging in the code i noticed that this is due to the failure message being hardcoded (see https://bitbucket.org/pytest-dev/pytest-timeout/src/ea3ba7b8f9b3ed4fe75d981f0f98765e71ef7a7a/pytest_timeout.py?at=default#pytest_timeout.py-225).
therefore, this ticket is to suggest allowing this failure message to be somehow customizable (preferably via hook).

Run fixture finalizers after a timeout

Original report by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


Often fixture finalizers can be in charge of killing subprocesses etc, in case of a timeout it would be nice if they still got run to clean up. This would probably also mean you need a hard timeout as well as a per-test timeout in case the finalizer itself hangs.

pytest-timeout doesn't work with pytest-rerunfailures.

Original report by Anonymous.


pytest-timeout plugin doesn't work when pytest-rerunfailures is used. Please see a example at the end of this bug report

  • pip list of the virtual environment you are using
alabaster (0.7.10)
apipkg (1.4)
appnope (0.1.0)
astroid (1.4.9)
Babel (2.4.0)
bleach (1.5.0)
CommonMark (0.5.4)
coverage (4.3.4)
cycler (0.10.0)
decorator (4.0.11)
docopt (0.6.2)
docutils (0.13.1)
entrypoints (0.2.2)
execnet (1.4.1)
flake8 (3.3.0)
html5lib (0.999)
imagesize (0.7.1)
ipykernel (4.6.1)
ipyparallel (6.0.2)
ipython (6.0.0)
ipython-genutils (0.2.0)
ipywidgets (6.0.0)
isort (4.2.5)
jedi (0.10.2)
Jinja2 (2.9.6)
joblib (0.11)
jsonschema (2.6.0)
jupyter (1.0.0)
jupyter-client (5.0.1)
jupyter-console (5.1.0)
jupyter-core (4.3.0)
lazy-object-proxy (1.2.2)
MarkupSafe (0.23)
matplotlib (2.0.2)
mccabe (0.6.1)
mistune (0.7.4)
nbconvert (5.1.1)
nbformat (4.3.0)
nose (1.3.7)
notebook (5.0.0)
numpy (1.12.1)
pandas (0.20.1)
pandocfilters (1.4.1)
pexpect (4.2.1)
pickleshare (0.7.4)
pip (9.0.1)
prompt-toolkit (1.0.14)
psycopg2 (2.7.1)
ptyprocess (0.5.1)
py (1.4.33)
pyarrow (0.2.0)
pycodestyle (2.3.1)
pyflakes (1.5.0)
Pygments (2.2.0)
pylint (1.6.4)
pyparsing (2.1.4)
pytest (3.0.7)
pytest-cache (1.0)
pytest-instafail (0.3.0)
pytest-rerunfailures (2.1.0)
pytest-timeout (1.0.0)
python-dateutil (2.6.0)
pytz (2017.2)
pyzmq (16.0.2)
qtconsole (4.3.0)
recommonmark (0.4.0)
requests (2.14.2)
scikit-learn (0.18.1)
scipy (0.19.0)
seaborn (0.7.1)
setuptools (27.2.0)
simplegeneric (0.8.1)
simplejson (3.10.0)
six (1.10.0)
snakeviz (0.4.1)
snowballstemmer (1.2.1)
Sphinx (1.5.6)
sphinx-rtd-theme (0.2.4)
SQLAlchemy (1.1.9)
terminado (0.6)
testpath (0.3)
tornado (4.5.1)
traitlets (4.3.2)
typing (3.6.1)
wcwidth (0.1.7)
wheel (0.29.0)
widgetsnbextension (2.0.0)
wrapt (1.10.10)
  • pytest and operating system versions
OS : OSX El Captian 
pytest --version
This is pytest version 3.0.7, 
  pytest-instafail-0.3.0 at 
  pytest-rerunfailures-2.1.0 at 
  pytest-timeout-1.0.0 at
  • Minimal example if possible
import pytest
import time


@pytest.mark.timeout(2)
@pytest.mark.flaky(3) # comment this line to see the test fail as expected
def test_new():
    time.sleep(10)
    assert True

Timeout without error

Original report by Anonymous.


Hey everyone,

currently, when a test exceeds the timeout limit and has to be stopped, it's handled as a failed test. Is there a way to stop the test after the timeout limit without handling it as an error?

Thanks a lot

Some tests failing on CI

Original report by Anonymous.


I am building a package for Alpine Linux, alpinelinux/aports#8021, and 8 tests are failing:

#!python

=========================== short test summary info ============================
--
457 | FAILED test_pytest_timeout.py::test_fix_setup[function-meth0]
458 | FAILED test_pytest_timeout.py::test_fix_setup[class-meth0]
459 | FAILED test_pytest_timeout.py::test_fix_setup[module-meth0]
460 | FAILED test_pytest_timeout.py::test_fix_setup[session-meth0]
461 | FAILED test_pytest_timeout.py::test_fix_finalizer[function-meth0]
462 | FAILED test_pytest_timeout.py::test_fix_finalizer[class-meth0]
463 | FAILED test_pytest_timeout.py::test_fix_finalizer[module-meth0]
464 | FAILED test_pytest_timeout.py::test_fix_finalizer[session-meth0]
465 | ===================== 8 failed, 27 passed in 42.96 seconds =====================

The testing environment is:

#!python

============================= test session starts ==============================
platform linux -- Python 3.7.3, pytest-4.4.0, py-1.8.0, pluggy-0.9.0
rootdir: /home/buildozer/aports/testing/py-pytest-timeout/src/pytest-timeout-1.3.3, inifile: tox.ini
plugins: timeout-1.3.3
collected 35 items

Timeout on one test aborts following tests?

Original report by LemonPi (Bitbucket: LemonPi, GitHub: LemonPi).


Currently if one test fails on a timeout, all other tests are aborted. Is this intended? Is it possible to execute the other tasks?

I'm using python 3.6.5 on windows with pytest 3.6.0

Sample code:

#!python

@pytest.mark.timeout(1)
def test_fail():
    while True:
        pass


def test_should_run():
    pass

test_should_run is never run

Timeout just the test

Original report by Pedro Algarvio (Bitbucket: [Pedro Algarvio](https://bitbucket.org/Pedro Algarvio), ).


Right now, the plugin includes all of the fixture prep work towards the actual test as part of the timeout. If we have enough prep work, bringing a DB daemon up, or similar, and a fairly low timeout value, we could hit timeout even before starting the actual testing.

By using pytest_pyfunc_call instead of pytest_runtest_protocol we could not include the fixture setup/teardown towards the actual timeout.

For backwards compatibility, this should probably be configurable.

Not working when retrying

I expect following test to fail after 1 second

import pytest
from retrying import retry

@retry(
    stop_max_delay=15*1000,
    wait_fixed=1000
)
def _loop_until_condition():
    assert 1 == 0

class TestSample:
	def test_something(self):
	    _loop_until_condition()
$ time pytest test_x.py --timeout 1
platform linux -- Python 3.6.8, pytest-4.4.0, py-1.6.0, pluggy-0.9.0
plugins: timeout-1.3.4
timeout: 1.0s
timeout method: signal
timeout func_only: False
collected 1 item

test_x.py F                                                                      [100%]

===FAILURES ===
___TestSample.test_something ___

self = <test_x.TestSample object at 0x7f5d5206b198>

    def test_something(self):
>       _loop_until_condition()

test_x.py:15:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../lib/python3.6/site-packages/retrying.py:49: in wrapped_f
    return Retrying(*dargs, **dkw).call(f, *args, **kw)
../../lib/python3.6/site-packages/retrying.py:212: in call
    raise attempt.get()
../../lib/python3.6/site-packages/retrying.py:247: in get
    six.reraise(self.value[0], self.value[1], self.value[2])
../../lib/python3.6/site-packages/six.py:686: in reraise
    raise value
../../lib/python3.6/site-packages/retrying.py:200: in call
    attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    @retry(
        stop_max_delay=15*1000,
        wait_fixed=1000
    )
    def _loop_until_condition():
>       assert 1 == 0
E       assert 1 == 0

test_x.py:11: AssertionError

real	0m23.207s
user 0m0.963s
sys	0m0.083s

Refs: #18

Timeout generates INTERNALERROR

Original report by Marc Finet (Bitbucket: marcrtone, ).


Hello,

I'm experiencing a weird issue with pytest-timeout on my raspberrypi with raspbian stretch (it's ok on my dev machine also debian stretch, but with older pytest/pytest-timeout)

On my raspberrypi:

platform linux -- Python 3.5.3, pytest-3.6.2, py-1.7.0, pluggy-0.6.0 -- /usr/bin/python3
cachedir: .pytest_cache                                                                                        
rootdir: /var/tmp/tests, inifile: pytest.ini    
plugins: timeout-1.0.0                                                                                              
collected 114 items / 113 deselected                                                                                                   
                                                                                                                      
protocol_test.py::test_status_version                                 
------------------------------------------------------------ live log setup ------------------------------------------------------------
15:51:53.935      protocol.py:267  INFO   FT232: True, HIDAPI: False, SPEED: 50, USE_INT: True
------------------------------------------------------------ live log call -------------------------------------------------------------
15:51:54.053 protocol_test.py:399  INFO   test_status_version()
                                                       
INTERNALERROR> Traceback (most recent call last):                                                                              
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/main.py", line 178, in wrap_session
INTERNALERROR>     session.exitstatus = doit(config, session) or 0                                                               
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/main.py", line 215, in _main
INTERNALERROR>     config.hook.pytest_runtestloop(session=session)  
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 617, in __call__
INTERNALERROR>     return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)                 
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 222, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)                                              
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 216, in <lambda>
INTERNALERROR>     firstresult=hook.spec_opts.get('firstresult'),                                        
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 201, in _multicall
INTERNALERROR>     return outcome.get_result()
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 76, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])                                                                                    
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 180, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/main.py", line 236, in pytest_runtestloop
INTERNALERROR>     item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 617, in __call__
INTERNALERROR>     return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 222, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 216, in <lambda>                           
INTERNALERROR>     firstresult=hook.spec_opts.get('firstresult'),                       
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 201, in _multicall
INTERNALERROR>     return outcome.get_result()          
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 76, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])                               
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 180, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)                                                   
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/runner.py", line 64, in pytest_runtest_protocol
INTERNALERROR>     runtestprotocol(item, nextitem=nextitem)                                   
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/runner.py", line 79, in runtestprotocol
INTERNALERROR>     reports.append(call_and_report(item, "call", log))  
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/runner.py", line 161, in call_and_report
INTERNALERROR>     report = hook.pytest_runtest_makereport(item=item, call=call)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 617, in __call__
INTERNALERROR>     return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 222, in _hookexec
INTERNALERROR>     return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/__init__.py", line 216, in <lambda>
INTERNALERROR>     firstresult=hook.spec_opts.get('firstresult'),
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 196, in _multicall
INTERNALERROR>     gen.send(outcome)                                                    
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/skipping.py", line 123, in pytest_runtest_makereport
INTERNALERROR>     rep = outcome.get_result()           
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 76, in get_result
INTERNALERROR>     raise ex[1].with_traceback(ex[2])                               
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pluggy/callers.py", line 180, in _multicall
INTERNALERROR>     res = hook_impl.function(*args)                                                   
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/runner.py", line 328, in pytest_runtest_makereport
INTERNALERROR>     longrepr = item.repr_failure(excinfo)                                      
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/python.py", line 672, in repr_failure
INTERNALERROR>     return self._repr_failure_py(excinfo, style=style)  
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/python.py", line 665, in _repr_failure_py
INTERNALERROR>     return super(FunctionMixin, self)._repr_failure_py(excinfo, style=style)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/nodes.py", line 295, in _repr_failure_py                     
INTERNALERROR>     tbfilter=tbfilter,                                                   
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/_code/code.py", line 472, in getrepr
INTERNALERROR>     return fmt.repr_excinfo(self)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/_code/code.py", line 712, in repr_excinfo
INTERNALERROR>     reprtraceback = self.repr_traceback(excinfo)                                                                        
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/_code/code.py", line 659, in repr_traceback
INTERNALERROR>     reprentry = self.repr_traceback_entry(entry, einfo)
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/_code/code.py", line 604, in repr_traceback_entry            
INTERNALERROR>     source = self._getentrysource(entry)                                       
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/_code/code.py", line 527, in _getentrysource                 
INTERNALERROR>     source = entry.getsource(self.astcache)     
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/_code/code.py", line 220, in getsource                                   
INTERNALERROR>     self.lineno, source, astnode=astnode
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/_code/source.py", line 349, in getstatementrange_ast
INTERNALERROR>     start, end = get_statement_startend2(lineno, astnode)                                      
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/_code/source.py", line 326, in get_statement_startend2
INTERNALERROR>     for x in ast.walk(node):                                                            
INTERNALERROR>   File "/usr/lib/python3.5/ast.py", line 216, in walk
INTERNALERROR>     node = todo.popleft()                                                                     
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pytest_timeout.py", line 101, in handler
INTERNALERROR>     timeout_sigalrm(item, timeout)                                                             
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/pytest_timeout.py", line 227, in timeout_sigalrm
INTERNALERROR>     pytest.fail('Timeout >%ss' % timeout)                                                     
INTERNALERROR>   File "/home/pi/.local/lib/python3.5/site-packages/_pytest/outcomes.py", line 96, in fail
INTERNALERROR>     raise Failed(msg=msg, pytrace=pytrace)                                                     
INTERNALERROR> Failed: Timeout >1s            
                                                                                                             
==================================================== 113 deselected in 7.75 seconds ====================================================

Same results with pytest-3.10.0 and timeout-1.3.2 (I went to an old setup as my dev machine on which test pass or timeout is correctly handled).

The thread method does not work:

============================================================================================================================== test session starts ==============================================================================================================================
platform linux -- Python 3.5.3, pytest-3.6.2, py-1.7.0, pluggy-0.6.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /var/tmp/tests, inifile: pytest.ini
plugins: timeout-1.0.0
collected 114 items / 113 deselected                                                                                                                                                                                                                                            

protocol_test.py::test_status_version
-------------------------------------------------------------------------------------------------------------------------------- live log setup ---------------------------------------------------------------------------------------------------------------------------------
15:57:54.376      protocol.py:267  INFO   FT232: True, HIDAPI: False, SPEED: 50, USE_INT: True
--------------------------------------------------------------------------------------------------------------------------------- live log call ---------------------------------------------------------------------------------------------------------------------------------
15:57:54.495 protocol_test.py:399  INFO   test_status_version()
Traceback (most recent call last):
  File "/home/pi/.local/lib/python3.5/site-packages/pytest_timeout.py", line 241, in timeout_timer
    stdout, stderr = capman.suspendcapture(item)
AttributeError: 'CaptureManager' object has no attribute 'suspendcapture'

(and same error with pytest-3.10.0 and timeout-1.3.2)

Notes:

  • the test involves a USB breakout with a FT232H chip.
  • my dev machine does not have the pluggy stuff
  • I cannot reproduce with a sleep that times out.

Any help appreciated.

Tests failed with pytest 2.8.0

Original report by Felix Yan (Bitbucket: felixonmars, GitHub: felixonmars).


The tests failed to run with pytest 2.8.0. It exits right after completing the first test and fails. Maybe related: pytest 2.8.0 will treat 0 tests discovered as an error while pytest 2.7.3 won't.

Terminal outputs:

============================= test session starts ==============================
platform linux -- Python 3.4.3, pytest-2.8.0, py-1.4.30, pluggy-0.3.1
rootdir: /build/python-pytest-timeout/src/pytest-timeout, inifile: tox.ini
plugins: timeout-0.5
collected 29 items

test_pytest_timeout.py .

Disable timeout on debugging

Original report by Anonymous.


Hi,

I am looking for an option to disable pytest-timeout when executing in debug mode,
even tests under @pytest.mark.timeout(...). Any option I could pass?

Thanks for help in advance.

use timeout to make a test fails, not to quit the entire testsuite.

Original report by Andrea Bisello (Bitbucket: abioneperhobby, ).


i would like to make a single test fails if it took over than n seconds of time,

but using pytest-timeout i will terminate the entire test suite.

i read

there is any working workaround?

thanks for the feedback.

[Docs] Clearly state that timeout value applies to a test, not test session

Original report by Андрей Парамонов (Bitbucket: aparamon, GitHub: aparamon).


Currently, docs say:

This is a plugin which will terminate tests after a certain timeout. When doing so it will show a stack dump of all threads running at the time. This is useful when running tests under a continuous integration server or simply if you don’t know why the test suite hangs.

It seems that the plugin will terminate the long-running test suite (i.e. timeout applies to the test session), however in reality timeout applies to every test item, independently.

It is proposed to re-phrase:

This is a plugin which terminates a test after a certain timeout.

pytest-xdist interop: signal only works in main thread

Original report by Buck Evan (Bitbucket: bukzor, GitHub: bukzor).


I'm getting this kind of error with increasing frequency as I add tests to my project.

#!python

INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/_pytest/main.py", line 84, in wrap_session
INTERNALERROR>     doit(config, session)
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/_pytest/main.py", line 122, in _main
INTERNALERROR>     config.hook.pytest_runtestloop(session=session)
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/_pytest/core.py", line 413, in __call__
INTERNALERROR>     return self._docall(methods, kwargs)
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/_pytest/core.py", line 424, in _docall
INTERNALERROR>     res = mc.execute()
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/_pytest/core.py", line 315, in execute
INTERNALERROR>     res = method(**kwargs)
INTERNALERROR>   File "<remote exec>", line 59, in pytest_runtestloop
INTERNALERROR>   File "<remote exec>", line 72, in run_tests
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/_pytest/core.py", line 413, in __call__
INTERNALERROR>     return self._docall(methods, kwargs)
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/_pytest/core.py", line 424, in _docall
INTERNALERROR>     res = mc.execute()
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/_pytest/core.py", line 315, in execute
INTERNALERROR>     res = method(**kwargs)
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/pytest_timeout.py", line 70, in pytest_runtest_protocol
INTERNALERROR>     timeout_setup(item)
INTERNALERROR>   File "/home/travis/build/Yelp/venv-update/.tox/test/lib/python3.4/site-packages/pytest_timeout.py", line 95, in timeout_setup
INTERNALERROR>     signal.signal(signal.SIGALRM, handler)
INTERNALERROR> ValueError: signal only works in main thread

Full detail:

New py.test fixtures teardown does not play nice

Original report by Floris Bruynooghe (Bitbucket: flub, GitHub: flub).


The teardown of the py.test 2.3 fixtures is executed outside of the timeout-managed code. Especially session-scoped fixtures appear to be torn down after the session itself is torn down. The result is that a hang in the teardown does not get caught by pytest-timeout

use only one thread for pytest-timeout

because only one timer is needed at a time I think you can block on a queue of timeouts with the timeout of the previously queued timeout or None:

Here's a sketch

_DONE = object()

def _worker(q):
    timeout = None
    while timeout is not _DONE:
        try:
            timeout = q.get(block=True, timeout=timeout)
        except queue.Empty:
            _kill_test_suite()

@attr.ib(frozen=True)
class _Timer(object):
    __q = attr.ib()
    def set_timeout(self, t):
        assert t > 0
        self.__q.put(t)
    def reset_timeout(self):
        self.__q.put(None)

    @contextlib.contextmanager
    def timer(cls):
        q = queue.Queue(maxsize=1)
        with threads.Thread(_worker, name=__name__, args=(q, )) as t:
            try:
                yield cls(q)
            finally:
                q.put(_DONE)

"put"ing a new timeout on the queue automatically "cancels" the previous one, so reset_timeout is only needed for pdb support

CI does not run py37 tox env

There are 2 tox envs using python3.7: py37 and linting. It seems only the linting one runs on CI, probably because it's the last one in the config. Ideally we'd fix CI to also run the py37 tox env.

signals should be blocked in thread when using thread timeout method

Original report by Christopher Hunt (Bitbucket: chrahunt, GitHub: chrahunt).


Currently in Python it's only possible to change your signal disposition on a thread-specific basis using signal.pthread_sigmask. When a test depends on certain signals being blocked but we use the thread method for pytest-timeout, the signal is still received by the process via the internal thread maintained by pytest-timeout and it is then propagated to the main thread by the Python runtime.

The fix is to surround the thread start with something like

old_mask = signal.pthread_sigmask(signal.SIG_SETMASK, range(1, signal.NSIG))
t.start()
signal.pthread_sigmask(signal.SIG_SETMASK, old_mask)

This works because the signal mask is inherited by spawned threads, and also avoids a potential race condition if we were to set the signal mask inside the thread target function itself.

Currently I work around this issue by patching threading.Thread.start to do the same as above.

Incompatibility with pytest 3.7.3

Original report by Bruno Oliveira (Bitbucket: nicoddemus, GitHub: nicoddemus).


Hi @flub!

I just discovered that pytest 3.7.3 broke pytest timeout due to changes in the internal CaptureManager API. I implemented the fix on my fork, but for some reason when I try to open a PR to this repository it wants to merge a bunch of commits which are not related to this change. My HG-fu is near non-existent so I'm not sure how to fix this.

Anyway the fix is simple, here is the commit:

https://bitbucket.org/nicoddemus/pytest-timeout/commits/c53b464dbd458205f5db4ce8849bba58221f3143

You might consider dropping support for old pytest versions versions (say <3.3).

Let me know if I can help in any way!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.