Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion Doc/library/argparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ ArgumentParser objects
epilog=None, parents=[], \
formatter_class=argparse.HelpFormatter, \
prefix_chars='-', fromfile_prefix_chars=None, \
fromfile_parent_relative=False, \
argument_default=None, conflict_handler='error', \
add_help=True, allow_abbrev=True)

Expand Down Expand Up @@ -168,6 +169,11 @@ ArgumentParser objects
* fromfile_prefix_chars_ - The set of characters that prefix files from
which additional arguments should be read (default: ``None``)

* fromfile_parent_relative_ - Whether to treat paths of included
argument files as relative to the location of the file they
are specified in (``True``) or to the current working directory
(``False``) (default: ``False``)

* argument_default_ - The global default value for arguments
(default: ``None``)

Expand All @@ -182,6 +188,9 @@ ArgumentParser objects
.. versionchanged:: 3.5
*allow_abbrev* parameter was added.

.. versionchanged:: TODO
*fromfile_parent_relative* parameter was added.

The following sections describe how each of these are used.


Expand Down Expand Up @@ -489,7 +498,7 @@ disallowed.
fromfile_prefix_chars
^^^^^^^^^^^^^^^^^^^^^

Sometimes, for example when dealing with a particularly long argument lists, it
Sometimes, for example when dealing with a particularly long argument list, it
may make sense to keep the list of arguments in a file rather than typing it out
at the command line. If the ``fromfile_prefix_chars=`` argument is given to the
:class:`ArgumentParser` constructor, then arguments that start with any of the
Expand All @@ -509,10 +518,26 @@ were in the same place as the original file referencing argument on the command
line. So in the example above, the expression ``['-f', 'foo', '@args.txt']``
is considered equivalent to the expression ``['-f', 'foo', '-f', 'bar']``.

Including argument files recursively is fine, as long as no infinite
loops are produced.

The ``fromfile_prefix_chars=`` argument defaults to ``None``, meaning that
arguments will never be treated as file references.


fromfile_parent_relative
^^^^^^^^^^^^^^^^^^^^^^^^

Before Python TODO, paths were always considered to be relative to the
current working directory. Now, when a file to include is specified
inside another one, its path can be treated as being relative to
the file it is contained in. To activate this behaviour, set the
``fromfile_parent_relative=`` parameter to ``True``. However, specifying
absolute paths is and has always been possible as well.

.. versionadded:: TODO


argument_default
^^^^^^^^^^^^^^^^

Expand Down
21 changes: 18 additions & 3 deletions Lib/argparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1591,6 +1591,9 @@ class ArgumentParser(_AttributeHolder, _ActionsContainer):
- prefix_chars -- Characters that prefix optional arguments
- fromfile_prefix_chars -- Characters that prefix files containing
additional arguments
- fromfile_parent_relative -- Whether to treat paths of included
files as relative to the place they were included from or the
current working directory
- argument_default -- The default value for all arguments
- conflict_handler -- String indicating how to handle conflicts
- add_help -- Add a -h/-help option
Expand All @@ -1606,6 +1609,7 @@ def __init__(self,
formatter_class=HelpFormatter,
prefix_chars='-',
fromfile_prefix_chars=None,
fromfile_parent_relative=False,
argument_default=None,
conflict_handler='error',
add_help=True,
Expand All @@ -1626,6 +1630,7 @@ def __init__(self,
self.epilog = epilog
self.formatter_class = formatter_class
self.fromfile_prefix_chars = fromfile_prefix_chars
self.fromfile_parent_relative = fromfile_parent_relative
self.add_help = add_help
self.allow_abbrev = allow_abbrev

Expand Down Expand Up @@ -2025,18 +2030,28 @@ def _read_args_from_files(self, arg_strings):

# replace arguments referencing files with the file content
else:
arg_strings = []

try:
with open(arg_string[1:]) as args_file:
arg_strings = []
for arg_line in args_file.read().splitlines():
for arg in self.convert_arg_line_to_args(arg_line):
# make nested includes relative to their parent
if self.fromfile_parent_relative and \
arg.startswith(self.fromfile_prefix_chars):
dirname = _os.path.dirname(arg_string[1:])
path = _os.path.join(dirname, arg[1:])
# eliminate ../a/../a constructs
path = _os.path.normpath(path)
arg = arg[0] + path
arg_strings.append(arg)
arg_strings = self._read_args_from_files(arg_strings)
new_arg_strings.extend(arg_strings)
except OSError:
err = _sys.exc_info()[1]
self.error(str(err))

arg_strings = self._read_args_from_files(arg_strings)
new_arg_strings.extend(arg_strings)

# return the modified argument list
return new_arg_strings

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added fromfile_parent_relative parameter to argparse.ArgumentParser to
allow paths of included argument files to be relative to the file they
were included by.