Reland "PRESUBMIT.py: Make CheckPydepsNeedsUpdating faster using concurrency"

This reverts commit cadd78c55c32de191ae57ab68c17a8f742a72b34.

Reason for reland: Removed py3 syntax

Original change's description:
> Revert "PRESUBMIT.py: Make CheckPydepsNeedsUpdating faster using concurrency"
>
> This reverts commit 09650bc010fc34b68adb285d6df13183f9431fa1.
>
> Reason for revert: Running as py2 for some.
>
> Original change's description:
> > PRESUBMIT.py: Make CheckPydepsNeedsUpdating faster using concurrency
> >
> > For DEPS rolls, all .pydeps files are checked, which can take ~30
> > seconds when done sequentially. Check them all concurrently, which on my
> > machine runs in < 2 seconds.
> >
> > Bug: None
> > Change-Id: I621a04456d8c18b0522b586c8eea4befe0e9674f
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3433606
> > Reviewed-by: Erik Staab <[email protected]>
> > Commit-Queue: Andrew Grieve <[email protected]>
> > Cr-Commit-Position: refs/heads/main@{#966727}
>
> Bug: None
> Change-Id: Ic5d902ba6d42312ff9fde8430eec23e47e0977ed
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3437351
> Auto-Submit: Andrew Grieve <[email protected]>
> Commit-Queue: Rubber Stamper <[email protected]>
> Bot-Commit: Rubber Stamper <[email protected]>
> Cr-Commit-Position: refs/heads/main@{#966840}

Bug: None
Change-Id: I1cab290df83d411d6d06a37c3b4563b608df38ce
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3437577
Auto-Submit: Andrew Grieve <[email protected]>
Reviewed-by: Erik Staab <[email protected]>
Commit-Queue: Erik Staab <[email protected]>
Cr-Commit-Position: refs/heads/main@{#966930}
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index f3d929b8..a1f19ddc 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -3,6 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import io
 import os.path
 import subprocess
 import unittest
@@ -506,9 +507,26 @@
 
 
 class PydepsNeedsUpdatingTest(unittest.TestCase):
+  class MockPopen:
+    def __init__(self, stdout_func):
+      self._stdout_func = stdout_func
 
-  class MockSubprocess(object):
+    def wait(self):
+      self.stdout = io.StringIO(self._stdout_func())
+      return 0
+
+  class MockSubprocess:
     CalledProcessError = subprocess.CalledProcessError
+    PIPE = 0
+
+    def __init__(self):
+      self._popen_func = None
+
+    def SetPopenCallback(self, func):
+      self._popen_func = func
+
+    def Popen(self, cmd, *args, **kwargs):
+      return PydepsNeedsUpdatingTest.MockPopen(lambda: self._popen_func(cmd))
 
   def _MockParseGclientArgs(self, is_android=True):
     return lambda: {'checkout_android': 'true' if is_android else 'false' }
@@ -604,11 +622,11 @@
       MockAffectedFile('A.py', []),
     ]
 
-    def mock_check_output(cmd, shell=False, env=None, encoding=None):
+    def popen_callback(cmd):
       self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
       return self.checker._file_cache['A.pydeps']
 
-    self.mock_input_api.subprocess.check_output = mock_check_output
+    self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
 
     results = self._RunCheck()
     self.assertEqual(0, len(results), 'Unexpected results: %r' % results)
@@ -622,14 +640,16 @@
       MockAffectedFile('A.py', []),
     ]
 
-    def mock_check_output(cmd, shell=False, env=None, encoding=None):
+    def popen_callback(cmd):
       self.assertEqual('CMD --output A.pydeps A --output ""', cmd)
       return 'changed data'
 
-    self.mock_input_api.subprocess.check_output = mock_check_output
+    self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
 
     results = self._RunCheck()
     self.assertEqual(1, len(results))
+    # Check that --output "" is not included.
+    self.assertNotIn('""', str(results[0]))
     self.assertIn('File is stale', str(results[0]))
 
   def testRelevantPyTwoChanges(self):
@@ -641,10 +661,10 @@
       MockAffectedFile('C.py', []),
     ]
 
-    def mock_check_output(cmd, shell=False, env=None, encoding=None):
+    def popen_callback(cmd):
       return 'changed data'
 
-    self.mock_input_api.subprocess.check_output = mock_check_output
+    self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
 
     results = self._RunCheck()
     self.assertEqual(2, len(results))
@@ -660,11 +680,11 @@
       MockAffectedFile('D.py', []),
     ]
 
-    def mock_check_output(cmd, shell=False, env=None, encoding=None):
+    def popen_callback(cmd):
       self.assertEqual('CMD --output D.pydeps D --output ""', cmd)
       return 'changed data'
 
-    self.mock_input_api.subprocess.check_output = mock_check_output
+    self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
     PRESUBMIT._ParseGclientArgs = self._MockParseGclientArgs(is_android=False)
 
     results = self._RunCheck()
@@ -687,11 +707,11 @@
       MockAffectedFile('A.py', []),
     ]
 
-    def mock_check_output(cmd, shell=False, env=None, encoding=None):
+    def popen_callback(cmd):
       self.assertEqual('CMD --gn-paths A --output A.pydeps --output ""', cmd)
       return 'changed data'
 
-    self.mock_input_api.subprocess.check_output = mock_check_output
+    self.mock_input_api.subprocess.SetPopenCallback(popen_callback)
 
     results = self._RunCheck()
     self.assertEqual(1, len(results))