644fab4
--- tests/runners.py
644fab4
+++ tests/runners.py
644fab4
@@ -18,6 +18,10 @@ from pytest import raises, skip
55e9f2e
 from pytest_relaxed import trap
55e9f2e
 from mock import patch, Mock, call
55e9f2e
 
55e9f2e
+from pytest import __version__ as pytest_version
55e9f2e
+from pytest import mark as pytest_mark
55e9f2e
+max_pytest_version = pytest_mark.skipif(pytest_version >= '3.3', reason='Test fails with more recent versions of pytest (GH#530)')
55e9f2e
+
55e9f2e
 from invoke import (
644fab4
     CommandTimedOut,
644fab4
     Config,
644fab4
@@ -168,16 +172,19 @@ class Runner_:
55e9f2e
                 assert False, "Invalid run() kwarg didn't raise TypeError"
55e9f2e
 
55e9f2e
     class warn:
55e9f2e
+        @max_pytest_version
55e9f2e
         def honors_config(self):
55e9f2e
             runner = self._runner(run={"warn": True}, exits=1)
55e9f2e
             # Doesn't raise Failure -> all good
55e9f2e
             runner.run(_)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def kwarg_beats_config(self):
55e9f2e
             runner = self._runner(run={"warn": False}, exits=1)
55e9f2e
             # Doesn't raise Failure -> all good
55e9f2e
             runner.run(_, warn=True)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def does_not_apply_to_watcher_errors(self):
55e9f2e
             runner = self._runner(out="stuff")
55e9f2e
             try:
644fab4
@@ -188,6 +195,7 @@ class Runner_:
55e9f2e
             else:
55e9f2e
                 assert False, "Did not raise Failure for WatcherError!"
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def does_not_apply_to_timeout_errors(self):
55e9f2e
             with raises(CommandTimedOut):
55e9f2e
                 self._runner(klass=_TimingOutRunner).run(
644fab4
@@ -196,6 +204,7 @@ class Runner_:
55e9f2e
 
55e9f2e
     class hide:
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def honors_config(self):
55e9f2e
             runner = self._runner(out="stuff", run={"hide": True})
55e9f2e
             r = runner.run(_)
644fab4
@@ -203,6 +212,7 @@ class Runner_:
55e9f2e
             assert sys.stdout.getvalue() == ""
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def kwarg_beats_config(self):
55e9f2e
             runner = self._runner(out="stuff")
55e9f2e
             r = runner.run(_, hide=True)
644fab4
@@ -210,51 +220,64 @@ class Runner_:
55e9f2e
             assert sys.stdout.getvalue() == ""
55e9f2e
 
55e9f2e
     class pty:
55e9f2e
+        @max_pytest_version
55e9f2e
         def pty_defaults_to_off(self):
55e9f2e
             assert self._run(_).pty is False
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def honors_config(self):
55e9f2e
             runner = self._runner(run={"pty": True})
55e9f2e
             assert runner.run(_).pty is True
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def kwarg_beats_config(self):
55e9f2e
             runner = self._runner(run={"pty": False})
55e9f2e
             assert runner.run(_, pty=True).pty is True
55e9f2e
 
55e9f2e
     class shell:
55e9f2e
+        @max_pytest_version
55e9f2e
         def defaults_to_bash_or_cmdexe_when_pty_True(self):
55e9f2e
             _expect_platform_shell(self._run(_, pty=True).shell)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def defaults_to_bash_or_cmdexe_when_pty_False(self):
55e9f2e
             _expect_platform_shell(self._run(_, pty=False).shell)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def may_be_overridden(self):
55e9f2e
             assert self._run(_, shell="/bin/zsh").shell == "/bin/zsh"
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def may_be_configured(self):
55e9f2e
             runner = self._runner(run={"shell": "/bin/tcsh"})
55e9f2e
             assert runner.run(_).shell == "/bin/tcsh"
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def kwarg_beats_config(self):
55e9f2e
             runner = self._runner(run={"shell": "/bin/tcsh"})
55e9f2e
             assert runner.run(_, shell="/bin/zsh").shell == "/bin/zsh"
55e9f2e
 
55e9f2e
     class env:
55e9f2e
+        @max_pytest_version
55e9f2e
         def defaults_to_os_environ(self):
55e9f2e
             assert self._run(_).env == os.environ
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def updates_when_dict_given(self):
55e9f2e
             expected = dict(os.environ, FOO="BAR")
55e9f2e
             assert self._run(_, env={"FOO": "BAR"}).env == expected
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def replaces_when_replace_env_True(self):
55e9f2e
             env = self._run(_, env={"JUST": "ME"}, replace_env=True).env
55e9f2e
             assert env == {"JUST": "ME"}
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def config_can_be_used(self):
55e9f2e
             env = self._run(_, settings={"run": {"env": {"FOO": "BAR"}}}).env
55e9f2e
             assert env == dict(os.environ, FOO="BAR")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def kwarg_wins_over_config(self):
55e9f2e
             settings = {"run": {"env": {"FOO": "BAR"}}}
55e9f2e
             kwarg = {"FOO": "NOTBAR"}
644fab4
@@ -262,6 +285,7 @@ class Runner_:
55e9f2e
             assert foo == "NOTBAR"
55e9f2e
 
55e9f2e
     class return_value:
55e9f2e
+        @max_pytest_version
55e9f2e
         def return_code(self):
55e9f2e
             """
55e9f2e
             Result has .return_code (and .exited) containing exit code int
644fab4
@@ -271,44 +295,54 @@ class Runner_:
55e9f2e
             assert r.return_code == 17
55e9f2e
             assert r.exited == 17
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def ok_attr_indicates_success(self):
55e9f2e
             runner = self._runner()
55e9f2e
             assert runner.run(_).ok is True  # default dummy retval is 0
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def ok_attr_indicates_failure(self):
55e9f2e
             runner = self._runner(exits=1)
55e9f2e
             assert runner.run(_, warn=True).ok is False
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def failed_attr_indicates_success(self):
55e9f2e
             runner = self._runner()
55e9f2e
             assert runner.run(_).failed is False  # default dummy retval is 0
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def failed_attr_indicates_failure(self):
55e9f2e
             runner = self._runner(exits=1)
55e9f2e
             assert runner.run(_, warn=True).failed is True
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def stdout_attribute_contains_stdout(self):
55e9f2e
             runner = self._runner(out="foo")
55e9f2e
             assert runner.run(_).stdout == "foo"
55e9f2e
             assert sys.stdout.getvalue() == "foo"
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def stderr_attribute_contains_stderr(self):
55e9f2e
             runner = self._runner(err="foo")
55e9f2e
             assert runner.run(_).stderr == "foo"
55e9f2e
             assert sys.stderr.getvalue() == "foo"
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def whether_pty_was_used(self):
55e9f2e
             assert self._run(_).pty is False
55e9f2e
             assert self._run(_, pty=True).pty is True
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def command_executed(self):
55e9f2e
             assert self._run(_).command == _
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def shell_used(self):
55e9f2e
             _expect_platform_shell(self._run(_).shell)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def hide_param_exposed_and_normalized(self):
55e9f2e
             assert self._run(_, hide=True).hide, "stdout" == "stderr"
55e9f2e
             assert self._run(_, hide=False).hide == tuple()
644fab4
@@ -316,26 +350,31 @@ class Runner_:
55e9f2e
 
55e9f2e
     class command_echoing:
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def off_by_default(self):
55e9f2e
             self._run("my command")
55e9f2e
             assert sys.stdout.getvalue() == ""
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def enabled_via_kwarg(self):
55e9f2e
             self._run("my command", echo=True)
55e9f2e
             assert "my command" in sys.stdout.getvalue()
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def enabled_via_config(self):
55e9f2e
             self._run("yup", settings={"run": {"echo": True}})
55e9f2e
             assert "yup" in sys.stdout.getvalue()
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def kwarg_beats_config(self):
55e9f2e
             self._run("yup", echo=True, settings={"run": {"echo": False}})
55e9f2e
             assert "yup" in sys.stdout.getvalue()
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def uses_ansi_bold(self):
55e9f2e
             self._run("my command", echo=True)
55e9f2e
             # TODO: vendor & use a color module
644fab4
@@ -374,6 +413,7 @@ class Runner_:
55e9f2e
         #
55e9f2e
         # Use UTF-7 as a valid encoding unlikely to be a real default derived
55e9f2e
         # from test-runner's locale.getpreferredencoding()
55e9f2e
+        @max_pytest_version
55e9f2e
         def defaults_to_encoding_method_result(self):
55e9f2e
             # Setup
55e9f2e
             runner = self._runner()
644fab4
@@ -384,6 +424,7 @@ class Runner_:
55e9f2e
             runner.default_encoding.assert_called_with()
55e9f2e
             assert runner.encoding == "UTF-7"
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def honors_config(self):
55e9f2e
             c = Context(Config(overrides={"run": {"encoding": "UTF-7"}}))
55e9f2e
             runner = _Dummy(c)
644fab4
@@ -419,27 +460,35 @@ class Runner_:
55e9f2e
             assert sys.stdout.getvalue() == expect_out
55e9f2e
             assert sys.stderr.getvalue() == expect_err
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def both_hides_everything(self):
55e9f2e
             self._expect_hidden("both")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def True_hides_everything(self):
55e9f2e
             self._expect_hidden(True)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def out_only_hides_stdout(self):
55e9f2e
             self._expect_hidden("out", expect_out="", expect_err="bar")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def err_only_hides_stderr(self):
55e9f2e
             self._expect_hidden("err", expect_out="foo", expect_err="")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def accepts_stdout_alias_for_out(self):
55e9f2e
             self._expect_hidden("stdout", expect_out="", expect_err="bar")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def accepts_stderr_alias_for_err(self):
55e9f2e
             self._expect_hidden("stderr", expect_out="foo", expect_err="")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def None_hides_nothing(self):
55e9f2e
             self._expect_hidden(None, expect_out="foo", expect_err="bar")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def False_hides_nothing(self):
55e9f2e
             self._expect_hidden(False, expect_out="foo", expect_err="bar")
55e9f2e
 
644fab4
@@ -460,28 +509,33 @@ class Runner_:
55e9f2e
                     False
55e9f2e
                 ), "run() did not raise ValueError for bad hide= value"  # noqa
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def does_not_affect_capturing(self):
55e9f2e
             assert self._runner(out="foo").run(_, hide=True).stdout == "foo"
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def overrides_echoing(self):
55e9f2e
             self._runner().run("invisible", hide=True, echo=True)
55e9f2e
             assert "invisible" not in sys.stdout.getvalue()
55e9f2e
 
55e9f2e
     class output_stream_overrides:
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def out_defaults_to_sys_stdout(self):
55e9f2e
             "out_stream defaults to sys.stdout"
55e9f2e
             self._runner(out="sup").run(_)
55e9f2e
             assert sys.stdout.getvalue() == "sup"
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def err_defaults_to_sys_stderr(self):
55e9f2e
             "err_stream defaults to sys.stderr"
55e9f2e
             self._runner(err="sup").run(_)
55e9f2e
             assert sys.stderr.getvalue() == "sup"
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def out_can_be_overridden(self):
55e9f2e
             "out_stream can be overridden"
55e9f2e
             out = StringIO()
644fab4
@@ -490,6 +544,7 @@ class Runner_:
644fab4
             assert sys.stdout.getvalue() == ""
644fab4
 
644fab4
         @trap
644fab4
+        @max_pytest_version
644fab4
         def overridden_out_is_never_hidden(self):
644fab4
             out = StringIO()
644fab4
             self._runner(out="sup").run(_, out_stream=out, hide=True)
644fab4
@@ -497,6 +552,7 @@ class Runner_:
55e9f2e
             assert sys.stdout.getvalue() == ""
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def err_can_be_overridden(self):
55e9f2e
             "err_stream can be overridden"
55e9f2e
             err = StringIO()
644fab4
@@ -505,6 +561,7 @@ class Runner_:
644fab4
             assert sys.stderr.getvalue() == ""
644fab4
 
644fab4
         @trap
644fab4
+        @max_pytest_version
644fab4
         def overridden_err_is_never_hidden(self):
644fab4
             err = StringIO()
644fab4
             self._runner(err="sup").run(_, err_stream=err, hide=True)
644fab4
@@ -512,11 +569,13 @@ class Runner_:
55e9f2e
             assert sys.stderr.getvalue() == ""
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def pty_defaults_to_sys(self):
55e9f2e
             self._runner(out="sup").run(_, pty=True)
55e9f2e
             assert sys.stdout.getvalue() == "sup"
55e9f2e
 
55e9f2e
         @trap
55e9f2e
+        @max_pytest_version
55e9f2e
         def pty_out_can_be_overridden(self):
55e9f2e
             out = StringIO()
55e9f2e
             self._runner(out="yo").run(_, pty=True, out_stream=out)
644fab4
@@ -525,12 +584,14 @@ class Runner_:
55e9f2e
 
55e9f2e
     class output_stream_handling:
55e9f2e
         # Mostly corner cases, generic behavior's covered above
55e9f2e
+        @max_pytest_version
55e9f2e
         def writes_and_flushes_to_stdout(self):
55e9f2e
             out = Mock(spec=StringIO)
55e9f2e
             self._runner(out="meh").run(_, out_stream=out)
55e9f2e
             out.write.assert_called_once_with("meh")
55e9f2e
             out.flush.assert_called_once_with()
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def writes_and_flushes_to_stderr(self):
55e9f2e
             err = Mock(spec=StringIO)
55e9f2e
             self._runner(err="whatever").run(_, err_stream=err)
644fab4
@@ -617,15 +678,18 @@ class Runner_:
55e9f2e
             assert not Fake.close_proc_stdin.called
55e9f2e
 
55e9f2e
     class failure_handling:
55e9f2e
+        @max_pytest_version
55e9f2e
         def fast_failures(self):
55e9f2e
             with raises(UnexpectedExit):
55e9f2e
                 self._runner(exits=1).run(_)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def non_1_return_codes_still_act_as_failure(self):
55e9f2e
             r = self._runner(exits=17).run(_, warn=True)
55e9f2e
             assert r.failed is True
55e9f2e
 
55e9f2e
         class UnexpectedExit_repr:
55e9f2e
+            @max_pytest_version
55e9f2e
             def similar_to_just_the_result_repr(self):
55e9f2e
                 try:
55e9f2e
                     self._runner(exits=23).run(_)
644fab4
@@ -645,6 +709,7 @@ class Runner_:
55e9f2e
                 self._stderr = lines("stderr")
55e9f2e
 
55e9f2e
             @trap
55e9f2e
+            @max_pytest_version
55e9f2e
             def displays_command_and_exit_code_by_default(self):
55e9f2e
                 try:
55e9f2e
                     self._runner(
644fab4
@@ -667,6 +732,7 @@ Stderr: already printed
55e9f2e
                     assert False, "Failed to raise UnexpectedExit!"
55e9f2e
 
55e9f2e
             @trap
55e9f2e
+            @max_pytest_version
55e9f2e
             def does_not_display_stderr_when_pty_True(self):
55e9f2e
                 try:
55e9f2e
                     self._runner(
644fab4
@@ -687,6 +753,7 @@ Stderr: n/a (PTYs have no stderr)
55e9f2e
                     assert str(e) == expected.format(_)
55e9f2e
 
55e9f2e
             @trap
55e9f2e
+            @max_pytest_version
55e9f2e
             def pty_stderr_message_wins_over_hidden_stderr(self):
55e9f2e
                 try:
55e9f2e
                     self._runner(
644fab4
@@ -698,6 +765,7 @@ Stderr: n/a (PTYs have no stderr)
55e9f2e
                     assert "Stderr: already printed" not in r
55e9f2e
 
55e9f2e
             @trap
55e9f2e
+            @max_pytest_version
55e9f2e
             def explicit_hidden_stream_tail_display(self):
55e9f2e
                 # All the permutations of what's displayed when, are in
55e9f2e
                 # subsequent test, which does 'x in y' assertions; this one
644fab4
@@ -744,6 +812,7 @@ stderr 25
55e9f2e
                     assert str(e) == expected.format(_)
55e9f2e
 
55e9f2e
             @trap
55e9f2e
+            @max_pytest_version
55e9f2e
             def displays_tails_of_streams_only_when_hidden(self):
55e9f2e
                 def oops(msg, r, hide):
55e9f2e
                     return "{}! hide={}; str output:\n\n{}".format(
644fab4
@@ -792,6 +861,7 @@ stderr 25
55e9f2e
         # TODO: may eventually turn into having Runner raise distinct Failure
55e9f2e
         # subclasses itself, at which point `reason` would probably go away.
55e9f2e
         class reason:
55e9f2e
+            @max_pytest_version
55e9f2e
             def is_None_for_regular_nonzero_exits(self):
55e9f2e
                 try:
55e9f2e
                     self._regular_error()
644fab4
@@ -804,6 +874,7 @@ stderr 25
55e9f2e
                 # TODO: when we implement 'exitcodes 1 and 2 are actually OK'
55e9f2e
                 skip()
55e9f2e
 
55e9f2e
+            @max_pytest_version
55e9f2e
             def is_exception_when_WatcherError_raised_internally(self):
55e9f2e
                 try:
55e9f2e
                     self._watcher_error()
644fab4
@@ -818,6 +889,7 @@ stderr 25
55e9f2e
         # no problem" and "raised as/attached to an exception when problem",
55e9f2e
         # possibly not - complicates how the APIs need to be adhered to.
55e9f2e
         class wrapped_result:
55e9f2e
+            @max_pytest_version
55e9f2e
             def most_attrs_are_always_present(self):
55e9f2e
                 attrs = ("command", "shell", "env", "stdout", "stderr", "pty")
55e9f2e
                 for method in (self._regular_error, self._watcher_error):
644fab4
@@ -830,6 +902,7 @@ stderr 25
55e9f2e
                         assert False, "Did not raise Failure!"
55e9f2e
 
55e9f2e
             class shell_exit_failure:
55e9f2e
+                @max_pytest_version
55e9f2e
                 def exited_is_integer(self):
55e9f2e
                     try:
55e9f2e
                         self._regular_error()
644fab4
@@ -838,6 +911,7 @@ stderr 25
55e9f2e
                     else:
55e9f2e
                         assert False, "Did not raise Failure!"
55e9f2e
 
55e9f2e
+                @max_pytest_version
55e9f2e
                 def ok_bool_etc_are_falsey(self):
55e9f2e
                     try:
55e9f2e
                         self._regular_error()
644fab4
@@ -849,6 +923,7 @@ stderr 25
55e9f2e
                     else:
55e9f2e
                         assert False, "Did not raise Failure!"
55e9f2e
 
55e9f2e
+                @max_pytest_version
55e9f2e
                 def stringrep_notes_exit_status(self):
55e9f2e
                     try:
55e9f2e
                         self._regular_error()
644fab4
@@ -858,6 +933,7 @@ stderr 25
55e9f2e
                         assert False, "Did not raise Failure!"
55e9f2e
 
55e9f2e
             class watcher_failure:
55e9f2e
+                @max_pytest_version
55e9f2e
                 def exited_is_None(self):
55e9f2e
                     try:
55e9f2e
                         self._watcher_error()
644fab4
@@ -866,6 +942,7 @@ stderr 25
55e9f2e
                         err = "Expected None, got {!r}".format(exited)
55e9f2e
                         assert exited is None, err
55e9f2e
 
55e9f2e
+                @max_pytest_version
55e9f2e
                 def ok_and_bool_still_are_falsey(self):
55e9f2e
                     try:
55e9f2e
                         self._watcher_error()
644fab4
@@ -877,6 +954,7 @@ stderr 25
55e9f2e
                     else:
55e9f2e
                         assert False, "Did not raise Failure!"
55e9f2e
 
55e9f2e
+                @max_pytest_version
55e9f2e
                 def stringrep_lacks_exit_status(self):
55e9f2e
                     try:
55e9f2e
                         self._watcher_error()
644fab4
@@ -889,6 +967,7 @@ stderr 25
55e9f2e
 
55e9f2e
     class threading:
55e9f2e
         # NOTE: see also the more generic tests in concurrency.py
55e9f2e
+        @max_pytest_version
55e9f2e
         def errors_within_io_thread_body_bubble_up(self):
55e9f2e
             class Oops(_Dummy):
55e9f2e
                 def handle_stdout(self, **kwargs):
644fab4
@@ -912,6 +991,7 @@ stderr 25
55e9f2e
             else:
55e9f2e
                 assert False, "Did not raise ThreadException as expected!"
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def io_thread_errors_str_has_details(self):
55e9f2e
             class Oops(_Dummy):
55e9f2e
                 def handle_stdout(self, **kwargs):
644fab4
@@ -939,6 +1019,7 @@ stderr 25
55e9f2e
         # StreamWatcher/Responder and their host Runner; Responder-only tests
55e9f2e
         # are in tests/watchers.py.
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def nothing_is_written_to_stdin_by_default(self):
55e9f2e
             # NOTE: technically if some goofus ran the tests by hand and mashed
55e9f2e
             # keys while doing so...this would fail. LOL?
644fab4
@@ -966,17 +1047,20 @@ stderr 25
55e9f2e
             runner.run(_, watchers=watchers, hide=True)
55e9f2e
             return klass.write_proc_stdin
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def watchers_responses_get_written_to_proc_stdin(self):
55e9f2e
             self._expect_response(
55e9f2e
                 out="the house was empty", responses={"empty": "handed"}
55e9f2e
             ).assert_called_once_with("handed")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def multiple_hits_yields_multiple_responses(self):
55e9f2e
             holla = call("how high?")
55e9f2e
             self._expect_response(
55e9f2e
                 out="jump, wait, jump, wait", responses={"jump": "how high?"}
55e9f2e
             ).assert_has_calls([holla, holla])
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def chunk_sizes_smaller_than_patterns_still_work_ok(self):
55e9f2e
             klass = self._mock_stdin_writer()
55e9f2e
             klass.read_chunk_size = 1  # < len('jump')
644fab4
@@ -989,6 +1073,7 @@ stderr 25
55e9f2e
             # And there weren't duplicates!
55e9f2e
             assert len(klass.write_proc_stdin.call_args_list) == 2
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def both_out_and_err_are_scanned(self):
55e9f2e
             bye = call("goodbye")
55e9f2e
             # Would only be one 'bye' if only scanning stdout
644fab4
@@ -998,6 +1083,7 @@ stderr 25
55e9f2e
                 responses={"hello": "goodbye"},
55e9f2e
             ).assert_has_calls([bye, bye])
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def multiple_patterns_works_as_expected(self):
55e9f2e
             calls = [call("betty"), call("carnival")]
55e9f2e
             # Technically, I'd expect 'betty' to get called before 'carnival',
644fab4
@@ -1010,6 +1096,7 @@ stderr 25
55e9f2e
                 responses={"boop": "betty", "robot": "carnival"},
55e9f2e
             ).assert_has_calls(calls, any_order=True)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def multiple_patterns_across_both_streams(self):
55e9f2e
             responses = {
55e9f2e
                 "boop": "betty",
644fab4
@@ -1026,6 +1113,7 @@ stderr 25
55e9f2e
                 responses=responses,
55e9f2e
             ).assert_has_calls(calls, any_order=True)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def honors_watchers_config_option(self):
55e9f2e
             klass = self._mock_stdin_writer()
55e9f2e
             responder = Responder("my stdout", "and my axe")
644fab4
@@ -1037,6 +1125,7 @@ stderr 25
55e9f2e
             runner.run(_, hide=True)
55e9f2e
             klass.write_proc_stdin.assert_called_once_with("and my axe")
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def kwarg_overrides_config(self):
55e9f2e
             # TODO: how to handle use cases where merging, not overriding, is
55e9f2e
             # the expected/unsurprising default? probably another config-only
644fab4
@@ -1211,6 +1300,7 @@ stderr 25
55e9f2e
     class character_buffered_stdin:
55e9f2e
         @skip_if_windows
55e9f2e
         @patch("invoke.terminals.tty")
55e9f2e
+        @max_pytest_version
55e9f2e
         def setcbreak_called_on_tty_stdins(self, mock_tty, mock_termios):
55e9f2e
             mock_termios.tcgetattr.return_value = make_tcattrs(echo=True)
55e9f2e
             self._run(_)
644fab4
@@ -1225,6 +1315,7 @@ stderr 25
55e9f2e
         @skip_if_windows
55e9f2e
         @patch("invoke.terminals.tty")
55e9f2e
         @patch("invoke.terminals.os")
55e9f2e
+        @max_pytest_version
55e9f2e
         def setcbreak_not_called_if_process_not_foregrounded(
55e9f2e
             self, mock_os, mock_tty
55e9f2e
         ):
644fab4
@@ -1238,6 +1329,7 @@ stderr 25
55e9f2e
 
55e9f2e
         @skip_if_windows
55e9f2e
         @patch("invoke.terminals.tty")
55e9f2e
+        @max_pytest_version
55e9f2e
         def tty_stdins_have_settings_restored_by_default(
55e9f2e
             self, mock_tty, mock_termios
55e9f2e
         ):
644fab4
@@ -1253,6 +1345,7 @@ stderr 25
55e9f2e
 
55e9f2e
         @skip_if_windows
55e9f2e
         @patch("invoke.terminals.tty")  # stub
55e9f2e
+        @max_pytest_version
55e9f2e
         def tty_stdins_have_settings_restored_on_KeyboardInterrupt(
55e9f2e
             self, mock_tty, mock_termios
55e9f2e
         ):
644fab4
@@ -1271,6 +1364,7 @@ stderr 25
55e9f2e
 
55e9f2e
         @skip_if_windows
55e9f2e
         @patch("invoke.terminals.tty")
55e9f2e
+        @max_pytest_version
55e9f2e
         def setcbreak_not_called_if_terminal_seems_already_cbroken(
55e9f2e
             self, mock_tty, mock_termios
55e9f2e
         ):
644fab4
@@ -1299,6 +1393,7 @@ stderr 25
55e9f2e
                 pass
55e9f2e
             return runner
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def called_on_KeyboardInterrupt(self):
55e9f2e
             runner = self._run_with_mocked_interrupt(
55e9f2e
                 _KeyboardInterruptingRunner
644fab4
@@ -1309,6 +1404,7 @@ stderr 25
55e9f2e
             runner = self._run_with_mocked_interrupt(_GenericExceptingRunner)
55e9f2e
             assert not runner.send_interrupt.called
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def sends_escape_byte_sequence(self):
55e9f2e
             for pty in (True, False):
55e9f2e
                 runner = _KeyboardInterruptingRunner(Context())
644fab4
@@ -1318,6 +1414,7 @@ stderr 25
55e9f2e
                 mock_stdin.assert_called_once_with(u"\x03")
55e9f2e
 
55e9f2e
     class timeout:
55e9f2e
+        @max_pytest_version
55e9f2e
         def start_timer_called_with_config_value(self):
55e9f2e
             runner = self._runner(timeouts={"command": 7})
55e9f2e
             runner.start_timer = Mock()
644fab4
@@ -1325,6 +1422,7 @@ stderr 25
55e9f2e
             runner.run(_)
55e9f2e
             runner.start_timer.assert_called_once_with(7)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def run_kwarg_honored(self):
55e9f2e
             runner = self._runner()
55e9f2e
             runner.start_timer = Mock()
644fab4
@@ -1332,6 +1430,7 @@ stderr 25
55e9f2e
             runner.run(_, timeout=3)
55e9f2e
             runner.start_timer.assert_called_once_with(3)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def kwarg_wins_over_config(self):
55e9f2e
             runner = self._runner(timeouts={"command": 7})
55e9f2e
             runner.start_timer = Mock()
644fab4
@@ -1339,6 +1438,7 @@ stderr 25
55e9f2e
             runner.run(_, timeout=3)
55e9f2e
             runner.start_timer.assert_called_once_with(3)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def raises_CommandTimedOut_with_timeout_info(self):
55e9f2e
             runner = self._runner(
55e9f2e
                 klass=_TimingOutRunner, timeouts={"command": 7}
644fab4
@@ -1512,6 +1612,7 @@ class Local_:
55e9f2e
 
55e9f2e
     class pty:
55e9f2e
         @mock_pty()
55e9f2e
+        @max_pytest_version
55e9f2e
         def when_pty_True_we_use_pty_fork_and_os_exec(self):
55e9f2e
             "when pty=True, we use pty.fork and os.exec*"
55e9f2e
             self._run(_, pty=True)
644fab4
@@ -1536,13 +1637,16 @@ class Local_:
55e9f2e
             expected_get.assert_called_once_with(exitstatus)
55e9f2e
             assert not unexpected_get.called
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def pty_uses_WEXITSTATUS_if_WIFEXITED(self):
55e9f2e
             self._expect_exit_check(True)
55e9f2e
 
55e9f2e
+        @max_pytest_version
55e9f2e
         def pty_uses_WTERMSIG_if_WIFSIGNALED(self):
55e9f2e
             self._expect_exit_check(False)
55e9f2e
 
55e9f2e
         @mock_pty(insert_os=True)
55e9f2e
+        @max_pytest_version
55e9f2e
         def WTERMSIG_result_turned_negative_to_match_subprocess(self, mock_os):
55e9f2e
             mock_os.WIFEXITED.return_value = False
55e9f2e
             mock_os.WIFSIGNALED.return_value = True
644fab4
@@ -1550,6 +1654,7 @@ class Local_:
55e9f2e
             assert self._run(_, pty=True, warn=True).exited == -2
55e9f2e
 
55e9f2e
         @mock_pty()
55e9f2e
+        @max_pytest_version
55e9f2e
         def pty_is_set_to_controlling_terminal_size(self):
55e9f2e
             self._run(_, pty=True)
55e9f2e
             # @mock_pty's asserts check the TIOC[GS]WINSZ calls for us
644fab4
@@ -1569,16 +1674,19 @@ class Local_:
55e9f2e
             assert runner.should_use_pty(pty=True, fallback=True) is False
55e9f2e
 
55e9f2e
         @mock_pty(trailing_error=OSError("Input/output error"))
55e9f2e
+        @max_pytest_version
55e9f2e
         def spurious_OSErrors_handled_gracefully(self):
55e9f2e
             # Doesn't-blow-up test.
55e9f2e
             self._run(_, pty=True)
55e9f2e
 
55e9f2e
         @mock_pty(trailing_error=OSError("I/O error"))
55e9f2e
+        @max_pytest_version
55e9f2e
         def other_spurious_OSErrors_handled_gracefully(self):
55e9f2e
             # Doesn't-blow-up test.
55e9f2e
             self._run(_, pty=True)
55e9f2e
 
55e9f2e
         @mock_pty(trailing_error=OSError("wat"))
55e9f2e
+        @max_pytest_version
55e9f2e
         def non_spurious_OSErrors_bubble_up(self):
55e9f2e
             try:
55e9f2e
                 self._run(_, pty=True)
644fab4
@@ -1589,12 +1697,14 @@ class Local_:
55e9f2e
 
55e9f2e
         class fallback:
55e9f2e
             @mock_pty(isatty=False)
55e9f2e
+            @max_pytest_version
55e9f2e
             def can_be_overridden_by_kwarg(self):
55e9f2e
                 self._run(_, pty=True, fallback=False)
55e9f2e
                 # @mock_pty's asserts will be mad if pty-related os/pty calls
55e9f2e
                 # didn't fire, so we're done.
55e9f2e
 
55e9f2e
             @mock_pty(isatty=False)
55e9f2e
+            @max_pytest_version
55e9f2e
             def can_be_overridden_by_config(self):
55e9f2e
                 self._runner(run={"fallback": False}).run(_, pty=True)
55e9f2e
                 # @mock_pty's asserts will be mad if pty-related os/pty calls
644fab4
@@ -1606,11 +1716,13 @@ class Local_:
55e9f2e
                 assert self._run(_, pty=True).pty is False
55e9f2e
 
55e9f2e
             @mock_pty(isatty=False)
55e9f2e
+            @max_pytest_version
55e9f2e
             def overridden_fallback_affects_result_pty_value(self):
55e9f2e
                 assert self._run(_, pty=True, fallback=False).pty is True
55e9f2e
 
55e9f2e
     class shell:
55e9f2e
         @mock_pty(insert_os=True)
55e9f2e
+        @max_pytest_version
55e9f2e
         def defaults_to_bash_or_cmdexe_when_pty_True(self, mock_os):
55e9f2e
             # NOTE: yea, windows can't run pty is true, but this is really
55e9f2e
             # testing config behavior, so...meh
644fab4
@@ -1625,6 +1737,7 @@ class Local_:
55e9f2e
             )
55e9f2e
 
55e9f2e
         @mock_pty(insert_os=True)
55e9f2e
+        @max_pytest_version
55e9f2e
         def may_be_overridden_when_pty_True(self, mock_os):
55e9f2e
             self._run(_, pty=True, shell="/bin/zsh")
55e9f2e
             assert mock_os.execve.call_args_list[0][0][0] == "/bin/zsh"
644fab4
@@ -1646,6 +1759,7 @@ class Local_:
55e9f2e
             assert env == expected
55e9f2e
 
55e9f2e
         @mock_pty(insert_os=True)
55e9f2e
+        @max_pytest_version
55e9f2e
         def uses_execve_for_pty_True(self, mock_os):
55e9f2e
             type(mock_os).environ = {"OTHERVAR": "OTHERVAL"}
55e9f2e
             self._run(_, pty=True, env={"FOO": "BAR"})