##// END OF EJS Templates
typing: manually add type annotations to `mercurial/vfs.py`...
Matt Harbison -
r52785:fa9e8a65 default
parent child Browse files
Show More
@@ -17,9 +17,12 b' import typing'
17 17
18 18 from typing import (
19 19 Any,
20 BinaryIO,
21 Callable,
20 22 Iterable,
21 23 Iterator,
22 24 List,
25 MutableMapping,
23 26 Optional,
24 27 Tuple,
25 28 Type,
@@ -36,13 +39,18 b' from . import ('
36 39 )
37 40
38 41 if typing.TYPE_CHECKING:
42 from . import (
43 ui as uimod,
44 )
45
39 46 _Tbackgroundfilecloser = TypeVar(
40 47 '_Tbackgroundfilecloser', bound='backgroundfilecloser'
41 48 )
42 49 _Tclosewrapbase = TypeVar('_Tclosewrapbase', bound='closewrapbase')
50 _OnErrorFn = Callable[[Exception], Optional[object]]
43 51
44 52
45 def _avoidambig(path: bytes, oldstat) -> None:
53 def _avoidambig(path: bytes, oldstat: util.filestat) -> None:
46 54 """Avoid file stat ambiguity forcibly
47 55
48 56 This function causes copying ``path`` file, if it is owned by
@@ -78,7 +86,7 b' class abstractvfs(abc.ABC):'
78 86 ...
79 87
80 88 @abc.abstractmethod
81 def _auditpath(self, path: bytes, mode: bytes) -> Any:
89 def _auditpath(self, path: bytes, mode: bytes) -> None:
82 90 ...
83 91
84 92 @abc.abstractmethod
@@ -93,7 +101,7 b' class abstractvfs(abc.ABC):'
93 101 pass
94 102 return b""
95 103
96 def tryreadlines(self, path: bytes, mode: bytes = b'rb') -> Any:
104 def tryreadlines(self, path: bytes, mode: bytes = b'rb') -> List[bytes]:
97 105 '''gracefully return an empty array for missing files'''
98 106 try:
99 107 return self.readlines(path, mode=mode)
@@ -115,12 +123,12 b' class abstractvfs(abc.ABC):'
115 123 with self(path, b'rb') as fp:
116 124 return fp.read()
117 125
118 def readlines(self, path: bytes, mode: bytes = b'rb') -> Any:
126 def readlines(self, path: bytes, mode: bytes = b'rb') -> List[bytes]:
119 127 with self(path, mode=mode) as fp:
120 128 return fp.readlines()
121 129
122 130 def write(
123 self, path: bytes, data: bytes, backgroundclose=False, **kwargs
131 self, path: bytes, data: bytes, backgroundclose: bool = False, **kwargs
124 132 ) -> int:
125 133 with self(path, b'wb', backgroundclose=backgroundclose, **kwargs) as fp:
126 134 return fp.write(data)
@@ -130,7 +138,7 b' class abstractvfs(abc.ABC):'
130 138 path: bytes,
131 139 data: Iterable[bytes],
132 140 mode: bytes = b'wb',
133 notindexed=False,
141 notindexed: bool = False,
134 142 ) -> None:
135 143 with self(path, mode=mode, notindexed=notindexed) as fp:
136 144 return fp.writelines(data)
@@ -157,7 +165,7 b' class abstractvfs(abc.ABC):'
157 165 def exists(self, path: Optional[bytes] = None) -> bool:
158 166 return os.path.exists(self.join(path))
159 167
160 def fstat(self, fp) -> os.stat_result:
168 def fstat(self, fp: BinaryIO) -> os.stat_result:
161 169 return util.fstat(fp)
162 170
163 171 def isdir(self, path: Optional[bytes] = None) -> bool:
@@ -249,7 +257,7 b' class abstractvfs(abc.ABC):'
249 257 ) -> None:
250 258 return util.makedirs(self.join(path), mode)
251 259
252 def makelock(self, info, path: bytes) -> None:
260 def makelock(self, info: bytes, path: bytes) -> None:
253 261 return util.makelock(info, self.join(path))
254 262
255 263 def mkdir(self, path: Optional[bytes] = None) -> None:
@@ -270,6 +278,12 b' class abstractvfs(abc.ABC):'
270 278 else:
271 279 return fd, fname
272 280
281 # TODO: This doesn't match osutil.listdir(). stat=False in pure;
282 # non-optional bool in cext. 'skip' is bool if we trust cext, or bytes
283 # going by how pure uses it. Also, cext returns a custom stat structure.
284 # from cext.osutil.pyi:
285 #
286 # path: bytes, st: bool, skip: Optional[bool]
273 287 def readdir(
274 288 self, path: Optional[bytes] = None, stat=None, skip=None
275 289 ) -> Any:
@@ -278,7 +292,7 b' class abstractvfs(abc.ABC):'
278 292 def readlock(self, path: bytes) -> bytes:
279 293 return util.readlock(self.join(path))
280 294
281 def rename(self, src: bytes, dst: bytes, checkambig=False) -> None:
295 def rename(self, src: bytes, dst: bytes, checkambig: bool = False) -> None:
282 296 """Rename from src to dst
283 297
284 298 checkambig argument is used with util.filestat, and is useful
@@ -312,7 +326,10 b' class abstractvfs(abc.ABC):'
312 326 return os.rmdir(self.join(path))
313 327
314 328 def rmtree(
315 self, path: Optional[bytes] = None, ignore_errors=False, forcibly=False
329 self,
330 path: Optional[bytes] = None,
331 ignore_errors: bool = False,
332 forcibly: bool = False,
316 333 ) -> None:
317 334 """Remove a directory tree recursively
318 335
@@ -320,7 +337,7 b' class abstractvfs(abc.ABC):'
320 337 """
321 338 if forcibly:
322 339
323 def onexc(function, path, excinfo):
340 def onexc(function, path: bytes, excinfo):
324 341 if function is not os.remove:
325 342 raise
326 343 # read-only files cannot be unlinked under Windows
@@ -357,17 +374,23 b' class abstractvfs(abc.ABC):'
357 374 return util.tryunlink(self.join(path))
358 375
359 376 def unlinkpath(
360 self, path: Optional[bytes] = None, ignoremissing=False, rmdir=True
377 self,
378 path: Optional[bytes] = None,
379 ignoremissing: bool = False,
380 rmdir: bool = True,
361 381 ) -> None:
362 382 return util.unlinkpath(
363 383 self.join(path), ignoremissing=ignoremissing, rmdir=rmdir
364 384 )
365 385
366 def utime(self, path: Optional[bytes] = None, t=None) -> None:
386 # TODO: could be Tuple[float, float] too.
387 def utime(
388 self, path: Optional[bytes] = None, t: Optional[Tuple[int, int]] = None
389 ) -> None:
367 390 return os.utime(self.join(path), t)
368 391
369 392 def walk(
370 self, path: Optional[bytes] = None, onerror=None
393 self, path: Optional[bytes] = None, onerror: Optional[_OnErrorFn] = None
371 394 ) -> Iterator[Tuple[bytes, List[bytes], List[bytes]]]:
372 395 """Yield (dirpath, dirs, files) tuple for each directory under path
373 396
@@ -386,7 +409,7 b' class abstractvfs(abc.ABC):'
386 409
387 410 @contextlib.contextmanager
388 411 def backgroundclosing(
389 self, ui, expectedcount=-1
412 self, ui: uimod.ui, expectedcount: int = -1
390 413 ) -> Iterator[Optional[backgroundfilecloser]]:
391 414 """Allow files to be closed asynchronously.
392 415
@@ -417,7 +440,7 b' class abstractvfs(abc.ABC):'
417 440 None # pytype: disable=attribute-error
418 441 )
419 442
420 def register_file(self, path) -> None:
443 def register_file(self, path: bytes) -> None:
421 444 """generic hook point to lets fncache steer its stew"""
422 445
423 446
@@ -432,13 +455,15 b' class vfs(abstractvfs):'
432 455 See pathutil.pathauditor() for details.
433 456 """
434 457
458 createmode: Optional[int]
459
435 460 def __init__(
436 461 self,
437 462 base: bytes,
438 audit=True,
439 cacheaudited=False,
440 expandpath=False,
441 realpath=False,
463 audit: bool = True,
464 cacheaudited: bool = False,
465 expandpath: bool = False,
466 realpath: bool = False,
442 467 ) -> None:
443 468 if expandpath:
444 469 base = util.expandpath(base)
@@ -459,15 +484,15 b' class vfs(abstractvfs):'
459 484 return util.checklink(self.base)
460 485
461 486 @util.propertycache
462 def _chmod(self):
487 def _chmod(self) -> bool:
463 488 return util.checkexec(self.base)
464 489
465 def _fixfilemode(self, name) -> None:
490 def _fixfilemode(self, name: bytes) -> None:
466 491 if self.createmode is None or not self._chmod:
467 492 return
468 493 os.chmod(name, self.createmode & 0o666)
469 494
470 def _auditpath(self, path, mode) -> None:
495 def _auditpath(self, path: bytes, mode: bytes) -> None:
471 496 if self._audit:
472 497 if os.path.isabs(path) and path.startswith(self.base):
473 498 path = os.path.relpath(path, self.base)
@@ -477,7 +502,9 b' class vfs(abstractvfs):'
477 502 self.audit(path, mode=mode)
478 503
479 504 def isfileorlink_checkdir(
480 self, dircache, path: Optional[bytes] = None
505 self,
506 dircache: MutableMapping[bytes, bool],
507 path: Optional[bytes] = None,
481 508 ) -> bool:
482 509 """return True if the path is a regular file or a symlink and
483 510 the directories along the path are "normal", that is
@@ -486,6 +513,8 b' class vfs(abstractvfs):'
486 513 Ignores the `_audit` setting, and checks the directories regardless.
487 514 `dircache` is used to cache the directory checks.
488 515 """
516 # TODO: Should be a None check on 'path', or shouldn't default to None
517 # because of the immediate call to util.localpath().
489 518 try:
490 519 for prefix in pathutil.finddirs_rev_noroot(util.localpath(path)):
491 520 if prefix in dircache:
@@ -505,13 +534,13 b' class vfs(abstractvfs):'
505 534 self,
506 535 path: bytes,
507 536 mode: bytes = b"rb",
508 atomictemp=False,
509 notindexed=False,
510 backgroundclose=False,
511 checkambig=False,
512 auditpath=True,
513 makeparentdirs=True,
514 ) -> Any:
537 atomictemp: bool = False,
538 notindexed: bool = False,
539 backgroundclose: bool = False,
540 checkambig: bool = False,
541 auditpath: bool = True,
542 makeparentdirs: bool = True,
543 ) -> Any: # TODO: should be BinaryIO if util.atomictempfile can be coersed
515 544 """Open ``path`` file, which is relative to vfs root.
516 545
517 546 By default, parent directories are created as needed. Newly created
@@ -650,14 +679,14 b' opener: Type[vfs] = vfs'
650 679
651 680
652 681 class proxyvfs(abstractvfs, abc.ABC):
653 def __init__(self, vfs: "vfs"):
682 def __init__(self, vfs: vfs) -> None:
654 683 self.vfs = vfs
655 684
656 685 @property
657 def createmode(self):
686 def createmode(self) -> Optional[int]:
658 687 return self.vfs.createmode
659 688
660 def _auditpath(self, path, mode) -> None:
689 def _auditpath(self, path: bytes, mode: bytes) -> None:
661 690 return self.vfs._auditpath(path, mode)
662 691
663 692 @property
@@ -676,10 +705,11 b' class proxyvfs(abstractvfs, abc.ABC):'
676 705 class filtervfs(proxyvfs, abstractvfs):
677 706 '''Wrapper vfs for filtering filenames with a function.'''
678 707
679 def __init__(self, vfs: "vfs", filter):
708 def __init__(self, vfs: vfs, filter) -> None:
680 709 proxyvfs.__init__(self, vfs)
681 710 self._filter = filter
682 711
712 # TODO: The return type should be BinaryIO
683 713 def __call__(self, path: bytes, *args, **kwargs) -> Any:
684 714 return self.vfs(self._filter(path), *args, **kwargs)
685 715
@@ -696,9 +726,10 b' filteropener: Type[filtervfs] = filtervf'
696 726 class readonlyvfs(proxyvfs):
697 727 '''Wrapper vfs preventing any writing.'''
698 728
699 def __init__(self, vfs: "vfs"):
729 def __init__(self, vfs: vfs) -> None:
700 730 proxyvfs.__init__(self, vfs)
701 731
732 # TODO: The return type should be BinaryIO
702 733 def __call__(self, path: bytes, mode: bytes = b'rb', *args, **kw) -> Any:
703 734 if mode not in (b'r', b'rb'):
704 735 raise error.Abort(_(b'this vfs is read only'))
@@ -717,13 +748,13 b' class closewrapbase(abc.ABC):'
717 748 def __init__(self, fh) -> None:
718 749 object.__setattr__(self, '_origfh', fh)
719 750
720 def __getattr__(self, attr) -> Any:
751 def __getattr__(self, attr: str) -> Any:
721 752 return getattr(self._origfh, attr)
722 753
723 def __setattr__(self, attr, value) -> None:
754 def __setattr__(self, attr: str, value: Any) -> None:
724 755 return setattr(self._origfh, attr, value)
725 756
726 def __delattr__(self, attr) -> None:
757 def __delattr__(self, attr: str) -> None:
727 758 return delattr(self._origfh, attr)
728 759
729 760 def __enter__(self: _Tclosewrapbase) -> _Tclosewrapbase:
@@ -759,7 +790,7 b' class delayclosedfile(closewrapbase):'
759 790 class backgroundfilecloser:
760 791 """Coordinates background closing of file handles on multiple threads."""
761 792
762 def __init__(self, ui, expectedcount=-1) -> None:
793 def __init__(self, ui: uimod.ui, expectedcount: int = -1) -> None:
763 794 self._running = False
764 795 self._entered = False
765 796 self._threads = []
General Comments 0
You need to be logged in to leave comments. Login now