Skip to content

gh-133653: Fix subclassing HelpFormatter #133668

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

Closed
wants to merge 3 commits into from

Conversation

hugovk
Copy link
Member

@hugovk hugovk commented May 8, 2025

The problem was with this code:

        if isinstance(self.formatter_class, type) and issubclass(
            self.formatter_class, HelpFormatter
        ):
            return self.formatter_class(
                prog=self.prog,
                prefix_chars=self.prefix_chars,
                color=self.color,
            )
        else:
            return self.formatter_class(prog=self.prog)

We want to set the extra arguments for HelpFormatter and argparse's own subclasses, which don't have their own __init__s.

But many third-party subclasses do have an __init__ and don't pass on kwargs. So we can't just check for a subclass of HelpFormatter, so let's try/except instead.

Lib/argparse.py Outdated
return self.formatter_class(
prog=self.prog,
prefix_chars=self.prefix_chars,
color=self.color,
)
else:
except TypeError:
Copy link
Member

Choose a reason for hiding this comment

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

TypeError seems a bit generic (you're calling user code).

What do you think about this?

len([v.kind for (k, v) in inspect.signature(self.formatter_class).parameters.items() if k in ('y', 'z') and v.kind in (inspect._ParameterKind.POSITIONAL_OR_KEYWORD, inspect._ParameterKind.KEYWORD_ONLY)]) == 2

Copy link
Member Author

Choose a reason for hiding this comment

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

That doesn't work: FAILED (failures=2, errors=156)

Copy link
Member Author

Choose a reason for hiding this comment

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

Wait, it does, obviously need to replace y and z :)

Copy link
Member

@serhiy-storchaka serhiy-storchaka left a comment

Choose a reason for hiding this comment

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

I would not like to use inspect.signature() here. It is not reliable. If it fails (or return incorrect result), you cannot do anything with this. It can only be used in interactive introspection, when errors can be ignored.

@hugovk
Copy link
Member Author

hugovk commented May 8, 2025

Would you prefer the try/except or another approach?

@serhiy-storchaka
Copy link
Member

No, I think the user code should be changed. They use undocumented feature.

@iritkatriel
Copy link
Member

We can do my original suggestion - make __init__ accept **kwargs and extract the new args with this.

Already two external libraries were broken by this in the first alpha testing. Leaving this as it is will break user code for sure.

@serhiy-storchaka
Copy link
Member

This would not help. The problem is that the user code does not accept any arguments besides prog. And they do this because they use undocumented feature.

@iritkatriel
Copy link
Member

What's the concern with inspect? That it won't work for some weird function? In that case we can just use the default values for these arguments.

@iritkatriel
Copy link
Member

Another option is to set these fields through a setter method and not via __init__.

@serhiy-storchaka
Copy link
Member

See alternative PR #133813.

@hugovk hugovk closed this May 10, 2025
@hugovk hugovk deleted the 3.14-fix-subclassing-helpformatter branch May 13, 2025 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants