[PATCH 1 of 5] py3: replace cStringIO with pycompat.bytesio

17 views
Skip to first unread message

Matt Harbison

unread,
Mar 26, 2019, 10:22:48 PM3/26/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553389237 14400
# Sat Mar 23 21:00:37 2019 -0400
# Node ID 84b197ec8feef823b74bce41317ae6c6721b73a5
# Parent c3cf4955663324e790f692d543c3fd3357d935f0
py3: replace cStringIO with pycompat.bytesio

Fixed up after running `2to3 -w -n -f imports -f imports2 .`. There are other
imports that need fixing, but not all have a pycompat alias. So I'm splitting
these up.

diff --git a/TortoiseHgOverlayServer.py b/TortoiseHgOverlayServer.py
--- a/TortoiseHgOverlayServer.py
+++ b/TortoiseHgOverlayServer.py
@@ -30,7 +30,6 @@
import errno
import time
import threading
-import cStringIO
import Queue
import traceback
import gc
@@ -52,7 +51,11 @@
from mercurial import demandimport
demandimport.IGNORES.add('win32com.shell')
demandimport.enable()
-from mercurial import error
+from mercurial import (
+ error,
+ pycompat,
+)
+
from mercurial.windows import posixfile, unlink, rename
from tortoisehg.util.i18n import agettext as _
from tortoisehg.util import hglib, thread2, paths, shlib, version
@@ -280,7 +283,7 @@
if roots:
_ui = hglib.loadui()
failedroots = set()
- errorstream = cStringIO.StringIO()
+ errorstream = pycompat.bytesio()
_stderr = sys.stderr
sys.stderr = errorstream
try:
diff --git a/hgext3rd/thg.py b/hgext3rd/thg.py
--- a/hgext3rd/thg.py
+++ b/hgext3rd/thg.py
@@ -17,7 +17,11 @@
import sys

from mercurial.i18n import _
-from mercurial import registrar, ui
+from mercurial import (
+ pycompat,
+ registrar,
+ ui,
+)

testedwith = '4.3'

@@ -107,8 +111,7 @@
def cmdview(ui, repo, *pats, **opts):
"""start light interactive history viewer from tortoisehg"""
enforceversion()
- import cStringIO
- mystderr = cStringIO.StringIO()
+ mystderr = pycompat.bytesio()
origstderr = sys.stderr
sys.stderr = mystderr
sys.__stdout__ = sys.stdout
diff --git a/i18n/msgfmt.py b/i18n/msgfmt.py
--- a/i18n/msgfmt.py
+++ b/i18n/msgfmt.py
@@ -35,7 +35,10 @@

import struct
import array
-from cStringIO import StringIO
+
+from mercurial import (
+ pycompat,
+)

__version__ = "1.1-pythongettext"

@@ -224,4 +227,4 @@
self.po.close()

def getAsFile(self):
- return StringIO(self.get())
+ return pycompat.bytesio(self.get())
diff --git a/tests/helpers.py b/tests/helpers.py
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -8,10 +8,10 @@
import tempfile
import time
from collections import defaultdict
-try:
- import cStringIO as StringIO
-except ImportError:
- import StringIO
+
+from mercurial import (
+ pycompat,
+)

from nose import tools

@@ -151,8 +151,8 @@
origwd = os.getcwd()
ui = hglib.loadui()
ui.setconfig('ui', 'strict', True)
- ui.fout = StringIO.StringIO()
- ui.ferr = StringIO.StringIO()
+ ui.fout = pycompat.bytesio()
+ ui.ferr = pycompat.bytesio()
args = list(args)
req = dispatch.request(args, ui=ui)
if hasattr(req, 'earlyoptions'):
diff --git a/tests/wconfig_test.py b/tests/wconfig_test.py
--- a/tests/wconfig_test.py
+++ b/tests/wconfig_test.py
@@ -1,8 +1,12 @@
import os, tempfile
from nose.tools import *
from nose.plugins.skip import SkipTest
-from StringIO import StringIO
-from mercurial import config, error
+from mercurial import (
+ config,
+ error,
+ pycompat,
+)
+
from tortoisehg.util import wconfig

import helpers
@@ -23,7 +27,7 @@
return wconfig.config(newrconfig(vals))

def written(c):
- dest = StringIO()
+ dest = pycompat.bytesio()
c.write(dest)
return dest.getvalue()

@@ -221,7 +225,7 @@
def check_read_write():
c = newwconfig()
s = '[foo]\nbar = baz'
- c.read(path='foo', fp=StringIO(s))
+ c.read(path='foo', fp=pycompat.bytesio(s))
assert_equals(s, written(c).rstrip())

@with_wconfig
@@ -229,16 +233,16 @@
def check_read_write_missing_section_header_error():
c = newwconfig()
s = 'bar = baz' # missing header
- c.read(path='foo', fp=StringIO(s))
- c.write(StringIO())
+ c.read(path='foo', fp=pycompat.bytesio(s))
+ c.write(pycompat.bytesio())

@with_wconfig
@raises(error.ParseError)
def check_read_write_parsing_error():
c = newwconfig()
s = '[foo]\n:bar = baz' # Mercurial can parse it but INIConfig can't
- c.read(path='foo', fp=StringIO(s))
- c.write(StringIO())
+ c.read(path='foo', fp=pycompat.bytesio(s))
+ c.write(pycompat.bytesio())

@with_wconfig
def check_write_after_dict_setitem():
@@ -262,7 +266,7 @@
def check_read_write_rem():
c = newwconfig()
s = '[foo]\nrem = x'
- c.read(path='foo', fp=StringIO(s))
+ c.read(path='foo', fp=pycompat.bytesio(s))
c.set('foo', 'rem', 'y')
assert_equals('[foo]\nrem = y', written(c).rstrip())

@@ -270,7 +274,7 @@
def check_read_write_suboption():
c = newwconfig()
s = '[foo]\nbar:baz = x'
- c.read(path='foo', fp=StringIO(s))
+ c.read(path='foo', fp=pycompat.bytesio(s))
c.set('foo', 'bar:baz', 'y')
assert_equals('[foo]\nbar:baz = y', written(c).rstrip())

@@ -278,7 +282,7 @@
def check_read_write_suboption_removal():
c = newwconfig()
s = '[foo]\nbar:baz = x\nbar = y'
- c.read(path='foo', fp=StringIO(s))
+ c.read(path='foo', fp=pycompat.bytesio(s))
del c['foo']['bar:baz']
assert_equals('[foo]\nbar = y', written(c).rstrip())

diff --git a/thg b/thg
--- a/thg
+++ b/thg
@@ -111,9 +111,9 @@
or getattr(sys, 'frozen', None) != 'windows_exe'):
sys.exit(tortoisehg.hgqt.run.dispatch(argv))
else:
- import cStringIO
+ from mercurial import pycompat
from mercurial.utils import procutil
- mystderr = cStringIO.StringIO()
+ mystderr = pycompat.bytesio()
origstderr = sys.stderr
sys.stderr = mystderr
sys.__stdout__ = sys.stdout
diff --git a/tortoisehg/hgqt/chunks.py b/tortoisehg/hgqt/chunks.py
--- a/tortoisehg/hgqt/chunks.py
+++ b/tortoisehg/hgqt/chunks.py
@@ -7,7 +7,6 @@

from __future__ import absolute_import

-import cStringIO
import os
import re

@@ -285,7 +284,7 @@
if isinstance(ctx, patchctx):
repo.thgbackup(ctx._path)
fp = util.atomictempfile(ctx._path, 'wb')
- buf = cStringIO.StringIO()
+ buf = pycompat.bytesio()
try:
if ctx._ph.comments:
buf.write('\n'.join(ctx._ph.comments))
@@ -327,7 +326,7 @@
wf = repo.wvfs(self.currentFile, 'wb', atomictemp=True)
wf.write(self.diffbrowse.origcontents)
wf.close()
- fp = cStringIO.StringIO()
+ fp = pycompat.bytesio()
chunks[0].write(fp)
for c in kchunks:
c.write(fp)
@@ -394,7 +393,7 @@
else:
# Apply chunks to wfile
repo.thgbackup(repo.wjoin(wfile))
- fp = cStringIO.StringIO()
+ fp = pycompat.bytesio()
for c in chunks:
c.write(fp)
fp.seek(0)
@@ -451,7 +450,7 @@
else:
return []
else:
- buf = cStringIO.StringIO()
+ buf = pycompat.bytesio()
diffopts = patch.diffopts(repo.ui, {'git':True})
m = matchmod.exact(repo.root, repo.root, [wfile])
for p in patch.diff(repo, ctx.p1().node(), None, match=m,
@@ -781,12 +780,12 @@
elif isinstance(self._ctx.rev(), str):
chunks = self._ctx._files[filename]
else:
- header = patch.parsepatch(cStringIO.StringIO(fd.diff))[0]
+ header = patch.parsepatch(pycompat.bytesio(fd.diff))[0]
chunks = [header] + header.hunks

utext = []
for chunk in chunks[1:]:
- buf = cStringIO.StringIO()
+ buf = pycompat.bytesio()
chunk.selected = False
chunk.write(buf)
chunk.lines = buf.getvalue().splitlines()
diff --git a/tortoisehg/hgqt/filedata.py b/tortoisehg/hgqt/filedata.py
--- a/tortoisehg/hgqt/filedata.py
+++ b/tortoisehg/hgqt/filedata.py
@@ -6,10 +6,18 @@
# GNU General Public License version 2, incorporated herein by reference.

import os, posixpath
-import cStringIO

-from mercurial import commands, error, match, patch, subrepo, util
-from mercurial import copies
+from mercurial import (
+ commands,
+ copies,
+ error,
+ match,
+ patch,
+ pycompat,
+ subrepo,
+ util,
+)
+
from mercurial.utils import (
dateutil,
)
@@ -377,7 +385,7 @@
diffopts = patch.difffeatureopts(repo.ui)
diffopts.git = True
m = match.exact(repo.root, repo.root, [wfile])
- fp = cStringIO.StringIO()
+ fp = pycompat.bytesio()

copy = {}
if oldname != wfile:
@@ -401,7 +409,7 @@
values = []
lines = 0
for chunk in self.changes.hunks:
- buf = cStringIO.StringIO()
+ buf = pycompat.bytesio()
chunk.write(buf)
chunk.excluded = False
val = buf.getvalue()
diff --git a/tortoisehg/hgqt/rejects.py b/tortoisehg/hgqt/rejects.py
--- a/tortoisehg/hgqt/rejects.py
+++ b/tortoisehg/hgqt/rejects.py
@@ -7,8 +7,6 @@

from __future__ import absolute_import

-import cStringIO
-
from . import qsci as Qsci
from .qtcore import (
QPoint,
@@ -30,7 +28,10 @@
QVBoxLayout,
)

-from mercurial import patch
+from mercurial import (
+ patch,
+ pycompat,
+)

from ..util import hglib
from ..util.i18n import _
@@ -131,7 +132,7 @@
editor.setMarginLineNumbers(1, True)
editor.setMarginWidth(1, str(editor.lines())+'X')

- buf = cStringIO.StringIO()
+ buf = pycompat.bytesio()
try:
buf.write('diff -r aaaaaaaaaaaa -r bbbbbbbbbbb %s\n' % path)
buf.write(open(path + '.rej', 'rb').read())
@@ -196,7 +197,7 @@
def showChunk(self, row):
if row == -1 or self.updating:
return
- buf = cStringIO.StringIO()
+ buf = pycompat.bytesio()
chunk = self.chunks[row]
chunk.write(buf)
chunkstr = buf.getvalue().decode(self._textEncoding(), 'replace')
diff --git a/tortoisehg/hgqt/repowidget.py b/tortoisehg/hgqt/repowidget.py
--- a/tortoisehg/hgqt/repowidget.py
+++ b/tortoisehg/hgqt/repowidget.py
@@ -9,7 +9,6 @@
from __future__ import absolute_import

import binascii
-import cStringIO
import os
import shlex # used by runCustomCommand
import subprocess # used by runCustomCommand
@@ -2243,7 +2242,7 @@
else:
cmd += ['--repository', self.repo.root]
_ui = self.repo.ui.copy()
- _ui.ferr = cStringIO.StringIO()
+ _ui.ferr = pycompat.bytesio()
# avoid circular import of hgqt.run by importing it inplace
from . import run
res = run.dispatch(cmd, u=_ui)
diff --git a/tortoisehg/util/hglib.py b/tortoisehg/util/hglib.py
--- a/tortoisehg/util/hglib.py
+++ b/tortoisehg/util/hglib.py
@@ -7,7 +7,6 @@

from __future__ import absolute_import

-import cStringIO
import glob
import os
import re
@@ -1177,7 +1176,7 @@
_ = _gettext # TODO: use unicode version globally
# shlex can't process unicode on Python < 2.7.3
cmdline = cmdline.encode('utf-8')
- src = cStringIO.StringIO(cmdline)
+ src = pycompat.bytesio(cmdline)
lex = shlex.shlex(src, posix=True)
lex.whitespace_split = True
lex.commenters = ''
diff --git a/tortoisehg/util/patchctx.py b/tortoisehg/util/patchctx.py
--- a/tortoisehg/util/patchctx.py
+++ b/tortoisehg/util/patchctx.py
@@ -9,7 +9,6 @@

import os
import binascii
-import cStringIO

from mercurial import patch, util, error
from mercurial import node
@@ -183,7 +182,7 @@
if wfile == self._parseErrorFileName:
return '\n\n\nErrors while parsing patch:\n'+str(self._parseerror)
if wfile in self._files:
- buf = cStringIO.StringIO()
+ buf = pycompat.bytesio()
for chunk in self._files[wfile]:
chunk.write(buf)
return buf.getvalue()
diff --git a/tortoisehg/util/wconfig.py b/tortoisehg/util/wconfig.py
--- a/tortoisehg/util/wconfig.py
+++ b/tortoisehg/util/wconfig.py
@@ -7,7 +7,6 @@

import os
import re
-import cStringIO
import ConfigParser
from mercurial import error, util, config as config_mod

@@ -264,7 +263,7 @@
def writefile(config, path):
"""Write the given config obj to the specified file"""
# normalize line endings
- buf = cStringIO.StringIO()
+ buf = pycompat.bytesio()
config.write(buf)
data = '\n'.join(buf.getvalue().splitlines()) + '\n'

Matt Harbison

unread,
Mar 26, 2019, 10:22:49 PM3/26/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553649936 14400
# Tue Mar 26 21:25:36 2019 -0400
# Node ID d25258c13e6fa12942aa2da4dd20e9da3cf5e5e5
# Parent 84b197ec8feef823b74bce41317ae6c6721b73a5
py3: replace cPickle with util.pickle

diff --git a/tortoisehg/hgqt/fileview.py b/tortoisehg/hgqt/fileview.py
--- a/tortoisehg/hgqt/fileview.py
+++ b/tortoisehg/hgqt/fileview.py
@@ -7,7 +7,6 @@

from __future__ import absolute_import

-import cPickle as pickle
import difflib
import os
import re
@@ -1118,7 +1117,7 @@
if ret != 0:
return
repo = self._repoAgentForFile().rawRepo()
- data = pickle.loads(str(sess.readAll()))
+ data = util.pickle.loads(str(sess.readAll()))
links = []
fctxcache = {} # (path, rev): fctx
for l in data[0]['lines']:

Matt Harbison

unread,
Mar 26, 2019, 10:22:49 PM3/26/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553650006 14400
# Tue Mar 26 21:26:46 2019 -0400
# Node ID 990d5e49012d2e7c667f6b7120f8d6c9d6d94a7e
# Parent d25258c13e6fa12942aa2da4dd20e9da3cf5e5e5
py3: replace Queue with pycompat.queue

diff --git a/TortoiseHgOverlayServer.py b/TortoiseHgOverlayServer.py
--- a/TortoiseHgOverlayServer.py
+++ b/TortoiseHgOverlayServer.py
@@ -30,7 +30,6 @@
import errno
import time
import threading
-import Queue
import traceback
import gc

@@ -314,7 +313,7 @@
finally:
sys.stderr = _stderr

-requests = Queue.Queue(0)
+requests = pycompat.queue.Queue(0)

def get_config():
show_taskbaricon = True
@@ -371,7 +370,7 @@
batch.append(args[0])
else:
deferred_requests.append(req)
- except Queue.Empty:
+ except pycompat.queue.Empty:
pass
for req in deferred_requests:
requests.put(req)

Matt Harbison

unread,
Mar 26, 2019, 10:22:50 PM3/26/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553651137 14400
# Tue Mar 26 21:45:37 2019 -0400
# Node ID fff2f342ca202576226ba9869556647f08f117ce
# Parent 990d5e49012d2e7c667f6b7120f8d6c9d6d94a7e
py3: import ConfigParser as configparser

I'm not sure if these hoops are needed. I've got `configparser.py` under
lib/site-packages, and `ConfigParser.py` under lib on pythpn 2.7.15. Listing
the attributes on each looks similar, but there are more with the lowercase
name.

diff --git a/tortoisehg/util/wconfig.py b/tortoisehg/util/wconfig.py
--- a/tortoisehg/util/wconfig.py
+++ b/tortoisehg/util/wconfig.py
@@ -7,8 +7,18 @@

import os
import re
-import ConfigParser
-from mercurial import error, util, config as config_mod
+
+from mercurial import (
+ config as config_mod,
+ error,
+ pycompat,
+ util,
+)
+
+if pycompat.ispy3:
+ import configparser
+else:
+ import ConfigParser as configparser

try:
from iniparse import INIConfig
@@ -199,10 +209,10 @@
try:
# TODO: optionxformvalue isn't used by INIConfig ?
return INIConfig(fp=fp, optionxformvalue=None)
- except ConfigParser.MissingSectionHeaderError as err:
+ except configparser.MissingSectionHeaderError as err:
raise error.ParseError(err.message.splitlines()[0],
'%s:%d' % (err.filename, err.lineno))
- except ConfigParser.ParsingError as err:
+ except configparser.ParsingError as err:
if err.errors:
loc = '%s:%d' % (err.filename, err.errors[0][0])
else:

Matt Harbison

unread,
Mar 26, 2019, 10:22:51 PM3/26/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553653041 14400
# Tue Mar 26 22:17:21 2019 -0400
# Node ID c089d07385e21f1809ae5bcf43ee63b81bb83cb0
# Parent fff2f342ca202576226ba9869556647f08f117ce
py3: import _winreg as winreg

This is kind of messy, and I've got no way to test bugtraq, so I don't want to
change anything. There's no thg equivalent of pycompat that I know of, and the
windows module handles this already, so it seems OK to use.

diff --git a/TortoiseHgOverlayServer.py b/TortoiseHgOverlayServer.py
--- a/TortoiseHgOverlayServer.py
+++ b/TortoiseHgOverlayServer.py
@@ -320,7 +320,11 @@
hgighlight_taskbaricon = True
version2cmenu = False
try:
- from _winreg import HKEY_CURRENT_USER, OpenKey, QueryValueEx
+ from mercurial.windows import winreg
+ HKEY_CURRENT_USER = winreg.HKEY_CURRENT_USER
+ OpenKey = winreg.OpenKey
+ QueryValueEx = winreg.QueryValueEx
+
hkey = OpenKey(HKEY_CURRENT_USER, r'Software\TortoiseHg')
t = ('1', 'True')
try: show_taskbaricon = QueryValueEx(hkey, 'ShowTaskbarIcon')[0] in t
@@ -333,7 +337,10 @@
except EnvironmentError: pass
try:
if not version2cmenu:
- from _winreg import CreateKey, SetValueEx, REG_SZ
+ CreateKey = winreg.CreateKey
+ SetValueEx = winreg.SetValueEx
+ REG_SZ = winreg.REG_SZ
+
try: promoted = QueryValueEx(hkey, 'PromotedItems')[0]
except EnvironmentError: promoted = ''
plist = [i.strip() for i in promoted.split(',')]
diff --git a/tortoisehg/hgqt/shellconf.py b/tortoisehg/hgqt/shellconf.py
--- a/tortoisehg/hgqt/shellconf.py
+++ b/tortoisehg/hgqt/shellconf.py
@@ -8,15 +8,15 @@

from __future__ import absolute_import

-from _winreg import (
- CreateKey,
- HKEY_CURRENT_USER,
- OpenKey,
- QueryValueEx,
- REG_DWORD,
- REG_SZ,
- SetValueEx,
-)
+from mercurial.windows import winreg
+
+CreateKey = winreg.CreateKey
+HKEY_CURRENT_USER = winreg.HKEY_CURRENT_USER
+OpenKey = winreg.OpenKey
+QueryValueEx = winreg.QueryValueEx
+REG_DWORD = winreg.REG_DWORD
+REG_SZ = winreg.REG_SZ
+SetValueEx = winreg.SetValueEx

from .qtgui import (
QApplication,
diff --git a/tortoisehg/util/bugtraq.py b/tortoisehg/util/bugtraq.py
--- a/tortoisehg/util/bugtraq.py
+++ b/tortoisehg/util/bugtraq.py
@@ -5,7 +5,13 @@
from comtypes.typeinfo import ITypeInfo
from comtypes.client import CreateObject
from comtypes.automation import _midlSAFEARRAY
-from _winreg import *
+try:
+ import _winreg as winreg
+ winreg.CloseKey
+ from _winreg import *
+except ImportError:
+ from winreg import *
+
from tortoisehg.hgqt import qtlib
from tortoisehg.util.i18n import _

diff --git a/tortoisehg/util/cachethg.py b/tortoisehg/util/cachethg.py
--- a/tortoisehg/util/cachethg.py
+++ b/tortoisehg/util/cachethg.py
@@ -18,7 +18,11 @@
excludepaths = []

try:
- from _winreg import HKEY_CURRENT_USER, OpenKey, QueryValueEx
+ from mercurial.windows import winreg
+ HKEY_CURRENT_USER = winreg.HKEY_CURRENT_USER
+ OpenKey = winreg.OpenKey
+ QueryValueEx = winreg.QueryValueEx
+
from win32api import GetTickCount
CACHE_TIMEOUT = 5000
try:
diff --git a/tortoisehg/util/debugthg.py b/tortoisehg/util/debugthg.py
--- a/tortoisehg/util/debugthg.py
+++ b/tortoisehg/util/debugthg.py
@@ -9,15 +9,15 @@

debugging = ''
try:
- import _winreg
+ from mercurial.windows import winreg
try:
- hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
+ hkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
r"Software\TortoiseHg", 0,
- _winreg.KEY_ALL_ACCESS)
- val = _winreg.QueryValueEx(hkey, 'OverlayDebug')[0]
+ winreg.KEY_ALL_ACCESS)
+ val = winreg.QueryValueEx(hkey, 'OverlayDebug')[0]
if val in ('1', 'True'):
debugging += 'O'
- val = _winreg.QueryValueEx(hkey, 'ContextMenuDebug')[0]
+ val = winreg.QueryValueEx(hkey, 'ContextMenuDebug')[0]
if val in ('1', 'True'):
debugging += 'M'
if debugging:
diff --git a/tortoisehg/util/gpg.py b/tortoisehg/util/gpg.py
--- a/tortoisehg/util/gpg.py
+++ b/tortoisehg/util/gpg.py
@@ -7,14 +7,14 @@
import os

if os.name == 'nt':
- import _winreg
+ from mercurial.windows import winreg

def findgpg(ui):
path = []
for key in (r"Software\GNU\GnuPG", r"Software\Wow6432Node\GNU\GnuPG"):
try:
- hkey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key)
- pfx = _winreg.QueryValueEx(hkey, 'Install Directory')[0]
+ hkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key)
+ pfx = winreg.QueryValueEx(hkey, 'Install Directory')[0]
for dirPath, dirNames, fileNames in os.walk(pfx):
for f in fileNames:
if f == 'gpg.exe':

Matt Harbison

unread,
Mar 26, 2019, 10:32:51 PM3/26/19
to TortoiseHg Developers

On Tuesday, March 26, 2019 at 10:22:51 PM UTC-4, Matt Harbison wrote:
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553653041 14400
#      Tue Mar 26 22:17:21 2019 -0400
# Node ID c089d07385e21f1809ae5bcf43ee63b81bb83cb0
# Parent  fff2f342ca202576226ba9869556647f08f117ce
py3: import _winreg as winreg

This is kind of messy, and I've got no way to test bugtraq, so I don't want to
change anything.  There's no thg equivalent of pycompat that I know of, and the
windows module handles this already, so it seems OK to use.

The only other pycompat style alias that I see could be useful so far is `basestring`.  There are a handful of uses in about 7 classes in tortoisehg/hgqt/*.  Not sure how we should handle that.  Maybe put the alias in hglib?

Yuya Nishihara

unread,
Mar 27, 2019, 6:09:38 PM3/27/19
to thg...@googlegroups.com, Matt Harbison
These StringIO can't be bytes streams on Python 3 because sys.stdout/stderr
have to be unicode streams.

Yuya Nishihara

unread,
Mar 27, 2019, 6:09:42 PM3/27/19
to thg...@googlegroups.com, Matt Harbison
On Tue, 26 Mar 2019 22:22:46 -0400, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_h...@yahoo.com>
> # Date 1553653041 14400
> # Tue Mar 26 22:17:21 2019 -0400
> # Node ID c089d07385e21f1809ae5bcf43ee63b81bb83cb0
> # Parent fff2f342ca202576226ba9869556647f08f117ce
> py3: import _winreg as winreg

> diff --git a/tortoisehg/util/debugthg.py b/tortoisehg/util/debugthg.py
> --- a/tortoisehg/util/debugthg.py
> +++ b/tortoisehg/util/debugthg.py
> @@ -9,15 +9,15 @@
>
> debugging = ''
> try:
> - import _winreg
> + from mercurial.windows import winreg
> try:
> - hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
> + hkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
> r"Software\TortoiseHg", 0,
> - _winreg.KEY_ALL_ACCESS)
> - val = _winreg.QueryValueEx(hkey, 'OverlayDebug')[0]
> + winreg.KEY_ALL_ACCESS)
> + val = winreg.QueryValueEx(hkey, 'OverlayDebug')[0]
> if val in ('1', 'True'):
> debugging += 'O'
> - val = _winreg.QueryValueEx(hkey, 'ContextMenuDebug')[0]
> + val = winreg.QueryValueEx(hkey, 'ContextMenuDebug')[0]

AttributeError was raised in place of ImportError on Unix probably because the
windows module could be imported. We'll need to get around it.

Yuya Nishihara

unread,
Mar 27, 2019, 6:09:45 PM3/27/19
to thg...@googlegroups.com
I don't check all of them, but maybe we can factor out isinstance(x, basestring)
as an hglib function, and replace basestring with (str, pycompat.unicode).

Matt Harbison

unread,
Mar 27, 2019, 10:45:58 PM3/27/19
to thg...@googlegroups.com, Yuya Nishihara
Should this just conditionally import the old or new name?

I guess I assumed that we would eventually wrap stdout and stderr somehow,
because it isn't clear to me how procutil.std{out,err} will work when they
actually alias sys.stdout.buffer on py3. (There's a TODO there about
needing a silly wrapper to translate to unicode.)


Yuya Nishihara

unread,
Mar 28, 2019, 6:50:29 PM3/28/19
to thg...@googlegroups.com, Matt Harbison
On Wed, 27 Mar 2019 22:45:51 -0400, Matt Harbison wrote:
> >> def cmdview(ui, repo, *pats, **opts):
> >> """start light interactive history viewer from tortoisehg"""
> >> enforceversion()
> >> - import cStringIO
> >> - mystderr = cStringIO.StringIO()
> >> + mystderr = pycompat.bytesio()
> >> origstderr = sys.stderr
> >> sys.stderr = mystderr
> >> sys.__stdout__ = sys.stdout
> >
> > These StringIO can't be bytes streams on Python 3 because
> > sys.stdout/stderr
> > have to be unicode streams.
>
> Should this just conditionally import the old or new name?
>
> I guess I assumed that we would eventually wrap stdout and stderr somehow,
> because it isn't clear to me how procutil.std{out,err} will work when they
> actually alias sys.stdout.buffer on py3. (There's a TODO there about
> needing a silly wrapper to translate to unicode.)

Let's make the wrapper disabled on Py3 for now (i.e. "if not ispy3: mystderr
= ..."), and add TODO comment.

IIRC, these hacks are just for py2exe, and py2exe isn't compatible with
recent Py3 versions.

Matt Harbison

unread,
Mar 30, 2019, 3:12:56 PM3/30/19
to thg...@googlegroups.com, Yuya Nishihara
I haven't tried it yet with core Mercurial, much less thg, but it looks
like somebody may be working on it:

https://github.com/albertosottile/py2exe/releases/tag/v0.9.3.0

Matt Harbison

unread,
Mar 30, 2019, 11:36:15 PM3/30/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553389237 14400
# Sat Mar 23 21:00:37 2019 -0400
# Node ID c9d324988cf19eafae0257ffdd7be756e9f3b149
# Parent 258a0ea16c6b399bc13648f04dfd851fa17e534a
py3: replace cStringIO with pycompat.bytesio

Fixed up after running `2to3 -w -n -f imports -f imports2 .`. There are other
imports that need fixing, but not all have a pycompat alias. So I'm splitting
these up.

TortoiseHgOverlayServer.py and thg replace stdio with byte buffers, which won't
work on py3. They need to be revisited to see if this is still necessary with
py2exe[1]. In the meantime, I conditionalized a couple things there to prevent
extra stacktraces on py3, since the local variable holding the buffer is used
further down in each case.

[1] https://groups.google.com/d/msg/thg-dev/dZbFjZugORs/sGOnxBpnBgAJ

diff --git a/TortoiseHgOverlayServer.py b/TortoiseHgOverlayServer.py
--- a/TortoiseHgOverlayServer.py
+++ b/TortoiseHgOverlayServer.py
@@ -30,7 +30,6 @@
import errno
import time
import threading
-import cStringIO
import Queue
import traceback
import gc
@@ -52,7 +51,11 @@
from mercurial import demandimport
demandimport.IGNORES.add('win32com.shell')
demandimport.enable()
-from mercurial import error
+from mercurial import (
+ error,
+ pycompat,
+)
+
from mercurial.windows import posixfile, unlink, rename
from tortoisehg.util.i18n import agettext as _
from tortoisehg.util import hglib, thread2, paths, shlib, version
@@ -280,9 +283,13 @@
if roots:
_ui = hglib.loadui()
failedroots = set()
- errorstream = cStringIO.StringIO()
_stderr = sys.stderr
- sys.stderr = errorstream
+
+ # TODO: Figure out if this hack for py2exe is still needed, and possibly
+ # wrap this to handle unicode on py3
+ if not pycompat.ispy3:
+ errorstream = pycompat.bytesio()
+ sys.stderr = errorstream
try:
# Ensure that all unset dirstate entries can be updated.
time.sleep(2)
@@ -305,9 +312,10 @@
if notifypaths:
shlib.shell_notify(list(notifypaths), noassoc=not updated_any)
logger.msg('Shell notified')
- errmsg = errorstream.getvalue()
- if errmsg:
- logger.msg('stderr: %s' % errmsg)
+ if not pycompat.ispy3:
+ errmsg = errorstream.getvalue()
+ if errmsg:
+ logger.msg('stderr: %s' % errmsg)
finally:
sys.stderr = _stderr

diff --git a/hgext3rd/thg.py b/hgext3rd/thg.py
--- a/hgext3rd/thg.py
+++ b/hgext3rd/thg.py
@@ -17,7 +17,11 @@
import sys

from mercurial.i18n import _
-from mercurial import registrar, ui
+from mercurial import (
+ pycompat,
+ registrar,
+ ui,
+)

testedwith = '4.3'

@@ -107,8 +111,7 @@
def cmdview(ui, repo, *pats, **opts):
"""start light interactive history viewer from tortoisehg"""
enforceversion()
- import cStringIO
- mystderr = cStringIO.StringIO()
+ mystderr = pycompat.bytesio()
origstderr = sys.stderr
sys.stderr = mystderr
sys.__stdout__ = sys.stdout
diff --git a/i18n/msgfmt.py b/i18n/msgfmt.py
--- a/i18n/msgfmt.py
+++ b/i18n/msgfmt.py
@@ -35,7 +35,10 @@

import struct
import array
-from cStringIO import StringIO
+
+from mercurial import (
+ pycompat,
+)

__version__ = "1.1-pythongettext"

@@ -224,4 +227,4 @@
self.po.close()

def getAsFile(self):
- return StringIO(self.get())
+ return pycompat.bytesio(self.get())
diff --git a/tests/helpers.py b/tests/helpers.py
--- a/tests/helpers.py
+++ b/tests/helpers.py
@@ -8,10 +8,10 @@
import tempfile
import time
from collections import defaultdict
-try:
- import cStringIO as StringIO
-except ImportError:
- import StringIO
+
+from mercurial import (
+ pycompat,
+)

from nose import tools

@@ -151,8 +151,8 @@
origwd = os.getcwd()
ui = hglib.loadui()
ui.setconfig('ui', 'strict', True)
- ui.fout = StringIO.StringIO()
- ui.ferr = StringIO.StringIO()
+ ui.fout = pycompat.bytesio()
+ ui.ferr = pycompat.bytesio()
args = list(args)
req = dispatch.request(args, ui=ui)
if hasattr(req, 'earlyoptions'):
diff --git a/tests/wconfig_test.py b/tests/wconfig_test.py
--- a/tests/wconfig_test.py
+++ b/tests/wconfig_test.py
@@ -1,8 +1,12 @@
import os, tempfile
from nose.tools import *
from nose.plugins.skip import SkipTest
-from StringIO import StringIO
-from mercurial import config, error
+from mercurial import (
+ config,
+ error,
+ pycompat,
+)
+
@@ -111,19 +111,26 @@
or getattr(sys, 'frozen', None) != 'windows_exe'):
sys.exit(tortoisehg.hgqt.run.dispatch(argv))
else:
- import cStringIO
+ from mercurial import pycompat
from mercurial.utils import procutil
- mystderr = cStringIO.StringIO()
origstderr = sys.stderr
- sys.stderr = mystderr
- sys.__stdout__ = sys.stdout
- sys.__stderr__ = sys.stderr
- procutil.stderr = sys.stderr
+
+ # TODO: Figure out if this hack for py2exe is still needed, and possibly
+ # wrap this to handle unicode on py3
+ if not pycompat.ispy3:
+ mystderr = pycompat.bytesio()
+ sys.stderr = mystderr
+ sys.__stdout__ = sys.stdout
+ sys.__stderr__ = sys.stderr
+ procutil.stderr = sys.stderr
ret = 0
try:
ret = tortoisehg.hgqt.run.dispatch(argv)
- sys.stderr = origstderr
- stderrout = mystderr.getvalue()
+ if not pycompat.ispy3:
+ sys.stderr = origstderr
+ stderrout = mystderr.getvalue()
+ else:
+ stderrout = ''
errors = ('Traceback', 'TypeError', 'NameError', 'AttributeError',
'NotImplementedError')
for l in stderrout.splitlines():
diff --git a/tortoisehg/hgqt/chunks.py b/tortoisehg/hgqt/chunks.py
--- a/tortoisehg/hgqt/chunks.py
+++ b/tortoisehg/hgqt/chunks.py
@@ -7,7 +7,6 @@

from __future__ import absolute_import

-import cStringIO
import os
import re
+from mercurial import (
@@ -7,8 +7,6 @@

from __future__ import absolute_import

-import cStringIO
-
from . import qsci as Qsci
from .qtcore import (
QPoint,
@@ -30,7 +28,10 @@
QVBoxLayout,
)

-from mercurial import patch
+from mercurial import (
@@ -9,7 +9,6 @@
from __future__ import absolute_import

import binascii
-import cStringIO
import os
import shlex # used by runCustomCommand
import subprocess # used by runCustomCommand
@@ -2243,7 +2242,7 @@
else:
cmd += ['--repository', self.repo.root]
_ui = self.repo.ui.copy()
- _ui.ferr = cStringIO.StringIO()
+ _ui.ferr = pycompat.bytesio()
# avoid circular import of hgqt.run by importing it inplace
from . import run
res = run.dispatch(cmd, u=_ui)
diff --git a/tortoisehg/util/hglib.py b/tortoisehg/util/hglib.py
--- a/tortoisehg/util/hglib.py
+++ b/tortoisehg/util/hglib.py
@@ -7,7 +7,6 @@

from __future__ import absolute_import

-import cStringIO
import glob
import os
import re
diff --git a/tortoisehg/util/wconfig.py b/tortoisehg/util/wconfig.py
--- a/tortoisehg/util/wconfig.py
+++ b/tortoisehg/util/wconfig.py
@@ -7,7 +7,6 @@

import os
import re
-import cStringIO
import ConfigParser
from mercurial import error, util, config as config_mod

Matt Harbison

unread,
Mar 30, 2019, 11:36:15 PM3/30/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553649936 14400
# Tue Mar 26 21:25:36 2019 -0400
# Node ID 589ccefa88f28affc6ccf6bc04f5a3effe034212
# Parent c9d324988cf19eafae0257ffdd7be756e9f3b149
py3: replace cPickle with util.pickle

diff --git a/tortoisehg/hgqt/fileview.py b/tortoisehg/hgqt/fileview.py
--- a/tortoisehg/hgqt/fileview.py
+++ b/tortoisehg/hgqt/fileview.py
@@ -7,7 +7,6 @@

from __future__ import absolute_import

-import cPickle as pickle
import difflib
import os
import re

Matt Harbison

unread,
Mar 30, 2019, 11:36:16 PM3/30/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553650006 14400
# Tue Mar 26 21:26:46 2019 -0400
# Node ID 6e704469845effc3f0e0b903ade5af688020b448
# Parent 589ccefa88f28affc6ccf6bc04f5a3effe034212
py3: replace Queue with pycompat.queue

diff --git a/TortoiseHgOverlayServer.py b/TortoiseHgOverlayServer.py
--- a/TortoiseHgOverlayServer.py
+++ b/TortoiseHgOverlayServer.py
@@ -30,7 +30,6 @@
import errno
import time
import threading
-import Queue
import traceback
import gc

@@ -319,7 +318,7 @@
finally:
sys.stderr = _stderr

-requests = Queue.Queue(0)
+requests = pycompat.queue.Queue(0)

def get_config():
show_taskbaricon = True
@@ -376,7 +375,7 @@

Matt Harbison

unread,
Mar 30, 2019, 11:36:17 PM3/30/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553651137 14400
# Tue Mar 26 21:45:37 2019 -0400
# Node ID 5afa97774fb931680b29832d5ab0e2d51406974e
# Parent 6e704469845effc3f0e0b903ade5af688020b448
py3: import ConfigParser as configparser

I'm not sure if these hoops are needed. I've got `configparser.py` under
lib/site-packages, and `ConfigParser.py` under lib on pythpn 2.7.15. Listing
the attributes on each looks similar, but there are more with the lowercase
name.

diff --git a/tortoisehg/util/wconfig.py b/tortoisehg/util/wconfig.py
--- a/tortoisehg/util/wconfig.py
+++ b/tortoisehg/util/wconfig.py
@@ -7,8 +7,18 @@

import os
import re
-import ConfigParser
-from mercurial import error, util, config as config_mod
+
+from mercurial import (

Matt Harbison

unread,
Mar 30, 2019, 11:36:18 PM3/30/19
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1553653041 14400
# Tue Mar 26 22:17:21 2019 -0400
# Node ID d36875d951d7da1416b1de4c8cf922e3ce49809a
# Parent 5afa97774fb931680b29832d5ab0e2d51406974e
py3: import _winreg as winreg

This is kind of messy, and I've got no way to test bugtraq, so I don't want to
change anything. There's no thg equivalent of pycompat that I know of, and the
windows module handles this already, so it seems OK to use.

diff --git a/TortoiseHgOverlayServer.py b/TortoiseHgOverlayServer.py
--- a/TortoiseHgOverlayServer.py
+++ b/TortoiseHgOverlayServer.py
@@ -325,7 +325,11 @@
hgighlight_taskbaricon = True
version2cmenu = False
try:
- from _winreg import HKEY_CURRENT_USER, OpenKey, QueryValueEx
+ from mercurial.windows import winreg
+ HKEY_CURRENT_USER = winreg.HKEY_CURRENT_USER
+ OpenKey = winreg.OpenKey
+ QueryValueEx = winreg.QueryValueEx
+
hkey = OpenKey(HKEY_CURRENT_USER, r'Software\TortoiseHg')
t = ('1', 'True')
try: show_taskbaricon = QueryValueEx(hkey, 'ShowTaskbarIcon')[0] in t
@@ -338,7 +342,10 @@
except EnvironmentError: pass
try:
if not version2cmenu:
- from _winreg import CreateKey, SetValueEx, REG_SZ
+ CreateKey = winreg.CreateKey
+ SetValueEx = winreg.SetValueEx
+ REG_SZ = winreg.REG_SZ
+
try: promoted = QueryValueEx(hkey, 'PromotedItems')[0]
except EnvironmentError: promoted = ''
plist = [i.strip() for i in promoted.split(',')]
diff --git a/tortoisehg/hgqt/shellconf.py b/tortoisehg/hgqt/shellconf.py
--- a/tortoisehg/hgqt/shellconf.py
+++ b/tortoisehg/hgqt/shellconf.py
@@ -8,15 +8,15 @@

from __future__ import absolute_import
+ from mercurial.windows import winreg
+ HKEY_CURRENT_USER = winreg.HKEY_CURRENT_USER
+ OpenKey = winreg.OpenKey
+ QueryValueEx = winreg.QueryValueEx
+
from win32api import GetTickCount
CACHE_TIMEOUT = 5000
try:
@@ -38,7 +42,7 @@
excludepaths.append(path)
except EnvironmentError:
pass
-except ImportError:
+except (AttributeError, ImportError): # AttributeError for winreg.* on Unix
from time import time as GetTickCount
CACHE_TIMEOUT = 5.0
debugging = debugthg.debug('O')
diff --git a/tortoisehg/util/debugthg.py b/tortoisehg/util/debugthg.py
--- a/tortoisehg/util/debugthg.py
+++ b/tortoisehg/util/debugthg.py
@@ -9,22 +9,22 @@

debugging = ''
try:
- import _winreg
+ from mercurial.windows import winreg
try:
- hkey = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER,
+ hkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
r"Software\TortoiseHg", 0,
- _winreg.KEY_ALL_ACCESS)
- val = _winreg.QueryValueEx(hkey, 'OverlayDebug')[0]
+ winreg.KEY_ALL_ACCESS)
+ val = winreg.QueryValueEx(hkey, 'OverlayDebug')[0]
if val in ('1', 'True'):
debugging += 'O'
- val = _winreg.QueryValueEx(hkey, 'ContextMenuDebug')[0]
+ val = winreg.QueryValueEx(hkey, 'ContextMenuDebug')[0]
if val in ('1', 'True'):
debugging += 'M'
if debugging:
import win32traceutil
except EnvironmentError:
pass
-except ImportError:
+except (AttributeError, ImportError): # AttributeError for winreg.* on Unix
import os
debugging = os.environ.get("DEBUG_THG", "")
if debugging.lower() in ("1", "true"):
diff --git a/tortoisehg/util/gpg.py b/tortoisehg/util/gpg.py
--- a/tortoisehg/util/gpg.py
+++ b/tortoisehg/util/gpg.py
@@ -7,14 +7,14 @@
import os

if os.name == 'nt':
- import _winreg
+ from mercurial.windows import winreg

Yuya Nishihara

unread,
Mar 31, 2019, 6:00:44 PM3/31/19
to thg...@googlegroups.com, Matt Harbison
On Sat, 30 Mar 2019 23:36:06 -0400, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_h...@yahoo.com>
> # Date 1553389237 14400
> # Sat Mar 23 21:00:37 2019 -0400
> # Node ID c9d324988cf19eafae0257ffdd7be756e9f3b149
> # Parent 258a0ea16c6b399bc13648f04dfd851fa17e534a
> py3: replace cStringIO with pycompat.bytesio

Queued, thanks.

> diff --git a/hgext3rd/thg.py b/hgext3rd/thg.py
> --- a/hgext3rd/thg.py
> +++ b/hgext3rd/thg.py
> @@ -17,7 +17,11 @@
> import sys
>
> from mercurial.i18n import _
> -from mercurial import registrar, ui
> +from mercurial import (
> + pycompat,
> + registrar,
> + ui,
> +)
>
> testedwith = '4.3'
>
> @@ -107,8 +111,7 @@
> def cmdview(ui, repo, *pats, **opts):
> """start light interactive history viewer from tortoisehg"""
> enforceversion()
> - import cStringIO
> - mystderr = cStringIO.StringIO()
> + mystderr = pycompat.bytesio()
> origstderr = sys.stderr
> sys.stderr = mystderr

This one wouldn't work on Py3.
Reply all
Reply to author
Forward
0 new messages