From 1df0f214a9fdb4dde7506576b144cf6a7fd01b65 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 10 Jun 2011 11:32:52 -0500 Subject: [PATCH] fix regression in netrc comment handling (closes #12009) --- Lib/netrc.py | 12 ++-- Lib/test/test_netrc.py | 131 +++++++++++++++++++++++++++++------------ Misc/ACKS | 1 + Misc/NEWS | 5 ++ 4 files changed, 105 insertions(+), 44 deletions(-) diff --git a/Lib/netrc.py b/Lib/netrc.py index a60b8b72fb9..c96db6f96a6 100644 --- a/Lib/netrc.py +++ b/Lib/netrc.py @@ -2,7 +2,7 @@ # Module and documentation by Eric S. Raymond, 21 Dec 1998 -import os, shlex +import io, os, shlex __all__ = ["netrc", "NetrcParseError"] @@ -37,12 +37,14 @@ class netrc: lexer.commenters = lexer.commenters.replace('#', '') while 1: # Look for a machine, default, or macdef top-level keyword + saved_lineno = lexer.lineno toplevel = tt = lexer.get_token() if not tt: break elif tt[0] == '#': - fp.readline(); - continue; + if lexer.lineno == saved_lineno and len(tt) == 1: + lexer.instream.readline() + continue elif tt == 'machine': entryname = lexer.get_token() elif tt == 'default': @@ -68,8 +70,8 @@ class netrc: self.hosts[entryname] = {} while 1: tt = lexer.get_token() - if (tt=='' or tt == 'machine' or - tt == 'default' or tt =='macdef'): + if (tt.startswith('#') or + tt in {'', 'machine', 'default', 'macdef'}): if password: self.hosts[entryname] = (login, account, password) lexer.push_token(tt) diff --git a/Lib/test/test_netrc.py b/Lib/test/test_netrc.py index da7ec050d25..ef70e3754a3 100644 --- a/Lib/test/test_netrc.py +++ b/Lib/test/test_netrc.py @@ -1,54 +1,107 @@ - -import netrc, os, unittest, sys +import netrc, os, unittest, sys, textwrap from test import support -TEST_NETRC = """ - - #this is a comment -#this is a comment -# this is a comment - -machine foo login log1 password pass1 account acct1 -machine bar login log1 password pass# account acct1 - -macdef macro1 -line1 -line2 - -macdef macro2 -line3 -line4 - -default login log2 password pass2 - -""" - temp_filename = support.TESTFN class NetrcTestCase(unittest.TestCase): - def setUp(self): - mode = 'w' - if sys.platform not in ['cygwin']: - mode += 't' - fp = open(temp_filename, mode) - fp.write(TEST_NETRC) - fp.close() - self.nrc = netrc.netrc(temp_filename) - def tearDown(self): os.unlink(temp_filename) - def test_case_1(self): - self.assertEqual(self.nrc.hosts['foo'], ('log1', 'acct1', 'pass1')) - self.assertEqual(self.nrc.hosts['default'], ('log2', None, 'pass2')) + def make_nrc(self, test_data): + test_data = textwrap.dedent(test_data) + mode = 'w' + if sys.platform != 'cygwin': + mode += 't' + with open(temp_filename, mode) as fp: + fp.write(test_data) + return netrc.netrc(temp_filename) + + def test_default(self): + nrc = self.make_nrc("""\ + machine host1.domain.com login log1 password pass1 account acct1 + default login log2 password pass2 + """) + self.assertEqual(nrc.hosts['host1.domain.com'], + ('log1', 'acct1', 'pass1')) + self.assertEqual(nrc.hosts['default'], ('log2', None, 'pass2')) def test_macros(self): - self.assertEqual(self.nrc.macros, {'macro1':['line1\n', 'line2\n'], - 'macro2':['line3\n', 'line4\n']}) + nrc = self.make_nrc("""\ + macdef macro1 + line1 + line2 + + macdef macro2 + line3 + line4 + """) + self.assertEqual(nrc.macros, {'macro1': ['line1\n', 'line2\n'], + 'macro2': ['line3\n', 'line4\n']}) + + def _test_passwords(self, nrc, passwd): + nrc = self.make_nrc(nrc) + self.assertEqual(nrc.hosts['host.domain.com'], ('log', 'acct', passwd)) + + def test_password_with_leading_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password #pass account acct + """, '#pass') + + def test_password_with_trailing_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password pass# account acct + """, 'pass#') + + def test_password_with_internal_hash(self): + self._test_passwords("""\ + machine host.domain.com login log password pa#ss account acct + """, 'pa#ss') + + def _test_comment(self, nrc, passwd='pass'): + nrc = self.make_nrc(nrc) + self.assertEqual(nrc.hosts['foo.domain.com'], ('bar', None, passwd)) + self.assertEqual(nrc.hosts['bar.domain.com'], ('foo', None, 'pass')) + + def test_comment_before_machine_line(self): + self._test_comment("""\ + # comment + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_before_machine_line_no_space(self): + self._test_comment("""\ + #comment + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_before_machine_line_hash_only(self): + self._test_comment("""\ + # + machine foo.domain.com login bar password pass + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line(self): + self._test_comment("""\ + machine foo.domain.com login bar password pass # comment + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line_no_space(self): + self._test_comment("""\ + machine foo.domain.com login bar password pass #comment + machine bar.domain.com login foo password pass + """) + + def test_comment_at_end_of_machine_line_pass_has_hash(self): + self._test_comment("""\ + machine foo.domain.com login bar password #pass #comment + machine bar.domain.com login foo password pass + """, '#pass') - def test_parses_passwords_with_hash_character(self): - self.assertEqual(self.nrc.hosts['bar'], ('log1', 'acct1', 'pass#')) def test_main(): support.run_unittest(NetrcTestCase) diff --git a/Misc/ACKS b/Misc/ACKS index c698d73e716..e74324f1123 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -564,6 +564,7 @@ Paul Moore Derek Morr James A Morrison Mher Movsisyan +Ruslan Mstoi Sjoerd Mullender Sape Mullender Michael Muller diff --git a/Misc/NEWS b/Misc/NEWS index ed70507c62c..6cf2867fdd4 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -7,6 +7,11 @@ What's New in Python 3.1.4? *Release date: 2011-05-XX* +Library +------- + +- Issue #12009: Fixed regression in netrc file comment handling. + Extension Modules -----------------