Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions singlestoredb/management/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -966,12 +966,12 @@ def listdir(
path = re.sub(r'^(\./|/)+', r'', str(path))
path = re.sub(r'/+$', r'', path) + '/'

# Single validation GET (info) rather than is_dir + info later
info = self.info(path)
if info.type != 'directory':
raise NotADirectoryError(f'path is not a directory: {path}')

out = self._listdir(path, recursive=recursive, return_meta=return_meta)
# Validate via listing GET; if response lacks 'content', it's not a directory
try:
out = self._listdir(path, recursive=recursive, return_meta=return_meta)
except Exception as exc:
# If the path doesn't exist or isn't a directory, _listdir will fail
raise NotADirectoryError(f'path is not a directory: {path}') from exc
if path != '/':
path_n = len(path.split('/')) - 1
if return_meta:
Expand All @@ -990,6 +990,7 @@ def download_file(
*,
overwrite: bool = False,
encoding: Optional[str] = None,
_skip_dir_check: bool = False,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than add this to a publicly visible API, how about we create a _download_file internal method with the extra parameter that is called by download_file. So the parameters for download_file stay the way they were before, but we call the _download_file internal version with _skip_dir_check when needed. That keeps internally used parameters out of the generated documentation.

) -> Optional[Union[bytes, str]]:
"""
Download the content of a file path.
Expand All @@ -1013,7 +1014,7 @@ def download_file(
"""
if local_path is not None and not overwrite and os.path.exists(local_path):
raise OSError('target file already exists; use overwrite=True to replace')
if self.is_dir(path):
if not _skip_dir_check and self.is_dir(path):
raise IsADirectoryError(f'file path is a directory: {path}')

out = self._manager._get(
Expand Down Expand Up @@ -1054,11 +1055,7 @@ def download_folder(
if local_path is not None and not overwrite and os.path.exists(local_path):
raise OSError('target path already exists; use overwrite=True to replace')

# Validate directory with single info call
info = self.info(path)
if info.type != 'directory':
raise NotADirectoryError(f'path is not a directory: {path}')

# listdir validates directory; no extra info call needed
entries = self.listdir(path, recursive=True, return_meta=True)
for entry in entries:
# Each entry is a dict with path relative to root and type
Expand All @@ -1073,7 +1070,7 @@ def download_folder(
remote_path = os.path.join(path, rel_path)
target_file = os.path.normpath(os.path.join(local_path, rel_path))
os.makedirs(os.path.dirname(target_file), exist_ok=True)
self.download_file(remote_path, target_file, overwrite=overwrite)
self.download_file(remote_path, target_file, overwrite=overwrite, _skip_dir_check=True)

def remove(self, path: PathLike) -> None:
"""
Expand Down
Loading