From 9abeb4ebcaf6c2cb8c941e9a73a88265cc6fc6aa Mon Sep 17 00:00:00 2001 From: Jan Lindemann Date: Fri, 16 Oct 2026 16:09:21 +0200 Subject: [PATCH] lib.FileContext.is_gettable: Add property Analogous to the is_dir() method, add an is_gettable() method: The last commit introduces FT_COMPOUND, a file type which is a hybrid between directory and regular file. is_dir() succeeds on it, so is_gettable() symmetrically provides a test find out if get() also works on a file. Signed-off-by: Jan Lindemann --- src/python/jw/pkg/lib/FileContext.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/python/jw/pkg/lib/FileContext.py b/src/python/jw/pkg/lib/FileContext.py index e452d871..aa61f10d 100644 --- a/src/python/jw/pkg/lib/FileContext.py +++ b/src/python/jw/pkg/lib/FileContext.py @@ -308,6 +308,30 @@ class FileContext(abc.ABC): async def is_dir(self, path: str, follow_symlinks: bool = True) -> bool: return await self._is_dir(self._chroot(path), follow_symlinks = follow_symlinks) + async def _is_gettable(self, path: str, follow_symlinks: bool) -> bool: + try: + return (await self._stat(path, follow_symlinks)).is_gettable + except NotImplementedError: + log( + DEBUG, + ( + f"{self.log_name} doesn't implement stat(), judging by " + f'trailing slash if {path} is a file' + ), + ) + return path[-1] != '/' + except FileNotFoundError as e: + log(DEBUG, f'{self.log_name}: Failed to stat({path}) ({str(e)})') + return False + except Exception as e: + log(ERR, f'{self.log_name}: Failed to stat({path}) ({str(e)})') + raise + + async def is_gettable(self, path: str, follow_symlinks: bool = True) -> bool: + return await self._is_gettable( + self._chroot(path), follow_symlinks = follow_symlinks + ) + async def _readdir(self, path: str) -> Iterable[str]: raise NotImplementedError( f'{self.log_name}: readdir("{path}") is not implemented'