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
3 changes: 2 additions & 1 deletion src/datajoint/builtin_codecs/attach.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ def decode(self, stored: bytes, *, key: dict | None = None) -> str:
# Write to download path
config = (key or {}).get("_config")
if config is None:
from ..settings import config
from ..settings import config # type: ignore[assignment]
assert config is not None
download_path = Path(config.get("download_path", "."))
download_path.mkdir(parents=True, exist_ok=True)
local_path = download_path / filename
Expand Down
3 changes: 2 additions & 1 deletion src/datajoint/builtin_codecs/filepath.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ def encode(self, value: Any, *, key: dict | None = None, store_name: str | None

config = (key or {}).get("_config")
if config is None:
from ..settings import config
from ..settings import config # type: ignore[assignment]
assert config is not None

path = str(value)

Expand Down
2 changes: 1 addition & 1 deletion src/datajoint/declare.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def prepare_declare(
adapter,
fk_attribute_map,
)
elif re.match(r"^(unique\s+)?index\s*.*$", line, re.I): # index
elif re.match(r"^(unique\s+)?index\s*\(.*\)$", line, re.I): # index
compile_index(line, index_sql, adapter)
else:
name, sql, store, comment = compile_attribute(line, in_key, foreign_key_sql, context, adapter)
Expand Down
23 changes: 15 additions & 8 deletions src/datajoint/hash_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@
datajoint.gc : Garbage collection for orphaned storage items.
"""

from __future__ import annotations

import base64
import hashlib
import logging
from typing import Any
from typing import TYPE_CHECKING, Any

from .errors import DataJointError
from .storage import StorageBackend

if TYPE_CHECKING:
from .settings import Config

logger = logging.getLogger(__name__.split(".")[0])


Expand Down Expand Up @@ -130,7 +135,7 @@ def build_hash_path(
return f"_hash/{schema_name}/{content_hash}"


def get_store_backend(store_name: str | None = None, config=None) -> StorageBackend:
def get_store_backend(store_name: str | None = None, config: Config | None = None) -> StorageBackend:
"""
Get a StorageBackend for hash-addressed storage.

Expand All @@ -147,13 +152,14 @@ def get_store_backend(store_name: str | None = None, config=None) -> StorageBack
StorageBackend instance.
"""
if config is None:
from .settings import config
from .settings import config # type: ignore[assignment]
assert config is not None
# get_store_spec handles None by using stores.default
spec = config.get_store_spec(store_name)
return StorageBackend(spec)


def get_store_subfolding(store_name: str | None = None, config=None) -> tuple[int, ...] | None:
def get_store_subfolding(store_name: str | None = None, config: Config | None = None) -> tuple[int, ...] | None:
"""
Get the subfolding configuration for a store.

Expand All @@ -170,7 +176,8 @@ def get_store_subfolding(store_name: str | None = None, config=None) -> tuple[in
Subfolding pattern (e.g., (2, 2)) or None for flat storage.
"""
if config is None:
from .settings import config
from .settings import config # type: ignore[assignment]
assert config is not None
spec = config.get_store_spec(store_name)
subfolding = spec.get("subfolding")
if subfolding is not None:
Expand All @@ -182,7 +189,7 @@ def put_hash(
data: bytes,
schema_name: str,
store_name: str | None = None,
config=None,
config: Config | None = None,
) -> dict[str, Any]:
"""
Store content using hash-addressed storage.
Expand Down Expand Up @@ -231,7 +238,7 @@ def put_hash(
}


def get_hash(metadata: dict[str, Any], config=None) -> bytes:
def get_hash(metadata: dict[str, Any], config: Config | None = None) -> bytes:
"""
Retrieve content using stored metadata.

Expand Down Expand Up @@ -275,7 +282,7 @@ def get_hash(metadata: dict[str, Any], config=None) -> bytes:
def delete_path(
path: str,
store_name: str | None = None,
config=None,
config: Config | None = None,
) -> bool:
"""
Delete content at the specified path from storage.
Expand Down
14 changes: 10 additions & 4 deletions tests/integration/test_declare.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,14 +339,20 @@ class WithSuchALongPartNameThatItCrashesMySQL(dj.Part):
schema_any(WhyWouldAnyoneCreateATableNameThisLong)


def test_regex_mismatch(schema_any):
def test_index_attribute_name(schema_any):
"""Attributes named 'index' should not be misclassified as index declarations (#1411)."""

class IndexAttribute(dj.Manual):
definition = """
index: int
index : int
---
index_value : float
"""

with pytest.raises(dj.DataJointError):
schema_any(IndexAttribute)
schema_any(IndexAttribute)
assert "index" in IndexAttribute.heading.attributes
assert "index_value" in IndexAttribute.heading.attributes
IndexAttribute.drop()


def test_table_name_with_underscores(schema_any):
Expand Down
Loading