Skip to content

gh-122353: Handle ValueError during imports #122389

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

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

Conversation

picnixz
Copy link
Member

@picnixz picnixz commented Jul 29, 2024

This is a simple fix but I am not an expert enough concerning the import system. The idea is to also catch the ValueError that could be raised by any function using the path_t AC converter (or by any other handler that is explicitly raising it).

@picnixz picnixz requested a review from serhiy-storchaka July 31, 2024 10:51
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.

Thank you. I have only two more comments.

Copy link
Member

@zooba zooba left a comment

Choose a reason for hiding this comment

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

The patch is good overall, but I want to be more fully convinced that (a) users shouldn't be told when they provide bad values, or (b) we shouldn't be raising OSError from the path converter instead. Discussion on #122353 please.

Comment on lines 424 to 425
If the *path* cannot be handled, this raises an :exc:`OSError`
or a :exc:`ValueError` depending on the reason.
Copy link
Member

Choose a reason for hiding this comment

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

We deliberately don't document ValueError in most cases because it's assumed to be a possibility whenever you pass in an invalid value. If we start documenting it, we'll end up having to put it on every single function.

I'd rather skip all these doc changes and keep with our usual conventions. It may be surprising at first, but the error does only occur when an invalid value is provided, and not due to OS/environment issues (which are the cause of the OSError, and we document functions that may do something that could result in an OSError because most do not).

Copy link
Member

Choose a reason for hiding this comment

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

Since OSError is already explicitly documented here, I do not see harm in mentioning also ValueError which depends on OS and environment. For example, UnicodeEncodeError (which is a subclass of ValueError) can be raised depending on the locale.

This is also important for end user to know which exceptions they should catch. OSError and ValueError are not raised in normal cases, but they can be raised depending on user data, OS and environment. It is easy to miss ValueError.

Such exceptions like TypeError, MemoryError, RecursionError should not be explicitly documented.

Copy link
Member

Choose a reason for hiding this comment

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

It depends on the OS, but not on the state of the OS (what I meant by "environment", as opposed to "environment variables" which are only one aspect of the overall state).

ValueError can be raised practically anywhere. If you aren't sure you're passing a valid value, you always need to handle ValueError. It's in the same category as TypeError, MemoryError and RecursionError (and AttributeError when calling a function, as this is essentially the same as TypeError).

Copy link
Contributor

Choose a reason for hiding this comment

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

Another phrasing issue here is the switch from the imperative "is to be raised" to the descriptive "this raises". It's an abstract method definition giving instructions to subclass authors, so the "is to be raised" phrasing should be kept.

Due to that, I do think it's reasonable to mention ValueError explicitly here, specifically so subclass method implementors don't feel obliged to catch it and turn it into OSError.

@bedevere-app
Copy link

bedevere-app bot commented Aug 6, 2024

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

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.

LGTM.

Comment on lines 424 to 425
If the *path* cannot be handled, this raises an :exc:`OSError`
or a :exc:`ValueError` depending on the reason.
Copy link
Member

Choose a reason for hiding this comment

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

Since OSError is already explicitly documented here, I do not see harm in mentioning also ValueError which depends on OS and environment. For example, UnicodeEncodeError (which is a subclass of ValueError) can be raised depending on the locale.

This is also important for end user to know which exceptions they should catch. OSError and ValueError are not raised in normal cases, but they can be raised depending on user data, OS and environment. It is easy to miss ValueError.

Such exceptions like TypeError, MemoryError, RecursionError should not be explicitly documented.

Copy link
Contributor

@ncoghlan ncoghlan left a comment

Choose a reason for hiding this comment

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

The test case update looks good to me, but several requests and suggestions inline for the details of the docs and implementation changes.

Comment on lines 424 to 425
If the *path* cannot be handled, this raises an :exc:`OSError`
or a :exc:`ValueError` depending on the reason.
Copy link
Contributor

Choose a reason for hiding this comment

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

Another phrasing issue here is the switch from the imperative "is to be raised" to the descriptive "this raises". It's an abstract method definition giving instructions to subclass authors, so the "is to be raised" phrasing should be kept.

Due to that, I do think it's reasonable to mention ValueError explicitly here, specifically so subclass method implementors don't feel obliged to catch it and turn it into OSError.

Comment on lines +558 to +559
If the *path* cannot be handled, this raises an :exc:`OSError`
or a :exc:`ValueError` depending on the reason.
Copy link
Contributor

Choose a reason for hiding this comment

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

Exceptions are covered in ResourceLoader abstract method documentation above.

Suggested change
If the *path* cannot be handled, this raises an :exc:`OSError`
or a :exc:`ValueError` depending on the reason.

Copy link
Member Author

Choose a reason for hiding this comment

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

Actually, I duplicated the entry because the ABC marked as deprecated since 3.7. As such, I'm not sure whether the ABC should update its documentation or not...

Comment on lines 619 to 620
When writing to the path fails by raising an :class:`OSError`
or a :class:`ValueError`, the exception is not propagated.
Copy link
Contributor

@ncoghlan ncoghlan Aug 9, 2024

Choose a reason for hiding this comment

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

This change is not correct, only a lack of write permissions should be silently ignored, everything else should be propagated (despite importlib itself being overly broad in the errors it suppresses).

Suggested change
When writing to the path fails by raising an :class:`OSError`
or a :class:`ValueError`, the exception is not propagated.
When writing to the path fails because the path is read-only
(:const:`errno.EACCES`/:exc:`PermissionError`), do not propagate the
exception. Other exceptions should still be propagated.

Copy link
Member Author

@picnixz picnixz Aug 12, 2024

Choose a reason for hiding this comment

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

Since the tests are failing, should we also protect against FileExistsError when writing the data? By suppressing OSError altogether, we actually suppressed FileExistsError in free-threaded builds and read-only errors (those with errno 30 but that are not explicitly PermissionError).

It seems that the FileExistsError only happens in free-threaded builds of Mac OS but I'm not sure whether it's related or not...

except OSError as exc:
# Could be a permission error, read-only filesystem: just forget
# about writing the data.
except (OSError, ValueError) as exc:
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be made narrower rather than broader (i.e. only ignoring PermissionError)

_bootstrap._verbose_message('could not create {!r}: {!r}',
parent, exc)
return
try:
_write_atomic(path, data, _mode)
_bootstrap._verbose_message('created {!r}', path)
except OSError as exc:
except (OSError, ValueError) as exc:
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto on the narrower catch.

@bedevere-app
Copy link

bedevere-app bot commented Aug 9, 2024

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@picnixz
Copy link
Member Author

picnixz commented Aug 12, 2024

There is a pending doc question I have but otherwise it should be good for a second round of reviews (btw, thank you all for your time). I have made the requested changes; please review again.

@bedevere-app
Copy link

bedevere-app bot commented Aug 12, 2024

Thanks for making the requested changes!

@serhiy-storchaka, @zooba, @ncoghlan: please review the changes made to this pull request.

@picnixz
Copy link
Member Author

picnixz commented Nov 7, 2024

@ncoghlan Could you have a look at the modified text and the question I had please (#122389 (comment))? Thank you! @zooba Could you confirm whether the latest changes are fine? Thank you!

@picnixz picnixz added the stale Stale PR or inactive for long period of time. label Mar 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting change review stale Stale PR or inactive for long period of time.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants