From c87ed60623e4f057620552a9dc754c9c9f1e02e7 Mon Sep 17 00:00:00 2001 From: Edward Lemur Date: Wed, 30 Oct 2019 22:40:40 +0000 Subject: [PATCH] git-cl: Fix some python3 compatibility errors. Also, fix bug in git cl status where the 'updated' field was used to compare messages, even though it doesn't exist (see [1]). This CL modifies it to use 'date', which does exist. [1] https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-message-info Bug: 1002209 Change-Id: I5a5e1193b8502c3ad35d94808ea178cad7f44ac6 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/1891259 Commit-Queue: Edward Lesmes Reviewed-by: Anthony Polito --- git_cl.py | 74 ++++++++++++++++++++-------------------- tests/git_cl_test.py | 80 +++++++++++++++++++++++--------------------- 2 files changed, 78 insertions(+), 76 deletions(-) diff --git a/git_cl.py b/git_cl.py index 398e3ebb7..ba05eb3a8 100755 --- a/git_cl.py +++ b/git_cl.py @@ -54,16 +54,13 @@ import subcommand import subprocess2 import watchlists -if sys.version_info.major == 2: - import httplib - import urllib2 as urllib_request - import urllib2 as urllib_error - import urlparse -else: - import http.client as httplib - import urllib.request as urllib_request - import urllib.error as urllib_error - import urllib.parse as urlparse +from third_party import six +from six.moves import urllib + + +if sys.version_info.major == 3: + basestring = (str,) # pylint: disable=redefined-builtin + __version__ = '2.0' @@ -157,14 +154,15 @@ def GetNoGitPagerEnv(): def RunCommand(args, error_ok=False, error_message=None, shell=False, **kwargs): try: - return subprocess2.check_output(args, shell=shell, **kwargs) + stdout = subprocess2.check_output(args, shell=shell, **kwargs) + return stdout.decode('utf-8', 'replace') except subprocess2.CalledProcessError as e: logging.debug('Failed running %s', args) if not error_ok: DieWithError( 'Command "%s" failed.\n%s' % ( ' '.join(args), error_message or e.stdout or '')) - return e.stdout + return e.stdout.decode('utf-8', 'replace') def RunGit(args, **kwargs): @@ -183,10 +181,10 @@ def RunGitWithCode(args, suppress_stderr=False): env=GetNoGitPagerEnv(), stdout=subprocess2.PIPE, stderr=stderr) - return code, out + return code, out.decode('utf-8', 'replace') except subprocess2.CalledProcessError as e: logging.debug('Failed running %s', ['git'] + args) - return e.returncode, e.stdout + return e.returncode, e.stdout.decode('utf-8', 'replace') def RunGitSilent(args): @@ -1017,7 +1015,7 @@ def ParseIssueNumberArgument(arg): url = gclient_utils.UpgradeToHttps(arg) try: - parsed_url = urlparse.urlparse(url) + parsed_url = urllib.parse.urlparse(url) except ValueError: return fail_result @@ -1322,7 +1320,7 @@ class Changelist(object): url = RunGit(['config', 'remote.%s.url' % remote], error_ok=True).strip() # Check if the remote url can be parsed as an URL. - host = urlparse.urlparse(url).netloc + host = urllib.parse.urlparse(url).netloc if host: self._cached_remote_url = (True, url) return url @@ -1342,7 +1340,7 @@ class Changelist(object): error_ok=True, cwd=url).strip() - host = urlparse.urlparse(url).netloc + host = urllib.parse.urlparse(url).netloc if not host: logging.error( 'Remote "%(remote)s" for branch "%(branch)s" points to ' @@ -1655,7 +1653,7 @@ class Changelist(object): if self._gerrit_host and '.' not in self._gerrit_host: # Abbreviated domain like "chromium" instead of chromium.googlesource.com. # This happens for internal stuff http://crbug.com/614312. - parsed = urlparse.urlparse(self.GetRemoteUrl()) + parsed = urllib.parse.urlparse(self.GetRemoteUrl()) if parsed.scheme == 'sso': print('WARNING: using non-https URLs for remote is likely broken\n' ' Your current remote is: %s' % self.GetRemoteUrl()) @@ -1668,7 +1666,7 @@ class Changelist(object): remote_url = self.GetRemoteUrl() if not remote_url: return None - return urlparse.urlparse(remote_url).netloc + return urllib.parse.urlparse(remote_url).netloc def GetCodereviewServer(self): if not self._gerrit_server: @@ -1678,7 +1676,7 @@ class Changelist(object): self._gerrit_server = self._GitGetBranchConfigValue( self.CodereviewServerConfigKey()) if self._gerrit_server: - self._gerrit_host = urlparse.urlparse(self._gerrit_server).netloc + self._gerrit_host = urllib.parse.urlparse(self._gerrit_server).netloc if not self._gerrit_server: # We assume repo to be hosted on Gerrit, and hence Gerrit server # has "-review" suffix for lowest level subdomain. @@ -1694,7 +1692,7 @@ class Changelist(object): if remote_url is None: logging.warn('can\'t detect Gerrit project.') return None - project = urlparse.urlparse(remote_url).path.strip('/') + project = urllib.parse.urlparse(remote_url).path.strip('/') if project.endswith('.git'): project = project[:-len('.git')] # *.googlesource.com hosts ensure that Git/Gerrit projects don't start with @@ -1743,7 +1741,7 @@ class Changelist(object): if not isinstance(cookie_auth, gerrit_util.CookiesAuthenticator): return - if urlparse.urlparse(self.GetRemoteUrl()).scheme != 'https': + if urllib.parse.urlparse(self.GetRemoteUrl()).scheme != 'https': print('WARNING: Ignoring branch %s with non-https remote %s' % (self.branch, self.GetRemoteUrl())) return @@ -1853,7 +1851,7 @@ class Changelist(object): try: data = self._GetChangeDetail([ 'DETAILED_LABELS', 'CURRENT_REVISION', 'SUBMITTABLE']) - except (httplib.HTTPException, GerritChangeNotExists): + except GerritChangeNotExists: return 'error' if data['status'] in ('ABANDONED', 'MERGED'): @@ -1875,7 +1873,7 @@ class Changelist(object): return 'unsent' owner = data['owner'].get('_account_id') - messages = sorted(data.get('messages', []), key=lambda m: m.get('updated')) + messages = sorted(data.get('messages', []), key=lambda m: m.get('date')) last_message_author = messages.pop().get('author', {}) while last_message_author: if last_message_author.get('email') == COMMIT_BOT_EMAIL: @@ -1902,8 +1900,7 @@ class Changelist(object): data = self._GetChangeDetail(['CURRENT_REVISION', 'CURRENT_COMMIT'], no_cache=force) current_rev = data['current_revision'] - return data['revisions'][current_rev]['commit']['message'].encode( - 'utf-8', 'ignore') + return data['revisions'][current_rev]['commit']['message'] def UpdateDescriptionRemote(self, description, force=False): if gerrit_util.HasPendingChangeEdit( @@ -2324,6 +2321,7 @@ class Changelist(object): # Flush after every line: useful for seeing progress when running as # recipe. filter_fn=lambda _: sys.stdout.flush()) + push_stdout = push_stdout.decode('utf-8', 'replace') except subprocess2.CalledProcessError as e: push_returncode = e.returncode DieWithError('Failed to create a change. Please examine output above ' @@ -2477,7 +2475,7 @@ class Changelist(object): parent = self._ComputeParent(remote, upstream_branch, custom_cl_base, options.force, change_desc) tree = RunGit(['rev-parse', 'HEAD:']).strip() - with tempfile.NamedTemporaryFile(delete=False) as desc_tempfile: + with tempfile.NamedTemporaryFile('w', delete=False) as desc_tempfile: desc_tempfile.write(change_desc.description) desc_tempfile.close() ref_to_push = RunGit(['commit-tree', tree, '-p', parent, @@ -2528,7 +2526,7 @@ class Changelist(object): # Add cc's from the --cc flag. if options.cc: cc.extend(options.cc) - cc = filter(None, [email.strip() for email in cc]) + cc = [email.strip() for email in cc if email.strip()] if change_desc.get_cced(): cc.extend(change_desc.get_cced()) if self._GetGerritHost() == 'chromium-review.googlesource.com': @@ -2729,7 +2727,7 @@ class Changelist(object): def GetGerritChange(self, patchset=None): """Returns a buildbucket.v2.GerritChange message for the current issue.""" - host = urlparse.urlparse(self.GetCodereviewServer()).hostname + host = urllib.parse.urlparse(self.GetCodereviewServer()).hostname issue = self.GetIssue() patchset = int(patchset or self.GetPatchset()) data = self._GetChangeDetail(['ALL_REVISIONS']) @@ -3193,7 +3191,7 @@ def urlretrieve(source, destination): This is necessary because urllib is broken for SSL connections via a proxy. """ with open(destination, 'w') as f: - f.write(urllib_request.urlopen(source).read()) + f.write(urllib.request.urlopen(source).read()) def hasSheBang(fname): @@ -3329,7 +3327,7 @@ class _GitCookiesChecker(object): if not hosts: print('No Git/Gerrit credentials found') return - lengths = [max(map(len, (row[i] for row in hosts))) for i in xrange(3)] + lengths = [max(map(len, (row[i] for row in hosts))) for i in range(3)] header = [('Host', 'User', 'Which file'), ['=' * l for l in lengths]] for row in (header + hosts): @@ -3896,7 +3894,7 @@ def CMDstatus(parser, args): for cl in sorted(changes, key=lambda c: c.GetBranch()): branch = cl.GetBranch() while branch not in branch_statuses: - c, status = output.next() + c, status = next(output) branch_statuses[c.GetBranch()] = status status = branch_statuses.pop(branch) url = cl.GetIssueURL() @@ -4081,10 +4079,10 @@ def CMDcomments(parser, args): if options.json_file: def pre_serialize(c): - dct = c.__dict__.copy() + dct = c._asdict().copy() dct['date'] = dct['date'].strftime('%Y-%m-%d %H:%M:%S.%f') return dct - write_json(options.json_file, map(pre_serialize, summary)) + write_json(options.json_file, [pre_serialize(x) for x in summary]) return 0 @@ -4666,7 +4664,7 @@ def GetTreeStatus(url=None): 'unknown' or 'unset'.""" url = url or settings.GetTreeStatusUrl(error_ok=True) if url: - status = urllib_request.urlopen(url).read().lower() + status = urllib.request.urlopen(url).read().lower() if status.find('closed') != -1 or status == '0': return 'closed' elif status.find('open') != -1 or status == '1': @@ -4680,7 +4678,7 @@ def GetTreeStatusReason(): with the reason for the tree to be opened or closed.""" url = settings.GetTreeStatusUrl() json_url = urlparse.urljoin(url, '/current?format=json') - connection = urllib_request.urlopen(json_url) + connection = urllib.request.urlopen(json_url) status = json.loads(connection.read()) connection.close() return status['message'] @@ -5446,7 +5444,7 @@ class OptionParser(optparse.OptionParser): # Store the options passed by the user in an _actual_options attribute. # We store only the keys, and not the values, since the values can contain # arbitrary information, which might be PII. - metrics.collector.add('arguments', actual_options.__dict__.keys()) + metrics.collector.add('arguments', list(actual_options.__dict__.keys())) levels = [logging.WARNING, logging.INFO, logging.DEBUG] logging.basicConfig( @@ -5469,7 +5467,7 @@ def main(argv): return dispatcher.execute(OptionParser(), argv) except auth.LoginRequiredError as e: DieWithError(str(e)) - except urllib_error.HTTPError as e: + except urllib.error.HTTPError as e: if e.code != 500: raise DieWithError( diff --git a/tests/git_cl_test.py b/tests/git_cl_test.py index e1b2266dd..b95a3ee20 100755 --- a/tests/git_cl_test.py +++ b/tests/git_cl_test.py @@ -10,11 +10,9 @@ import json import logging import os import shutil -import StringIO import sys import tempfile import unittest -import urlparse sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) @@ -31,6 +29,11 @@ import git_common import git_footers import subprocess2 +if sys.version_info.major == 2: + from StringIO import StringIO +else: + from io import StringIO + def callError(code=1, cmd='', cwd='', stdout='', stderr=''): return subprocess2.CalledProcessError(code, cmd, cwd, stdout, stderr) @@ -571,13 +574,13 @@ class GitCookiesCheckerTest(TestCase): def test_report_no_problems(self): self.test_analysis_nothing() - self.mock(sys, 'stdout', StringIO.StringIO()) + self.mock(sys, 'stdout', StringIO()) self.assertFalse(self.c.find_and_report_problems()) self.assertEqual(sys.stdout.getvalue(), '') def test_report(self): self.test_analysis() - self.mock(sys, 'stdout', StringIO.StringIO()) + self.mock(sys, 'stdout', StringIO()) self.mock(git_cl.gerrit_util.CookiesAuthenticator, 'get_gitcookies_path', classmethod(lambda _: '~/.gitcookies')) self.assertTrue(self.c.find_and_report_problems()) @@ -713,7 +716,7 @@ class TestGitCl(TestCase): self.assertTrue(git_cl.ask_for_explicit_yes('prompt')) def test_LoadCodereviewSettingsFromFile_gerrit(self): - codereview_file = StringIO.StringIO('GERRIT_HOST: true') + codereview_file = StringIO('GERRIT_HOST: true') self.calls = [ ((['git', 'config', '--unset-all', 'rietveld.cc'],), CERR1), ((['git', 'config', '--unset-all', 'rietveld.tree-status-url'],), CERR1), @@ -1240,7 +1243,7 @@ class TestGitCl(TestCase): reviewers = reviewers or [] cc = cc or [] - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.mock(git_cl.gerrit_util, 'CookiesAuthenticator', CookiesAuthenticatorMockFactory( same_auth=('git-owner.example.com', '', 'pass'))) @@ -1354,7 +1357,7 @@ class TestGitCl(TestCase): change_id='I123456789') def test_gerrit_patchset_title_special_chars(self): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self._run_gerrit_upload_test( ['-f', '-t', 'We\'ll escape ^_ ^ special chars...@{u}'], 'desc\n\nBUG=\n\nChange-Id: I123456789', @@ -1520,7 +1523,7 @@ class TestGitCl(TestCase): git_cl.sys.stdout.getvalue()) def test_upload_branch_deps(self): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) def mock_run_git(*args, **_kwargs): if args[0] == ['for-each-ref', '--format=%(refname:short) %(upstream:short)', @@ -1778,7 +1781,7 @@ class TestGitCl(TestCase): detect_gerrit_server=False, actual_codereview=None, codereview_in_url=False): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.mock(git_cl, 'IsGitVersionAtLeast', lambda *args: True) if new_branch: @@ -1972,13 +1975,13 @@ class TestGitCl(TestCase): def test_checkout_not_found(self): """Tests git cl checkout .""" - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.calls = self._checkout_calls() self.assertEqual(1, git_cl.main(['checkout', '99999'])) def test_checkout_no_branch_issues(self): """Tests git cl checkout .""" - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.calls = [ ((['git', 'config', '--local', '--get-regexp', 'branch\\..*\\.gerritissue'], ), CERR1), @@ -2011,7 +2014,7 @@ class TestGitCl(TestCase): self.assertIsNone(cl.EnsureAuthenticated(force=False)) def test_gerrit_ensure_authenticated_conflict(self): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) cl = self._test_gerrit_ensure_authenticated_common(auth={ 'chromium.googlesource.com': ('git-one.example.com', None, 'secret1'), @@ -2097,7 +2100,7 @@ class TestGitCl(TestCase): self.assertEqual(0, git_cl.main(['set-commit'])) def test_description_display(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stdout', out) self.mock(git_cl, 'Changelist', ChangelistMock) @@ -2107,7 +2110,7 @@ class TestGitCl(TestCase): self.assertEqual('foo\n', out.getvalue()) def test_StatusFieldOverrideIssueMissingArgs(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stderr', out) try: @@ -2116,7 +2119,7 @@ class TestGitCl(TestCase): self.assertEqual(ex.code, 2) self.assertRegexpMatches(out.getvalue(), r'--field must be specified') - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stderr', out) try: @@ -2126,7 +2129,7 @@ class TestGitCl(TestCase): self.assertRegexpMatches(out.getvalue(), r'--field must be specified') def test_StatusFieldOverrideIssue(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stdout', out) def assertIssue(cl_self, *_args): @@ -2151,7 +2154,7 @@ class TestGitCl(TestCase): git_cl.main(['set-close', '--issue', '1', '--gerrit']), 0) def test_description(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stdout', out) self.calls = [ ((['git', 'symbolic-ref', 'HEAD'],), 'feature'), @@ -2175,11 +2178,11 @@ class TestGitCl(TestCase): self.assertEqual('foobar\n', out.getvalue()) def test_description_set_raw(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stdout', out) self.mock(git_cl, 'Changelist', ChangelistMock) - self.mock(git_cl.sys, 'stdin', StringIO.StringIO('hihi')) + self.mock(git_cl.sys, 'stdin', StringIO('hihi')) self.assertEqual(0, git_cl.main(['description', '-n', 'hihi'])) self.assertEqual('hihi', ChangelistMock.desc) @@ -2202,7 +2205,7 @@ class TestGitCl(TestCase): def UpdateDescriptionRemote(_, desc, force=False): self.assertEqual(desc, 'Some.\n\nChange-Id: xxx\nBug: 123') - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.mock(git_cl.Changelist, 'GetDescription', lambda *args: current_desc) self.mock(git_cl.Changelist, 'UpdateDescriptionRemote', @@ -2232,7 +2235,7 @@ class TestGitCl(TestCase): desc) return desc - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.mock(git_cl.Changelist, 'GetDescription', lambda *args: current_desc) self.mock(git_cl.gclient_utils, 'RunEditor', RunEditor) @@ -2247,17 +2250,17 @@ class TestGitCl(TestCase): self.assertEqual(0, git_cl.main(['description', '--gerrit'])) def test_description_set_stdin(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stdout', out) self.mock(git_cl, 'Changelist', ChangelistMock) - self.mock(git_cl.sys, 'stdin', StringIO.StringIO('hi \r\n\t there\n\nman')) + self.mock(git_cl.sys, 'stdin', StringIO('hi \r\n\t there\n\nman')) self.assertEqual(0, git_cl.main(['description', '-n', '-'])) self.assertEqual('hi\n\t there\n\nman', ChangelistMock.desc) def test_archive(self): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.calls = [ ((['git', 'for-each-ref', '--format=%(refname)', 'refs/heads'],), @@ -2276,7 +2279,7 @@ class TestGitCl(TestCase): self.assertEqual(0, git_cl.main(['archive', '-f'])) def test_archive_current_branch_fails(self): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.calls = [ ((['git', 'for-each-ref', '--format=%(refname)', 'refs/heads'],), 'refs/heads/master'), @@ -2290,7 +2293,7 @@ class TestGitCl(TestCase): self.assertEqual(1, git_cl.main(['archive', '-f'])) def test_archive_dry_run(self): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.calls = [ ((['git', 'for-each-ref', '--format=%(refname)', 'refs/heads'],), @@ -2307,7 +2310,7 @@ class TestGitCl(TestCase): self.assertEqual(0, git_cl.main(['archive', '-f', '--dry-run'])) def test_archive_no_tags(self): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.calls = [ ((['git', 'for-each-ref', '--format=%(refname)', 'refs/heads'],), @@ -2325,7 +2328,7 @@ class TestGitCl(TestCase): self.assertEqual(0, git_cl.main(['archive', '-f', '--notags'])) def test_cmd_issue_erase_existing(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stdout', out) self.calls = [ ((['git', 'symbolic-ref', 'HEAD'],), 'feature'), @@ -2342,7 +2345,7 @@ class TestGitCl(TestCase): self.assertEqual(0, git_cl.main(['issue', '0'])) def test_cmd_issue_erase_existing_with_change_id(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stdout', out) self.mock(git_cl.Changelist, 'GetDescription', lambda _: 'This is a description\n\nChange-Id: Ideadbeef') @@ -2363,7 +2366,7 @@ class TestGitCl(TestCase): self.assertEqual(0, git_cl.main(['issue', '0'])) def test_cmd_issue_json(self): - out = StringIO.StringIO() + out = StringIO() self.mock(git_cl.sys, 'stdout', out) self.calls = [ ((['git', 'symbolic-ref', 'HEAD'],), 'feature'), @@ -2378,7 +2381,7 @@ class TestGitCl(TestCase): self.assertEqual(0, git_cl.main(['issue', '--json', 'output.json'])) def _common_GerritCommitMsgHookCheck(self): - self.mock(git_cl.sys, 'stdout', StringIO.StringIO()) + self.mock(git_cl.sys, 'stdout', StringIO()) self.mock(git_cl.os.path, 'abspath', lambda path: self._mocked_call(['abspath', path])) self.mock(git_cl.os.path, 'exists', @@ -2441,7 +2444,7 @@ class TestGitCl(TestCase): 'url': 'https://git.googlesource.com/test/+/deadbeef'}], } cl.SubmitIssue = lambda wait_for_merge: None - out = StringIO.StringIO() + out = StringIO() self.mock(sys, 'stdout', out) self.assertEqual(0, cl.CMDLand(force=True, bypass_hooks=True, @@ -2537,7 +2540,7 @@ class TestGitCl(TestCase): } self.mock(git_cl.gerrit_util, 'CookiesAuthenticator', CookiesAuthenticatorMock) - self.mock(sys, 'stdout', StringIO.StringIO()) + self.mock(sys, 'stdout', StringIO()) git_cl._GitCookiesChecker().print_current_creds(include_netrc=True) self.assertEqual(list(sys.stdout.getvalue().splitlines()), [ ' Host\t User\t Which file', @@ -2546,7 +2549,8 @@ class TestGitCl(TestCase): ' host.googlesource.com\t user\t.gitcookies', ' host2.googlesource.com\tuser3\t .netrc', ]) - sys.stdout.buf = '' + sys.stdout.seek(0) + sys.stdout.truncate(0) git_cl._GitCookiesChecker().print_current_creds(include_netrc=False) self.assertEqual(list(sys.stdout.getvalue().splitlines()), [ ' Host\tUser\t Which file', @@ -2566,7 +2570,7 @@ class TestGitCl(TestCase): # git cl also checks for existence other files not relevant to this test. return None self.mock(os.path, 'exists', exists_mock) - self.mock(sys, 'stdout', StringIO.StringIO()) + self.mock(sys, 'stdout', StringIO()) def test_creds_check_gitcookies_not_configured(self): self._common_creds_check_mocks() @@ -2631,7 +2635,7 @@ class TestGitCl(TestCase): '-a', 'msg'])) def test_git_cl_comments_fetch_gerrit(self): - self.mock(sys, 'stdout', StringIO.StringIO()) + self.mock(sys, 'stdout', StringIO()) self.calls = [ ((['git', 'config', 'branch.foo.gerritserver'],), ''), ((['git', 'config', 'branch.foo.merge'],), ''), @@ -2782,7 +2786,7 @@ class TestGitCl(TestCase): # git cl comments also fetches robot comments (which are considered a type # of autogenerated comment), and unlike other types of comments, only robot # comments from the latest patchset are shown. - self.mock(sys, 'stdout', StringIO.StringIO()) + self.mock(sys, 'stdout', StringIO()) self.calls = [ ((['git', 'config', 'branch.foo.gerritserver'],), ''), ((['git', 'config', 'branch.foo.merge'],), ''), @@ -3037,7 +3041,7 @@ class CMDTestCaseBase(unittest.TestCase): def setUp(self): super(CMDTestCaseBase, self).setUp() - mock.patch('git_cl.sys.stdout', StringIO.StringIO()).start() + mock.patch('git_cl.sys.stdout', StringIO()).start() mock.patch('git_cl.uuid.uuid4', return_value='uuid4').start() mock.patch('git_cl.Changelist.GetIssue', return_value=123456).start() mock.patch('git_cl.Changelist.GetCodereviewServer',