Skip to content

Commit 68e19a2

Browse files
authored
Fix earthaccess.EarthAccessFile method lookup (#620)
1 parent 4510ac1 commit 68e19a2

File tree

6 files changed

+49
-25
lines changed

6 files changed

+49
-25
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
- Removed Broken Link "Introduction to NASA earthaccess"
3737
([#779](https://github.com/nsidc/earthaccess/issues/779))
3838
([**@Sherwin-14**](https://github.com/Sherwin-14))
39+
* Remove the base class on `EarthAccessFile` to fix method resolution
40+
([#610](https://github.com/nsidc/earthaccess/issues/610))
41+
([**@itcarroll**](https://github.com/itcarroll))
3942

4043
### Removed
4144

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Documentation for `EarthAccessFile`
2+
3+
::: earthaccess.store.EarthAccessFile
4+
options:
5+
inherited_members: true
6+
show_root_heading: true
7+
show_source: false

earthaccess/api.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from .auth import Auth
1212
from .results import DataCollection, DataGranule
1313
from .search import CollectionQuery, DataCollections, DataGranules, GranuleQuery
14-
from .store import Store
14+
from .store import EarthAccessFile, Store
1515
from .system import PROD, System
1616
from .utils import _validation as validate
1717

@@ -242,8 +242,8 @@ def download(
242242
def open(
243243
granules: Union[List[str], List[DataGranule]],
244244
provider: Optional[str] = None,
245-
) -> List[AbstractFileSystem]:
246-
"""Returns a list of fsspec file-like objects that can be used to access files
245+
) -> List[EarthAccessFile]:
246+
"""Returns a list of file-like objects that can be used to access files
247247
hosted on S3 or HTTPS by third party libraries like xarray.
248248
249249
Parameters:
@@ -252,7 +252,7 @@ def open(
252252
provider: e.g. POCLOUD, NSIDC_CPRD, etc.
253253
254254
Returns:
255-
a list of s3fs "file pointers" to s3 files.
255+
A list of "file pointers" to remote (i.e. s3 or https) files.
256256
"""
257257
provider = _normalize_location(provider)
258258
results = earthaccess.__store__.open(granules=granules, provider=provider)

earthaccess/store.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,22 @@
2626
logger = logging.getLogger(__name__)
2727

2828

29-
class EarthAccessFile(fsspec.spec.AbstractBufferedFile):
30-
def __init__(self, f: fsspec.AbstractFileSystem, granule: DataGranule) -> None:
29+
class EarthAccessFile:
30+
"""Handle for a file-like object pointing to an on-prem or Earthdata Cloud granule."""
31+
32+
def __init__(
33+
self, f: fsspec.spec.AbstractBufferedFile, granule: DataGranule
34+
) -> None:
35+
"""EarthAccessFile connects an Earthdata search result with an open file-like object.
36+
37+
No methods exist on the class, which passes all attribute and method calls
38+
directly to the file-like object given during initialization. An instance of
39+
this class can be treated like that file-like object itself.
40+
41+
Parameters:
42+
f: a file-like object
43+
granule: a granule search result
44+
"""
3145
self.f = f
3246
self.granule = granule
3347

@@ -43,14 +57,14 @@ def __reduce__(self) -> Any:
4357
)
4458

4559
def __repr__(self) -> str:
46-
return str(self.f)
60+
return repr(self.f)
4761

4862

4963
def _open_files(
5064
url_mapping: Mapping[str, Union[DataGranule, None]],
5165
fs: fsspec.AbstractFileSystem,
5266
threads: Optional[int] = 8,
53-
) -> List[fsspec.AbstractFileSystem]:
67+
) -> List[EarthAccessFile]:
5468
def multi_thread_open(data: tuple) -> EarthAccessFile:
5569
urls, granule = data
5670
return EarthAccessFile(fs.open(urls), granule)
@@ -322,17 +336,17 @@ def open(
322336
self,
323337
granules: Union[List[str], List[DataGranule]],
324338
provider: Optional[str] = None,
325-
) -> List[Any]:
326-
"""Returns a list of fsspec file-like objects that can be used to access files
339+
) -> List[EarthAccessFile]:
340+
"""Returns a list of file-like objects that can be used to access files
327341
hosted on S3 or HTTPS by third party libraries like xarray.
328342
329343
Parameters:
330-
granules: a list of granules(DataGranule) instances or list of URLs,
331-
e.g. s3://some-granule
332-
provider: an option
344+
granules: a list of granule instances **or** list of URLs, e.g. `s3://some-granule`.
345+
If a list of URLs is passed, we need to specify the data provider.
346+
provider: e.g. POCLOUD, NSIDC_CPRD, etc.
333347
334348
Returns:
335-
A list of s3fs "file pointers" to s3 files.
349+
A list of "file pointers" to remote (i.e. s3 or https) files.
336350
"""
337351
if len(granules):
338352
return self._open(granules, provider)
@@ -344,17 +358,6 @@ def _open(
344358
granules: Union[List[str], List[DataGranule]],
345359
provider: Optional[str] = None,
346360
) -> List[Any]:
347-
"""Returns a list of fsspec file-like objects that can be used to access files
348-
hosted on S3 or HTTPS by third party libraries like xarray.
349-
350-
Parameters:
351-
granules: a list of granules(DataGranule) instances or list of URLs,
352-
e.g. s3://some-granule
353-
provider: an option
354-
355-
Returns:
356-
A list of s3fs "file pointers" to s3 files.
357-
"""
358361
raise NotImplementedError("granules should be a list of DataGranule or URLs")
359362

360363
@_open.register

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ nav:
100100
- "Granule Queries": "user-reference/granules/granules-query.md"
101101
- "Granule Results": "user-reference/granules/granules.md"
102102
- Store:
103+
- "EarthAccessFile": "user-reference/store/earthaccessfile.md"
103104
- "Store": "user-reference/store/store.md"
104105
- Auth:
105106
- "Auth": "user-reference/auth/auth.md"

tests/unit/test_store.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import responses
88
import s3fs
99
from earthaccess import Auth, Store
10+
from earthaccess.store import EarthAccessFile
1011

1112

1213
class TestStoreSessions(unittest.TestCase):
@@ -126,3 +127,12 @@ def test_store_can_create_s3_fsspec_session(self):
126127
store.get_s3_filesystem()
127128

128129
return None
130+
131+
132+
def test_earthaccess_file_getattr():
133+
fs = fsspec.filesystem("memory")
134+
with fs.open("/foo", "wb") as f:
135+
earthaccess_file = EarthAccessFile(f, granule="foo")
136+
assert f.tell() == earthaccess_file.tell()
137+
# cleanup
138+
fs.store.clear()

0 commit comments

Comments
 (0)