FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

bpo-28806: Improve the netrc library by zhangyangyu · Pull Request #127 · python/cpython · GitHub

Repository navigation

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (2) .rst  (1) All 2 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
16 changes: 7 additions & 9 deletions Doc/library/netrc.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ the Unix :program:`ftp` program and other FTP clients.

.. class:: netrc([file])

A :class:`~netrc.netrc` instance or subclass instance encapsulates data from a netrc
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
Expand All @@ -32,6 +32,12 @@ the Unix :program:`ftp` program and other FTP clients.

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

.. versionchanged:: 3.7

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

3.8

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

3.8

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

you can retarget it for python 3.9

The entry in the netrc file no longer needs to contain all tokens. The missing
tokens' value default to an empty string. All the tokens and their values now
can contain arbitrary characters, like whitespace and non-ASCII characters.
If the login name is anonymous, it won't trigger the security check.


.. exception:: NetrcParseError

Expand Down Expand Up @@ -75,11 +81,3 @@ Instances of :class:`~netrc.netrc` have public instance variables:
.. attribute:: netrc.macros

Dictionary mapping macro names to string lists.

.. note::

Passwords are limited to a subset of the ASCII character set. All ASCII
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.

99 changes: 72 additions & 27 deletions Lib/netrc.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,51 @@ def __str__(self):
return "%s (%s, line %s)" % (self.msg, self.filename, self.lineno)


class _netrclex:
def __init__(self, fp):
self.lineno = 1
self.instream = fp
self.whitespace = "\n\t\r "
self._stack = []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

It is not a stack, it is a queue. I suggest to rename it to pushback, as in shlex.lexer.


def _read_char(self):
ch = self.instream.read(1)
if ch == "\n":
self.lineno += 1
return ch

def get_token(self):
if self._stack:
return self._stack.pop(0)
token = ""
fiter = iter(self._read_char, "")
for ch in fiter:
if ch in self.whitespace:
continue
if ch == "\"":

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

'"'?

for ch in fiter:
if ch != "\"":

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I would revert this condition.

if ch == '"':
    return token

And removed continue.

if ch == "\\":
ch = self._read_char()
token += ch
continue
return token
else:
if ch == "\\":
ch = self._read_char()
token += ch
for ch in fiter:
if ch not in self.whitespace:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

The same as above.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I suggest to add a flag for denoting whether the terminating whitespace was '\n'. It will be helpful for comments and macdef.

if ch == "\\":
ch = self._read_char()
token += ch
continue
return token
return token

def push_token(self, token):
self._stack.append(token)

class netrc:
def __init__(self, file=None):
default_netrc = file is None
Expand All @@ -33,61 +78,61 @@ def __init__(self, file=None):
self._parse(file, fp, default_netrc)

def _parse(self, file, fp, default_netrc):
lexer = shlex.shlex(fp)
lexer.wordchars += r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
lexer.commenters = lexer.commenters.replace('#', '')
lexer = _netrclex(fp)
while 1:
# Look for a machine, default, or macdef top-level keyword
saved_lineno = lexer.lineno
toplevel = tt = lexer.get_token()
prev_lineno = lexer.lineno
tt = lexer.get_token()
if not tt:
break
elif tt[0] == '#':
if lexer.lineno == saved_lineno and len(tt) == 1:
if prev_lineno == lexer.lineno:
lexer.instream.readline()
continue
elif tt == 'machine':
entryname = lexer.get_token()
elif tt == 'default':
entryname = 'default'
elif tt == 'macdef': # Just skip to end of macdefs
elif tt == 'macdef':
entryname = lexer.get_token()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

You need to read and ignore the rest of the line after the macro name.

self.macros[entryname] = []
lexer.whitespace = ' \t'
while 1:
line = lexer.instream.readline()
if not line or line == '\012':
lexer.whitespace = ' \t\r\n'
if not line:
raise NetrcParseError(
"Macro definition missing null line terminator.",
file, lexer.lineno)
if line == '\n':

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Add a comment.

break
self.macros[entryname].append(line)
continue
else:
raise NetrcParseError(
"bad toplevel token %r" % tt, file, lexer.lineno)

if not entryname:
raise NetrcParseError("missing %r name" % tt, file, lexer.lineno)

# We're looking at start of an entry for a named machine or default.
login = ''
account = password = None
login = account = password = ''
self.hosts[entryname] = {}
while 1:
prev_lineno = lexer.lineno
tt = lexer.get_token()
if (tt.startswith('#') or
tt in {'', 'machine', 'default', '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)
if tt.startswith('#'):
if lexer.lineno == prev_lineno:
lexer.instream.readline()
continue
if tt in {'', 'machine', 'default', 'macdef'}:
self.hosts[entryname] = (login, account, password)
lexer.push_token(tt)
break
elif tt == 'login' or tt == 'user':
login = lexer.get_token()
elif tt == 'account':
account = lexer.get_token()
elif tt == 'password':
if os.name == 'posix' and default_netrc:
if os.name == 'posix' and default_netrc and login != "anonymous":

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

This assumes that login has already been parsed, but the netrc format does not require providing login token before password token. It would be better to perform this check on storing parsed data into self.hosts[entryname], when all machine-related data is parsed and available.

prop = os.fstat(fp.fileno())
if prop.st_uid != os.getuid():
import pwd
Expand Down Expand Up @@ -127,10 +172,10 @@ def __repr__(self):
rep = ""
for host in self.hosts.keys():
attrs = self.hosts[host]
rep = rep + "machine "+ host + "\n\tlogin " + repr(attrs[0]) + "\n"
rep = rep + "machine "+ host + "\n\tlogin " + attrs[0] + "\n"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Perhaps we need a special function which escapes whitespaces and other special characters?

if attrs[1]:
rep = rep + "account " + repr(attrs[1])
rep = rep + "\tpassword " + repr(attrs[2]) + "\n"
rep = rep + "account " + attrs[1]
rep = rep + "\tpassword " + attrs[2] + "\n"
for macro in self.macros.keys():
rep = rep + "macdef " + macro + "\n"
for line in self.macros[macro]:
Expand Down
Loading

Back | FazBrowse Home | New Git URL