8000 gh-126390: Support for preserving order of options and nonoption arguments in gnu_getopt() by serhiy-storchaka · Pull Request #126393 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-126390: Support for preserving order of options and nonoption arguments in gnu_getopt() #126393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
8000
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
gh-126390: Support for preserving order of options and nonoption argu…
…ments in gnu_getopt()
  • Loading branch information
serhiy-storchaka committed Nov 11, 2024
commit 0659bd2b3885dca8e4234a904dc10a5945bfc5f8
24 changes: 24 additions & 0 deletions Doc/library/getopt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ exception:
variable :envvar:`!POSIXLY_CORRECT` is set, then option processing stops as
soon as a non-option argument is encountered.

If the first character of the option string is ``'-'``, non-option arguments
that are followed by options are added to the list of option-and-value pairs
as a pair that has ``None`` as its first element and the list of non-option
arguments as its second element.
The second element of the :func:`!gnu_getopt` result is a list of
program arguments after the last option.

.. versionchanged:: 3.14
Support for returning intermixed options and non-option arguments in order.


.. exception:: GetoptError

Expand Down Expand Up @@ -144,6 +154,20 @@ Optional arguments should be specified explicitly:
>>> args
['a1', 'a2']

The order of options and non-option arguments can be preserved:

.. doctest::

>>> s = 'a1 -x a2 a3 a4 --long a5 a6'
>>> args = s.split()
>>> args
['a1', '-x', 'a2', 'a3', 'a4', '--long', 'a5', 'a6']
>>> optlist, args = getopt.gnu_getopt(args, '-x:', ['long='])
>>> optlist
[(None, ['a1']), ('-x', 'a2'), (None, ['a3', 'a4']), ('--long', 'a5')]
>>> args
['a6']

In a script, typical usage is something like this:

.. testcode::
Expand Down
3 changes: 3 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ getopt
* Add support for options with optional arguments.
(Contributed by Serhiy Storchaka in :gh:`126374`.)

* Add support for returning intermixed options and non-option arguments in order.
(Contributed by Serhiy Storchaka in :gh:`126390`.)

http
----

Expand Down
16 changes: 12 additions & 4 deletions Lib/getopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
# TODO for gnu_getopt():
#
# - GNU getopt_long_only mechanism
# - allow the caller to specify ordering
# - RETURN_IN_ORDER option
# - GNU extension with '-' as first character of option string
# - an option string with a W followed by semicolon should
# treat "-W foo" as "--foo"

Expand Down Expand Up @@ -116,8 +113,13 @@ def gnu_getopt(args, shortopts, longopts = []):
else:
longopts = list(longopts)

return_in_order = False
if shortopts.startswith('-'):
shortopts = shortopts[1:]
all_options_first = False
return_in_order = True
# Allow options after non-option arguments?
if shortopts.startswith('+'):
elif shortopts.startswith('+'):
shortopts = shortopts[1:]
all_options_first = True
elif os.environ.get("POSIXLY_CORRECT"):
Expand All @@ -131,8 +133,14 @@ def gnu_getopt(args, shortopts, longopts = []):
break

if args[0][:2] == '--':
if return_in_order and prog_args:
opts.append((None, prog_args))
prog_args = []
opts, args = do_longs(opts, args[0][2:], longopts, args[1:])
elif args[0][:1] == '-' and args[0] != '-':
if return_in_order and prog_args:
opts.append((None, prog_args))
prog_args = []
opts, args = do_shorts(opts, args[0][1:], shortopts, args[1:])
else:
if all_options_first:
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_getopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ def test_gnu_getopt(self):
self.assertEqual(args, ['-'])
self.assertEqual(opts, [('-a', ''), ('-b', '-')])

# Return positional arguments intermixed with options.
opts, args = getopt.gnu_getopt(cmdline, '-ab:', ['alpha', 'beta='])
self.assertEqual(args, ['arg2'])
self.assertEqual(opts, [('-a', ''), (None, ['arg1']), ('-b', '1'), ('--alpha', ''),
('--beta', '2'), ('--beta', '3')])

# Posix style via +
opts, args = getopt.gnu_getopt(cmdline, '+ab:', ['alpha', 'beta='])
self.assertEqual(opts, [('-a', '')])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add support for returning intermixed options and non-option arguments in
order in :func:`getopt.gnu_getopt`.
0