D299: pycompat: introduce a wrapper for __builtins__.{raw_,}input()
durin42 (Augie Fackler)
phabricator at mercurial-scm.org
Wed Aug 9 14:25:04 UTC 2017
durin42 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.
REVISION SUMMARY
In order to make this work, we have to wrap the io streams in a
TextIOWrapper so that __builtins__.input() can do unicode IO on Python
3. We can't just restore the original (unicode) sys.std* because we
might be running a cmdserver, and if we blindly restore sys.* to the
original values then we end up breaking the cmdserver. Sadly,
TextIOWrapper tries to close the underlying stream during its __del__,
so we have to make a sublcass to prevent that.
If you see errors like:
TypeError: a bytes-like object is required, not 'str'
On an input() or print() call on Python 3, the substitution of
sys.std* is probably the root cause.
REPOSITORY
rHG Mercurial
REVISION DETAIL
https://phab.mercurial-scm.org/D299
AFFECTED FILES
hgext/hgk.py
mercurial/pycompat.py
mercurial/ui.py
CHANGE DETAILS
diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -1219,7 +1219,7 @@
# prompt ' ' must exist; otherwise readline may delete entire line
# - http://bugs.python.org/issue12833
with self.timeblockedsection('stdio'):
- line = raw_input(' ')
+ line = pycompat.bytesinput(r' ')
sys.stdin = oldin
sys.stdout = oldout
diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py
--- a/mercurial/pycompat.py
+++ b/mercurial/pycompat.py
@@ -69,6 +69,23 @@
stdout = sys.stdout.buffer
stderr = sys.stderr.buffer
+ class noclosetextio(io.TextIOWrapper):
+ def __del__(self):
+ """Override __del__ so it doesn't close the underlying stream."""
+
+ def bytesinput(*args, **kwargs):
+ origs = {}
+ try:
+ for stream in 'stdin stdout stderr'.split():
+ s = getattr(sys, stream)
+ origs[stream] = s
+ if not isinstance(s, io.TextIOBase):
+ setattr(sys, stream, noclosetextio(s))
+ return bytestr(input(*args, **kwargs))
+ finally:
+ for stream, restore in origs.items():
+ setattr(sys, stream, restore)
+
# Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
# we can use os.fsencode() to get back bytes argv.
#
@@ -303,6 +320,7 @@
stdin = sys.stdin
stdout = sys.stdout
stderr = sys.stderr
+ bytesinput = raw_input
if getattr(sys, 'argv', None) is not None:
sysargv = sys.argv
sysplatform = sys.platform
diff --git a/hgext/hgk.py b/hgext/hgk.py
--- a/hgext/hgk.py
+++ b/hgext/hgk.py
@@ -48,6 +48,7 @@
commands,
obsolete,
patch,
+ pycompat,
registrar,
scmutil,
)
@@ -96,7 +97,7 @@
while True:
if opts['stdin']:
try:
- line = raw_input().split(' ')
+ line = pycompat.bytesinput().split(' ')
node1 = line[0]
if len(line) > 1:
node2 = line[1]
@@ -177,7 +178,7 @@
prefix = ""
if opts['stdin']:
try:
- (type, r) = raw_input().split(' ')
+ (type, r) = pycompat.bytesinput().split(' ')
prefix = " "
except EOFError:
return
@@ -195,7 +196,7 @@
catcommit(ui, repo, n, prefix)
if opts['stdin']:
try:
- (type, r) = raw_input().split(' ')
+ (type, r) = pycompat.bytesinput().split(' ')
except EOFError:
break
else:
To: durin42, #hg-reviewers
Cc: mercurial-devel
More information about the Mercurial-devel
mailing list