Feature or enhancement
Proposal:
gh-58032 proposed, and eventually put a PendingDeprecationWarning on argparse.FileType, for the reasonable reason that it's, as written, impossible to properly close files when a failure occurs during parsing after a file has been opened (leading to ResourceWarnings), and even when parsing completes successfully, it's difficult for the caller to properly manage what it returns; with args.infile, args.outfile: works well enough up until the caller passes - as an argument, and now you're closing your own stdin/stdout unexpectedly.
My proposal is:
- Add an argument (keyword-only to avoid interfering with potential changes to
FileType to match open) to FileType, named stack or manager, that, if passed, will be treated as API compatible with contextlib.ExitStack (I can't imagine needing anything else, but any type providing a suitable .enter_context and .callback is adequate); when the file is opened, it will be registered on the ExitStack, via enter_context for the common case, and by registering a callback to flush it for the - case.
- Only issue the
PendingDeprecationWarning for FileTypes created without providing an ExitStack to manage them; FileType as a whole would no longer be deprecated, only using it in antipatterns
- Document a basic recipe for using
FileType so correct use would be obvious, along the lines of:
with contextlib.ExitStack() as stack:
parser = argparse.ArgumentParser(description="FileType example")
parser.add_argument('infile', type=argparse.FileType(stack=stack), help="File to read")
parser.add_argument('outfile', type=argparse.FileType("w", stack=stack), help="File to write")
args = parser.parse_args()
# Do stuff with args.infile and args.outfile
# Or use stack.pop_all() to transfer resource ownership elsewhere
# Stack is closed here, all newly opened files are closed, any standard handles are flushed but not closed
The changes required are tiny, it continues to allow a race-free way to verify the legality of file arguments to the program (by opening them, the only truly race-free way) without requiring uglier patterns like:
try:
infile = open(args.infile)
except OSError as e:
parser.print_usage(file=sys.stderr)
sys.exit(f"Couldn't open {args.infile!r}: {e}")
with infile:
# Repeat for outfile
and keeping it relatively easy to write simple argparse-based programs.
Has this already been discussed elsewhere?
No response given
Links to previous discussion of this feature:
No response
Feature or enhancement
Proposal:
gh-58032 proposed, and eventually put a
PendingDeprecationWarningonargparse.FileType, for the reasonable reason that it's, as written, impossible to properly close files when a failure occurs during parsing after a file has been opened (leading toResourceWarnings), and even when parsing completes successfully, it's difficult for the caller to properly manage what it returns;with args.infile, args.outfile:works well enough up until the caller passes-as an argument, and now you're closing your ownstdin/stdoutunexpectedly.My proposal is:
FileTypeto matchopen) toFileType, namedstackormanager, that, if passed, will be treated as API compatible withcontextlib.ExitStack(I can't imagine needing anything else, but any type providing a suitable.enter_contextand.callbackis adequate); when the file is opened, it will be registered on theExitStack, viaenter_contextfor the common case, and by registering a callback toflushit for the-case.PendingDeprecationWarningforFileTypes created without providing anExitStackto manage them;FileTypeas a whole would no longer be deprecated, only using it in antipatternsFileTypeso correct use would be obvious, along the lines of:The changes required are tiny, it continues to allow a race-free way to verify the legality of file arguments to the program (by opening them, the only truly race-free way) without requiring uglier patterns like:
and keeping it relatively easy to write simple
argparse-based programs.Has this already been discussed elsewhere?
No response given
Links to previous discussion of this feature:
No response