commit:     e7af2910a9b2adacca62a54f3dc5df69ab9d233c
Author:     Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Sun Dec  7 16:32:54 2025 +0000
Commit:     Brian Harring <ferringb <AT> gmail <DOT> com>
CommitDate: Sun Dec  7 16:33:49 2025 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/snakeoil.git/commit/?id=e7af2910

chore: fix test.protect_process so it handles being ran from w/in the tests 
directory itself

Signed-off-by: Brian Harring <ferringb <AT> gmail.com>

 src/snakeoil/test/__init__.py | 48 ++++++++++++++++++++++++-------------------
 tests/test_test.py            | 30 +++++++++++++++++++--------
 2 files changed, 48 insertions(+), 30 deletions(-)

diff --git a/src/snakeoil/test/__init__.py b/src/snakeoil/test/__init__.py
index 89bab4c..9b8ef5b 100644
--- a/src/snakeoil/test/__init__.py
+++ b/src/snakeoil/test/__init__.py
@@ -10,7 +10,6 @@ __all__ = (
     "Slots",
 )
 
-import functools
 import os
 import random
 import string
@@ -51,19 +50,16 @@ def protect_process(
     extra_env: dict[str, str] | None = None,
 ):
     def wrapper(functor):
-        @functools.wraps(functor)
-        def _inner_run(self, *args, **kwargs):
-            # we're in the child.  Just run it.
-            if os.environ.get(marker_env_var, False):
-                return functor(self, *args, **kwargs)
-
-            # we're in the parent.  if capsys is in there, we have
-            # to intercept it for the code below.
-            capsys = kwargs.get("capsys")
+        if os.environ.get(marker_env_var, False):
+            functor.__protect_process_is_child__ = True
+            return functor
+
+        @staticmethod
+        def parent_runner(pytestconfig):
             env = os.environ.copy()
             if extra_env:
                 env.update(extra_env)
-            env[marker_env_var] = "disable"
+            env[marker_env_var] = "in_child"
             test = (
                 os.environ["PYTEST_CURRENT_TEST"]
                 if forced_test is None
@@ -72,24 +68,34 @@ def protect_process(
             # 
https://docs.pytest.org/en/latest/example/simple.html#pytest-current-test-environment-variable
             assert test.endswith(" (call)")
             test = test[: -len(" (call)")]
-            args = [sys.executable, "-m", "pytest", "-v", test]
+            # pytestconfig.rootpath is used so that if someone has cd'd within 
the tests directory, the test
+            # can still be found.  PYTEST_CURRENT_TEST is rooted against the 
root, thus this requirement
+            args = [
+                sys.executable,
+                "-m",
+                "pytest",
+                "-v",
+                f"{pytestconfig.rootpath}/{test}",
+            ]
             p = subprocess.Popen(
                 args,
                 env=env,
-                stdout=None if capsys else subprocess.PIPE,
-                stderr=None if capsys else subprocess.PIPE,
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
             )
 
             stdout, stderr = p.communicate()
-            if capsys:
-                result = capsys.readouterr()
-                stdout, stderr = result.out, result.err
-            ret = p.wait()
-            assert ret == 0, (
-                f"subprocess run: {args!r}\nnon zero exit: 
{ret}\nstdout:\n{stdout.decode()}'n\nstderr:\n{stderr.decode()}"
+            exit_code = p.wait()
+            assert 0 == exit_code, (
+                f"subprocess run: {args!r}\nnon zero exit: 
{exit_code}\nstdout:\n{stdout.decode()}'n\nstderr:\n{stderr.decode()}"
             )
 
-        return _inner_run
+        # do not do a functools wraps; it'll stomp our pytestconfig signature. 
 Just do basic transfer.
+        for a in ("__name__", "__module__", "__qualname__"):
+            if (val := getattr(functor, a, None)) is not None:
+                setattr(parent_runner, a, val)
+        parent_runner.__protect_process_is_child__ = False
+        return parent_runner
 
     return wrapper
 

diff --git a/tests/test_test.py b/tests/test_test.py
index f325d66..5fc2a3b 100644
--- a/tests/test_test.py
+++ b/tests/test_test.py
@@ -6,12 +6,18 @@ from snakeoil import test
 
 
 class Test_protect_process:
-    def test_success(self, capsys):
+    def test_success(self, pytestconfig, capsys, in_child=False):
         @test.protect_process()
-        def no_fail(self) -> None:
+        def no_fail() -> None:
             pass
 
-        assert None is no_fail(capsys)
+        if no_fail.__protect_process_is_child__:  # pyright: 
ignore[reportFunctionMemberAccess]
+            assert None is no_fail()
+            return
+
+        assert None is no_fail(pytestconfig=pytestconfig)  # pyright: 
ignore[reportCallIssue]
+        if in_child:
+            return
         captured = capsys.readouterr()
         assert "" == captured.out, (
             "no stdout should be captured for success: {captured.out}"
@@ -20,19 +26,25 @@ class Test_protect_process:
             "no stderr should be captured for success: {captured.err}"
         )
 
-    def test_failure(self, capsys):
+    def test_failure(self, pytestconfig):
         unique_string = 
"asdfasdfasdfasdfdasdfdasdfasdfasdfasdfasdfasdfasdfsadf"
 
         @test.protect_process(extra_env={unique_string: unique_string})
-        def fail(self, capsys) -> None:
+        def fail() -> None:
             raise AssertionError(unique_string)
 
-        if os.environ.get(unique_string):
-            # we're in the child.
-            fail(self, capsys)
+        if fail.__protect_process_is_child__:  # pyright: 
ignore[reportFunctionMemberAccess]
+            is_in_env = os.environ.get(unique_string) == unique_string
+            assert is_in_env, (
+                "unique_string wasn't in the child.  extra_env didn't pass 
down"
+            )
+            # trigger the exception.
+            fail()
+            # chuck this if we make it this far, because it means fail is 
misimplemented or
+            # protect_process didn't return the raw functor to run
             raise Exception("implementation is broke, fail didn't throw an 
exception")
 
         with pytest.raises(AssertionError) as failed:
-            fail(self, capsys)
+            fail(pytestconfig=pytestconfig)  # pyright: ignore[reportCallIssue]
 
         assert unique_string in str(failed.value)

Reply via email to