mirror of
https://github.com/python/cpython.git
synced 2024-12-02 06:14:49 +08:00
b34ef94d46
Let netrc handle entries with login fields (mail servers for instance) by having login default to ''. Backport candidate.
112 lines
4.0 KiB
Python
112 lines
4.0 KiB
Python
"""An object-oriented interface to .netrc files."""
|
|
|
|
# Module and documentation by Eric S. Raymond, 21 Dec 1998
|
|
|
|
import os, shlex
|
|
|
|
__all__ = ["netrc", "NetrcParseError"]
|
|
|
|
|
|
class NetrcParseError(Exception):
|
|
"""Exception raised on syntax errors in the .netrc file."""
|
|
def __init__(self, msg, filename=None, lineno=None):
|
|
self.filename = filename
|
|
self.lineno = lineno
|
|
self.msg = msg
|
|
Exception.__init__(self, msg)
|
|
|
|
def __str__(self):
|
|
return "%s (%s, line %s)" % (self.msg, self.filename, self.lineno)
|
|
|
|
|
|
class netrc:
|
|
def __init__(self, file=None):
|
|
if file is None:
|
|
try:
|
|
file = os.path.join(os.environ['HOME'], ".netrc")
|
|
except KeyError:
|
|
raise IOError("Could not find .netrc: $HOME is not set")
|
|
fp = open(file)
|
|
self.hosts = {}
|
|
self.macros = {}
|
|
lexer = shlex.shlex(fp)
|
|
lexer.wordchars += r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
|
|
while 1:
|
|
# Look for a machine, default, or macdef top-level keyword
|
|
toplevel = tt = lexer.get_token()
|
|
if not tt:
|
|
break
|
|
elif tt == 'machine':
|
|
entryname = lexer.get_token()
|
|
elif tt == 'default':
|
|
entryname = 'default'
|
|
elif tt == 'macdef': # Just skip to end of macdefs
|
|
entryname = lexer.get_token()
|
|
self.macros[entryname] = []
|
|
lexer.whitespace = ' \t'
|
|
while 1:
|
|
line = lexer.instream.readline()
|
|
if not line or line == '\012':
|
|
lexer.whitespace = ' \t\r\n'
|
|
break
|
|
self.macros[entryname].append(line)
|
|
continue
|
|
else:
|
|
raise NetrcParseError(
|
|
"bad toplevel token %r" % tt, file, lexer.lineno)
|
|
|
|
# We're looking at start of an entry for a named machine or default.
|
|
login = ''
|
|
account = password = None
|
|
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)
|
|
lexer.push_token(tt)
|
|
break
|
|
else:
|
|
raise NetrcParseError(
|
|
"malformed %s entry %s terminated by %s"
|
|
% (toplevel, entryname, repr(tt)),
|
|
file, lexer.lineno)
|
|
elif tt == 'login' or tt == 'user':
|
|
login = lexer.get_token()
|
|
elif tt == 'account':
|
|
account = lexer.get_token()
|
|
elif tt == 'password':
|
|
password = lexer.get_token()
|
|
else:
|
|
raise NetrcParseError("bad follower token %r" % tt,
|
|
file, lexer.lineno)
|
|
|
|
def authenticators(self, host):
|
|
"""Return a (user, account, password) tuple for given host."""
|
|
if host in self.hosts:
|
|
return self.hosts[host]
|
|
elif 'default' in self.hosts:
|
|
return self.hosts['default']
|
|
else:
|
|
return None
|
|
|
|
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 macro in self.macros.keys():
|
|
rep = rep + "macdef " + macro + "\n"
|
|
for line in self.macros[macro]:
|
|
rep = rep + line
|
|
rep = rep + "\n"
|
|
return rep
|
|
|
|
if __name__ == '__main__':
|
|
print netrc()
|