belangeo / pyo

Python DSP module
GNU Lesser General Public License v3.0
1.28k stars 130 forks source link

Found bug with stdout during pyo.Server initialization #261

Closed smojef closed 5 months ago

smojef commented 1 year ago

The following line #768 is problematic: https://github.com/belangeo/pyo/blob/d705bc8a121a1bdaa849b9711070b82a565b8c20/pyo/lib/_core.py#L765-L770 because it overrides the current sys.stdout without prior backup and later assumes it was sys.__stdout__. This actually prevents the print statement from working after pyo.Server() initialization in special contexts, such as the interactive debugging environment of VS Code and maybe Jupyter Notebooks.

Steps to reproduce:

import sys
import pyo

class StdoutWrapper:
    def __init__(self, stdout):
        self._stdout = stdout

    def write(self, s):
        return self._stdout.write(s)

    def flush(self):
        return self._stdout.flush()

print("Before server init")
print(f" stdout is {repr(sys.stdout)}")

print("Using a non-default stdout")
sys.stdout = StdoutWrapper(sys.stdout)
print(f" stdout is {repr(sys.stdout)}")

prev_stdout = sys.stdout # Saving stdout
server = pyo.Server(sr=8000, nchnls=1, buffersize=256, duplex=False, audio='manual')

print("After Server init")
print(f" stdout is {repr(sys.stdout)}")

assert sys.stdout == prev_stdout

Assert will fail:

Before server init
 stdout is <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
Using a non-default stdout
 stdout is <__main__.StdoutWrapper object at 0x000001F802F49E10>
After Server init
 stdout is <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
Traceback (most recent call last):
  File "C:\!repos\me_py_hack\DBoxLabRaw\test_pyo_stdout_bug.py", line 27, in <module>
    assert sys.stdout == prev_stdout
AssertionError

A recommended fix would be to use a try / finally block to save and restore the current stdout.

stripwax commented 1 year ago

or just use contextlib.redirect_stdout

On Fri, 17 Mar 2023, 20:55 smojef, @.***> wrote:

The following line #768 is problematic:

https://github.com/belangeo/pyo/blob/d705bc8a121a1bdaa849b9711070b82a565b8c20/pyo/lib/_core.py#L765-L770 because it overrides the current sys.stdout without prior backup and later assumes it was sys.stdout. This actually prevents the print statement from working after pyo.Server() initialization in special contexts, such as the interactive debugging environment of VS Code and maybe Jupyter Notebooks.

Steps to reproduce:

import sysimport pyo class StdoutWrapper: def init(self, stdout): self._stdout = stdout

def write(self, s):
    return self._stdout.write(s)

def flush(self):
    return self._stdout.flush()

print("Before server init")print(f" stdout is {repr(sys.stdout)}") print("Using a non-default stdout")sys.stdout = StdoutWrapper(sys.stdout)print(f" stdout is {repr(sys.stdout)}") prev_stdout = sys.stdout # Saving stdoutserver = pyo.Server(sr=8000, nchnls=1, buffersize=256, duplex=False, audio='manual') print("After Server init")print(f" stdout is {repr(sys.stdout)}") assert sys.stdout == prev_stdout

Assert will fail:

Before server init stdout is <_io.TextIOWrapper name='' mode='w' encoding='utf-8'> Using a non-default stdout stdout is <main.StdoutWrapper object at 0x000001F802F49E10> After Server init stdout is <_io.TextIOWrapper name='' mode='w' encoding='utf-8'> Traceback (most recent call last): File "C:!repos\me_py_hack\DBoxLabRaw\test_pyo_stdout_bug.py", line 27, in assert sys.stdout == prev_stdout AssertionError

A recommended fix would be to use a try / finally block to save and restore the current stdout.

— Reply to this email directly, view it on GitHub https://github.com/belangeo/pyo/issues/261, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABF47HGY2DDOTXF4TGF3FETW4TFVRANCNFSM6AAAAAAV67RSPE . You are receiving this because you are subscribed to this thread.Message ID: @.***>

smojef commented 1 year ago

I created pull request #262 using the try/finally approach, but the contextlib.redirect_stdout suggestion from @stripwax seems more elegant ;-)

belangeo commented 5 months ago

Fixed in master with contextlib.redirect_stdout.