This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: zoneinfo: ZoneInfo raises IsADirectoryError instead of ZoneInfoNotFoundError
Type: behavior Stage: patch review
Components: Library (Lib) Versions: Python 3.10, Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: josh.ja.butt, p-ganssle, python-dev, vstinner
Priority: normal Keywords: patch

Created on 2020-08-12 11:42 by josh.ja.butt, last changed 2022-04-11 14:59 by admin.

Pull Requests
URL Status Linked Edit
PR 21839 open python-dev, 2020-08-12 11:43
Messages (10)
msg375225 - (view) Author: Joshua (josh.ja.butt) * Date: 2020-08-12 11:42
Attempting to parse specific keys in zoneinfo.ZoneInfo with tzdata installed will raise unhandled exceptions

e.g. on windows

>>> import zoneinfo
>>> zoneinfo.ZoneInfo('Pacific')
PermissionError: [Errno 13] Permission denied: 'C:\\Program Files\\Python39\\lib\\site-packages\\tzdata\\zoneinfo\\Pacific'

>>> import zoneinfo
>>> zoneinfo.ZoneInfo('__init__.py')
ValueError: Invalid TZif file: magic not found

This happens when non TZif files or directories in the tzdata.zoneinfo module are used as keys.
msg375226 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-08-12 11:49
Hi. It seems like you are running Windows.

About the permission error, how did you install tzdata? Did you install it as an admin user and do you run Python as a different user?
msg375228 - (view) Author: Joshua (josh.ja.butt) * Date: 2020-08-12 11:53
tzdata was installed as an admin user, however this behaviour was
reproducible on a linux installation where for the ZoneInfo.('Pacific')
instance an IsADirectoryError would instead be raised.

On Wed, Aug 12, 2020 at 9:50 PM STINNER Victor <report@bugs.python.org>
wrote:

>
> STINNER Victor <vstinner@python.org> added the comment:
>
> Hi. It seems like you are running Windows.
>
> About the permission error, how did you install tzdata? Did you install it
> as an admin user and do you run Python as a different user?
>
> ----------
> nosy: +vstinner
>
> _______________________________________
> Python tracker <report@bugs.python.org>
> <https://bugs.python.org/issue41530>
> _______________________________________
>
msg375233 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-08-12 13:13
Oh right, 'Pacific' is a directory, not a valid zone, and so ZoneInfoNotFoundError should be raised. I see.

Example:

$ ./python -m venv env
$ env/bin/python -m pip install tzdata
$ env/bin/python 

# ZoneInfoNotFoundError expected, get IsADirectoryError
>>> import zoneinfo; zoneinfo.ZoneInfo('Pacific')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/vstinner/python/master/Lib/zoneinfo/_common.py", line 12, in load_tzdata
    return importlib.resources.open_binary(package_name, resource_name)
  File "/home/vstinner/python/master/Lib/importlib/resources.py", line 40, in open_binary
    return reader.open_resource(resource)
  File "/home/vstinner/python/master/Lib/importlib/abc.py", line 419, in open_resource
    return self.files().joinpath(resource).open('rb')
  File "/home/vstinner/python/master/Lib/pathlib.py", line 1238, in open
    return io.open(self, mode, buffering, encoding, errors, newline,
IsADirectoryError: [Errno 21] Is a directory: '/home/vstinner/python/master/env/lib/python3.10/site-packages/tzdata/zoneinfo/Pacific'

# valid zone
>>> import zoneinfo; zoneinfo.ZoneInfo('Pacific/Noumea')
zoneinfo.ZoneInfo(key='Pacific/Noumea')

# raise ZoneInfoNotFoundError as expected (from FileNotFoundError)
>>> import zoneinfo; zoneinfo.ZoneInfo('xxx')
Traceback (most recent call last):
  File "/home/vstinner/python/master/Lib/zoneinfo/_common.py", line 12, in load_tzdata
    return importlib.resources.open_binary(package_name, resource_name)
  File "/home/vstinner/python/master/Lib/importlib/resources.py", line 40, in open_binary
    return reader.open_resource(resource)
  File "/home/vstinner/python/master/Lib/importlib/abc.py", line 419, in open_resource
    return self.files().joinpath(resource).open('rb')
  File "/home/vstinner/python/master/Lib/pathlib.py", line 1238, in open
    return io.open(self, mode, buffering, encoding, errors, newline,
  File "/home/vstinner/python/master/Lib/pathlib.py", line 1106, in _opener
    return self._accessor.open(self, flags, mode)
FileNotFoundError: [Errno 2] No such file or directory: '/home/vstinner/python/master/env/lib/python3.10/site-packages/tzdata/zoneinfo/xxx'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/vstinner/python/master/Lib/zoneinfo/_common.py", line 24, in load_tzdata
    raise ZoneInfoNotFoundError(f"No time zone found with key {key}")
zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key xxx'
msg375234 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-08-12 13:16
On Linux, converting IsADirectoryError to ZoneInfoNotFoundError is easy.

But on Windows, I don't think that converting any PermissionError into a ZoneInfoNotFoundError is a good idea. Maybe if PermissionError happens, we should check if the path is a directory.

Pseudo-code:

try:
  <open and read file>
except OSError as exc:
  if os.path.isdir(zone_path):
    raise ZoneInfoNotFoundError
  else:
    raise
msg375235 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2020-08-12 13:20
Oh, I dislike Roundup UI. I didn't notice that a PR was submitted: PR 21839 (now closed).
msg375238 - (view) Author: Joshua (josh.ja.butt) * Date: 2020-08-12 13:24
I had opened a PR which just caught IsADirectoryError and PermissionError
but closed it as you'd mentioned that handling PermissionError that way
probably would not be the best, and I agree. I can reopen and modify to
check path on OSerror if you'd like otherwise feel free to handle however
you see fit.
msg375239 - (view) Author: Paul Ganssle (p-ganssle) * (Python committer) Date: 2020-08-12 13:25
I think that `ZoneInfo('__init__.py')` is also a problem, but a slightly different one. That comes from the fact that in order to support `importlib.resources`, each of the zoneinfo subdirectories needs an `__init__.py`, but the ZoneInfo constructor should probably ignore those, since they are added by `tzdata` and not actually part of a tzdata distribution.
msg375240 - (view) Author: Paul Ganssle (p-ganssle) * (Python committer) Date: 2020-08-12 13:26
By the way, it might be easiest to start with a PR against backports.zoneinfo, because I have a lot more linting, coverage and format checks set up there: https://github.com/pganssle/zoneinfo
msg375251 - (view) Author: Joshua (josh.ja.butt) * Date: 2020-08-12 14:46
I'll reopen the PR with an attempted resolution of the OSError related
issues however. In my quick testing it seems at least on Linux
backports.zoneinfo segfaults when trying `ZoneInfo('__init__.py')` so that
might be a larger issue for Paul to look into.
History
Date User Action Args
2022-04-11 14:59:34adminsetgithub: 85702
2020-08-12 14:46:45josh.ja.buttsetmessages: + msg375251
2020-08-12 13:26:50p-gansslesetmessages: + msg375240
2020-08-12 13:25:21p-gansslesetmessages: + msg375239
2020-08-12 13:24:28josh.ja.buttsetmessages: + msg375238
2020-08-12 13:20:37vstinnersetmessages: + msg375235
2020-08-12 13:16:13vstinnersetmessages: + msg375234
2020-08-12 13:13:24vstinnersetmessages: + msg375233
title: Unhandled exceptions in zoneinfo.ZoneInfo constructor -> zoneinfo: ZoneInfo raises IsADirectoryError instead of ZoneInfoNotFoundError
2020-08-12 11:53:45josh.ja.buttsetmessages: + msg375228
2020-08-12 11:49:35vstinnersetnosy: + vstinner
messages: + msg375226
2020-08-12 11:47:35vstinnersetnosy: + p-ganssle
2020-08-12 11:43:31python-devsetkeywords: + patch
nosy: + python-dev

pull_requests: + pull_request20967
stage: patch review
2020-08-12 11:42:16josh.ja.buttcreate