Skip to content

argparse - make return type from add_subparsers public #101503

Open

Description

@highvelcty

This issue was brought up and closed as part of issue # 41592.

The add_subparsers method returns a protected _SubParsersAction instance. To add a sub-parser, the public add_parser method of the protected _SubParsersAction instance must be used.

  1. It is unexpected to require the use of a public method of a protected class instance.
  2. The protected return type breaks type hinting because
    1. protected and should not be imported
    2. it is not available for import

Real world use case example:

sub_parsers_action = parser.add_subparsers(...)

def build_subcmd(sub_parsers_action: _SubParsersAction):
    ...

The ask is to make the type of whatever is returned from add_subparsers public.

Linked PRs

Activity

  1. hpaulj commented on Mar 8, 2023

    @hpaulj

    Do you really have to include type hinting when creating a utility function like this?

    I'll admit that I haven't paid much attention to typing, but as it stands there's nothing in argparse that makes any concession to that.

    My arguments (as paulj3) in the earlier issue are still relevant.

  2. highvelcty commented on Mar 14, 2023

    @highvelcty
    Author

    It is not required, but it is a development aide.

    It was a bit difficult for me to understand how sub-command tree branches can be formed with the following construct. However, I was able to figure it out from the good documentation surrounding it. Type hint coherency would help to further communicate this.

    ArgumentParser(...).add_subparsers(...)  -> _SubParsersAction
    _SubParsersAction.add_parser(...) -> ArgumentParser
  3. hpaulj commented on Mar 14, 2023

    @hpaulj

    There are several other functions that return "private" objects

     a = parser.add_argument(...)
    

    a will be some subclass of Action, e.g argparse._StoreAction. This is just a variation on the subparsers case. Normally we don't hang on to reference to this Action object, but it is available for later use. The Action is stored in the parser._actions list. On occasion programs use this list to do specific things with one or more of the Actions.

      g = parser.add_argument_group(....)
    

    return an argparse._ArgumentGroup object. Same for mutually exclusive groups.

    These groups, and the parser itself are subclasses of argparse._ActionsContainer. Most of the class hierarchy behind argparse objects is "hidden", that is, not documented or listed in the argparse.__all__, but they are none the less available to the programmer.

    argparse was created for py2, long before typing and even annotations were around. It's a clean OOP structure, but the documentation is use oriented, Normally ArgumentParser is the only class that's created directly (via class name and its init. Nearly everything else is produced by a factory function or method. Those are what's documented, not the classes.

    Also you can substitute your own classes, or subclasses, in many places. The HelpFormatter, the action parameter of add_argument, even the parser class returned by add_parser, By fiddling with the registry you can change the class returned by add_subparsers. And nearly all of the substitutions use duck typing.

    Many methods use (*args, **kwargs) signatures, So the signature itself tells us, or any 'inspector', little about the parameters. In the case of add_argument, the details about how **kwargs are handled depend on the Action subclass that's being used. There are issues where people complain about add_argument accepting parameters that don't work, or don't even make sense. In some cases the 'errors' are ignored, in others they they are raised at low levels. In general the more you push the boundaries of what's documented, the more important it is to be able read the argparse.py code yourself.

  4. jmracek commented on Mar 29, 2023

    @jmracek

    Do you really have to include type hinting when creating a utility function like this?

    I am forced to do this due to company wide lint rules. I had the exact same use case as @highvelcty. I tried to track down the type returned by add_subparsers() in the public documentation to no success, and further Googling landed me on this issue.

  5. added
    type-featureA feature request or enhancement
    stdlibStandard Library Python modules in the Lib/ directory
    on Mar 30, 2023
  6. Warchant commented on Apr 19, 2023

    @Warchant

    +1 - please make that type public.
    add_subparsers now returns _SubParsersAction[ArgumentParser]

  7. wvenialbo commented on Jun 30, 2023

    @wvenialbo

    I also require this feature to comply with my company's coding lint rules.

  8. wajda commented on Sep 23, 2024

    @wajda

    Do you really have to include type hinting when creating a utility function like this?

    Oh yes, of course I do, and I would encourage every Python developer to use type hints as much as possible!
    We write code primarily for humans, not machines. Think about this way - when you are reading a piece of code does it really matter if it's a piece of a simple 50-line utility function or a complex 50,000-line project - the code is code and you need to be able to easily understand it, change it and maintain it. And from that perspective proper type hints are vital.
    I completely agree with @highvelcty, a public function or a method can only return a public type otherwise it's simply drives the type hints on this part of API useless.
    Please make the _SubParsersAction public or return another public abstraction instead.

  9. hpaulj commented on Sep 23, 2024

    @hpaulj
  10. hpaulj commented on Sep 23, 2024

    @hpaulj
  11. smheidrich commented on Apr 8, 2025

    @smheidrich
    Contributor

    add_argument as well as add_subparsers returns a _Action
    subclass instance. Users shouldn't try to instantiate such classes
    directly. _Action instances need to be properly 'vetted' before they are
    created

    The type hint wouldn't have to be the exact class that is returned, a Protocol containing the publicly documented methods would be perfectly fine.

  12. added 2 commits that reference this issue on Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytopic-typingtype-featureA feature request or enhancement

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions