changeset 36795:9b513888ea23

ui: do not use rawinput() when we have to replace sys.stdin/stdout See the inline comment for why. The current Python3 hack doesn't work if more than one user inputs are expected because TextIOWrapper fills its internal buffer at the first read() request. Maybe we could write an unbuffered TextIOWrapper, but I don't want to make things more complicated. Instead, this patch reinvents raw_input(' ') of no readline support.
author Yuya Nishihara <yuya@tcha.org>
date Tue, 06 Mar 2018 02:38:53 -0600
parents fa53a1d1f16e
children aa0fc12743c7
files contrib/python3-whitelist mercurial/ui.py
diffstat 2 files changed, 20 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/python3-whitelist	Tue Mar 06 02:32:26 2018 -0600
+++ b/contrib/python3-whitelist	Tue Mar 06 02:38:53 2018 -0600
@@ -3,6 +3,7 @@
 test-addremove-similar.t
 test-addremove.t
 test-amend-subrepo.t
+test-amend.t
 test-ancestor.py
 test-annotate.py
 test-annotate.t
@@ -185,6 +186,8 @@
 test-largefiles-cache.t
 test-largefiles-misc.t
 test-largefiles-small-disk.t
+test-largefiles-update.t
+test-lfs-largefiles.t
 test-locate.t
 test-lock-badness.t
 test-log.t
@@ -196,11 +199,13 @@
 test-manifest.t
 test-match.py
 test-mdiff.py
+test-merge-changedelete.t
 test-merge-closedheads.t
 test-merge-commit.t
 test-merge-criss-cross.t
 test-merge-default.t
 test-merge-force.t
+test-merge-halt.t
 test-merge-internal-tools-pattern.t
 test-merge-local.t
 test-merge-remove.t
@@ -228,11 +233,13 @@
 test-mq-qimport-fail-cleanup.t
 test-mq-qpush-exact.t
 test-mq-qqueue.t
+test-mq-qrefresh-interactive.t
 test-mq-qrefresh-replace-log-message.t
 test-mq-qrefresh.t
 test-mq-qrename.t
 test-mq-qsave.t
 test-mq-safety.t
+test-mq-subrepo.t
 test-mq-symlinks.t
 test-mv-cp-st-diff.t
 test-narrow-archive.t
--- a/mercurial/ui.py	Tue Mar 06 02:32:26 2018 -0600
+++ b/mercurial/ui.py	Tue Mar 06 02:38:53 2018 -0600
@@ -1264,6 +1264,10 @@
         return i
 
     def _readline(self):
+        # Replacing stdin/stdout temporarily is a hard problem on Python 3
+        # because they have to be text streams with *no buffering*. Instead,
+        # we use rawinput() only if call_readline() will be invoked by
+        # PyOS_Readline(), so no I/O will be made at Python layer.
         usereadline = (self._isatty(self.fin) and self._isatty(self.fout)
                        and util.isstdin(self.fin) and util.isstdout(self.fout))
         if usereadline:
@@ -1280,13 +1284,16 @@
         # prompt ' ' must exist; otherwise readline may delete entire line
         # - http://bugs.python.org/issue12833
         with self.timeblockedsection('stdio'):
-            sin, sout = sys.stdin, sys.stdout
-            try:
-                sys.stdin = encoding.strio(self.fin)
-                sys.stdout = encoding.strio(self.fout)
+            if usereadline:
                 line = encoding.strtolocal(pycompat.rawinput(r' '))
-            finally:
-                sys.stdin, sys.stdout = sin, sout
+            else:
+                self.fout.write(b' ')
+                self.fout.flush()
+                line = self.fin.readline()
+                if not line:
+                    raise EOFError
+                if line.endswith(pycompat.oslinesep):
+                    line = line[:-len(pycompat.oslinesep)]
 
         # When stdin is in binary mode on Windows, it can cause
         # raw_input() to emit an extra trailing carriage return