Skip to content

Commit e8dde32

Browse files
dmerejkowskyberkerpeksag
authored andcommitted
bpo-28334: fix netrc not working when $HOME is not set
Also add more tests to check that proper exceptions are raised
1 parent 3df02db commit e8dde32

File tree

5 files changed

+52
-10
lines changed

5 files changed

+52
-10
lines changed

Doc/library/netrc.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ the Unix :program:`ftp` program and other FTP clients.
2020

2121
A :class:`~netrc.netrc` instance or subclass instance encapsulates data from a netrc
2222
file. The initialization argument, if present, specifies the file to parse. If
23-
no argument is given, the file :file:`.netrc` in the user's home directory will
24-
be read. Parse errors will raise :exc:`NetrcParseError` with diagnostic
23+
no argument is given, the file :file:`.netrc` in the user's home directory --
24+
as determined by :func:`os.path.expanduser` -- will be read.
25+
Parse errors will raise :exc:`NetrcParseError` with diagnostic
2526
information including the file name, line number, and terminating token.
2627
If no argument is specified on a POSIX system, the presence of passwords in
2728
the :file:`.netrc` file will raise a :exc:`NetrcParseError` if the file
@@ -32,6 +33,10 @@ the Unix :program:`ftp` program and other FTP clients.
3233

3334
.. versionchanged:: 3.4 Added the POSIX permission check.
3435

36+
.. versionchanged:: 3.7
37+
Now uses :func:`os.path.expanduser` to find the location of the
38+
:file:`.netrc` file when *file* is not passed as argument.
39+
3540

3641
.. exception:: NetrcParseError
3742

@@ -82,4 +87,3 @@ Instances of :class:`~netrc.netrc` have public instance variables:
8287
punctuation is allowed in passwords, however, note that whitespace and
8388
non-printable characters are not allowed in passwords. This is a limitation
8489
of the way the .netrc file is parsed and may be removed in the future.
85-

Lib/netrc.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@ class netrc:
2323
def __init__(self, file=None):
2424
default_netrc = file is None
2525
if file is None:
26-
try:
27-
file = os.path.join(os.environ['HOME'], ".netrc")
28-
except KeyError:
29-
raise OSError("Could not find .netrc: $HOME is not set") from None
26+
file = os.path.join(os.path.expanduser("~"), ".netrc")
3027
self.hosts = {}
3128
self.macros = {}
3229
with open(file) as fp:

Lib/test/test_netrc.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import netrc, os, unittest, sys, tempfile, textwrap
2+
from unittest import mock
23
from test import support
34

45

@@ -126,8 +127,44 @@ def test_security(self):
126127
os.chmod(fn, 0o622)
127128
self.assertRaises(netrc.NetrcParseError, netrc.netrc)
128129

129-
def test_main():
130-
support.run_unittest(NetrcTestCase)
130+
def test_file_not_found_in_home(self):
131+
d = support.TESTFN
132+
os.mkdir(d)
133+
self.addCleanup(support.rmtree, d)
134+
with support.EnvironmentVarGuard() as environ:
135+
environ.set('HOME', d)
136+
self.assertRaises(FileNotFoundError, netrc.netrc)
137+
138+
def test_file_not_found_explicit(self):
139+
self.assertRaises(FileNotFoundError, netrc.netrc,
140+
file='unlikely_netrc')
141+
142+
def test_home_not_set(self):
143+
fake_home = support.TESTFN
144+
os.mkdir(fake_home)
145+
self.addCleanup(support.rmtree, fake_home)
146+
fake_netrc_path = os.path.join(fake_home, '.netrc')
147+
with open(fake_netrc_path, 'w') as f:
148+
f.write('machine foo.domain.com login bar password pass')
149+
os.chmod(fake_netrc_path, 0o600)
150+
151+
orig_expanduser = os.path.expanduser
152+
called = []
153+
154+
def fake_expanduser(s):
155+
called.append(s)
156+
with support.EnvironmentVarGuard() as environ:
157+
environ.set('HOME', fake_home)
158+
result = orig_expanduser(s)
159+
return result
160+
161+
with support.swap_attr(os.path, 'expanduser', fake_expanduser):
162+
nrc = netrc.netrc()
163+
login, account, password = nrc.authenticators('foo.domain.com')
164+
self.assertEqual(login, 'bar')
165+
166+
self.assertTrue(called)
167+
131168

132169
if __name__ == "__main__":
133-
test_main()
170+
unittest.main()

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,7 @@ Bill van Melle
10311031
Lucas Prado Melo
10321032
Ezio Melotti
10331033
Doug Mennella
1034+
Dimitri Merejkowsky
10341035
Brian Merrell
10351036
Alexis Métaireau
10361037
Luke Mewburn
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Use :func:`os.path.expanduser` to find the ``~/.netrc`` file in
2+
:class:`netrc.netrc`. If the file does not exist, a
3+
:exc:`FileNotFoundError` is raised. Patch by Dimitri Merejkowsky.

0 commit comments

Comments
 (0)