69027[netrc.patch,qbase,qtip,tip]:69023 e4fca1041921 2011-03-29 00:25 +0200 saffroy netrc: support more than one entry per host diff -r cc04b591d768 -r e4fca1041921 Lib/netrc.py --- a/Lib/netrc.py Mon Mar 28 13:46:28 2011 +0300 +++ b/Lib/netrc.py Tue Mar 29 00:25:34 2011 +0200 @@ -27,6 +27,7 @@ except KeyError: raise IOError("Could not find .netrc: $HOME is not set") self.hosts = {} + self.allhosts = {} self.macros = {} with open(file) as fp: self._parse(file, fp) @@ -65,13 +66,17 @@ # We're looking at start of an entry for a named machine or default. login = '' account = password = None + if entryname not in self.allhosts: + self.allhosts[entryname] = [] self.hosts[entryname] = {} while 1: tt = lexer.get_token() if (tt=='' or tt == 'machine' or tt == 'default' or tt =='macdef'): if password: - self.hosts[entryname] = (login, account, password) + a = (login, account, password) + self.allhosts[entryname].append(a) + self.hosts[entryname] = a lexer.push_token(tt) break else: @@ -89,10 +94,16 @@ raise NetrcParseError("bad follower token %r" % tt, file, lexer.lineno) - def authenticators(self, host): + def authenticators(self, host, login=None): """Return a (user, account, password) tuple for given host.""" if host in self.hosts: - return self.hosts[host] + if login: + for a in self.allhosts[host]: + if a[0] == login: + return a + return None + else: + return self.hosts[host] elif 'default' in self.hosts: return self.hosts['default'] else: @@ -101,12 +112,12 @@ def __repr__(self): """Dump the class data in the format of a .netrc file.""" rep = "" - for host in self.hosts.keys(): - attrs = self.hosts[host] - rep = rep + "machine "+ host + "\n\tlogin " + repr(attrs[0]) + "\n" - if attrs[1]: - rep = rep + "account " + repr(attrs[1]) - rep = rep + "\tpassword " + repr(attrs[2]) + "\n" + for host, attrlist in self.allhosts.items(): + for attrs in attrlist: + rep = rep + "machine "+ host + "\n\tlogin " + repr(attrs[0]) + "\n" + if attrs[1]: + rep = rep + "account " + repr(attrs[1]) + rep = rep + "\tpassword " + repr(attrs[2]) + "\n" for macro in self.macros.keys(): rep = rep + "macdef " + macro + "\n" for line in self.macros[macro]: diff -r cc04b591d768 -r e4fca1041921 Lib/test/test_netrc.py --- a/Lib/test/test_netrc.py Mon Mar 28 13:46:28 2011 +0300 +++ b/Lib/test/test_netrc.py Tue Mar 29 00:25:34 2011 +0200 @@ -21,6 +21,9 @@ default login log2 password pass2 +machine baz login log3 password pass3 account acct3 +machine baz login log4 password pass4 account acct4 + """ temp_filename = test_support.TESTFN @@ -50,6 +53,11 @@ def test_parses_passwords_with_hash_character(self): self.assertEqual(self.nrc.hosts['bar'], ('log1', 'acct1', 'pass#')) + def test_handle_several_accounts_per_host(self): + self.assertEqual(self.nrc.hosts['baz'], ('log4', 'acct4', 'pass4')) + self.assertEqual(self.nrc.authenticators('baz'), ('log4', 'acct4', 'pass4')) + self.assertEqual(self.nrc.authenticators('baz', 'log3'), ('log3', 'acct3', 'pass3')) + def test_main(): test_support.run_unittest(NetrcTestCase)