[Python-checkins] bpo-28334: netrc() now uses expanduser() to find .netrc file (GH-4537)

Berker Peksag webhook-mailer at python.org
Sat Nov 25 05:37:26 EST 2017


https://github.com/python/cpython/commit/8d9bb11d8fcbf10cc9b1eb0a647bcf3658a4e3dd
commit: 8d9bb11d8fcbf10cc9b1eb0a647bcf3658a4e3dd
branch: master
author: Berker Peksag <berker.peksag at gmail.com>
committer: GitHub <noreply at github.com>
date: 2017-11-25T13:37:22+03:00
summary:

bpo-28334: netrc() now uses expanduser() to find .netrc file (GH-4537)

Previously, netrc.netrc() was raised an exception if $HOME is not set.

Authored-By: Dimitri Merejkowsky <dimitri.merejkowsky at tanker.io>

files:
A Misc/NEWS.d/next/Library/2017-11-24-11-50-41.bpo-28334.3gGGlt.rst
M Doc/library/netrc.rst
M Lib/netrc.py
M Lib/test/test_netrc.py
M Misc/ACKS

diff --git a/Doc/library/netrc.rst b/Doc/library/netrc.rst
index 64aa3ac7c8a..3d29ac49b91 100644
--- a/Doc/library/netrc.rst
+++ b/Doc/library/netrc.rst
@@ -20,8 +20,10 @@ the Unix :program:`ftp` program and other FTP clients.
 
    A :class:`~netrc.netrc` instance or subclass instance encapsulates data from  a netrc
    file.  The initialization argument, if present, specifies the file to parse.  If
-   no argument is given, the file :file:`.netrc` in the user's home directory will
-   be read.  Parse errors will raise :exc:`NetrcParseError` with diagnostic
+   no argument is given, the file :file:`.netrc` in the user's home directory --
+   as determined by :func:`os.path.expanduser` -- will be read.  Otherwise,
+   a :exc:`FileNotFoundError` exception will be raised.
+   Parse errors will raise :exc:`NetrcParseError` with diagnostic
    information including the file name, line number, and terminating token.
    If no argument is specified on a POSIX system, the presence of passwords in
    the :file:`.netrc` file will raise a :exc:`NetrcParseError` if the file
@@ -32,6 +34,10 @@ the Unix :program:`ftp` program and other FTP clients.
 
    .. versionchanged:: 3.4 Added the POSIX permission check.
 
+   .. versionchanged:: 3.7
+      :func:`os.path.expanduser` is used to find the location of the
+      :file:`.netrc` file when *file* is not passed as argument.
+
 
 .. exception:: NetrcParseError
 
@@ -82,4 +88,3 @@ Instances of :class:`~netrc.netrc` have public instance variables:
    punctuation is allowed in passwords, however, note that whitespace and
    non-printable characters are not allowed in passwords.  This is a limitation
    of the way the .netrc file is parsed and may be removed in the future.
-
diff --git a/Lib/netrc.py b/Lib/netrc.py
index baf8f1d99d9..f0ae48cfed9 100644
--- a/Lib/netrc.py
+++ b/Lib/netrc.py
@@ -23,10 +23,7 @@ class netrc:
     def __init__(self, file=None):
         default_netrc = file is None
         if file is None:
-            try:
-                file = os.path.join(os.environ['HOME'], ".netrc")
-            except KeyError:
-                raise OSError("Could not find .netrc: $HOME is not set") from None
+            file = os.path.join(os.path.expanduser("~"), ".netrc")
         self.hosts = {}
         self.macros = {}
         with open(file) as fp:
diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py
index ca6f27d03c3..f59e5371aca 100644
--- a/Lib/test/test_netrc.py
+++ b/Lib/test/test_netrc.py
@@ -1,4 +1,5 @@
 import netrc, os, unittest, sys, tempfile, textwrap
+from unittest import mock
 from test import support
 
 
@@ -126,8 +127,44 @@ def test_security(self):
             os.chmod(fn, 0o622)
             self.assertRaises(netrc.NetrcParseError, netrc.netrc)
 
-def test_main():
-    support.run_unittest(NetrcTestCase)
+    def test_file_not_found_in_home(self):
+        d = support.TESTFN
+        os.mkdir(d)
+        self.addCleanup(support.rmtree, d)
+        with support.EnvironmentVarGuard() as environ:
+            environ.set('HOME', d)
+            self.assertRaises(FileNotFoundError, netrc.netrc)
+
+    def test_file_not_found_explicit(self):
+        self.assertRaises(FileNotFoundError, netrc.netrc,
+                          file='unlikely_netrc')
+
+    def test_home_not_set(self):
+        fake_home = support.TESTFN
+        os.mkdir(fake_home)
+        self.addCleanup(support.rmtree, fake_home)
+        fake_netrc_path = os.path.join(fake_home, '.netrc')
+        with open(fake_netrc_path, 'w') as f:
+            f.write('machine foo.domain.com login bar password pass')
+        os.chmod(fake_netrc_path, 0o600)
+
+        orig_expanduser = os.path.expanduser
+        called = []
+
+        def fake_expanduser(s):
+            called.append(s)
+            with support.EnvironmentVarGuard() as environ:
+                environ.set('HOME', fake_home)
+                result = orig_expanduser(s)
+                return result
+
+        with support.swap_attr(os.path, 'expanduser', fake_expanduser):
+            nrc = netrc.netrc()
+            login, account, password = nrc.authenticators('foo.domain.com')
+            self.assertEqual(login, 'bar')
+
+        self.assertTrue(called)
+
 
 if __name__ == "__main__":
-    test_main()
+    unittest.main()
diff --git a/Misc/ACKS b/Misc/ACKS
index 05113903f06..fc7154f762e 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1031,6 +1031,7 @@ Bill van Melle
 Lucas Prado Melo
 Ezio Melotti
 Doug Mennella
+Dimitri Merejkowsky
 Brian Merrell
 Alexis Métaireau
 Luke Mewburn
diff --git a/Misc/NEWS.d/next/Library/2017-11-24-11-50-41.bpo-28334.3gGGlt.rst b/Misc/NEWS.d/next/Library/2017-11-24-11-50-41.bpo-28334.3gGGlt.rst
new file mode 100644
index 00000000000..074036b1d31
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2017-11-24-11-50-41.bpo-28334.3gGGlt.rst
@@ -0,0 +1,3 @@
+Use :func:`os.path.expanduser` to find the ``~/.netrc`` file in
+:class:`netrc.netrc`.  If it does not exist, :exc:`FileNotFoundError`
+is raised.  Patch by Dimitri Merejkowsky.



More information about the Python-checkins mailing list