Repository: wagtail/wagtail

Issue:
updatemodulepaths stdout.write error
### Issue Summary

updatemodulepaths uses `sys.stdout.write(line.encode("utf-8"))` which is not supported in python3.
I think this should be `sys.stdout.write(line)`

### Steps to Reproduce

1. run `wagtail updatemodulepaths` in a project where updates need to be made.

### Technical details

-   Python version: 3.7.11
-   Wagtail version: 3.0.1



Discussion:
Hi @adi1 - thanks for the report.

The `line.encode("utf-8")` was introduced in #8450, and is needed when running on Windows because it opens files in Windows-1252 encoding rather than UTF-8 by default, and there's no way to override this when using the [fileinput](https://docs.python.org/3/library/fileinput.html) library (until Python 3.10).

This line of code runs inside a `with fileinput.FileInput(...)` block, where `sys.stdout` has been substituted with a file opened in binary mode, so `sys.stdout.write(line.encode("utf-8"))` should be correct as far as I can see. Can you give more detail about the error you're getting, and the OS you're running on?
Hi @gasman . I am running on Linux 5.18 x86_64, here is my python header:

```
Python 3.7.11 (default, Jul  6 2021, 11:31:48) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
```

To reproduce this, you can create a file `foo.py` anywhere in your project with the contents `import wagtail.core.utils` and run `wagtail updatemodulepaths`

Basically, `original_line = raw_original_line.decode("utf-8")` converts the `bytes` into a `str`, then you are calling `line.encode('utf-8')` which converts the `str` back to `bytes`.

Trying to write `bytes` to `sys.stdout` will fail on my system.

```
>>> sys.stdout.write('foo'.encode('utf-8'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: write() argument must be str, not bytes
```

Hard to say if this is specific to my system or not, but this stdout behaviour is consistent across other versions of python3, although I haven't tested many.


Thanks - I can confirm I'm seeing the same issue on Python 3.7.12, but not 3.8.

(This is when testing the `wagtail updatemodulepaths` command directly - running `sys.stdout.write('foo'.encode('utf-8'))` on the python command line isn't a valid test for this, as it needs to be run inside a `with fileinput.FileInput` block to match what updatemodulepaths is doing.)

Resolving patch:
diff --git a/wagtail/bin/wagtail.py b/wagtail/bin/wagtail.py
--- a/wagtail/bin/wagtail.py
+++ b/wagtail/bin/wagtail.py
@@ -353,7 +353,14 @@ def _rewrite_file(self, filename):
                     found_unicode_error = True
                 else:
                     line = self._rewrite_line(original_line)
-                    sys.stdout.write(line.encode("utf-8"))
+                    if CURRENT_PYTHON >= (3, 8):
+                        sys.stdout.write(line.encode("utf-8"))
+                    else:
+                        # Python 3.7 opens the output stream in text mode, so write the line back as
+                        # text rather than bytes:
+                        # https://github.com/python/cpython/commit/be6dbfb43b89989ccc83fbc4c5234f50f44c47ad
+                        sys.stdout.write(line)
+
                     if line != original_line:
                         change_count += 1
 


Test patch: