Repository: pyinstaller/pyinstaller

Issue:
NullWriter has no attribute 'closed'
This is similar to issue #1883
It is triggered when using the "click" library in a PyInstaller --noconsole application.

A workaround is as follows:
```python
# fixup somw problems from pyinstaller
if "NullWriter" in str(type(sys.stdout)):
    sys.stdout.closed = sys.stderr.closed = False
```
I suggest adding a class attribute, closed=False to fix this.
You may want to add the "errors" and "newlines" attributes as well, see the python docs.




Discussion:
Came across basically the same issue with `reconfigure`:
> AttributeError: 'NullWriter' object has no attribute 'reconfigure'

Honestly, I find the practice of overwriting `sys.stdout`/`sys.stderr` in https://github.com/pyinstaller/pyinstaller/blob/7b2b93a186de0d47b67eed0077d748c8feb6d190/PyInstaller/loader/pyiboot01_bootstrap.py#L80-L84
quite questionable. The Python docs say that the two are "file objects" and "regular text files" ([source](https://docs.python.org/3/library/sys.html#sys.stdout)), the APIs of which are defined in the `io` module ([source](https://docs.python.org/3/glossary.html#term-file-object)). Replacing these objects with a class not derived from `TextIOWrapper`, `TextIOBase` or at least `IOBase` is a recipe for incompatibilities such as #1883 or the ones reported here.

Regarding the above workaround, I'd probably prefer a more focused approach using

```python
if not hasattr(sys.stdout, "closed"):
    ...
```
> Honestly, I find the practice of overwriting `sys.stdout`/`sys.stderr` in
> 
> https://github.com/pyinstaller/pyinstaller/blob/7b2b93a186de0d47b67eed0077d748c8feb6d190/PyInstaller/loader/pyiboot01_bootstrap.py#L80-L84
> quite questionable.

I second that sentiment. Judging by the surrounding comments, this was added as a work-around for an issue from 15 years ago (http://bugs.python.org/issue1415), which has been addressed in python 3.0. So I think it is time to get rid of the `NullWriter`. I'm quite sure this will trip some user code that fails to check if `sys.stderr`/`sys.stdout` are `None` before accessing it, but that's the behavior they would get in `pythonw.exe`, as well, and should handle it themselves however they see it fit (e.g., by installing their own equivalent file-like object).

Resolving patch:
diff --git a/PyInstaller/loader/pyiboot01_bootstrap.py b/PyInstaller/loader/pyiboot01_bootstrap.py
--- a/PyInstaller/loader/pyiboot01_bootstrap.py
+++ b/PyInstaller/loader/pyiboot01_bootstrap.py
@@ -55,34 +55,6 @@
     python_path.append(os.path.abspath(pth))
     sys.path = python_path
 
-
-# Implement workaround for prints in non-console mode. In non-console mode (with "pythonw"), print randomly fails with
-# "[errno 9] Bad file descriptor" when the printed text is flushed (e.g., buffer full); this is because the sys.stdout
-# object is bound to an invalid file descriptor.
-# Python 3000 has a fix for it (http://bugs.python.org/issue1415), but we feel that a workaround in PyInstaller is a
-# good thing, because most people first encounter this problem with PyInstaller as they do not usually run their code
-# with "pythonw" (and it is difficult to debug, anyway).
-class NullWriter:
-    softspace = 0
-    encoding = 'UTF-8'
-
-    def write(*args):
-        pass
-
-    def flush(*args):
-        pass
-
-    # Some packages are checking if stdout/stderr is available (e.g., youtube-dl). For details, see #1883.
-    def isatty(self):
-        return False
-
-
-# sys.stdout/err is None in GUI mode on Windows.
-if sys.stdout is None:
-    sys.stdout = NullWriter()
-if sys.stderr is None:
-    sys.stderr = NullWriter()
-
 # At least on Windows, Python seems to hook up the codecs on this import, so it is not enough to just package up all
 # the encodings.
 #


Test patch: