Skip to content

Commit

Permalink
Enabled support for colon character in HAzureBlockBlobStore
Browse files Browse the repository at this point in the history
  • Loading branch information
Timo Strunk authored and Timo Strunk committed Mar 5, 2024
1 parent b5e2d9e commit 726c396
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 10 deletions.
8 changes: 8 additions & 0 deletions minimalkv/_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@
Allowed are all alphanumeric characters, as well as ``!"`#$%&'()+,-.<=>?@[]^_{}~/``. and spaces"""
VALID_KEY_RE_EXTENDED = re.compile(VALID_KEY_REGEXP_EXTENDED)
"""A compiled version of :data:`~minimalkv._constants.VALID_KEY_REGEXP_EXTENDED`."""

VALID_KEY_REGEXP_COLON_EXTENDED = "^[%s0-9a-zA-Z:]+$" % re.escape(
VALID_NON_NUM_EXTENDED
)
"""This regular expression is the same as :data:`~minimalkv._constants.VALID_KEY_REGEXP_EXTENDED`
but also allows a colon."""
VALID_KEY_RE_COLON_EXTENDED = re.compile(VALID_KEY_REGEXP_COLON_EXTENDED)
"""A compiled version of :data:`~minimalkv._constants.VALID_KEY_REGEXP_COLON_EXTENDED`."""
4 changes: 2 additions & 2 deletions minimalkv/_hstores.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os

from minimalkv._mixins import ExtendedKeyspaceMixin
from minimalkv._mixins import ExtendedKeyspaceMixin, ExtendedKeyspaceMixinColon
from minimalkv.fs import FilesystemStore
from minimalkv.memory import DictStore
from minimalkv.memory.redisstore import RedisStore
Expand All @@ -19,7 +19,7 @@ class HRedisStore(ExtendedKeyspaceMixin, RedisStore): # noqa D
pass


class HAzureBlockBlobStore(ExtendedKeyspaceMixin, AzureBlockBlobStore): # noqa D
class HAzureBlockBlobStore(ExtendedKeyspaceMixinColon, AzureBlockBlobStore): # noqa D
pass


Expand Down
39 changes: 36 additions & 3 deletions minimalkv/_mixins.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import abc
import re
from io import BytesIO
from typing import BinaryIO, Callable, Optional, Union

from minimalkv._constants import FOREVER, NOT_SET, VALID_KEY_RE_EXTENDED
from minimalkv._constants import (
FOREVER,
NOT_SET,
VALID_KEY_RE_COLON_EXTENDED,
VALID_KEY_RE_EXTENDED,
)


class UrlMixin:
Expand Down Expand Up @@ -387,7 +394,7 @@ def _move(self, source: str, dest: str) -> str:
return dest


class ExtendedKeyspaceMixin:
class ExtendedKeyspaceMixinBase:
"""A mixin to extend the keyspace to allow slashes and spaces in keynames.
Attention: A single / is NOT allowed.
Expand All @@ -397,6 +404,19 @@ class ExtendedKeyspaceMixin:
"""

@property
@abc.abstractmethod
def VALID_KEY_RE(self) -> re.Pattern:
"""
Method returning a compiled regular expression to validate the key
Returns
-------
re.Pattern:
Expression to validate against
"""
raise NotImplementedError("Implement this property in child classes")

def _check_valid_key(self, key: Optional[str]) -> None:
"""Check if a key is valid and raises a ValueError if its not.
Expand All @@ -412,5 +432,18 @@ def _check_valid_key(self, key: Optional[str]) -> None:
if key is not None:
if not isinstance(key, str):
raise ValueError("%r is not a valid key type" % key)
elif not VALID_KEY_RE_EXTENDED.match(key) or key == "/":
elif not self.VALID_KEY_RE.match(key) or key == "/":
breakpoint()
raise ValueError("%r contains illegal characters" % key)


class ExtendedKeyspaceMixin(ExtendedKeyspaceMixinBase):
@property
def VALID_KEY_RE(self) -> re.Pattern:
return VALID_KEY_RE_EXTENDED


class ExtendedKeyspaceMixinColon(ExtendedKeyspaceMixinBase):
@property
def VALID_KEY_RE(self) -> re.Pattern:
return VALID_KEY_RE_COLON_EXTENDED
2 changes: 2 additions & 0 deletions minimalkv/contrib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from minimalkv._constants import (
VALID_KEY_RE_COLON_EXTENDED,
VALID_KEY_RE_EXTENDED,
VALID_KEY_REGEXP_EXTENDED,
VALID_NON_NUM_EXTENDED,
Expand All @@ -9,5 +10,6 @@
"VALID_NON_NUM_EXTENDED",
"VALID_KEY_REGEXP_EXTENDED",
"VALID_KEY_RE_EXTENDED",
"VALID_KEY_RE_COLON_EXTENDED",
"ExtendedKeyspaceMixin",
]
19 changes: 14 additions & 5 deletions tests/test_azure_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from basic_store import BasicStore, OpenSeekTellStore
from conftest import ExtendedKeyspaceTests

from minimalkv._mixins import ExtendedKeyspaceMixin
from minimalkv._hstores import HAzureBlockBlobStore
from minimalkv.net.azurestore import AzureBlockBlobStore

asb = pytest.importorskip("azure.storage.blob")
Expand Down Expand Up @@ -86,10 +86,7 @@ def store(self):
pytest.skip("Compatibility issues with azurite and azure-storage-blob<12")
container = str(uuid())

class ExtendedKeysStore(ExtendedKeyspaceMixin, AzureBlockBlobStore):
pass

with ExtendedKeysStore(
with HAzureBlockBlobStore(
conn_string=conn_string, container=container, public=False
) as store:
yield store
Expand Down Expand Up @@ -139,6 +136,18 @@ def test_azure_dangling_port_explicit_close_multi():
store.close()


@pytest.mark.filterwarnings("error")
def test_azure_colon_compatibility():
container = str(uuid())
conn_string = get_azure_conn_string()
with HAzureBlockBlobStore(conn_string=conn_string, container=container) as store:
if not hasattr(store, "blob_container_client"):
# This test only runs for azurestore_new
return
store.put("Test:file", b"Test data")
assert store.get("Test:file") == b"Test data"


def test_azure_setgetstate():
container = str(uuid())
conn_string = get_azure_conn_string()
Expand Down

0 comments on commit 726c396

Please sign in to comment.