I love the argparse
module. argparse.FileType
is helpful too, unless you want the default to be something other than sys.std*
since the default output file is created even if you supply a
value.
For example:
parser.add_argument('--outfile', type=FileType('w'), default="out.txt")
will create out.txt even if you specify a file with --outfile.
The best I can come up with is:
class MagicFileType(object):
def __init__(self, *args, **kwargs):
# save args/kwargs and set filetype to None
self.filetype = None
self.args = args
self.kwargs = kwargs
def __getattr__(self, attr):
""" Delegate everything to the filetype """
# If we haven't created it, now is the time to do so
if self.filetype is None:
self.filetype = FileType(*self.args, **self.kwargs)
self.filetype = self.filetype(self.filename)
return getattr(self.filetype, attr)
def __call__(self, filename):
""" Just cache the filename """
# This is called when the default is created
# Just cache the filename for now.
self.filename = filename
return self
But if feels like this should be easier, am I missing something?
There was a relatively recent change in argparse
, http://bugs.python.org/issue12776 (Aug 2012), that delays the evaluation of the default value. Originally a string default would be passed through type
(via _get_value
) at the start of parsing, resulting in the opening (and creation) of a FileType file (whether it would be needed or not). In this patch, the string is written to the Namespace, but not evaluated until the end of parsing, when it can determine whether another value was provided or not. Basically, this line was moved from early in parse_known_args
to the end of _parse_known_args
default = self._get_value(action, action.default)
In http://bugs.python.org/issue13824 I proposed a patch that provides a FileContext
type. Its main difference from FileType
is that it wraps the open(file...)
in a partial
. That way the file isn't opened (or created) until actually used in a with args.output() as f:
context.
That patch deals with some other things like testing whether the file can be created or not (using os.access
) and wrapping stdin/out
in a dummy context so it does not try to close it.
Without testing, you could modify FileType
like this:
class FileOpener(argparse.FileType):
# delayed FileType;
# sample use:
# with args.input.open() as f: f.read()
def __call__(self, string):
# optionally test string
self.filename = string
return self
def open(self):
return super(FileOpener,self).__call__(self.filename)
file = property(open, None, None, 'open file property')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With