Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/dateutil/_tzdata_impl.py: 37%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

30 statements  

1"""This is an implementation of functions that interact with the tzdata module. 

2 

3It will only live as long as :mod:`dateutil.zoneinfo` lives; when the 

4``dateutil.zoneinfo`` module is removed, this can all move under :mod:`tz`. 

5""" 

6 

7import importlib.resources 

8from typing import BinaryIO, TextIO 

9 

10_TZDATA_LOAD_EXCEPTIONS = ( 

11 ImportError, 

12 FileNotFoundError, 

13 UnicodeEncodeError, 

14 IsADirectoryError, 

15 ValueError, 

16) 

17 

18 

19def _open_text(package: str, resource: str) -> TextIO: 

20 return ( 

21 importlib.resources.files(package) 

22 .joinpath(resource) 

23 .open("r", encoding="utf-8") 

24 ) 

25 

26 

27def _open_binary(package: str, resource: str) -> BinaryIO: 

28 return importlib.resources.files(package).joinpath(resource).open("rb") 

29 

30 

31def _is_package_directory(package: str, resource: str) -> bool: 

32 """Checks for directories before opening resources on Windows.""" 

33 try: 

34 return importlib.resources.files(package).joinpath(resource).is_dir() 

35 except ImportError: 

36 return False 

37 

38 

39def _load_tzdata(key): 

40 components = key.split("/") 

41 package_name = ".".join(["tzdata.zoneinfo"] + components[:-1]) 

42 resource_name = components[-1] 

43 

44 # Empty or relative path components cannot name a zone, and they produce 

45 # module names that the import machinery handles inconsistently across 

46 # versions, so treat them as not found up front. A key naming a directory 

47 # (a subpackage) is not a zone either, and opening it raises a 

48 # platform-dependent error, see CPython gh-85702. 

49 if any(c in ("", ".", "..") for c in components) or _is_package_directory( 

50 package_name, resource_name 

51 ): 

52 raise TZFileNotFound("Time zone not found: %s", zone_key=key) 

53 

54 try: 

55 return _open_binary(package_name, resource_name) 

56 except _TZDATA_LOAD_EXCEPTIONS: 

57 # ImportError: package does not exist (or tzdata is not installed) 

58 # FileNotFoundError: the key is not a file in the package 

59 # UnicodeEncodeError: the key is not encodable as a filename 

60 # IsADirectoryError: the key names a package rather than a resource 

61 # ValueError: the key is not a valid path (e.g. contains a NUL byte) 

62 raise TZFileNotFound("Time zone not found: %s", zone_key=key) from None 

63 

64 

65def _load_tzdata_keys(): 

66 with _open_text("tzdata", "zones") as f: 

67 return list(filter(None, (l.strip() for l in f))) 

68 

69 

70class TZFileNotFound(ValueError): 

71 """Indicates that a time zone file isn't present in tzdata.""" 

72 

73 def __init__(self, msg: str, *args: object, zone_key: str) -> None: 

74 super().__init__(msg % zone_key, *args) 

75 self.zone_key = zone_key