Mercurial > public > mercurial-scm > hg
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 |