Skip to content

Instantly share code, notes, and snippets.

@angstwad
Last active December 2, 2024 22:39
Show Gist options
  • Save angstwad/e4bdaa249158fbe1f1ddfb0e9327b9e5 to your computer and use it in GitHub Desktop.
Save angstwad/e4bdaa249158fbe1f1ddfb0e9327b9e5 to your computer and use it in GitHub Desktop.
Better argparse.FileType - lazily open files passed as arguments rather than them being opened immediately
import argparse
import pathlib
from typing import IO, Self
class LazyFileType(argparse.FileType):
"""Subclasses `argparse.FileType` in order to provide a way to lazily open
files for reading/writing from arguments. Initializes the same as the
parent, but provides `open` method which returns the file object.
Usage:
```
parser = argparse.ArgumentParser()
parser.add_argument('f', type=LazyFileType('w'))
args = parser.parse_args()
with args.f.open() as f:
for line in foo:
...
```
Provides an alternate constructor for use with the `default` kwarg to
`ArgumentParser.add_argument`.
Usage:
```
parser.add_argument('-f', type=LazyFileType('w'),
default=LazyFileType.default('some_file.txt')
```
"""
def __call__(self, string: str) -> typing.Self: # type: ignore
self.filename = string # pylint: disable=attribute-defined-outside-init
if 'r' in self._mode or 'x' in self._mode:
if not pathlib.Path(self.filename).exists():
m = (f"can't open {self.filename}: No such file or directory: "
f"'{self.filename}'")
raise argparse.ArgumentTypeError(m)
return self
def open(self) -> IO:
"""Opens and returns file for reading
:rtype: io.TextIOWrapper
"""
return open(self.filename, self._mode, self._bufsize, self._encoding, self._errors)
@classmethod
def default(cls, string: str, **kwargs) -> Self:
"""Alternate constructor for a default argument to argparse argument
Args:
string: filename to open
**kwargs: arguments to `__init__`
Returns:
instance of `LazyFileType`
"""
inst = cls(**kwargs)
inst.filename = string # pylint: disable=attribute-defined-outside-init
return inst
Copyright 2024 Paul Durivage <[email protected]>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment