74 lines
1.7 KiB
Python
74 lines
1.7 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class DirectoryEntry:
|
|
"""Directory metadata used by the navigator layer."""
|
|
|
|
name: str
|
|
path: Path
|
|
has_children: bool
|
|
|
|
|
|
def list_directories(path: Path, show_hidden: bool = False) -> list[DirectoryEntry]:
|
|
"""Return direct child directories sorted by name."""
|
|
|
|
directory_path = path.expanduser().resolve()
|
|
entries: list[DirectoryEntry] = []
|
|
|
|
try:
|
|
children = list(directory_path.iterdir())
|
|
except PermissionError:
|
|
return []
|
|
|
|
for child in children:
|
|
try:
|
|
is_directory = child.is_dir()
|
|
except OSError:
|
|
continue
|
|
|
|
if not is_directory:
|
|
continue
|
|
if not show_hidden and child.name.startswith("."):
|
|
continue
|
|
|
|
entries.append(
|
|
DirectoryEntry(
|
|
name=child.name,
|
|
path=child,
|
|
has_children=has_subdirectories(child, show_hidden=show_hidden),
|
|
)
|
|
)
|
|
|
|
return sorted(entries, key=lambda entry: entry.name.casefold())
|
|
|
|
|
|
def has_subdirectories(path: Path, show_hidden: bool = False) -> bool:
|
|
"""Return whether the directory contains at least one subdirectory."""
|
|
|
|
directory_path = path.expanduser().resolve()
|
|
|
|
try:
|
|
children = list(directory_path.iterdir())
|
|
except PermissionError:
|
|
return False
|
|
|
|
for child in children:
|
|
try:
|
|
is_directory = child.is_dir()
|
|
except OSError:
|
|
continue
|
|
|
|
if not is_directory:
|
|
continue
|
|
|
|
if not show_hidden and child.name.startswith("."):
|
|
continue
|
|
|
|
return True
|
|
|
|
return False
|