Skip to content

Commit 53757db

Browse files
yarikopticclaude
andcommitted
refactor: move imports to top level, document import policy in CLAUDE.md
Move json, h5py, get_nwb_extensions, and _SCHEMA_BAREASSET_HAS_DATASTANDARD imports to module top level in tests. Keep pynwb_utils import deferred in bases.py (heavy transitive deps: h5py/pynwb/hdmf/numpy) per existing convention. Add import guidance to CLAUDE.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 906603e commit 53757db

4 files changed

Lines changed: 10 additions & 16 deletions

File tree

CLAUDE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
3131
- Prefer specific exceptions over generic ones
3232
- For CLI, use click library patterns
3333
- Imports organized: stdlib, third-party, local (alphabetical within groups)
34+
- **Imports must be at the top of the file** — do NOT place imports inside
35+
functions or methods unless there is a concrete reason (circular dependency,
36+
or heavy transitive imports like `pynwb`/`h5py`/`nwbinspector` that would
37+
slow down module load for unrelated code paths). When deferring an import
38+
for weight, add the comment `# Avoid heavy import by importing within function:`.
3439

3540
## Documentation
3641
- Keep docstrings updated when changing function signatures

dandi/files/bases.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ def get_metadata(
520520
metadata.path = self.path
521521
if _SCHEMA_BAREASSET_HAS_DATASTANDARD:
522522
kwargs: dict[str, Any] = dict(nwb_standard)
523-
# Populate NWB extensions (ndx-*) from the h5 specifications group
523+
# Avoid heavy import by importing within function:
524524
from dandi.pynwb_utils import get_nwb_extensions
525525

526526
try:

dandi/tests/test_files.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import json
34
from operator import attrgetter
45
import os
56
from pathlib import Path
@@ -16,6 +17,7 @@
1617
from ..consts import ZARR_MIME_TYPE, dandiset_metadata_file
1718
from ..dandiapi import AssetType, RemoteZarrAsset
1819
from ..exceptions import UnknownAssetError
20+
from ..files.bases import _SCHEMA_BAREASSET_HAS_DATASTANDARD
1921
from ..files import (
2022
BIDSDatasetDescriptionAsset,
2123
DandisetMetadataFile,
@@ -616,8 +618,6 @@ class TestBIDSDatasetDescriptionDataStandard:
616618

617619
@staticmethod
618620
def _make_bids_dd(tmp_path: Path, content: dict) -> BIDSDatasetDescriptionAsset:
619-
import json
620-
621621
dd_path = tmp_path / "dataset_description.json"
622622
dd_path.write_text(json.dumps(content))
623623
return BIDSDatasetDescriptionAsset(
@@ -628,8 +628,6 @@ def _make_bids_dd(tmp_path: Path, content: dict) -> BIDSDatasetDescriptionAsset:
628628

629629
@staticmethod
630630
def _standard_names(metadata): # type: ignore[no-untyped-def]
631-
from ..files.bases import _SCHEMA_BAREASSET_HAS_DATASTANDARD
632-
633631
if not _SCHEMA_BAREASSET_HAS_DATASTANDARD:
634632
pytest.skip("dandischema too old, no dataStandard on BareAsset")
635633
return [s.name for s in (metadata.dataStandard or [])]
@@ -674,8 +672,6 @@ def test_hed_detected_with_list_hedversion(self, tmp_path: Path) -> None:
674672

675673
def test_hed_library_schemas_as_extensions(self, tmp_path: Path) -> None:
676674
"""HED library schemas in list HEDVersion populate extensions."""
677-
from ..files.bases import _SCHEMA_BAREASSET_HAS_DATASTANDARD
678-
679675
if not _SCHEMA_BAREASSET_HAS_DATASTANDARD:
680676
pytest.skip("dandischema too old, no dataStandard on BareAsset")
681677
asset = self._make_bids_dd(

dandi/tests/test_pynwb_utils.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import re
77
from typing import Any, NoReturn
88

9+
import h5py
910
import numpy as np
1011
from pynwb import NWBHDF5IO, NWBFile, TimeSeries
1112

12-
from ..pynwb_utils import _sanitize_nwb_version, nwb_has_external_links
13+
from ..pynwb_utils import _sanitize_nwb_version, get_nwb_extensions, nwb_has_external_links
1314

1415

1516
def test_pynwb_io(simple1_nwb: Path) -> None:
@@ -107,10 +108,6 @@ def test_nwb_has_external_links(tmp_path):
107108

108109
def test_get_nwb_extensions(tmp_path: Path) -> None:
109110
"""Test extraction of NWB extensions from HDF5 specifications group."""
110-
import h5py
111-
112-
from ..pynwb_utils import get_nwb_extensions
113-
114111
h5path = tmp_path / "test.nwb"
115112
with h5py.File(h5path, "w") as f:
116113
specs = f.create_group("specifications")
@@ -133,10 +130,6 @@ def test_get_nwb_extensions(tmp_path: Path) -> None:
133130

134131
def test_get_nwb_extensions_no_specs(tmp_path: Path) -> None:
135132
"""No specifications group returns empty dict."""
136-
import h5py
137-
138-
from ..pynwb_utils import get_nwb_extensions
139-
140133
h5path = tmp_path / "test.nwb"
141134
with h5py.File(h5path, "w") as f:
142135
f.attrs["nwb_version"] = "2.7.0"

0 commit comments

Comments
 (0)