Mercurial > public > mercurial-scm > hg
comparison mercurial/vfs.py @ 52901:6ee3c401882b
vfs: avoid passing None to `shutil.rmtree()` for the exception handler
Even though the code looks like it will handle it, pytype 2024.10.11 complains.
So the simplest thing to do is pass along a no-op function that it would use
internally if it was explicitly provided None.
The specific error was:
/home/mharbison/projects/mercurial/mercurial-devel/mercurial/vfs.py:360:20:
error: in rmtree: Function _RmtreeType.__call__ was called with the wrong arguments [wrong-arg-types]
Expected: (self, path, ignore_errors, *, dir_fd, onexc: Callable[[Callable, str, Exception], object])
Actually passed: (self, path, ignore_errors, onexc: Optional[Callable[[Any, bytes, Any], Any]])
Attributes of protocol Callable[[Callable, str, Exception], object] are not implemented on None: __call__
return shutil.rmtree(
~~~~~~~~~~~~~~
self.join(path), ignore_errors=ignore_errors, onexc=onexc
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
)
~~~~~~~~~~~~~
Note that it expects a str on the callback. I thought maybe there would be an
@overload, and it could handle both. But looking at the code in Python 3.11,
they call `os.fsdecode(path)` on some platforms when given bytes, and pass that
str to the callback. So adjust the typehint accordingly, and leave a note.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Tue, 11 Feb 2025 22:44:21 -0500 |
parents | 5cc8deb96b48 |
children | b6f24a92b399 |
comparison
equal
deleted
inserted
replaced
52900:0fd4b2af347b | 52901:6ee3c401882b |
---|---|
341 | 341 |
342 If ``forcibly``, this tries to remove READ-ONLY files, too. | 342 If ``forcibly``, this tries to remove READ-ONLY files, too. |
343 """ | 343 """ |
344 if forcibly: | 344 if forcibly: |
345 | 345 |
346 def onexc(function, path: bytes, excinfo): | 346 def onexc(function: Callable, path: str, excinfo: Exception): |
347 # Note: str is passed here even if bytes are passed to rmtree | |
348 # on platforms where `shutil._use_fd_functions == True`. It is | |
349 # bytes otherwise. Fortunately, the methods used here accept | |
350 # both. | |
347 if function is not os.remove: | 351 if function is not os.remove: |
348 raise | 352 raise |
349 # read-only files cannot be unlinked under Windows | 353 # read-only files cannot be unlinked under Windows |
350 s = os.stat(path) | 354 s = os.stat(path) |
351 if (s.st_mode & stat.S_IWRITE) != 0: | 355 if (s.st_mode & stat.S_IWRITE) != 0: |
352 raise | 356 raise |
353 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE) | 357 os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE) |
354 os.remove(path) | 358 os.remove(path) |
355 | 359 |
356 else: | 360 else: |
357 onexc = None | 361 |
362 def onexc(*args): | |
363 pass | |
364 | |
358 try: | 365 try: |
359 # pytype: disable=wrong-keyword-args | 366 # pytype: disable=wrong-keyword-args |
360 return shutil.rmtree( | 367 return shutil.rmtree( |
361 self.join(path), ignore_errors=ignore_errors, onexc=onexc | 368 self.join(path), ignore_errors=ignore_errors, onexc=onexc |
362 ) | 369 ) |