You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ArgumentParser.add_subparsers() returns a _SubParsersAction. This requires user code using type annotations to use a protected type which causes type checkers like PyCharm to complain. For example:
Turning a class public or not requires a lot more discussion by the argparse maintainers (I'm definitely not one of them). Have you considered this workaround for PyCharm?
from argparse import (
_SubParsersAction, # noqa
ArgumentParser,
)
Yes - that was the first thing I tried and why I logged the bug. I will log a bug with Pycharm but it still seems like the long term solution is to make _SubParsersAction public since it is used like a public object. I thought that logging the bug here would be the start of the discussion by the argparse maintainers. Where can I get their attention?
I've nosied Raymond on this bug, he should be receiving our messages.
paulj3 commented on Oct 25, 2021
paulj3mannequin
Mannequin
More actions
add_argument also returns a Action subclass object. All of those subclasses are "private". While that return reference is usually ignored, sometimes it is useful to it, assigning it to a variable or list. The documentation could be clearer about access to Action objects.
sourcedelica commented on Oct 25, 2021
sourcedelicamannequin
MannequinAuthor
More actions
But is _SubParsersAction really private if there are methods on it that are required to use (add_parser())?
paulj3 commented on Oct 25, 2021
paulj3mannequin
Mannequin
More actions
A _SubParsersAction is private to the extent that users should not attempt to create it directly, and thus don't need to know the details - beyond what's documented:
"The add_subparsers() method is normally called with no arguments and returns a special action object. This object has a single method, add_parser(), which takes a command name and any ArgumentParser constructor arguments, and returns an ArgumentParser object that can be modified as usual."
All action objects have methods like __call__ and format_usage. The subparsers Action has other methods, but add_parser is the only new "public" method.
There's a tension in writing documentation between getting all details just right, and providing just enough for most users. As it is, many new users are over whelmed by the documentation.
My understanding is that the "private/public" designation is a convenience for users, and not enforced by Python developers.
I gather though that some corporate users have policies that prohibit modification of "private" objects, supposedly due to a fear that Python could modify or eliminate those objects without proper notification. Somehow the "public" documentation sets that part of the code in stone. My experience here is that it's easier modify the documentation to fit the code than the other way around :)
I'd love to resurface this issue or, at least, voice my disappointment with the resolution. The _SubParsersAction simply has to be a public class if we are expected to handle instances of it and be able to pass them around. The documentation is meant to document the public API but the code is still in charge of what that public API is, and the fact that there is a class with an add_parser() method that we should call means it's public.
If the developers don't want us to initialize it, then an abstract class or protocol should be defined and made public so we can import it and use it as a type hint without having access to the concrete class for us to instantiate.
This is not in any way related to pycharm.
Additionally, the __all__ variable in arparse.py doesn't even expose _SubParsersAction so there are now two things telling us that we should never import this class. The fact that it's not exposed by __all__, and the fact that the class name starts with an underscore. The fact that the documentation is promising to keep things stable does not negate the fact that the code is warning us, in two different ways, that what we are doing is very much not stable. It's not acceptable to think that when we run into private values in the code, we should go make sure things are actually private in the documentation.
Here's an example of what could be exposed by the library (ignoring any versioning differences):
@paulj3, @Fidget-Spinner: I would really like you to revisit this issue since it causes a large amount of confusion on large projects and teams where this constantly pops up as unstable tech debt because we import private classes and have to explain to folks that the library maintainers are telling us to just not worry about this one case.
@ms-lolo reading again, I see what you mean. Thank you for explaining further. I will reopen the issue. This is the most I can do, as I do not maintain the argparse module and I am not comfortable changing anything in there.
oh no, this was a great answer thank you @Fidget-Spinner! do you have any idea how we might be able to find someone that could help work on this? otherwise just having this issue open will already provide some benefits for us in internal conversations.
@Fidget-Spinner, had a chat with @gvanrossum and it sounds like we have a philosophical disagreement. This is unlikely to be changed so I think you can go ahead and close the issue after all.
For folks running into this issue, creating a protocol for the class and using that in your type hints will at least prevent you from needing to import and ignore warnings for protected classes. The one I've created on my side looks like the one I showed in the comments above. Linters will properly allow you to pass in an instance of argparse._SubParsersAction as long as your protocol matches the signature of argparse._SubParsersAction. I'm a PyCharm user and can confirm this works fine.
Activity
sourcedelica commentedon Aug 19, 2020
ArgumentParser.add_subparsers() returns a _SubParsersAction. This requires user code using type annotations to use a protected type which causes type checkers like PyCharm to complain. For example:
You can't use plain Action because Action doesn't have the add_parser() method.
Fidget-Spinner commentedon Oct 22, 2021
Turning a class public or not requires a lot more discussion by the argparse maintainers (I'm definitely not one of them). Have you considered this workaround for PyCharm?
from argparse import (
_SubParsersAction, # noqa
ArgumentParser,
)
Fidget-Spinner commentedon Oct 22, 2021
Closing this because this is a linter problem (inside PyCharm), not a Python problem. In the earlier message I provided a solution for PyCharm.
PS, mypy --strict doesn't complain when I import _SubParsersAction, meaning most type checkers likely won't complain either.
Thanks for your time!
1 remaining item
sourcedelica commentedon Oct 22, 2021
Yes - that was the first thing I tried and why I logged the bug. I will log a bug with Pycharm but it still seems like the long term solution is to make _SubParsersAction public since it is used like a public object. I thought that logging the bug here would be the start of the discussion by the argparse maintainers. Where can I get their attention?
Fidget-Spinner commentedon Oct 22, 2021
I've nosied Raymond on this bug, he should be receiving our messages.
paulj3 commentedon Oct 25, 2021
add_argumentalso returns a Action subclass object. All of those subclasses are "private". While that return reference is usually ignored, sometimes it is useful to it, assigning it to a variable or list. The documentation could be clearer about access to Action objects.sourcedelica commentedon Oct 25, 2021
But is _SubParsersAction really private if there are methods on it that are required to use (add_parser())?
paulj3 commentedon Oct 25, 2021
A _SubParsersAction is private to the extent that users should not attempt to create it directly, and thus don't need to know the details - beyond what's documented:
"The add_subparsers() method is normally called with no arguments and returns a special action object. This object has a single method, add_parser(), which takes a command name and any ArgumentParser constructor arguments, and returns an ArgumentParser object that can be modified as usual."
All action objects have methods like __call__ and format_usage. The subparsers Action has other methods, but add_parser is the only new "public" method.
There's a tension in writing documentation between getting all details just right, and providing just enough for most users. As it is, many new users are over whelmed by the documentation.
My understanding is that the "private/public" designation is a convenience for users, and not enforced by Python developers.
I gather though that some corporate users have policies that prohibit modification of "private" objects, supposedly due to a fear that Python could modify or eliminate those objects without proper notification. Somehow the "public" documentation sets that part of the code in stone. My experience here is that it's easier modify the documentation to fit the code than the other way around :)
ms-lolo commentedon Nov 18, 2022
I'd love to resurface this issue or, at least, voice my disappointment with the resolution. The
_SubParsersActionsimply has to be a public class if we are expected to handle instances of it and be able to pass them around. The documentation is meant to document the public API but the code is still in charge of what that public API is, and the fact that there is a class with anadd_parser()method that we should call means it's public.If the developers don't want us to initialize it, then an abstract class or protocol should be defined and made public so we can import it and use it as a type hint without having access to the concrete class for us to instantiate.
This is not in any way related to pycharm.
Additionally, the
__all__variable inarparse.pydoesn't even expose_SubParsersActionso there are now two things telling us that we should never import this class. The fact that it's not exposed by__all__, and the fact that the class name starts with an underscore. The fact that the documentation is promising to keep things stable does not negate the fact that the code is warning us, in two different ways, that what we are doing is very much not stable. It's not acceptable to think that when we run into private values in the code, we should go make sure things are actually private in the documentation.Here's an example of what could be exposed by the library (ignoring any versioning differences):
@paulj3, @Fidget-Spinner: I would really like you to revisit this issue since it causes a large amount of confusion on large projects and teams where this constantly pops up as unstable tech debt because we import private classes and have to explain to folks that the library maintainers are telling us to just not worry about this one case.
Fidget-Spinner commentedon Nov 19, 2022
@ms-lolo reading again, I see what you mean. Thank you for explaining further. I will reopen the issue. This is the most I can do, as I do not maintain the argparse module and I am not comfortable changing anything in there.
I don't know if argparse even has a maintainer, considering it has no maintainers listed in the experts index https://devguide.python.org/core-developers/experts/index.html.
Fidget-Spinner commentedon Nov 19, 2022
Sorry if this isn't the answer you want, and about me closing this issue too hastily in the first place.
ms-lolo commentedon Nov 21, 2022
oh no, this was a great answer thank you @Fidget-Spinner! do you have any idea how we might be able to find someone that could help work on this? otherwise just having this issue open will already provide some benefits for us in internal conversations.
gvanrossum commentedon Nov 22, 2022
@ms-lolo If you are at MS can you contact me on Teams chat? That might be quicker than going back and forth on the issue.
ms-lolo commentedon Nov 22, 2022
@Fidget-Spinner, had a chat with @gvanrossum and it sounds like we have a philosophical disagreement. This is unlikely to be changed so I think you can go ahead and close the issue after all.
For folks running into this issue, creating a protocol for the class and using that in your type hints will at least prevent you from needing to import and ignore warnings for protected classes. The one I've created on my side looks like the one I showed in the comments above. Linters will properly allow you to pass in an instance of
argparse._SubParsersActionas long as your protocol matches the signature ofargparse._SubParsersAction. I'm a PyCharm user and can confirm this works fine.