comparison mercurial/utils/resourceutil.py @ 51665:32a1c9226dd9

typing: add type hints to `mercurial/utils/resourceutil.py` The `except` path requires byte args (because of the byte based manipulation in `_package_path()`), while the `else` case tolerates `AnyStr`. Pytype was unable to figure this out, and we should make sure the interface is the same for all environments.
author Matt Harbison <matt_harbison@yahoo.com>
date Wed, 10 Jul 2024 15:49:16 -0400
parents d718eddf01d9
children 493034cc3265
comparison
equal deleted inserted replaced
51663:8e3f6b5bf720 51665:32a1c9226dd9
9 9
10 10
11 import _imp 11 import _imp
12 import os 12 import os
13 import sys 13 import sys
14 import typing
14 15
15 from .. import pycompat 16 from .. import pycompat
17
18
19 if typing.TYPE_CHECKING:
20 from typing import (
21 BinaryIO,
22 Iterator,
23 )
16 24
17 25
18 def mainfrozen(): 26 def mainfrozen():
19 """return True if we are a frozen executable. 27 """return True if we are a frozen executable.
20 28
37 # The installers store the files outside of library.zip, like 45 # The installers store the files outside of library.zip, like
38 # C:\Program Files\Mercurial\defaultrc\*.rc. This strips the 46 # C:\Program Files\Mercurial\defaultrc\*.rc. This strips the
39 # leading "mercurial." off of the package name, so that these 47 # leading "mercurial." off of the package name, so that these
40 # pseudo resources are found in their directory next to the 48 # pseudo resources are found in their directory next to the
41 # executable. 49 # executable.
42 def _package_path(package): 50 def _package_path(package: bytes) -> bytes:
43 dirs = package.split(b".") 51 dirs = package.split(b".")
44 assert dirs[0] == b"mercurial" 52 assert dirs[0] == b"mercurial"
45 return os.path.join(_rootpath, *dirs[1:]) 53 return os.path.join(_rootpath, *dirs[1:])
46 54
47 55
48 else: 56 else:
49 datapath = os.path.dirname(os.path.dirname(pycompat.fsencode(__file__))) 57 datapath = os.path.dirname(os.path.dirname(pycompat.fsencode(__file__)))
50 _rootpath = os.path.dirname(datapath) 58 _rootpath = os.path.dirname(datapath)
51 59
52 def _package_path(package): 60 def _package_path(package: bytes) -> bytes:
53 return os.path.join(_rootpath, *package.split(b".")) 61 return os.path.join(_rootpath, *package.split(b"."))
54 62
55 63
56 try: 64 try:
57 # importlib.resources exists from Python 3.7; see fallback in except clause 65 # importlib.resources exists from Python 3.7; see fallback in except clause
70 78
71 except (ImportError, AttributeError): 79 except (ImportError, AttributeError):
72 # importlib.resources was not found (almost definitely because we're on a 80 # importlib.resources was not found (almost definitely because we're on a
73 # Python version before 3.7) 81 # Python version before 3.7)
74 82
75 def open_resource(package, name): 83 def open_resource(package: bytes, name: bytes) -> "BinaryIO":
76 path = os.path.join(_package_path(package), name) 84 path = os.path.join(_package_path(package), name)
77 return open(path, "rb") 85 return open(path, "rb")
78 86
79 def is_resource(package, name): 87 def is_resource(package: bytes, name: bytes) -> bool:
80 path = os.path.join(_package_path(package), name) 88 path = os.path.join(_package_path(package), name)
81 89
82 try: 90 try:
83 return os.path.isfile(pycompat.fsdecode(path)) 91 return os.path.isfile(pycompat.fsdecode(path))
84 except (IOError, OSError): 92 except (IOError, OSError):
85 return False 93 return False
86 94
87 def contents(package): 95 def contents(package: bytes) -> "Iterator[bytes]":
88 path = pycompat.fsdecode(_package_path(package)) 96 path = pycompat.fsdecode(_package_path(package))
89 97
90 for p in os.listdir(path): 98 for p in os.listdir(path):
91 yield pycompat.fsencode(p) 99 yield pycompat.fsencode(p)
92 100
93 101
94 else: 102 else:
95 from .. import encoding 103 from .. import encoding
96 104
97 def open_resource(package, name): 105 def open_resource(package: bytes, name: bytes) -> "BinaryIO":
98 if hasattr(resources, 'files'): 106 if hasattr(resources, 'files'):
99 return ( 107 return (
100 resources.files( # pytype: disable=module-attr 108 resources.files( # pytype: disable=module-attr
101 pycompat.sysstr(package) 109 pycompat.sysstr(package)
102 ) 110 )
106 else: 114 else:
107 return resources.open_binary( # pytype: disable=module-attr 115 return resources.open_binary( # pytype: disable=module-attr
108 pycompat.sysstr(package), pycompat.sysstr(name) 116 pycompat.sysstr(package), pycompat.sysstr(name)
109 ) 117 )
110 118
111 def is_resource(package, name): 119 def is_resource(package: bytes, name: bytes) -> bool:
112 return resources.is_resource( # pytype: disable=module-attr 120 return resources.is_resource( # pytype: disable=module-attr
113 pycompat.sysstr(package), encoding.strfromlocal(name) 121 pycompat.sysstr(package), encoding.strfromlocal(name)
114 ) 122 )
115 123
116 def contents(package): 124 def contents(package: bytes) -> "Iterator[bytes]":
117 # pytype: disable=module-attr 125 # pytype: disable=module-attr
118 for r in resources.contents(pycompat.sysstr(package)): 126 for r in resources.contents(pycompat.sysstr(package)):
119 # pytype: enable=module-attr 127 # pytype: enable=module-attr
120 yield encoding.strtolocal(r) 128 yield encoding.strtolocal(r)