Issue #18401: pdb tests don't read ~/.pdbrc anymore

Patch by Martin Matusiak and Sam Kimbrel.
diff --git a/Lib/pdb.py b/Lib/pdb.py
index b11ac0a..7eb78b9 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -52,7 +52,8 @@
 directory, it is read in and executed as if it had been typed at the
 debugger prompt.  This is particularly useful for aliases.  If both
 files exist, the one in the home directory is read first and aliases
-defined there can be overridden by the local file.
+defined there can be overridden by the local file.  This behavior can be
+disabled by passing the "readrc=False" argument to the Pdb constructor.
 
 Aside from aliases, the debugger is not directly programmable; but it
 is implemented as a class from which you can derive your own debugger
@@ -135,7 +136,7 @@
 class Pdb(bdb.Bdb, cmd.Cmd):
 
     def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
-                 nosigint=False):
+                 nosigint=False, readrc=True):
         bdb.Bdb.__init__(self, skip=skip)
         cmd.Cmd.__init__(self, completekey, stdin, stdout)
         if stdout:
@@ -158,18 +159,19 @@
 
         # Read $HOME/.pdbrc and ./.pdbrc
         self.rcLines = []
-        if 'HOME' in os.environ:
-            envHome = os.environ['HOME']
+        if readrc:
+            if 'HOME' in os.environ:
+                envHome = os.environ['HOME']
+                try:
+                    with open(os.path.join(envHome, ".pdbrc")) as rcFile:
+                        self.rcLines.extend(rcFile)
+                except OSError:
+                    pass
             try:
-                with open(os.path.join(envHome, ".pdbrc")) as rcFile:
+                with open(".pdbrc") as rcFile:
                     self.rcLines.extend(rcFile)
             except OSError:
                 pass
-        try:
-            with open(".pdbrc") as rcFile:
-                self.rcLines.extend(rcFile)
-        except OSError:
-            pass
 
         self.commands = {} # associates a command list to breakpoint numbers
         self.commands_doprompt = {} # for each bp num, tells if the prompt
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index a63ccd8..c39cc97 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -1,8 +1,10 @@
 # A test suite for pdb; not very comprehensive at the moment.
 
 import doctest
+import os
 import pdb
 import sys
+import tempfile
 import types
 import unittest
 import subprocess
@@ -34,7 +36,7 @@
     """This tests the custom displayhook for pdb.
 
     >>> def test_function(foo, bar):
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     pass
 
     >>> with PdbTestInput([
@@ -74,7 +76,7 @@
     ...     return foo.upper()
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     ret = test_function_2('baz')
     ...     print(ret)
 
@@ -173,7 +175,7 @@
     """Test basic commands related to breakpoints.
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     print(1)
     ...     print(2)
     ...     print(3)
@@ -305,7 +307,7 @@
     ...     return foo
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     ret = test_function_2('baz')
 
     >>> with PdbTestInput([  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
@@ -328,7 +330,7 @@
     -> ret = test_function_2('baz')
     (Pdb) list
       1         def test_function():
-      2             import pdb; pdb.Pdb(nosigint=True).set_trace()
+      2             import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
       3  ->         ret = test_function_2('baz')
     [EOF]
     (Pdb) step
@@ -391,7 +393,7 @@
     ...         print('Exception!')
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     test_function_2()
     ...     print('Not reached.')
 
@@ -424,7 +426,7 @@
     -> 1/0
     (Pdb) list
       1         def test_function():
-      2             import pdb; pdb.Pdb(nosigint=True).set_trace()
+      2             import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
       3  ->         test_function_2()
       4             print('Not reached.')
     [EOF]
@@ -448,7 +450,7 @@
 
     >>> def skip_module():
     ...     import string
-    ...     import pdb; pdb.Pdb(skip=['stri*'], nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(skip=['stri*'], nosigint=True, readrc=False).set_trace()
     ...     string.capwords('FOO')
 
     >>> with PdbTestInput([
@@ -477,7 +479,7 @@
     >>> def skip_module():
     ...     def callback():
     ...         return None
-    ...     import pdb; pdb.Pdb(skip=['module_to_skip*'], nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(skip=['module_to_skip*'], nosigint=True, readrc=False).set_trace()
     ...     mod.foo_pony(callback)
 
     >>> with PdbTestInput([
@@ -518,7 +520,7 @@
     """Test that "continue" and "next" work properly in bottom frame (issue #5294).
 
     >>> def test_function():
-    ...     import pdb, sys; inst = pdb.Pdb(nosigint=True)
+    ...     import pdb, sys; inst = pdb.Pdb(nosigint=True, readrc=False)
     ...     inst.set_trace()
     ...     inst.botframe = sys._getframe()  # hackery to get the right botframe
     ...     print(1)
@@ -558,7 +560,7 @@
 
 def pdb_invoke(method, arg):
     """Run pdb.method(arg)."""
-    getattr(pdb.Pdb(nosigint=True), method)(arg)
+    getattr(pdb.Pdb(nosigint=True, readrc=False), method)(arg)
 
 
 def test_pdb_run_with_incorrect_argument():
@@ -607,7 +609,7 @@
     ...     x = 2
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     test_function_2()
     ...     test_function_2()
     ...     test_function_2()
@@ -673,7 +675,7 @@
     ...     yield 2
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     it = test_gen()
     ...     try:
     ...         if next(it) != 0:
@@ -733,7 +735,7 @@
     ...     yield 2
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     it = test_gen()
     ...     try:
     ...         if next(it) != 0:
@@ -788,7 +790,7 @@
     ...     yield 2
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     for i in test_gen():
     ...         print(i)
     ...     print("finished")
@@ -830,7 +832,7 @@
     ...     return 1
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     for i in test_gen():
     ...         print('value', i)
     ...     x = 123
@@ -875,7 +877,7 @@
     ...     return x
 
     >>> def test_function():
-    ...     import pdb; pdb.Pdb(nosigint=True).set_trace()
+    ...     import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
     ...     for i in test_gen():
     ...         print('value', i)
     ...     x = 123
@@ -1025,7 +1027,7 @@
                 import pdb
 
                 def start_pdb():
-                    pdb.Pdb().set_trace()
+                    pdb.Pdb(readrc=False).set_trace()
                     x = 1
                     y = 1
 
@@ -1054,13 +1056,47 @@
             .format(expected, stdout))
 
 
+    def test_readrc_kwarg(self):
+        save_home = os.environ['HOME']
+        save_dir = os.getcwd()
+        script = """import pdb; pdb.Pdb(readrc=False).set_trace()
+
+print('hello')
+"""
+        del os.environ['HOME']
+        try:
+            with tempfile.TemporaryDirectory() as dirname:
+                os.chdir(dirname)
+                with open('.pdbrc', 'w') as f:
+                    f.write("invalid\n")
+
+                with open('main.py', 'w') as f:
+                    f.write(script)
+
+                cmd = [sys.executable, 'main.py']
+                proc = subprocess.Popen(
+                    cmd,
+                    stdout=subprocess.PIPE,
+                    stdin=subprocess.PIPE,
+                    stderr=subprocess.PIPE,
+                )
+                self.addCleanup(proc.stdout.close)
+                self.addCleanup(proc.stderr.close)
+                stdout, stderr = proc.communicate(b'q\n')
+                self.assertNotIn("NameError: name 'invalid' is not defined",
+                              stdout.decode())
+
+        finally:
+            os.environ['HOME'] = save_home
+            os.chdir(save_dir)
+
     def tearDown(self):
         support.unlink(support.TESTFN)
 
 
 def load_tests(*args):
     from test import test_pdb
-    suites = [unittest.makeSuite(PdbTestCase), doctest.DocTestSuite(test_pdb)]
+    suites = [unittest.makeSuite(PdbTestCase)]
     return unittest.TestSuite(suites)