Skip to content

Commit

Permalink
feat: allow creating parent directories for a file store (#3526)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Maksim R <maksim@dohop.com>
Co-authored-by: Jacob Coffee <jacob@z7x.org>
Co-authored-by: Janek Nouvertné <provinzkraut@posteo.de>
Co-authored-by: Cody Fincher <204685+cofin@users.noreply.github.com>
Co-authored-by: euri10 <benoit.barthelet@gmail.com>
  • Loading branch information
6 people authored Jun 13, 2024
1 parent 95951db commit f179aee
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
14 changes: 12 additions & 2 deletions litestar/stores/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,25 @@ def _safe_file_name(name: str) -> str:
class FileStore(NamespacedStore):
"""File based, thread and process safe, asynchronous key/value store."""

__slots__ = {"path": "file path"}
__slots__ = {"path": "file path", "create_directories": "flag to create directories in path"}

def __init__(self, path: PathLike[str]) -> None:
def __init__(self, path: PathLike[str], *, create_directories: bool = False) -> None:
"""Initialize ``FileStorage``.
Args:
path: Path to store data under
create_directories: Create the directories in ``path`` if they don't exist
Default: ``False``
.. versionadded:: 2.9.0
"""
self.path = Path(path)
self.create_directories = create_directories

async def __aenter__(self) -> None:
if self.create_directories:
await self.path.mkdir(exist_ok=True, parents=True)
return

def with_namespace(self, namespace: str) -> FileStore:
"""Return a new instance of :class:`FileStore`, using a sub-path of the current store's path."""
Expand Down
13 changes: 13 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import os
import random
import shutil
import string
import sys
from datetime import datetime
Expand Down Expand Up @@ -92,6 +93,18 @@ def file_store(tmp_path: Path) -> FileStore:
return FileStore(path=tmp_path)


@pytest.fixture()
def file_store_create_directories(tmp_path: Path) -> FileStore:
path = tmp_path / "subdir1" / "subdir2"
return FileStore(path=path, create_directories=True)


@pytest.fixture()
def file_store_create_directories_flag_false(tmp_path: Path) -> FileStore:
shutil.rmtree(tmp_path, ignore_errors=True) # in case the path was already created by different tests - we clean it
return FileStore(path=tmp_path.joinpath("subdir"), create_directories=False)


@pytest.fixture(
params=[pytest.param("redis_store", marks=pytest.mark.xdist_group("redis")), "memory_store", "file_store"]
)
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/test_stores.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,19 @@ async def test_file_init_directory(file_store: FileStore) -> None:
await file_store.set("foo", b"bar")


async def test_file_init_subdirectory(file_store_create_directories: FileStore) -> None:
file_store = file_store_create_directories
async with file_store:
await file_store.set("foo", b"bar")


async def test_file_init_subdirectory_negative(file_store_create_directories_flag_false: FileStore) -> None:
file_store = file_store_create_directories_flag_false
async with file_store:
with pytest.raises(FileNotFoundError):
await file_store.set("foo", b"bar")


async def test_file_path(file_store: FileStore) -> None:
await file_store.set("foo", b"bar")

Expand Down

0 comments on commit f179aee

Please sign in to comment.