Skip to content
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

gh-126180: Remove getopt and optparse deprecation notices #126227

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
18 changes: 9 additions & 9 deletions Doc/howto/argparse-optparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,8 @@
Upgrading optparse code
==========================

Originally, the :mod:`argparse` module had attempted to maintain compatibility
with :mod:`optparse`. However, :mod:`optparse` was difficult to extend
transparently, particularly with the changes required to support
``nargs=`` specifiers and better usage messages. When most everything in
:mod:`optparse` had either been copy-pasted over or monkey-patched, it no
longer seemed practical to try to maintain the backwards compatibility.

The :mod:`argparse` module improves on the :mod:`optparse`
module in a number of ways including:
The :mod:`argparse` module offers several higher level features not natively
provided by the :mod:`optparse` module, including:

* Handling positional arguments.
* Supporting subcommands.
Expand All @@ -23,6 +16,13 @@ module in a number of ways including:
* Producing more informative usage messages.
* Providing a much simpler interface for custom ``type`` and ``action``.

Originally, the :mod:`argparse` module attempted to maintain compatibility
with :mod:`optparse`. However, :mod:`optparse` was difficult to extend
transparently, particularly with the changes required to support
``nargs=`` specifiers and better usage messages. When most everything in
:mod:`optparse` had either been copy-pasted over or monkey-patched, it no
longer seemed practical to try to maintain the backwards compatibility.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me try squinting at this from a slightly different angle, feel free to ignore...

:mod:argparse was originally created to address some needs that the design of :mod:optparse made difficult to implement. While initially the majority of the :mod:optparse interface was imported as a transitional aid, maintaining backwards compatibility was never a goal.

A partial upgrade path from :mod:`optparse` to :mod:`argparse`:

* Replace all :meth:`optparse.OptionParser.add_option` calls with
Expand Down
14 changes: 9 additions & 5 deletions Doc/howto/argparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ recommended command-line parsing module in the Python standard library.

.. note::

There are two other modules that fulfill the same task, namely
:mod:`getopt` (an equivalent for ``getopt()`` from the C
language) and the deprecated :mod:`optparse`.
Note also that :mod:`argparse` is based on :mod:`optparse`,
and therefore very similar in terms of usage.
The standard library includes two other libraries directly related
to command-line parameter processing: the lower level :mod:`optparse`
module (which may require more code to configure for a given application,
but also allows an application to request behaviors that ``argparse``
doesn't support), and the very low level :mod:`getopt` (which specifically
serves as an equivalent to :c:func:`!getopt` from the C language).
Copy link

@mwichmann mwichmann Nov 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python getopt provides behavior that combines the classic getopt and the GNU getopt_long, so the reference (I realize it was there in the original) is incomplete. And to be a little nitpicky, the ISO C standard says nothing about getopt (POSIX does, but only the single-char getopt) so From C could be mildly confusing. Maybe something like: (which specifically serves as an equivalent to the getopt family of functions familiar to C language programmers)?

While neither of those modules is covered directly in this guide, many of
the core concepts in ``argparse`` first originated in ``optparse``, so
some aspects of this tutorial will also be relevant to ``optparse`` users.


Concepts
Expand Down
5 changes: 0 additions & 5 deletions Doc/library/allos.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,9 @@ but they are available on most other systems as well. Here's an overview:
os.rst
io.rst
time.rst
argparse.rst
logging.rst
logging.config.rst
logging.handlers.rst
getpass.rst
curses.rst
curses.ascii.rst
curses.panel.rst
platform.rst
errno.rst
ctypes.rst
14 changes: 14 additions & 0 deletions Doc/library/argparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@

**Source code:** :source:`Lib/argparse.py`

.. note::

While :mod:`argparse` is the recommended standard library module for
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not recommend it for now. You can use it on your own risk. optparse may need more work, but it works as expected. I would recommend it for beginners, which cannot distinguish their own errors from peculiarities of the library.

Copy link
Contributor Author

@ncoghlan ncoghlan Oct 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this PR, I'd like to stick with the status quo as far as recommendations go (that is, only taking the step back from "argparse is the only non-deprecated argument processing option in the standard library").

Taking the extra step to saying "argparse is not recommended over optparse anymore, even for end user applications" would then be a separate follow up question.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Keep the argparse recommendation. We're not going to dis-recommend the most widely used Python argument parsing library in the world (that causes churn and angst from users). Nor are we going to be adding yet another one to the stdlib in the future. argparse supports most users quite well, "warts" and all, with plenty of popular third party options for yet other behaviors beyond our stdlib options.

*implementing* basic command line applications, authors of third party
command line argument processing libraries may find that the
lower level :mod:`optparse` module serves as a better foundation for
that use case. ``optparse`` (or one of the third party libraries
based on it) may also be worth considering for applications where
``argparse`` doesn't support behaviors that the application requires
(such as entirely disabling support for interspersed options and
positional arguments, or stricter adherence to common Unix and Linux
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd editorialize a little less and elide "stricter" & "common Unix and Linux" and simplify this to "adherence to command line interface concentions related to the handling of values that start with -"

command line interface conventions related to the handling of option
parameter values that start with ``-``).

--------------

.. sidebar:: Tutorial
Expand Down
21 changes: 21 additions & 0 deletions Doc/library/cmdlinelibs.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.. _cmdlinelibs:

********************************
Command Line Interface Libraries
********************************

The modules described in this chapter assist with implementing
command line and terminal interfaces for applications.

Here's an overview:

.. toctree::
:maxdepth: 1

argparse.rst
optparse.rst
Comment on lines +15 to +16
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would place optparse above argparse.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If anything, this list sure be in purely alphabetical order. passive aggressive opinions via list ordering aren't helpful. 😄

getpass.rst
fileinput.rst
curses.rst
curses.ascii.rst
curses.panel.rst
1 change: 0 additions & 1 deletion Doc/library/filesys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ in this chapter is:

pathlib.rst
os.path.rst
fileinput.rst
stat.rst
filecmp.rst
tempfile.rst
Expand Down
82 changes: 61 additions & 21 deletions Doc/library/getopt.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,13 @@

**Source code:** :source:`Lib/getopt.py`

.. deprecated:: 3.13
The :mod:`getopt` module is :term:`soft deprecated` and will not be
developed further; development will continue with the :mod:`argparse`
module.

.. note::
gpshead marked this conversation as resolved.
Show resolved Hide resolved

The :mod:`getopt` module is a parser for command line options whose API is
designed to be familiar to users of the C :c:func:`!getopt` function. Users who
are unfamiliar with the C :c:func:`!getopt` function or who would like to write
less code and get better help and error messages should consider using the
:mod:`argparse` module instead.
This module is considered feature complete. A more object-oriented and
extensible alternative to this API is provided in the :mod:`optparse`
module. Further functional enhancements for command line parameter
processing are provided either as third party modules on PyPI,
or else as features in the :mod:`argparse` module.

--------------

Expand All @@ -28,6 +23,12 @@
options similar to those supported by GNU software may be used as well via an
optional third argument.

Users who are unfamiliar with the Unix :c:func:`!getopt` function should consider
using the :mod:`argparse` module instead. Users who are familiar with the Unix
:c:func:`!getopt` function, but would like to get equivalent behavior while
writing less code and getting better help and error messages should consider
using the :mod:`optparse` module.

This module provides two functions and an
exception:

Expand Down Expand Up @@ -144,26 +145,65 @@
output = a
else:
assert False, "unhandled option"
# ...
process(args, output=output, verbose=verbose)

if __name__ == "__main__":
main()

Note that an equivalent command line interface could be produced with less code
and more informative help and error messages by using the :mod:`argparse` module::
and more informative help and error messages by using the :mod:`optparse` module::

import argparse
import optparse

if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output')
parser.add_argument('-v', dest='verbose', action='store_true')
args = parser.parse_args()
# ... do something with args.output ...
# ... do something with args.verbose ..
parser = optparse.OptionParser()
parser.add_option('-o', '--output')
parser.add_option('-v', dest='verbose', action='store_true')
opts, args = parser.parse_args()
process(args, output=opts.output, verbose=opts.verbose)

A roughly equivalent command line interface for this case can also be
produced by using the :mod:`argparse` module::

import argparse

Check warning on line 168 in Doc/library/getopt.rst

View workflow job for this annotation

GitHub Actions / Docs / Docs

Literal block expected; none found. [docutils]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong indentation. Also, add .. testcode::.


if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output')
parser.add_argument('-v', dest='verbose', action='store_true')
parser.add_argument('rest', nargs='*')
args = parser.parse_args()
process(args.rest, output=args.output, verbose=args.verbose)

However, unlike the ``optparse`` example, this ``argparse`` example will
handle some parameter combinations differently from the way the ``getopt``
version would handle them. For example (amongst other differences):

* supplying ``-o -v`` gives ``output="-v"`` and ``verbose=False``
for both ``getopt`` and ``optparse``,
but a usage error with ``argparse``
(complaining that no value has been supplied for ``-o/--output``,
since ``-v`` is interpreted as meaning the verbosity flag)
* similarly, supplying ``-o --`` gives ``output="--"`` and ``args=()``
for both ``getopt`` and ``optparse``,
but a usage error with ``argparse``
(also complaining that no value has been supplied for ``-o/--output``,
since ``--`` is interpreted as terminating the option processing
and treating all remaining values as positional arguments)
* supplying ``-o=foo`` gives ``output="=foo"``
for both ``getopt`` and ``optparse``,
but gives ``output="foo"`` with ``argparse``
(since ``=`` is special cased as an alternative separator for
option parameter values)

Whether these differing behaviors in the ``argparse`` version are
considered desirable or a problem will depend on the specific command line
application use case.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@serhiy-storchaka ^^^ is the main reason I don't think we should walk back the default argparse recommendation. Many (probably even most) Python devs would consider argparse to be in the right for these 3 examples, and getopt/optparse the ones doing something dubious (even if what they're doing is the common Unix convention).

The discrepancies are valid reasons for reverting the soft deprecation (optparse can genuinely be used to define command line behaviours that argparse doesn't support), but it will take less arguable examples than these ones to make the case that optparse should be preferred over argparse in general.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to write about these peculiarities in the argparse module documentation. The getopt module documentation is not the place where users will search information about the argparse module.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed. I like that we're giving a list of differences in behavior, but I think it makes more sense to put this in a common section :ref:'d from all three of our command line parsing module docs. I don't expect anyone reading argparse (most likely) or optparse (likely) docs to find this in the getopt docs (presumed least likely to be read).


.. seealso::

Module :mod:`argparse`
Alternative command line option and argument parsing library.
Module :mod:`optparse`
More object-oriented command line option parsing.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the salient feature of optparse over getopt is that it’s more convenient and automated! «more OO» is not a selling point


Module :mod:`argparse`
More opinionated command line option and argument parsing library.
1 change: 1 addition & 0 deletions Doc/library/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ the `Python Package Index <https://pypi.org>`_.
fileformats.rst
crypto.rst
allos.rst
cmdlinelibs.rst
concurrency.rst
ipc.rst
netdata.rst
Expand Down
51 changes: 43 additions & 8 deletions Doc/library/optparse.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,53 @@

**Source code:** :source:`Lib/optparse.py`

.. deprecated:: 3.2
The :mod:`optparse` module is :term:`soft deprecated` and will not be
developed further; development will continue with the :mod:`argparse`
module.
.. note::

This module is considered feature complete. Further functional enhancements for
command line parameter processing are provided either as third party modules on
PyPI, or else as features in the :mod:`argparse` module.

.. note::

The higher level :mod:`argparse` (rather than this module) is the recommended
standard library module for implementing command line applications unless one
of the following caveats applies:

* the application requires additional control over the way options and
positional parameters are interleaved on the command line (including
the ability to disable the interleaving feature completely)
* the application requires additional control over the incremental parsing
of command line elements (while ``argparse`` does support this, the
exact way it works in practice is undesirable for some use cases)
* the application requires additional control over the handling of options
which accept parameter values that may start with ``-`` (such as delegated
options to be passed to invoked subprocesses)
* the application requires some other command line parameter processing
behavior which ``argparse`` does not support, but which can be implemented
in terms of the lower level interface offered by ``optparse``

These ``argparse`` caveats also mean that :mod:`optparse` is likely to
provide a better foundation for library authors *writing* third party
command line argument processing libraries.

.. seealso::

:pypi:`click` is a third party argument processing library (originally
based on ``optparse``), which allows command line applications to be
developed as a set of decorated command implementation functions.

Other third party libraries, such as :pypi:`typer` or :pypi:`msgspec-click`,
allow command line interfaces to be specified in ways that effectively
integrate with static checking of Python type annotations.

--------------

:mod:`optparse` is a more convenient, flexible, and powerful library for parsing
command-line options than the old :mod:`getopt` module. :mod:`optparse` uses a
more declarative style of command-line parsing: you create an instance of
:class:`OptionParser`, populate it with options, and parse the command
line. :mod:`optparse` allows users to specify options in the conventional
command-line options than the minimalist :mod:`getopt` module.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replacing old with minimalist is the only actual wording change here (the rest is just reflowing text)

:mod:`optparse` uses a more declarative style of command-line parsing:
you create an instance of :class:`OptionParser`,
populate it with options, and parse the command line.
:mod:`optparse` allows users to specify options in the conventional
GNU/POSIX syntax, and additionally generates usage and help messages for you.

Here's an example of using :mod:`optparse` in a simple script::
Expand Down
17 changes: 14 additions & 3 deletions Doc/library/superseded.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@
Superseded Modules
******************

The modules described in this chapter are deprecated or :term:`soft deprecated` and only kept for
backwards compatibility. They have been superseded by other modules.
The modules described in this chapter have been superseded by other modules
for most use cases, and are retained primarily to preserve backwards compatibility.

Modules may appear in this chapter because they only cover a limited subset of
a problem space, and a more generally applicable solution is available elsewhere
in the standard library (for example, :mod:`getopt` covers the very specific
task of "mimic the C :c:func:`!getopt` API in Python", rather than the broader
command line option parsing and argument parsing capabilities offered by
:mod:`optparse` and :mod:`argparse`).

Alternatively, modules may appear in this chapter because they are deprecated
outright, and awaiting removal in a future release, or they are
:term:`soft deprecated` and their use is actively discouraged in new projects.
With the removal of various obsolete modules through :pep:`594`, there are
currently no modules in this latter category.

.. toctree::
:maxdepth: 1

getopt.rst
optparse.rst
24 changes: 16 additions & 8 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1648,6 +1648,22 @@ opcode
(Contributed by Irit Katriel in :gh:`105481`.)


optparse
--------

* This module is no longer considered :term:`soft deprecated`.
While :mod:`argparse` remains preferred for new projects that
aren't using a third party command line argument processing
library, there are aspects of the way ``argparse`` works that
mean the lower level ``optparse`` module may provide a better
foundation for *writing* argument processing libraries, and
for implementing command line applications which adhere more
strictly than ``argparse`` does to various Unix command line
processing conventions that originate in the behaviour of the
C :c:func:`!getopt` function .
(Contributed by Alyssa Coghlan and Serhiy Storchaka in :gh:`126180`.)


pathlib
-------

Expand Down Expand Up @@ -1787,14 +1803,6 @@ New Deprecations
Check membership in :data:`~dis.hasarg` instead.
(Contributed by Irit Katriel in :gh:`109319`.)

* :mod:`getopt` and :mod:`optparse`:

* Both modules are now :term:`soft deprecated`,
with :mod:`argparse` preferred for new projects.
This is a new soft-deprecation for the :mod:`!getopt` module,
whereas the :mod:`!optparse` module was already *de facto* soft deprecated.
(Contributed by Victor Stinner in :gh:`106535`.)

* :mod:`gettext`:

* Deprecate non-integer numbers as arguments to functions and methods
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
:mod:`getopt` and :mod:`optparse` are no longer marked as deprecated.
There are legitimate reasons to use one of these modules in preference to
:mod:`argparse`, and none of these modules are at risk of being removed
from the standard library. Of the three, ``argparse`` remains the
recommended default choice, *unless* one of the concerns noted at the top of
the ``optparse`` module documentation applies.
Loading