diff -r 3e897eef0fac Lib/argparse.py --- a/Lib/argparse.py Wed Mar 02 19:40:50 2016 +0200 +++ b/Lib/argparse.py Sat Mar 05 19:44:17 2016 +0200 @@ -1172,17 +1172,21 @@ # 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: + 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)) diff -r 3e897eef0fac Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py Wed Mar 02 19:40:50 2016 +0200 +++ b/Lib/test/test_argparse.py Sat Mar 05 19:44:17 2016 +0200 @@ -16,7 +16,13 @@ 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): @@ -91,16 +97,11 @@ # 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) - for key in list(vars(result)): - if getattr(result, key) is sys.stdout: - setattr(result, key, old_stdout) - if getattr(result, key) is sys.stderr: - setattr(result, key, old_stderr) return result except SystemExit: code = sys.exc_info()[1].code @@ -1477,6 +1478,19 @@ return self.name == other.name == text +class FilenoMode(object): + + 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""" @@ -1497,7 +1511,8 @@ ('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'))), ] @@ -1537,7 +1552,8 @@ ('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'))), ] @@ -1576,7 +1592,8 @@ ('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'))), ] @@ -1591,7 +1608,8 @@ ('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'))), ] @@ -1601,16 +1619,16 @@ 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):