diff -r ae047ebe10f9 Lib/argparse.py --- a/Lib/argparse.py Wed Dec 11 17:21:13 2013 -0600 +++ b/Lib/argparse.py Thu Dec 12 02:31:41 2013 -0800 @@ -1145,13 +1145,16 @@ builtin open() function. - errors -- A string indicating how encoding and decoding errors are to be handled. Accepts the same value as the builtin open() function. + - expanduser -- A boolean specifying if os.path.expanduser should be called on the path + before opening """ - def __init__(self, mode='r', bufsize=-1, encoding=None, errors=None): + def __init__(self, mode='r', bufsize=-1, encoding=None, errors=None, expanduser=False): self._mode = mode self._bufsize = bufsize self._encoding = encoding self._errors = errors + self._expanduser = expanduser def __call__(self, string): # the special argument "-" means sys.std{in,out} @@ -1163,6 +1166,9 @@ else: msg = _('argument "-" with mode %r') % self._mode raise ValueError(msg) + else: + if self._expanduser: + string = _os.path.expanduser(string) # all other arguments are used as file names try: diff -r ae047ebe10f9 Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py Wed Dec 11 17:21:13 2013 -0600 +++ b/Lib/test/test_argparse.py Thu Dec 12 02:31:41 2013 -0800 @@ -1588,6 +1588,39 @@ type('foo') m.assert_called_with('foo', *args) +class TestFileTypeExpandUser(TestCase): + """ Test that tilde is expanded correctly """ + + def test_open_tilde(self): + FT = argparse.FileType + foo = '~/fo~o' + expandedfoo = os.path.expanduser(foo) + cases = [ + # Expand + (FT('rb', expanduser=True), expandedfoo, ('rb', -1, None, None)), + (FT('w', 1, expanduser=True), expandedfoo, ('w', 1, None, None)), + (FT('w', errors='replace', expanduser=True), expandedfoo,('w', -1, None, 'replace')), + (FT('wb', encoding='big5', expanduser=True), expandedfoo, ('wb', -1, 'big5', None)), + (FT('w', 0, 'l1', 'strict', expanduser=True), expandedfoo, ('w', 0, 'l1', 'strict')), + # Don't expand + (FT('rb', expanduser=False), foo, ('rb', -1, None, None)), + (FT('w', 1, expanduser=False), foo, ('w', 1, None, None)), + (FT('w', errors='replace', expanduser=False), foo,('w', -1, None, 'replace')), + (FT('wb', encoding='big5', expanduser=False), foo, ('wb', -1, 'big5', None)), + (FT('w', 0, 'l1', 'strict', expanduser=False), foo, ('w', 0, 'l1', 'strict')), + # default + (FT('rb'), foo, ('rb', -1, None, None)), + (FT('w', 1), foo, ('w', 1, None, None)), + (FT('w', errors='replace'), foo, ('w', -1, None, 'replace')), + (FT('wb', encoding='big5'), foo, ('wb', -1, 'big5', None)), + (FT('w', 0, 'l1', 'strict'), foo, ('w', 0, 'l1', 'strict')), + ] + with mock.patch('builtins.open') as m: + for type, targetfilename, args in cases: + type(foo) + m.assert_called_with(targetfilename, *args) + + class TestTypeCallable(ParserTestCase): """Test some callables as option/argument types"""