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: 8 additions & 2 deletions dandi/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
from typing import List

from _pytest.config import Config
from _pytest.config.argparsing import Parser
from _pytest.nodes import Item

from .tests.fixtures import * # noqa: F401, F403 # lgtm [py/polluting-import]


def pytest_addoption(parser):
def pytest_addoption(parser: Parser) -> None:
parser.addoption(
"--dandi-api",
action="store_true",
Expand All @@ -10,7 +16,7 @@ def pytest_addoption(parser):
)


def pytest_collection_modifyitems(items, config):
def pytest_collection_modifyitems(items: List[Item], config: Config) -> None:
# Based on <https://pythontesting.net/framework/pytest/pytest-run-tests
# -using-particular-fixture/>
if config.getoption("--dandi-api"):
Expand Down
5 changes: 4 additions & 1 deletion dandi/dandiarchive.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,10 @@ def parse(cls, url: str, *, map_instance: bool = True) -> ParsedDandiURL:
)
)
known_instance = get_instance(settings["map_instance"])
parsed_url.api_url = known_instance.api
assert known_instance.api is not None
parsed_url.api_url = cast(
AnyHttpUrl, parse_obj_as(AnyHttpUrl, known_instance.api)
)
continue # in this run we ignore and match further
elif "instance_name" in groups:
try:
Expand Down
41 changes: 27 additions & 14 deletions dandi/dandiset.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Classes/utilities for support of a dandiset"""
from pathlib import Path
from typing import Optional, Type, TypeVar, Union

from dandischema.models import get_schema_version

Expand All @@ -9,32 +10,34 @@

lgr = get_logger()

D = TypeVar("D", bound="Dandiset")

class Dandiset(object):

class Dandiset:
"""A prototype class for all things dandiset"""

__slots__ = ["metadata", "path", "path_obj", "_metadata_file_obj"]

def __init__(self, path, allow_empty=False):
def __init__(self, path: Union[str, Path], allow_empty: bool = False) -> None:
self.path = str(path)
self.path_obj = Path(path)
if not allow_empty and not (self.path_obj / dandiset_metadata_file).exists():
raise ValueError(f"No dandiset at {path}")

self.metadata = None
self.metadata: Optional[dict] = None
self._metadata_file_obj = self.path_obj / dandiset_metadata_file
self._load_metadata()

@classmethod
def find(cls, path):
def find(cls: Type[D], path: Union[str, Path, None]) -> Optional[D]:
"""Find a dandiset possibly pointing to a directory within it"""
dandiset_path = find_parent_directory_containing(dandiset_metadata_file, path)
# TODO?: identify "class" for the dandiset to use (this one or APIDandiset)
if dandiset_path:
if dandiset_path is not None:
return cls(dandiset_path)
return None

def _load_metadata(self):
def _load_metadata(self) -> None:
if self._metadata_file_obj.exists():
with open(self._metadata_file_obj) as f:
# TODO it would cast 000001 if not explicitly string into
Expand All @@ -44,7 +47,7 @@ def _load_metadata(self):
self.metadata = None

@classmethod
def get_dandiset_record(cls, meta):
def get_dandiset_record(cls, meta: dict) -> str:
dandiset_identifier = cls._get_identifier(meta)
if not dandiset_identifier:
lgr.warning("No identifier for a dandiset was provided in %s", str(meta))
Expand All @@ -61,7 +64,7 @@ def get_dandiset_record(cls, meta):
yaml_rec = yaml_dump(meta)
return header + yaml_rec

def update_metadata(self, meta):
def update_metadata(self, meta: dict) -> None:
"""Update existing metadata record in dandiset.yaml"""
if not meta:
lgr.debug("No updates to metadata, returning")
Expand All @@ -84,7 +87,7 @@ def update_metadata(self, meta):
self._load_metadata()

@classmethod
def _get_identifier(cls, metadata):
def _get_identifier(cls, metadata: dict) -> Optional[str]:
"""Given a metadata record, determine identifier"""
# ATM since we have dichotomy in dandiset metadata schema from drafts
# and from published versions, we will just test both locations
Expand All @@ -108,14 +111,19 @@ def _get_identifier(cls, metadata):
f"with 'propertyID: DANDI': {id_}"
)
id_ = str(id_.get("value", ""))
elif id_.startswith("DANDI:"):
# result of https://github.com/dandi/dandi-cli/pull/348 which
id_ = id_[len("DANDI:") :]
elif id_ is not None:
assert isinstance(id_, str)
if id_.startswith("DANDI:"):
# result of https://github.com/dandi/dandi-cli/pull/348 which
id_ = id_[len("DANDI:") :]

assert id_ is None or isinstance(id_, str)
return id_

@property
def identifier(self):
def identifier(self) -> str:
if self.metadata is None:
raise ValueError("No metadata record found in Dandiset")
id_ = self._get_identifier(self.metadata)
if not id_:
raise ValueError(
Expand All @@ -127,7 +135,12 @@ def identifier(self):
class APIDandiset(Dandiset):
"""A dandiset to replace "classical" Dandiset whenever we migrate to new API based server"""

def __init__(self, path, allow_empty=False, schema_version=None):
def __init__(
self,
path: Union[str, Path],
allow_empty: bool = False,
schema_version: Optional[str] = None,
) -> None:
if schema_version is not None:
current_version = get_schema_version()
if schema_version != current_version:
Expand Down
1 change: 1 addition & 0 deletions dandi/delete.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ def register_url(self, url: str) -> None:
def register_local_path_equivalent(self, instance_name: str, filepath: str) -> None:
instance = get_instance(instance_name)
api_url = instance.api
assert api_url is not None
dandiset_id, asset_path = find_local_asset(filepath)
if not self.set_dandiset(api_url, dandiset_id):
return
Expand Down
Loading