comparison mercurial/util.py @ 51717:ed28085827ec

typing: explicitly type some `mercurial.util` eol code to avoid @overload Unlike the previous commit, this makes a material difference in the generated stub file- the `pycompat.identity()` aliases generated an @overload like this: @overload def fromnativeeol(a: _T0) -> _T0: ... ... which might fail to detect a bad argument, like str. This drops the @overload for the 3 related methods, so there's a single definition for each. The `typelib.BinaryIO_Proxy` is used for subclassing (the same as was done in 8147abc05794), so that it is a `BinaryIO` type during type checking, but still inherits `object` at runtime. That way, we don't need to implement unused abstract methods.
author Matt Harbison <matt_harbison@yahoo.com>
date Fri, 19 Jul 2024 16:49:46 -0400
parents ca7bde5dbafb
children 278af66e6595
comparison
equal deleted inserted replaced
51716:e618a1756b08 51717:ed28085827ec
30 import shutil 30 import shutil
31 import stat 31 import stat
32 import sys 32 import sys
33 import time 33 import time
34 import traceback 34 import traceback
35 import typing
35 import warnings 36 import warnings
36 37
37 from typing import ( 38 from typing import (
38 Any, 39 Any,
40 BinaryIO,
41 Callable,
39 Iterable, 42 Iterable,
40 Iterator, 43 Iterator,
41 List, 44 List,
42 Optional, 45 Optional,
43 Tuple, 46 Tuple,
53 encoding, 56 encoding,
54 error, 57 error,
55 i18n, 58 i18n,
56 policy, 59 policy,
57 pycompat, 60 pycompat,
61 typelib,
58 urllibcompat, 62 urllibcompat,
59 ) 63 )
60 from .utils import ( 64 from .utils import (
61 compression, 65 compression,
62 hashutil, 66 hashutil,
2905 (1, 1 << 10, _(b'%.2f KB')), 2909 (1, 1 << 10, _(b'%.2f KB')),
2906 (1, 1, _(b'%.0f bytes')), 2910 (1, 1, _(b'%.0f bytes')),
2907 ) 2911 )
2908 2912
2909 2913
2910 class transformingwriter: 2914 class transformingwriter(typelib.BinaryIO_Proxy):
2911 """Writable file wrapper to transform data by function""" 2915 """Writable file wrapper to transform data by function"""
2912 2916
2913 def __init__(self, fp, encode): 2917 def __init__(self, fp: BinaryIO, encode: Callable[[bytes], bytes]) -> None:
2914 self._fp = fp 2918 self._fp = fp
2915 self._encode = encode 2919 self._encode = encode
2916 2920
2917 def close(self): 2921 def close(self) -> None:
2918 self._fp.close() 2922 self._fp.close()
2919 2923
2920 def flush(self): 2924 def flush(self) -> None:
2921 self._fp.flush() 2925 self._fp.flush()
2922 2926
2923 def write(self, data): 2927 def write(self, data: bytes) -> int:
2924 return self._fp.write(self._encode(data)) 2928 return self._fp.write(self._encode(data))
2925 2929
2926 2930
2927 # Matches a single EOL which can either be a CRLF where repeated CR 2931 # Matches a single EOL which can either be a CRLF where repeated CR
2928 # are removed or a LF. We do not care about old Macintosh files, so a 2932 # are removed or a LF. We do not care about old Macintosh files, so a
2936 2940
2937 def tocrlf(s: bytes) -> bytes: 2941 def tocrlf(s: bytes) -> bytes:
2938 return _eolre.sub(b'\r\n', s) 2942 return _eolre.sub(b'\r\n', s)
2939 2943
2940 2944
2941 def _crlfwriter(fp): 2945 def _crlfwriter(fp: typelib.BinaryIO_Proxy) -> typelib.BinaryIO_Proxy:
2942 return transformingwriter(fp, tocrlf) 2946 return transformingwriter(fp, tocrlf)
2943 2947
2944 2948
2945 if pycompat.oslinesep == b'\r\n': 2949 if pycompat.oslinesep == b'\r\n':
2946 tonativeeol = tocrlf 2950 tonativeeol = tocrlf
2948 nativeeolwriter = _crlfwriter 2952 nativeeolwriter = _crlfwriter
2949 else: 2953 else:
2950 tonativeeol = pycompat.identity 2954 tonativeeol = pycompat.identity
2951 fromnativeeol = pycompat.identity 2955 fromnativeeol = pycompat.identity
2952 nativeeolwriter = pycompat.identity 2956 nativeeolwriter = pycompat.identity
2957
2958 if typing.TYPE_CHECKING:
2959 # Replace the various overloads that come along with aliasing other methods
2960 # with the narrow definition that we care about in the type checking phase
2961 # only. This ensures that both Windows and POSIX see only the definition
2962 # that is actually available.
2963
2964 def tonativeeol(s: bytes) -> bytes:
2965 raise NotImplementedError
2966
2967 def fromnativeeol(s: bytes) -> bytes:
2968 raise NotImplementedError
2969
2970 def nativeeolwriter(fp: typelib.BinaryIO_Proxy) -> typelib.BinaryIO_Proxy:
2971 raise NotImplementedError
2953 2972
2954 2973
2955 # TODO delete since workaround variant for Python 2 no longer needed. 2974 # TODO delete since workaround variant for Python 2 no longer needed.
2956 def iterfile(fp): 2975 def iterfile(fp):
2957 return fp 2976 return fp