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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1186,17 +1186,22 @@ def __call__(self, string):
# the special argument "-" means sys.std{in,out}
if string == '-':
if 'r' in self._mode:
return _sys.stdin
file = _sys.stdin.fileno()
elif 'w' in self._mode:
return _sys.stdout
file = _sys.stdout.fileno()
else:
msg = _('argument "-" with mode %r') % self._mode
raise ValueError(msg)
closefd = False
else:
# all other arguments are used as file names
file = string
closefd = True


# all other arguments are used as file names
try:
return open(string, self._mode, self._bufsize, self._encoding,
self._errors)
return open(file, self._mode, self._bufsize, self._encoding,
self._errors, closefd=closefd)
except OSError as e:
message = _("can't open '%s': %s")
raise ArgumentTypeError(message % (string, e))
Expand Down
48 changes: 34 additions & 14 deletions Lib/test/test_argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@
from test import support
from unittest import mock
class StdIOBuffer(StringIO):
pass
def __init__(self, fileno=None):
self._real_fileno = fileno
super().__init__()

def fileno(self):
return self._real_fileno

class TestCase(unittest.TestCase):

Expand Down Expand Up @@ -91,8 +96,8 @@ def stderr_to_parser_error(parse_args, *args, **kwargs):
# use it as the ArgumentParserError message
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = StdIOBuffer()
sys.stderr = StdIOBuffer()
sys.stdout = StdIOBuffer(sys.stdout.fileno())
sys.stderr = StdIOBuffer(sys.stderr.fileno())
try:
try:
result = parse_args(*args, **kwargs)
Expand Down Expand Up @@ -1476,6 +1481,17 @@ def __eq__(self, other):
text = text.decode('ascii')
return self.name == other.name == text

class FilenoMode(object):

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.

Inheriting object is redundant.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It doesn't matter, it is similar to class RFile(object) in the file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Do I need to modify it?


def __init__(self, file, mode):
self.fileno = file.fileno()
self.mode = mode

def __eq__(self, other):
return self.fileno == other.fileno() and self.mode == other.mode

def __repr__(self):
return "FilenoMode({}, {!r})".format(self.fileno, self.mode)

class TestFileTypeR(TempDirMixin, ParserTestCase):
"""Test the FileType option/argument type for reading files"""
Expand All @@ -1497,7 +1513,8 @@ def setUp(self):
('foo', NS(x=None, spam=RFile('foo'))),
('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
('-x - -', NS(x=FilenoMode(sys.stdin, 'r'),
spam=FilenoMode(sys.stdin, 'r'))),
('readonly', NS(x=None, spam=RFile('readonly'))),
]

Expand Down Expand Up @@ -1537,7 +1554,8 @@ def setUp(self):
('foo', NS(x=None, spam=RFile('foo'))),
('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
('-x - -', NS(x=FilenoMode(sys.stdin, 'rb'),
spam=FilenoMode(sys.stdin, 'rb'))),
]


Expand Down Expand Up @@ -1576,7 +1594,8 @@ def setUp(self):
('foo', NS(x=None, spam=WFile('foo'))),
('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
('-x - -', NS(x=FilenoMode(sys.stdout, 'w'),
spam=FilenoMode(sys.stdout, 'w'))),
]


Expand All @@ -1591,7 +1610,8 @@ class TestFileTypeWB(TempDirMixin, ParserTestCase):
('foo', NS(x=None, spam=WFile('foo'))),
('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
('-x - -', NS(x=FilenoMode(sys.stdout, 'wb'),
spam=FilenoMode(sys.stdout, 'wb'))),
]


Expand All @@ -1601,16 +1621,16 @@ class TestFileTypeOpenArgs(TestCase):
def test_open_args(self):
FT = argparse.FileType
cases = [
(FT('rb'), ('rb', -1, None, None)),
(FT('w', 1), ('w', 1, None, None)),
(FT('w', errors='replace'), ('w', -1, None, 'replace')),
(FT('wb', encoding='big5'), ('wb', -1, 'big5', None)),
(FT('w', 0, 'l1', 'strict'), ('w', 0, 'l1', 'strict')),
(FT('rb'), ('rb', -1, None, None), {"closefd": True}),
(FT('w', 1), ('w', 1, None, None), {"closefd": True}),
(FT('w', errors='replace'), ('w', -1, None, 'replace'), {"closefd": True}),
(FT('wb', encoding='big5'), ('wb', -1, 'big5', None), {"closefd": True}),
(FT('w', 0, 'l1', 'strict'), ('w', 0, 'l1', 'strict'), {"closefd": True}),
]
with mock.patch('builtins.open') as m:
for type, args in cases:
for type, args, kwargs in cases:
type('foo')
m.assert_called_with('foo', *args)
m.assert_called_with('foo', *args, **kwargs)


class TestTypeCallable(ParserTestCase):
Expand Down