Mercurial > public > mercurial-scm > hg
comparison mercurial/vfs.py @ 51887:ad83e4f9b40e
typing: correct pytype mistakes in `mercurial/vfs.py`
With the previous changes in this series (prior to merging the *.pyi file), this
wasn't too bad- the only definitively wrong things were the `data` argument to
`writelines()`, and the return type on `backgroundclosing()` (both of these
errors were dropped in the previous commit; for some reason pytype doesn't like
`contextlib._GeneratorContextManager`, even though that's what it determined it
is):
File "/mnt/c/Users/Matt/hg/mercurial/vfs.py", line 411, in abstractvfs:
Bad return type 'contextlib._GeneratorContextManager' for generator function abstractvfs.backgroundclosing [bad-yield-annotation]
Expected Generator, Iterable or Iterator
PyCharm thinks this is `Generator[backgroundfilecloser], Any, None]`, which can
be reduced to `Iterator[backgroundfilecloser]`, but pytype flagged the line that
calls `yield` without an argument unless it's also `Optional`. PyCharm is happy
either way. For some reason, `Iterable` didn't work for pytype:
File "/mnt/c/Users/Matt/hg/mercurial/vfs.py", line 390, in abstractvfs:
Function contextlib.contextmanager was called with the wrong arguments [wrong-arg-types]
Expected: (func: Callable[[Any], Iterator])
Actually passed: (func: Callable[[Any, Any, Any], Iterable[Optional[Any]]])
Attributes of protocol Iterator[_T_co] are not implemented on Iterable[Optional[Any]]: __next__
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Fri, 20 Sep 2024 16:36:28 -0400 |
parents | 38720073aa34 |
children | fa9e8a6521c1 |
comparison
equal
deleted
inserted
replaced
51886:38720073aa34 | 51887:ad83e4f9b40e |
---|---|
124 ) -> int: | 124 ) -> int: |
125 with self(path, b'wb', backgroundclose=backgroundclose, **kwargs) as fp: | 125 with self(path, b'wb', backgroundclose=backgroundclose, **kwargs) as fp: |
126 return fp.write(data) | 126 return fp.write(data) |
127 | 127 |
128 def writelines( | 128 def writelines( |
129 self, path: bytes, data: bytes, mode: bytes = b'wb', notindexed=False | 129 self, |
130 path: bytes, | |
131 data: Iterable[bytes], | |
132 mode: bytes = b'wb', | |
133 notindexed=False, | |
130 ) -> None: | 134 ) -> None: |
131 with self(path, mode=mode, notindexed=notindexed) as fp: | 135 with self(path, mode=mode, notindexed=notindexed) as fp: |
132 return fp.writelines(data) | 136 return fp.writelines(data) |
133 | 137 |
134 def append(self, path: bytes, data: bytes) -> int: | 138 def append(self, path: bytes, data: bytes) -> int: |
360 ) | 364 ) |
361 | 365 |
362 def utime(self, path: Optional[bytes] = None, t=None) -> None: | 366 def utime(self, path: Optional[bytes] = None, t=None) -> None: |
363 return os.utime(self.join(path), t) | 367 return os.utime(self.join(path), t) |
364 | 368 |
365 def walk(self, path: Optional[bytes] = None, onerror=None): | 369 def walk( |
370 self, path: Optional[bytes] = None, onerror=None | |
371 ) -> Iterator[Tuple[bytes, List[bytes], List[bytes]]]: | |
366 """Yield (dirpath, dirs, files) tuple for each directory under path | 372 """Yield (dirpath, dirs, files) tuple for each directory under path |
367 | 373 |
368 ``dirpath`` is relative one from the root of this vfs. This | 374 ``dirpath`` is relative one from the root of this vfs. This |
369 uses ``os.sep`` as path separator, even you specify POSIX | 375 uses ``os.sep`` as path separator, even you specify POSIX |
370 style ``path``. | 376 style ``path``. |
377 prefixlen = len(pathutil.normasprefix(root)) | 383 prefixlen = len(pathutil.normasprefix(root)) |
378 for dirpath, dirs, files in os.walk(self.join(path), onerror=onerror): | 384 for dirpath, dirs, files in os.walk(self.join(path), onerror=onerror): |
379 yield (dirpath[prefixlen:], dirs, files) | 385 yield (dirpath[prefixlen:], dirs, files) |
380 | 386 |
381 @contextlib.contextmanager | 387 @contextlib.contextmanager |
382 def backgroundclosing(self, ui, expectedcount=-1): | 388 def backgroundclosing( |
389 self, ui, expectedcount=-1 | |
390 ) -> Iterator[Optional[backgroundfilecloser]]: | |
383 """Allow files to be closed asynchronously. | 391 """Allow files to be closed asynchronously. |
384 | 392 |
385 When this context manager is active, ``backgroundclose`` can be passed | 393 When this context manager is active, ``backgroundclose`` can be passed |
386 to ``__call__``/``open`` to result in the file possibly being closed | 394 to ``__call__``/``open`` to result in the file possibly being closed |
387 asynchronously, on a background thread. | 395 asynchronously, on a background thread. |
721 def __enter__(self: _Tclosewrapbase) -> _Tclosewrapbase: | 729 def __enter__(self: _Tclosewrapbase) -> _Tclosewrapbase: |
722 self._origfh.__enter__() | 730 self._origfh.__enter__() |
723 return self | 731 return self |
724 | 732 |
725 @abc.abstractmethod | 733 @abc.abstractmethod |
726 def __exit__(self, exc_type, exc_value, exc_tb): | 734 def __exit__(self, exc_type, exc_value, exc_tb) -> None: |
727 ... | 735 ... |
728 | 736 |
729 @abc.abstractmethod | 737 @abc.abstractmethod |
730 def close(self): | 738 def close(self) -> None: |
731 ... | 739 ... |
732 | 740 |
733 | 741 |
734 class delayclosedfile(closewrapbase): | 742 class delayclosedfile(closewrapbase): |
735 """Proxy for a file object whose close is delayed. | 743 """Proxy for a file object whose close is delayed. |
739 | 747 |
740 def __init__(self, fh, closer) -> None: | 748 def __init__(self, fh, closer) -> None: |
741 super(delayclosedfile, self).__init__(fh) | 749 super(delayclosedfile, self).__init__(fh) |
742 object.__setattr__(self, '_closer', closer) | 750 object.__setattr__(self, '_closer', closer) |
743 | 751 |
744 def __exit__(self, exc_type, exc_value, exc_tb): | 752 def __exit__(self, exc_type, exc_value, exc_tb) -> None: |
745 self._closer.close(self._origfh) | 753 self._closer.close(self._origfh) |
746 | 754 |
747 def close(self) -> None: | 755 def close(self) -> None: |
748 self._closer.close(self._origfh) | 756 self._closer.close(self._origfh) |
749 | 757 |
791 | 799 |
792 def __enter__(self: _Tbackgroundfilecloser) -> _Tbackgroundfilecloser: | 800 def __enter__(self: _Tbackgroundfilecloser) -> _Tbackgroundfilecloser: |
793 self._entered = True | 801 self._entered = True |
794 return self | 802 return self |
795 | 803 |
796 def __exit__(self, exc_type, exc_value, exc_tb) -> None: # TODO | 804 def __exit__(self, exc_type, exc_value, exc_tb) -> None: |
797 self._running = False | 805 self._running = False |
798 | 806 |
799 # Wait for threads to finish closing so open files don't linger for | 807 # Wait for threads to finish closing so open files don't linger for |
800 # longer than lifetime of context manager. | 808 # longer than lifetime of context manager. |
801 for t in self._threads: | 809 for t in self._threads: |
858 def _checkambig(self) -> None: | 866 def _checkambig(self) -> None: |
859 oldstat = self._oldstat | 867 oldstat = self._oldstat |
860 if oldstat.stat: | 868 if oldstat.stat: |
861 _avoidambig(self._origfh.name, oldstat) | 869 _avoidambig(self._origfh.name, oldstat) |
862 | 870 |
863 def __exit__(self, exc_type, exc_value, exc_tb) -> None: # TODO | 871 def __exit__(self, exc_type, exc_value, exc_tb) -> None: |
864 self._origfh.__exit__(exc_type, exc_value, exc_tb) | 872 self._origfh.__exit__(exc_type, exc_value, exc_tb) |
865 self._checkambig() | 873 self._checkambig() |
866 | 874 |
867 def close(self) -> None: | 875 def close(self) -> None: |
868 self._origfh.close() | 876 self._origfh.close() |