Repository: minrk/wurlitzer

Issue:
`sys_pipes()` hangs on mac os
Running the following code causes `sys_pipes()` to hang on mac os.  

`__init__.py` file: 

```python
from wurlitzer import sys_pipes

print("Before")
with sys_pipes():
    print("After sys pipes")
print("Done")
```

Output is: 

<img width="841" alt="image" src="https://github.com/minrk/wurlitzer/assets/5657503/660be7d0-4fb1-4d4e-bb06-b55d76f854b9">

Computer info:

<img width="257" alt="image" src="https://github.com/minrk/wurlitzer/assets/5657503/2ba28b5c-97fc-48e5-9662-4f9e7c8e1e93">

Version info:

```
$ poetry show wurlitzer
 name         : wurlitzer
 version      : 3.0.3
 description  : Capture C-level output in context managers

$ python --version
Python 3.10.12
```

**I cannot reproduce when running in docker.**


Discussion:

Patch:
diff --git a/wurlitzer.py b/wurlitzer.py
index 7e7db95..39089a7 100644
--- a/wurlitzer.py
+++ b/wurlitzer.py
@@ -532,10 +532,29 @@ class _LogPipe(io.BufferedWriter):
 def sys_pipes(encoding=_default_encoding, bufsize=None):
     """Redirect C-level stdout/stderr to sys.stdout/stderr
 
-    This is useful of sys.sdout/stderr are already being forwarded somewhere.
+    This is useful of sys.sdout/stderr are already being forwarded somewhere,
+    e.g. in a Jupyter kernel.
 
     DO NOT USE THIS if sys.stdout and sys.stderr are not already being forwarded.
     """
+    # check that we aren't forwarding stdout to itself
+    for name in ("stdout", "stderr"):
+        stream = getattr(sys, name)
+        capture_stream = getattr(sys, "__{}__".format(name))
+        try:
+            fd = stream.fileno()
+            capture_fd = capture_stream.fileno()
+        except Exception:
+            # ignore errors - if sys.stdout doesn't need a fileno,
+            # it's definitely not the original sys.__stdout__
+            continue
+        else:
+            if fd == capture_fd:
+                raise ValueError(
+                    "Cannot forward sys.__{0}__ to sys.{0}: they are the same! Maybe you want wurlitzer.pipes()?".format(
+                        name
+                    )
+                )
     return pipes(sys.stdout, sys.stderr, encoding=encoding, bufsize=bufsize)
 
 


Test patch:
diff --git a/test.py b/test.py
index 0a604c7..78bdada 100644
--- a/test.py
+++ b/test.py
@@ -104,6 +104,16 @@ def test_sys_pipes():
     assert stderr.getvalue() == u"Hi, stdérr\n"
 
 
+def test_sys_pipes_check():
+    # pytest redirects stdout; un-redirect it for the test
+    with mock.patch('sys.stdout', sys.__stdout__), mock.patch(
+        'sys.stderr', sys.__stderr__
+    ):
+        with pytest.raises(ValueError):
+            with sys_pipes():
+                pass
+
+
 def test_redirect_everything():
     stdout = io.StringIO()
     stderr = io.StringIO()