diff --git a/dandi/misctypes.py b/dandi/misctypes.py index 20887a6ab..9ed2dcf07 100644 --- a/dandi/misctypes.py +++ b/dandi/misctypes.py @@ -345,7 +345,10 @@ def open(self) -> IO[bytes]: # Optional dependency: import fsspec - return cast(IO[bytes], fsspec.open(self.url, mode="rb")) + # We need to call open() on the return value of fsspec.open() because + # otherwise the filehandle will only be opened when used to enter a + # context manager. + return cast(IO[bytes], fsspec.open(self.url, mode="rb").open()) def get_size(self) -> int: return self.size diff --git a/dandi/tests/test_dandiapi.py b/dandi/tests/test_dandiapi.py index 0aa9e8170..4d354b809 100644 --- a/dandi/tests/test_dandiapi.py +++ b/dandi/tests/test_dandiapi.py @@ -25,7 +25,13 @@ dandiset_identifier_regex, dandiset_metadata_file, ) -from ..dandiapi import DandiAPIClient, RemoteAsset, RemoteZarrAsset, Version +from ..dandiapi import ( + DandiAPIClient, + RemoteAsset, + RemoteBlobAsset, + RemoteZarrAsset, + Version, +) from ..download import download from ..exceptions import NotFoundError, SchemaVersionError from ..files import GenericAsset, dandi_file @@ -745,3 +751,21 @@ def test_rename_type_mismatch(text_dandiset: SampleDandiset, dest: str) -> None: assert asset1a.get_raw_metadata()["path"] == "file.txt" with pytest.raises(NotFoundError): text_dandiset.dandiset.get_asset_by_path(dest) + + +def test_asset_as_readable_open(new_dandiset: SampleDandiset, tmp_path: Path) -> None: + p = tmp_path / "foo.txt" + # Write bytes so that the LF doesn't get converted on Windows: + p.write_bytes(b"This is test text.\n") + d = new_dandiset.dandiset + d.upload_raw_asset(p, {"path": "foo.txt"}) + (asset,) = d.get_assets() + assert isinstance(asset, RemoteBlobAsset) + # The purpose of this test is to check that RemoteReadableAsset.open() + # returns a filehandle that can immediately be used, so don't use a `with` + # block here, as that opens fsspec file objects. + fp = asset.as_readable().open() + try: + assert fp.read() == b"This is test text.\n" + finally: + fp.close()