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-127805: Clarify Formatter initialization in logging.rst #127850

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Uvi-12
Copy link

@Uvi-12 Uvi-12 commented Dec 12, 2024

Clarified that the fmt argument in Handler.setFormatter must be an initialized Formatter instance in the logging.rst documentation.

Issue:
Resolves #127805


📚 Documentation preview 📚: https://cpython-previews--127850.org.readthedocs.build/en/127850/library/logging.html#logging.Handler.setFormatter

@Uvi-12 Uvi-12 requested a review from vsajip as a code owner December 12, 2024 04:34
Copy link

cpython-cla-bot bot commented Dec 12, 2024

All commit authors signed the Contributor License Agreement.
CLA signed

@ZeroIntensity ZeroIntensity added needs backport to 3.12 bug and security fixes needs backport to 3.13 bugs and security fixes labels Dec 12, 2024
@Uvi-12 Uvi-12 requested a review from ZeroIntensity December 12, 2024 14:18
Copy link
Member

@ZeroIntensity ZeroIntensity left a comment

Choose a reason for hiding this comment

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

Thanks! LGTM.

cc @picnixz for a second look.

Doc/library/logging.rst Outdated Show resolved Hide resolved
@Uvi-12 Uvi-12 requested a review from picnixz December 13, 2024 18:04
@Uvi-12
Copy link
Author

Uvi-12 commented Dec 13, 2024

Thank you @picnixz @ZeroIntensity for reviewing PR! If everything looks good, please proceed with merging it.

@ZeroIntensity
Copy link
Member

Neither of us have merge permissions, we're triagers (though Bénédikt might soon)! You'll have to wait for a core dev to get to this.

@Uvi-12
Copy link
Author

Uvi-12 commented Dec 13, 2024

Neither of us have merge permissions, we're triagers (though Bénédikt might soon)! You'll have to wait for a core dev to get to this.

Thank you for clarifying, @ZeroIntensity! I apologize for the oversight, as I’m still new to Python and the contribution process.

@vsajip
Copy link
Member

vsajip commented Dec 14, 2024

The wording of the change might imply that the instance has to be one of the Formatter class only, and not a subclass. In fact I wonder that the person who raised the issue thought that it was being suggested that you pass a class to a handler in setFormatter - passing a class to an API is a rather less common case than passing an instance, generally, in Python, right?

@picnixz
Copy link
Member

picnixz commented Dec 14, 2024

Well... even if it's an instance of a subclass, isinstance(formatter, Formatter) would still work right? So I think the formulation is fine. But maybe I'm biased?

@Uvi-12
Copy link
Author

Uvi-12 commented Dec 15, 2024

Thank you, @vsajip and @picnixz, for the feedback!

@jlynchMicron, who created the issue, reviewed the PR and confirmed that the changes are correct in their comment.

The current wording is meant to make it clear that the formatter argument must be an initialized instance of Formatter or a subclass. I agree that it might sound like only Formatter is allowed, which could be confusing.

Would it help if I updated the wording to say something like "an initialized instance of Formatter or one of its subclasses"? Let me know, and I can make the changes to avoid any misunderstanding.

@vsajip
Copy link
Member

vsajip commented Dec 15, 2024

Well... even if it's an instance of a subclass, isinstance(formatter, Formatter) would still work right?

Yes, but we're talking about just a documentation change. For example, I think the existing text (mentioning Formatter) is already reasonably understandable to mean a Formatter instance rather than the Formatter class, but if this is likely to be a point of confusion for some people, we might as well spell it out in a bit more detail, as suggested ...

Would it help if I updated the wording to say something like "an initialized instance of Formatter or one of its subclasses"?

Yes, I think it would.

@picnixz
Copy link
Member

picnixz commented Dec 15, 2024

Ok, I see your point. To be consistent, should we also update the setFilter docs just below?

@vsajip
Copy link
Member

vsajip commented Dec 15, 2024

should we also update the setFilter docs just below?

I guess we could. But let's think about this - do we really want to go through the documentation checking for all instances of where a class is mentioned, meaning that an instance is required, and updating all cases in case they might be misunderstood?

The usual way to interpret when you say "pass in a Formatter" is to infer that an instance is to be passed, and and not the Formatter class itself - so I don't actually believe the issue is valid and this PR is needed, but I don't want to appear inflexible if it's just a tiny change to the documentation.

But then someone might say "it's not really clear that Logger.addHandler takes an instance of a handler, I thought it meant a handler class" and there you go again. I'd like to avoid that - for example, this API has been pretty much the same for twenty years, and in all that time, nobody else has seemingly gotten confused into thinking that a class is to be passed rather than an instance - at least, not enough to raise an issue about it.

Sometimes the problem is the documentation, but sometimes it's reader comprehension (bearing in mind different people have different mother tongues, different levels of experience as developers, etc). Whatever the documentation says, there will be some readers who can misinterpret it - IMO one can only go so far in accommodating all such cases.

@Uvi-12
Copy link
Author

Uvi-12 commented Dec 15, 2024

Sometimes the problem is the documentation, but sometimes it's reader comprehension (bearing in mind different people have different mother tongues, different levels of experience as developers, etc). Whatever the documentation says, there will be some readers who can misinterpret it - IMO one can only go so far in accommodating all such cases.

Yes, I agree with the points you raised. I think it's important to keep things clear from our side, but also acknowledge that there's a limit to how much we can accommodate every potential misinterpretation. That said, if you have any suggestions for additional documentation or clarifications that could make the intent absolutely clear, we can certainly consider them. Otherwise, we can close the issue if we believe it's a matter of reader comprehension.

@Uvi-12
Copy link
Author

Uvi-12 commented Dec 15, 2024

But then someone might say "it's not really clear that Logger.addHandler takes an instance of a handler, I thought it meant a handler class" and there you go again. I'd like to avoid that - for example, this API has been pretty much the same for twenty years, and in all that time, nobody else has seemingly gotten confused into thinking that a class is to be passed rather than an instance - at least, not enough to raise an issue about it.

While I agree with the point that the usual interpretation of "pass in a Formatter" implies an instance rather than the class itself, the fact that this issue was raised indicates some level of confusion among readers, which suggests that clarifying it in the documentation could be helpful. However, we don't need to go through every API documentation and update it proactively; if users face issues, they can raise them, and we can address them like this issue.

@vsajip Could you please let me know your thoughts on this or what steps you'd recommend to take next?

@jlynchMicron
Copy link

jlynchMicron commented Dec 16, 2024

Just to chime in here as the person that originally raised the issue; maybe it's just me, but I have written a lot of funky python code that has functions that takes in uninitialized classes as function arguments. I think this sort of thing happens more in the data conditioning and database ORM space where dataclasses are used as formats/templates for data conditioning (which is kinda what a Formatter class does).

So that being said, I could be in the minority when reading documentation that says pass in a class and not immediately think to instantiate that class first. The error generated from using the format function of an un-instantiated Formatter is sort of non-intuitive until you realize that the "record" argument is being passed in as "self".

This issue was an attempt to possibly address that confusion for others.

@Uvi-12
Copy link
Author

Uvi-12 commented Dec 17, 2024

@jlynchMicron @vsajip Taking everyone’s feedback into account, I understand that the API has been stable for years and that the usual interpretation of “pass in a Formatter” inherently implies an instance rather than the class itself. However, given that the issue was raised—alongside @jlynchMicron’s experience—it does suggest that there might be room for confusion for some readers. The proposed wording update to "an initialized instance of Formatter or one of its subclasses" aims to clarify the intent without adding unnecessary verbosity.

That said, I’d like to confirm: would you recommend proceeding with this wording change for clarity, extending it to setFilter for consistency as suggested by @picnixz, or do you think the issue and PR could be closed altogether, considering your points on reader comprehension and the longstanding clarity of the API? I’ll proceed based on your final recommendation.

@picnixz
Copy link
Member

picnixz commented Dec 17, 2024

The confusion might arise from the fact that we refer to "Formatter" which leads to the Formatter class by saying "Sets the Formatter [...]". How about rephrasing it as

Sets the formatter object for this handler to *fmt*. The *fmt* argument
must be a :class:`Formatter` instance or ``None``.

I feel that mentioning subclasses or "initialized" would be overly verbose. While I see the distinction with "initialized" (through __init__) and newly created (with __new__ only), I don't think we expect a non-initialized object in general.

Concerning setFilter, maybe consistency is not needed. The reason is that we may have multiple filters and a None filter is not expected. However, a None formatter is allowed. So it should be mentioned (currently it's not even mentioned). So the
consistency question is (on my side) dropped.

An alternative to changing the wording is to refer to some examples, without changing the current wording. From there, it would become clearer what we expect right?

@Uvi-12
Copy link
Author

Uvi-12 commented Dec 20, 2024

The confusion might arise from the fact that we refer to "Formatter" which leads to the Formatter class by saying "Sets the Formatter [...]". How about rephrasing it as

Sets the formatter object for this handler to *fmt*. The *fmt* argument
must be a :class:`Formatter` instance or ``None``.

Concerning setFilter, maybe consistency is not needed. The reason is that we may have multiple filters and a None filter is not expected. However, a None formatter is allowed. So it should be mentioned (currently it's not even mentioned). So the consistency question is (on my side) dropped.

I too think of it as the correct approach. Shall I update the PR with this change?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting core review docs Documentation in the Doc dir needs backport to 3.12 bug and security fixes needs backport to 3.13 bugs and security fixes skip news
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.

Logger formatter class initialization state clarification
5 participants