From 0b8798965a1a39b009af34fecbc1cbb64206373a Mon Sep 17 00:00:00 2001 From: Peter Donis Date: Mon, 4 Apr 2016 00:27:47 -0400 Subject: [PATCH 1/2] Use import-time aliasing polystr = str and polybytes = bytes under Python 2. --- reposurgeon | 69 +++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/reposurgeon b/reposurgeon index f6da934e7..4659c937d 100755 --- a/reposurgeon +++ b/reposurgeon @@ -122,44 +122,39 @@ version="3.37" master_encoding = 'latin-1' -def polystr(o): - "Polymorphic string factory function" - # This is something of a hack: on Python 2, bytes is an alias - # for str, so this ends up just giving a str back for all inputs; - # but on Python 3, if fed a byte string, it decodes it to Unicode - # using the specified master encoding, which should be either 'ascii' - # if you're sure all data being handled will be ASCII data, or - # 'latin-1' otherwise; this ensures that the original bytes can be - # recovered by re-encoding - if isinstance(o, str): - return o - if not isinstance(o, bytes): - return str(o) - return str(o, encoding=master_encoding) - -def polybytes(s): - "Polymorphic string encoding function" - # This is the reverse of the above hack; on Python 2 it returns - # all strings unchanged, but on Python 3 it encodes Unicode strings - # back to bytes using the specified master encoding - if isinstance(s, bytes): - return s - if not isinstance(s, str): - return bytes(s) - return bytes(s, encoding=master_encoding) - -def string_escape(s): - "Polymorphic string_escape/unicode_escape" - # This hack is necessary because Unicode strings in Python 3 don't - # have a decode method, so there's no simple way to ask it for the - # equivalent of decode('string_escape') in Python 2. This function - # assumes that it will be called with an object of the default - # string type, i.e., a `str` (Python 2 byte string, Python 3 - # Unicode string) - if isinstance(s, bytes): - # Must be a Python 2 string +if str is bytes: # Python 2 + + polystr = str + polybytes = bytes + + def string_escape(s): return s.decode('string_escape') - return s.encode(master_encoding).decode('unicode_escape') + +else: # Python 3 + + def polystr(o): + "Polymorphic string factory function" + if isinstance(o, str): + return o + if not isinstance(o, bytes): + return str(o) + return str(o, encoding=master_encoding) + + def polybytes(s): + "Polymorphic string encoding function" + if isinstance(s, bytes): + return s + if not isinstance(s, str): + return bytes(s) + return bytes(s, encoding=master_encoding) + + def string_escape(s): + "Polymorphic string_escape/unicode_escape" + # This hack is necessary because Unicode strings in Python 3 don't + # have a decode method, so there's no simple way to ask it for the + # equivalent of decode('string_escape') in Python 2. This function + # assumes that it will be called with a Python 3 'str' instance + return s.encode(master_encoding).decode('unicode_escape') def make_wrapper(fp): "Wrapper factory function to enforce master encoding" -- GitLab From a33b7302f11e03f9034813f242902f594fc91315 Mon Sep 17 00:00:00 2001 From: Peter Donis Date: Mon, 4 Apr 2016 18:29:35 -0400 Subject: [PATCH 2/2] Only wrap standard I/O streams under Python 3. --- reposurgeon | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/reposurgeon b/reposurgeon index 4659c937d..50cca6647 100755 --- a/reposurgeon +++ b/reposurgeon @@ -129,6 +129,9 @@ if str is bytes: # Python 2 def string_escape(s): return s.decode('string_escape') + + def make_wrapper(fp): + return fp else: # Python 3 @@ -156,35 +159,27 @@ else: # Python 3 # assumes that it will be called with a Python 3 'str' instance return s.encode(master_encoding).decode('unicode_escape') -def make_wrapper(fp): - "Wrapper factory function to enforce master encoding" - # This can be used to wrap normally binary streams for API - # compatibility with functions that need a text stream in - # Python 3; it ensures that the binary bytes are decoded using - # the master encoding we use to turn bytes to Unicode in - # polystr above; on Python 2 this just returns the stream - # unchanged (the standard I/O streams are checked to see - # whether we are on Python 2 or 3, the same as the check used - # in make_std_wrapper below, for consistency) - if any(isinstance(s, io.TextIOWrapper) for s in (sys.stdin, sys.stdout, sys.stderr)): + def make_wrapper(fp): + "Wrapper factory function to enforce master encoding" + # This can be used to wrap normally binary streams for API + # compatibility with functions that need a text stream in + # Python 3; it ensures that the binary bytes are decoded using + # the master encoding we use to turn bytes to Unicode in + # polystr above # newline="\n" ensures that Python 3 won't mangle line breaks return io.TextIOWrapper(fp, encoding=master_encoding, newline="\n") - return fp - -def make_std_wrapper(stream): - "Standard input/output wrapper factory function" - # This ensures that the encoding of standard output and standard - # error on Python 3 matches the master encoding we use to turn - # bytes to Unicode in polystr above; it has no effect on Python 2 - # since the output streams are binary - if isinstance(stream, io.TextIOWrapper): + + def make_std_wrapper(stream): + "Standard input/output wrapper factory function" + # This ensures that the encoding of standard output and standard + # error on Python 3 matches the master encoding we use to turn + # bytes to Unicode in polystr above # line_buffering=True ensures that interactive command sessions work as expected return io.TextIOWrapper(stream.buffer, encoding=master_encoding, newline="\n", line_buffering=True) - return stream -sys.stdin = make_std_wrapper(sys.stdin) -sys.stdout = make_std_wrapper(sys.stdout) -sys.stderr = make_std_wrapper(sys.stderr) + sys.stdin = make_std_wrapper(sys.stdin) + sys.stdout = make_std_wrapper(sys.stdout) + sys.stderr = make_std_wrapper(sys.stderr) # Other hacks for Python 3 if not hasattr(sys, 'intern'): -- GitLab