Skip to content

Commit

Permalink
fix: file handling when directory does not exist (#2206)
Browse files Browse the repository at this point in the history
Allows users to create files in subdirectories that don't yet exist by
creating them; previously, this failed in an unintuitive way.
  • Loading branch information
akshayka authored Sep 3, 2024
1 parent 06eda80 commit 63b3b1d
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 25 deletions.
9 changes: 9 additions & 0 deletions marimo/_server/file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from __future__ import annotations

import os
import pathlib
from typing import Any, Dict, Optional

from marimo import _loggers
Expand Down Expand Up @@ -58,11 +59,18 @@ def _assert_path_is_the_same(self, filename: str) -> None:
detail="Save handler cannot rename files.",
)

def _create_parent_directories(self, filename: str) -> None:
try:
pathlib.Path(filename).parent.mkdir(parents=True, exist_ok=True)
except Exception:
pass

def _create_file(
self,
filename: str,
contents: str = "",
) -> None:
self._create_parent_directories(filename)
try:
with open(filename, "w", encoding="utf-8") as f:
f.write(contents)
Expand All @@ -74,6 +82,7 @@ def _create_file(

def _rename_file(self, new_filename: str) -> None:
assert self.filename is not None
self._create_parent_directories(new_filename)
try:
os.rename(self.filename, new_filename)
except Exception as err:
Expand Down
53 changes: 28 additions & 25 deletions marimo/_server/files/os_file_system.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,34 @@ def get_root(self) -> str:
def list_files(self, path: str) -> List[FileInfo]:
files: List[FileInfo] = []
folders: List[FileInfo] = []
with os.scandir(path) as it:
for entry in it:
if entry.name in IGNORE_LIST:
continue
try:
is_directory = entry.is_dir()
entry_stat = entry.stat()
except OSError:
# do not include files that fail to read
# (e.g. recursive/broken symlinks)
continue

info = FileInfo(
id=entry.path,
path=entry.path,
name=entry.name,
is_directory=is_directory,
is_marimo_file=not is_directory
and self._is_marimo_file(entry.path),
last_modified=entry_stat.st_mtime,
)
if is_directory:
folders.append(info)
else:
files.append(info)
try:
with os.scandir(path) as it:
for entry in it:
if entry.name in IGNORE_LIST:
continue
try:
is_directory = entry.is_dir()
entry_stat = entry.stat()
except OSError:
# do not include files that fail to read
# (e.g. recursive/broken symlinks)
continue

info = FileInfo(
id=entry.path,
path=entry.path,
name=entry.name,
is_directory=is_directory,
is_marimo_file=not is_directory
and self._is_marimo_file(entry.path),
last_modified=entry_stat.st_mtime,
)
if is_directory:
folders.append(info)
else:
files.append(info)
except OSError:
pass

return sorted(folders, key=natural_sort_file) + sorted(
files, key=natural_sort_file
Expand Down
18 changes: 18 additions & 0 deletions tests/_server/test_file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ def test_rename_create_new_file(app_file_manager: AppFileManager) -> None:
os.remove(new_filename)


def test_rename_create_new_directory_file(
app_file_manager: AppFileManager,
) -> None:
app_file_manager.filename = None
new_directory = "new_directory"
new_filename = os.path.join(new_directory, "new_file.py")
if os.path.exists(new_filename):
os.remove(new_filename)
if os.path.exists(new_directory):
os.rmdir(new_directory)
try:
app_file_manager.rename(new_filename)
assert os.path.exists(new_filename)
finally:
os.remove(new_filename)
os.rmdir(new_directory)


def test_rename_different_filetype(app_file_manager: AppFileManager) -> None:
initial_filename = app_file_manager.filename
assert initial_filename
Expand Down

0 comments on commit 63b3b1d

Please sign in to comment.