Skip to content

Commit 50b8026

Browse files
committed
chore: add base file_keeper:proxy adapter
1 parent 3e82968 commit 50b8026

File tree

8 files changed

+108
-17
lines changed

8 files changed

+108
-17
lines changed

docs/adapters/proxy.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

docs/configuration.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,6 @@ No specific settings
156156

157157
[opendal operators]: https://opendal.apache.org/docs/python/api/operator/
158158

159-
### `file_keeper:proxy`
160-
161-
| Setting | Type | Default | Description |
162-
|-----------|------|---------|-------------------------------------|
163-
| `adapter` | str | `None` | Name of the proxified adapter. |
164-
| `options` | dict | `{}` | Settings for the proxified adapter. |
165-
166-
167159
### `file_keeper:redis`
168160

169161
| Setting | Type | Default | Description |

mkdocs.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ nav:
9696
- adapters/fs.md
9797
- adapters/memory.md
9898
- adapters/null.md
99-
- adapters/proxy.md
10099
- adapters/redis.md
101100
- adapters/sqlalchemy.md
102101
- adapters/zip.md

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ self = ["file_keeper"]
117117
addopts = "-p no:ckan"
118118
markers = [
119119
"fk_storage_option: modify storage configuration",
120+
"expect_storage_capability: test relies on given capability available in the storage fixture"
120121
]
121122

122123
[tool.pyright]

src/file_keeper/default/adapters/memory.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Memory adapter."""
2+
23
from __future__ import annotations
34

45
import dataclasses
@@ -25,8 +26,9 @@ class Settings(fk.Settings):
2526

2627
class Uploader(fk.Uploader):
2728
"""Memory uploader."""
29+
2830
storage: MemoryStorage
29-
capabilities: fk.Capability = fk.Capability.UPLOADER_CAPABILITIES
31+
capabilities: fk.Capability = fk.Capability.CREATE | fk.Capability.MULTIPART
3032

3133
@override
3234
def upload(self, location: fk.Location, upload: fk.Upload, extras: dict[str, Any]) -> fk.FileData:
@@ -107,8 +109,18 @@ def multipart_complete(self, data: fk.FileData, extras: dict[str, Any]) -> fk.Fi
107109

108110
class Manager(fk.Manager):
109111
"""Memory manager."""
112+
110113
storage: MemoryStorage
111-
capabilities: fk.Capability = fk.Capability.MANAGER_CAPABILITIES
114+
capabilities: fk.Capability = (
115+
fk.Capability.ANALYZE
116+
| fk.Capability.SCAN
117+
| fk.Capability.COPY
118+
| fk.Capability.MOVE
119+
| fk.Capability.APPEND
120+
| fk.Capability.COMPOSE
121+
| fk.Capability.EXISTS
122+
| fk.Capability.REMOVE
123+
)
112124

113125
@override
114126
def remove(self, data: fk.FileData, extras: dict[str, Any]) -> bool:
@@ -189,6 +201,7 @@ def analyze(self, location: fk.Location, extras: dict[str, Any]) -> fk.FileData:
189201

190202
class Reader(fk.Reader):
191203
"""Memory reader."""
204+
192205
storage: MemoryStorage
193206
capabilities: fk.Capability = fk.Capability.READER_CAPABILITIES
194207

src/file_keeper/default/adapters/null.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Null adapter."""
2+
23
from __future__ import annotations
34

45
import dataclasses
@@ -20,6 +21,7 @@ class Settings(fk.Settings):
2021

2122
class Uploader(fk.Uploader):
2223
"""Null uploader."""
24+
2325
storage: NullStorage
2426
capabilities: fk.Capability = fk.Capability.UPLOADER_CAPABILITIES
2527

@@ -48,9 +50,26 @@ def multipart_complete(self, data: fk.FileData, extras: dict[str, Any]) -> fk.Fi
4850
def multipart_remove(self, data: fk.FileData, extras: dict[str, Any]) -> bool:
4951
return False
5052

53+
@override
54+
def resumable_start(self, data: fk.FileData, extras: dict[str, Any]) -> fk.FileData:
55+
return super().resumable_start(data, extras)
56+
57+
@override
58+
def resumable_refresh(self, data: fk.FileData, extras: dict[str, Any]) -> fk.FileData:
59+
return super().resumable_refresh(data, extras)
60+
61+
@override
62+
def resumable_resume(self, data: fk.FileData, extras: dict[str, Any]) -> fk.FileData:
63+
return super().resumable_resume(data, extras)
64+
65+
@override
66+
def resumable_remove(self, data: fk.FileData, extras: dict[str, Any]) -> bool:
67+
return super().resumable_remove(data, extras)
68+
5169

5270
class Manager(fk.Manager):
5371
"""Null manager."""
72+
5473
storage: NullStorage
5574
capabilities: fk.Capability = fk.Capability.MANAGER_CAPABILITIES
5675

@@ -86,9 +105,14 @@ def scan(self, extras: dict[str, Any]) -> Iterable[str]:
86105
def analyze(self, location: fk.Location, extras: dict[str, Any]) -> fk.FileData:
87106
return fk.FileData(location)
88107

108+
@override
109+
def signed(self, action: fk.SignedAction, duration: int, location: fk.Location, extras: dict[str, Any]) -> str:
110+
return location
111+
89112

90113
class Reader(fk.Reader):
91114
"""Null reader."""
115+
92116
storage: NullStorage
93117
capabilities: fk.Capability = fk.Capability.READER_CAPABILITIES
94118

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,41 @@
11
"""Proxy-storage adapter."""
2+
23
from __future__ import annotations
34

5+
import dataclasses
6+
from collections.abc import Mapping
7+
from typing import Any, ClassVar
8+
49
import file_keeper as fk
510

6-
# settings:
7-
# * adapter(str)
8-
# * options(dict)
11+
12+
@dataclasses.dataclass
13+
class Settings(fk.Settings):
14+
"""Proxy settings."""
15+
16+
options: dict[str, Any] = dataclasses.field(default_factory=dict)
17+
18+
storage: fk.Storage = None # pyright: ignore[reportAssignmentType]
19+
20+
def __post_init__(self, **kwargs: Any):
21+
super().__post_init__(**kwargs)
22+
23+
if not self.storage:
24+
self.storage = fk.make_storage(self.name, self.options)
925

1026

1127
@fk.Storage.register
1228
class ProxyStorage:
1329
"""Wrapper for other storages."""
30+
1431
hidden = True
32+
ProxySettingsFactory: ClassVar[type[Settings]] = Settings
33+
proxy_settings: Settings
34+
35+
def __init__(self, settings: Mapping[str, Any] | Settings, /):
36+
self.proxy_settings = ( # pyright: ignore[reportAttributeAccessIssue]
37+
settings if isinstance(settings, Settings) else self.ProxySettingsFactory.from_dict(settings)
38+
)
39+
40+
def __getattr__(self, name: str):
41+
return getattr(self.proxy_settings.storage, name)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from __future__ import annotations
2+
3+
from pathlib import Path
4+
from typing import Any
5+
6+
import pytest
7+
from faker import Faker
8+
9+
import file_keeper as fk
10+
import file_keeper.default.adapters.proxy as proxy
11+
12+
Settings = proxy.Settings
13+
Storage = proxy.ProxyStorage
14+
15+
16+
@pytest.fixture
17+
def storage(storage_settings: dict[str, Any]):
18+
settings = {"options": {"type": "file_keeper:memory"}}
19+
settings.update(storage_settings)
20+
21+
return Storage(settings)
22+
23+
24+
class TestSettings:
25+
def test_creation(self, tmp_path: Path): ...
26+
27+
28+
class TestStorage:
29+
def test_basic(self, storage: fk.Storage, faker: Faker):
30+
assert isinstance(storage.proxy_settings.storage, fk.adapters["file_keeper:memory"]) # pyright: ignore[reportAttributeAccessIssue]
31+
32+
assert storage.settings is storage.proxy_settings.storage.settings # pyright: ignore[reportAttributeAccessIssue]
33+
34+
content = faker.binary(100)
35+
info = storage.upload(fk.Location("test"), fk.make_upload(content))
36+
37+
assert storage.content(info) == content
38+
assert storage.proxy_settings.storage.content(info) == content # pyright: ignore[reportAttributeAccessIssue]

0 commit comments

Comments
 (0)