Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for complex storage names #154

Merged
merged 2 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
22 changes: 16 additions & 6 deletions sqlalchemy_file/storage.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import contextlib
import warnings
from typing import Any, ClassVar, Dict, Iterator, Optional
from typing import Any, ClassVar, Dict, Iterator, Optional, Tuple

from libcloud.storage.base import Container
from libcloud.storage.types import ObjectDoesNotExistError
Expand Down Expand Up @@ -122,10 +122,11 @@ def save_file(

@classmethod
def get_file(cls, path: str) -> StoredFile:
"""Retrieve the file with `provided` path,
path is expected to be `storage_name/file_id`.
"""Retrieve the file with `provided` path.

The path is expected to be `storage_name/file_id`.
"""
upload_storage, file_id = path.split("/")
upload_storage, file_id = cls._get_storage_and_file_id(path)
return StoredFile(StorageManager.get(upload_storage).get_object(file_id))

@classmethod
Expand All @@ -134,7 +135,7 @@ def delete_file(cls, path: str) -> bool:

The path is expected to be `storage_name/file_id`.
"""
upload_storage, file_id = path.split("/")
upload_storage, file_id = cls._get_storage_and_file_id(path)
obj = StorageManager.get(upload_storage).get_object(file_id)
if obj.driver.name == LOCAL_STORAGE_DRIVER_NAME:
"""Try deleting associated metadata file"""
Expand All @@ -145,6 +146,15 @@ def delete_file(cls, path: str) -> bool:

@classmethod
def _clear(cls) -> None:
"""This is only for testing pourposes, resets the StorageManager."""
"""This is only for testing purposes, resets the StorageManager."""
cls._default_storage_name = None
cls._storages = {}

@classmethod
def _get_storage_and_file_id(cls, path: str) -> Tuple[str, str]:
"""Extract the storage name and file_id from the path.

The path is expected to be `storage_name/file_id`.
"""
path_parts = path.split("/")
return "/".join(path_parts[:-1]), path_parts[-1]
19 changes: 19 additions & 0 deletions tests/test_storage_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ class TestStorageManager:
def setup_method(self, method) -> None:
StorageManager._clear()

def test_get_storage_and_file_id(self) -> None:
assert StorageManager._get_storage_and_file_id("storage/file") == (
"storage",
"file",
)
assert StorageManager._get_storage_and_file_id("storage/folder/file") == (
"storage/folder",
"file",
)

def test_first_configured_is_default(self) -> None:
StorageManager.add_storage("first", get_dummy_container("first"))
StorageManager.add_storage("second", get_dummy_container("second"))
Expand All @@ -19,6 +29,15 @@ def test_changing_default_storage_works(self) -> None:
StorageManager.set_default("second")
assert StorageManager.get_default() == "second"

def test_complex_storage_name(self) -> None:
StorageManager.add_storage(
"storage/folder", get_dummy_container("storage/folder")
)
StorageManager.add_storage(
"storage/folder/subfolder", get_dummy_container("storage/folder/subfolder")
)
assert StorageManager.get_default() == "storage/folder"

def test_no_storage_is_detected(self) -> None:
with pytest.raises(RuntimeError):
StorageManager.get_default()
Expand Down
Loading