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: 10 additions & 0 deletions earthaccess/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,13 @@ class ServiceOutage(Exception):
"""

pass


class EulaNotAccepted(DownloadFailure):
"""The user has not accepted the EULA.

This should be raised when a user attempts to access data that requires
EULA acceptance, but they have not accepted the EULA.
"""

pass
11 changes: 10 additions & 1 deletion earthaccess/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from .auth import Auth
from .daac import DAAC_TEST_URLS, find_provider
from .exceptions import DownloadFailure, EulaNotAccepted
from .results import DataGranule
from .search import DataCollections

Expand Down Expand Up @@ -847,7 +848,15 @@ def _download_file(self, url: str, directory: Path) -> Path:
self._clone_session_in_local_thread(original_session)
session = self.thread_locals.local_thread_session
with session.get(url, stream=True, allow_redirects=True) as r:
r.raise_for_status()
if r.status_code in [401, 403]:
text = (r.text or "").lower()
if "eula" in text:
raise EulaNotAccepted(f"Eula Acceptance Failure for {url}")
if r.status_code >= 400:
raise DownloadFailure(
f"Download failed for {url}. Status code: {r.status_code}"
)

with open(path, "wb") as f:
# Cap memory usage for large files at 1MB per write to disk per thread
# https://docs.python-requests.org/en/latest/user/quickstart/#raw-response-content
Expand Down
92 changes: 92 additions & 0 deletions tests/unit/test_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,102 @@
import s3fs
from earthaccess import Auth, Store
from earthaccess.auth import SessionWithHeaderRedirection
from earthaccess.exceptions import DownloadFailure, EulaNotAccepted
from earthaccess.store import EarthAccessFile, _open_files
from pqdm.threads import pqdm


class TestEula(unittest.TestCase):
@patch.dict(
os.environ,
{
"EARTHDATA_USERNAME": "user_no_eula",
"EARTHDATA_PASSWORD": "password",
},
clear=True,
)
@responses.activate
def setUp(self):
json_response = {"access_token": "EDL-token-1", "expiration_date": "12/15/2021"}
responses.add(
responses.GET,
"https://urs.earthdata.nasa.gov/profile",
json=json_response,
status=200,
)
responses.add(
responses.POST,
"https://urs.earthdata.nasa.gov/api/users/find_or_create_token",
json=json_response,
status=200,
)

self.auth = Auth()
self.auth.login(strategy="environment")
assert self.auth.authenticated

@responses.activate
def test_eula_detects_401_errors(self):
response = " blah blah Eula bing!"
mocked_url = "https://example.com/protected_file.nc"
responses.add(
responses.GET,
"https://urs.earthdata.nasa.gov/profile",
json={},
status=200,
)
responses.add(
responses.GET,
url=mocked_url,
body=response,
status=401,
)
store = Store(self.auth)
with self.assertRaisesRegex(
EulaNotAccepted, f"Eula Acceptance Failure for {mocked_url}"
):
store.get([mocked_url], "/tmp")

@responses.activate
def test_detects_non_eula_errors(self):
response = " blah blah error!"
mocked_url = "https://example.com/protected_file.nc"
responses.add(
responses.GET,
"https://urs.earthdata.nasa.gov/profile",
json={},
status=200,
)
responses.add(
responses.GET,
url=mocked_url,
body=response,
status=401,
)
store = Store(self.auth)
with self.assertRaisesRegex(
DownloadFailure, f"Download failed for {mocked_url}. Status code: 401"
):
store.get([mocked_url], "/tmp")

def tearDown(self):
self.auth = None

@responses.activate
def test_store_can_create_https_fsspec_session(self):
responses.add(
responses.GET,
"https://urs.earthdata.nasa.gov/profile",
json={},
status=200,
)
store = Store(self.auth)
assert isinstance(store.auth, Auth)
https_fs = store.get_fsspec_session()
assert type(https_fs) is type(fsspec.filesystem("https"))
return None


class TestStoreSessions(unittest.TestCase):
@responses.activate
@patch.dict(
Expand Down