Skip to content
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
10 changes: 10 additions & 0 deletions aiofiledol/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,17 @@ def _resolve_key(store, k):
This REPLACES ``store._id_of_key(k)`` -- it walks the whole chain including the
leaf, so the two must never be composed. For an un-wrapped store no layer defines
``_id_of_key`` and ``k`` is returned verbatim.

A key the store itself already accepts (a path under its ``rootdir``) is also
taken verbatim. ``wrapped_self`` cannot tell whether a method was reached through
a wrapper or called on the inner store directly, so without this guard merely
WRAPPING an instance -- ``wrap_kvs(bare_store, ...)`` -- would make that instance's
own absolute-key ``aget``/``asetitem`` push the key through the wrapper's
``id_of_key`` a second time (``rootdir + rootdir + name``). Relative keys never
match an absolute ``rootdir`` pattern, so they still get resolved.
"""
if store.is_valid_key(k):
return k
return inner_most_key(wrapped_self(store), k, default=k)


Expand Down
44 changes: 44 additions & 0 deletions aiofiledol/tests/test_relative_path_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,47 @@ def test_bare_reader_still_takes_absolute_keys(tmp_path, monkeypatch):

s = AioFileBytesReader(rootdir, max_levels=0)
assert asyncio.run(s.aget(os.path.join(rootdir, KEY))) == REAL


def test_bare_store_keeps_absolute_keys_after_being_instance_wrapped(
tmp_path, monkeypatch
):
"""Wrapping an instance must not change what that instance's own methods do.

``wrapped_self`` climbs from the bare store to any live wrapper of it, so the
bare store's absolute key used to be pushed through the wrapper's ``id_of_key``
too, reading ``rootdir + rootdir + name``.
"""
from dol import wrap_kvs

rootdir = _store_dir(tmp_path, "realstore", REAL)
monkeypatch.chdir(_store_dir(tmp_path, "elsewhere"))

bare = AioFileBytesReader(rootdir, max_levels=0)
wrapped = wrap_kvs(
bare,
id_of_key=lambda k: rootdir + k,
key_of_id=lambda _id: _id[len(rootdir) :],
)

assert asyncio.run(wrapped.aget(KEY)) == REAL # through the wrapper
assert asyncio.run(bare.aget(os.path.join(rootdir, KEY))) == REAL # directly


def test_bare_persister_writes_where_told_after_being_instance_wrapped(tmp_path):
from dol import wrap_kvs

from aiofiledol import AioFileBytesPersister

rootdir = _store_dir(tmp_path, "realstore")
bare = AioFileBytesPersister(rootdir, max_levels=0)
_wrapped = wrap_kvs(
bare,
id_of_key=lambda k: rootdir + k,
key_of_id=lambda _id: _id[len(rootdir) :],
)

target = os.path.join(rootdir, KEY)
asyncio.run(bare.asetitem(target, REAL))
with open(target, "rb") as fp:
assert fp.read() == REAL
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ classifiers = [
"Framework :: AsyncIO",
]
dependencies = [
"dol",
"dol>=0.3.50", # wrapped_self (dol#18) first shipped in 0.3.50
"aiofile",
]

Expand Down
Loading