comparison mercurial/pycompat.py @ 49803:55d45d0de4e7

typing: add type hints to pycompat.bytestr The problem with leaving pytype to its own devices here was that for functions that returned a bytestr, pytype inferred `Union[bytes, int]`. It now accepts that it can be treated as plain bytes. I wasn't able to figure out the arg type for `__getitem__`- `SupportsIndex` (which PyCharm indicated is how the superclass function is typed) got flagged: File "/mnt/c/Users/Matt/hg/mercurial/pycompat.py", line 236, in __getitem__: unsupported operand type(s) for item retrieval: bytestr and SupportsIndex [unsupported-operands] Function __getitem__ on bytestr expects int But some caller got flagged when I marked it as `int`. There's some minor spillover problems elsewhere- pytype doesn't seem to recognize that `bytes.startswith()` can optionally take a 3rd and 4th arg, so those few places have the warning disabled. It also flags where the tar API is being abused, but that would be a tricky refactor (and would require typing extensions until py3.7 is dropped), so disable those too.
author Matt Harbison <matt_harbison@yahoo.com>
date Wed, 14 Dec 2022 01:51:33 -0500
parents f3f33980f19b
children c5a06cc37401
comparison
equal deleted inserted replaced
49802:f3f33980f19b 49803:55d45d0de4e7
27 import sys 27 import sys
28 import tempfile 28 import tempfile
29 import xmlrpc.client as xmlrpclib 29 import xmlrpc.client as xmlrpclib
30 30
31 from typing import ( 31 from typing import (
32 Iterable,
33 Iterator,
32 List, 34 List,
33 Optional, 35 Optional,
36 Type,
37 TypeVar,
34 ) 38 )
35 39
36 ispy3 = sys.version_info[0] >= 3 40 ispy3 = sys.version_info[0] >= 3
37 ispypy = '__pypy__' in sys.builtin_module_names 41 ispypy = '__pypy__' in sys.builtin_module_names
38 TYPE_CHECKING = False 42 TYPE_CHECKING = False
39 43
40 if not globals(): # hide this from non-pytype users 44 if not globals(): # hide this from non-pytype users
41 import typing 45 import typing
42 46
43 TYPE_CHECKING = typing.TYPE_CHECKING 47 TYPE_CHECKING = typing.TYPE_CHECKING
48
49 _Tbytestr = TypeVar('_Tbytestr', bound='bytestr')
44 50
45 51
46 def future_set_exception_info(f, exc_info): 52 def future_set_exception_info(f, exc_info):
47 f.set_exception(exc_info[0]) 53 f.set_exception(exc_info[0])
48 54
210 # since the appropriate bytes format is done internally. 216 # since the appropriate bytes format is done internally.
211 # 217 #
212 # https://github.com/google/pytype/issues/500 218 # https://github.com/google/pytype/issues/500
213 if TYPE_CHECKING: 219 if TYPE_CHECKING:
214 220
215 def __init__(self, s=b''): 221 def __init__(self, s: object = b'') -> None:
216 pass 222 pass
217 223
218 def __new__(cls, s=b''): 224 def __new__(cls: Type[_Tbytestr], s: object = b'') -> _Tbytestr:
219 if isinstance(s, bytestr): 225 if isinstance(s, bytestr):
220 return s 226 return s
221 if not isinstance( 227 if not isinstance(
222 s, (bytes, bytearray) 228 s, (bytes, bytearray)
223 ) and not builtins.hasattr( # hasattr-py3-only 229 ) and not builtins.hasattr( # hasattr-py3-only
224 s, u'__bytes__' 230 s, u'__bytes__'
225 ): 231 ):
226 s = str(s).encode('ascii') 232 s = str(s).encode('ascii')
227 return bytes.__new__(cls, s) 233 return bytes.__new__(cls, s)
228 234
229 def __getitem__(self, key): 235 def __getitem__(self, key) -> bytes:
230 s = bytes.__getitem__(self, key) 236 s = bytes.__getitem__(self, key)
231 if not isinstance(s, bytes): 237 if not isinstance(s, bytes):
232 s = bytechr(s) 238 s = bytechr(s)
233 return s 239 return s
234 240
235 def __iter__(self): 241 def __iter__(self) -> Iterator[bytes]:
236 return iterbytestr(bytes.__iter__(self)) 242 return iterbytestr(bytes.__iter__(self))
237 243
238 def __repr__(self): 244 def __repr__(self) -> str:
239 return bytes.__repr__(self)[1:] # drop b'' 245 return bytes.__repr__(self)[1:] # drop b''
240 246
241 247
242 def iterbytestr(s): 248 def iterbytestr(s: Iterable[int]) -> Iterator[bytes]:
243 """Iterate bytes as if it were a str object of Python 2""" 249 """Iterate bytes as if it were a str object of Python 2"""
244 return map(bytechr, s) 250 return map(bytechr, s)
245 251
246 252
247 def maybebytestr(s): 253 def maybebytestr(s):