# HG changeset patch # User Matt Harbison # Date 1536890820 14400 # Node ID 3b421154d2ca1d0b70a1f19a19dcb70e4fb331a1 # Parent 47ac5d93d7080528b70fb9e6e41756ca0d9e1b27 py3: fix str vs bytes in enough places to run `hg version` on Windows I don't have Visual Studio 2015 at home, but this now works with a handful of extensions (blackbox, extdiff, patchbomb, phabricator and rebase, but not evolve): $ HGMODULEPOLICY=py py -3 ../hg version Enabling the evolve extension causes the usual "failed to import ..." line, but then print this before the usual version output: ('commit', '[b'debugancestor', b'debugapplystreamclonebundle', ..., b'verify', b'version']') ... where the elided part seems to be every command and alias known. diff -r 47ac5d93d708 -r 3b421154d2ca mercurial/color.py --- a/mercurial/color.py Thu Sep 13 20:54:53 2018 -0400 +++ b/mercurial/color.py Thu Sep 13 22:07:00 2018 -0400 @@ -408,21 +408,21 @@ _INVALID_HANDLE_VALUE = -1 class _COORD(ctypes.Structure): - _fields_ = [('X', ctypes.c_short), - ('Y', ctypes.c_short)] + _fields_ = [(r'X', ctypes.c_short), + (r'Y', ctypes.c_short)] class _SMALL_RECT(ctypes.Structure): - _fields_ = [('Left', ctypes.c_short), - ('Top', ctypes.c_short), - ('Right', ctypes.c_short), - ('Bottom', ctypes.c_short)] + _fields_ = [(r'Left', ctypes.c_short), + (r'Top', ctypes.c_short), + (r'Right', ctypes.c_short), + (r'Bottom', ctypes.c_short)] class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure): - _fields_ = [('dwSize', _COORD), - ('dwCursorPosition', _COORD), - ('wAttributes', _WORD), - ('srWindow', _SMALL_RECT), - ('dwMaximumWindowSize', _COORD)] + _fields_ = [(r'dwSize', _COORD), + (r'dwCursorPosition', _COORD), + (r'wAttributes', _WORD), + (r'srWindow', _SMALL_RECT), + (r'dwMaximumWindowSize', _COORD)] _STD_OUTPUT_HANDLE = 0xfffffff5 # (DWORD)-11 _STD_ERROR_HANDLE = 0xfffffff4 # (DWORD)-12 @@ -484,7 +484,7 @@ w32effects = None else: origattr = csbi.wAttributes - ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)', + ansire = re.compile(b'\033\[([^m]*)m([^\033]*)(.*)', re.MULTILINE | re.DOTALL) def win32print(ui, writefunc, *msgs, **opts): @@ -516,15 +516,15 @@ # them if not found pass # hack to ensure regexp finds data - if not text.startswith('\033['): - text = '\033[m' + text + if not text.startswith(b'\033['): + text = b'\033[m' + text # Look for ANSI-like codes embedded in text m = re.match(ansire, text) try: while m: - for sattr in m.group(1).split(';'): + for sattr in m.group(1).split(b';'): if sattr: attr = mapcolor(int(sattr), attr) ui.flush() diff -r 47ac5d93d708 -r 3b421154d2ca mercurial/pure/osutil.py --- a/mercurial/pure/osutil.py Thu Sep 13 20:54:53 2018 -0400 +++ b/mercurial/pure/osutil.py Thu Sep 13 22:07:00 2018 -0400 @@ -14,6 +14,7 @@ import stat as statmod from .. import ( + encoding, pycompat, ) @@ -193,7 +194,8 @@ def _raiseioerror(name): err = ctypes.WinError() - raise IOError(err.errno, '%s: %s' % (name, err.strerror)) + raise IOError(err.errno, r'%s: %s' % (encoding.strfromlocal(name), + err.strerror)) class posixfile(object): '''a file object aiming for POSIX-like semantics @@ -207,14 +209,14 @@ remains but cannot be opened again or be recreated under the same name, until all reading processes have closed the file.''' - def __init__(self, name, mode='r', bufsize=-1): - if 'b' in mode: + def __init__(self, name, mode=b'r', bufsize=-1): + if b'b' in mode: flags = _O_BINARY else: flags = _O_TEXT - m0 = mode[0] - if m0 == 'r' and '+' not in mode: + m0 = mode[0:1] + if m0 == b'r' and b'+' not in mode: flags |= _O_RDONLY access = _GENERIC_READ else: @@ -223,15 +225,15 @@ flags |= _O_RDWR access = _GENERIC_READ | _GENERIC_WRITE - if m0 == 'r': + if m0 == b'r': creation = _OPEN_EXISTING - elif m0 == 'w': + elif m0 == b'w': creation = _CREATE_ALWAYS - elif m0 == 'a': + elif m0 == b'a': creation = _OPEN_ALWAYS flags |= _O_APPEND else: - raise ValueError("invalid mode: %s" % mode) + raise ValueError(r"invalid mode: %s" % pycompat.sysstr(mode)) fh = _kernel32.CreateFileA(name, access, _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE, diff -r 47ac5d93d708 -r 3b421154d2ca mercurial/windows.py --- a/mercurial/windows.py Thu Sep 13 20:54:53 2018 -0400 +++ b/mercurial/windows.py Thu Sep 13 22:07:00 2018 -0400 @@ -389,7 +389,7 @@ """ global _quotere if _quotere is None: - _quotere = re.compile(r'(\\*)("|\\$)') + _quotere = re.compile(br'(\\*)("|\\$)') global _needsshellquote if _needsshellquote is None: # ":" is also treated as "safe character", because it is used as a part @@ -397,11 +397,11 @@ # safe because shlex.split() (kind of) treats it as an escape char and # drops it. It will leave the next character, even if it is another # "\". - _needsshellquote = re.compile(r'[^a-zA-Z0-9._:/-]').search + _needsshellquote = re.compile(br'[^a-zA-Z0-9._:/-]').search if s and not _needsshellquote(s) and not _quotere.search(s): # "s" shouldn't have to be quoted return s - return '"%s"' % _quotere.sub(r'\1\1\\\2', s) + return b'"%s"' % _quotere.sub(br'\1\1\\\2', s) def _unquote(s): if s.startswith(b'"') and s.endswith(b'"'):