diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml index 1788c49..1d360ef 100644 --- a/.github/workflows/unit.yaml +++ b/.github/workflows/unit.yaml @@ -11,6 +11,7 @@ on: env: EARTHENGINE_SERVICE_ACCOUNT: ${{ secrets.EARTHENGINE_SERVICE_ACCOUNT }} EARTHENGINE_PROJECT: ${{ secrets.EARTHENGINE_PROJECT }} + EARTHENGINE_TOKEN: ${{ secrets.EARTHENGINE_TOKEN }} jobs: lint: diff --git a/pytest_gee/__init__.py b/pytest_gee/__init__.py index b765043..ff60062 100644 --- a/pytest_gee/__init__.py +++ b/pytest_gee/__init__.py @@ -1,4 +1,5 @@ """The init file of the package.""" + from __future__ import annotations import json @@ -30,20 +31,27 @@ def init_ee_from_token(): Note: As all init method of pytest-gee, this method will fallback to a regular ``ee.Initialize()`` if the environment variable is not found e.g. on your local computer. """ - if "EARTHENGINE_TOKEN" in os.environ: + credential_folder_path = Path.home() / ".config" / "earthengine" + credential_file_path = credential_folder_path / "credentials" + + if "EARTHENGINE_TOKEN" in os.environ and not credential_file_path.exists(): # write the token to the appropriate folder ee_token = os.environ["EARTHENGINE_TOKEN"] - credential_folder_path = Path.home() / ".config" / "earthengine" credential_folder_path.mkdir(parents=True, exist_ok=True) - credential_file_path = credential_folder_path / "credentials" credential_file_path.write_text(ee_token) - project_id = os.environ.get("EARTHENGINE_PROJECT", ee.data._cloud_api_user_project) - if project_id is None: - raise ValueError( - "The project name cannot be detected." - "Please set the EARTHENGINE_PROJECT environment variable." + # Extract the project name from credentials + _credentials = json.loads(credential_file_path.read_text()) + project_id = os.environ.get( + "EARTHENGINE_PROJECT", _credentials.get("project_id", _credentials.get("project", None)) + ) + + if not project_id: + raise NameError( + "The project name cannot be detected. " + "Please set the EARTHENGINE_PROJECT environment variable. " + "Or authenticate using `earthengine set_project project_name`." ) # if the user is in local development the authentication should diff --git a/tests/conftest.py b/tests/conftest.py index 9428ff7..4dc4bbd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,7 @@ """Pytest session configuration.""" +import os + import ee import pytest @@ -8,7 +10,11 @@ def pytest_configure(): """Init GEE in the test environment.""" - pytest_gee.init_ee_from_service_account() + if os.getenv("EARTHENGINE_SERVICE_ACCOUNT"): + pytest_gee.init_ee_from_service_account() + + if os.getenv("EARTHENGINE_TOKEN"): + pytest_gee.init_ee_from_token() @pytest.fixture(scope="session") diff --git a/tests/test_pytest_gee.py b/tests/test_pytest_gee.py index af18aa8..7398535 100644 --- a/tests/test_pytest_gee.py +++ b/tests/test_pytest_gee.py @@ -1,5 +1,11 @@ """Test the pytest_gee package.""" + +import json +import os +from pathlib import Path + import ee +import pytest import pytest_gee @@ -10,6 +16,58 @@ def test_hash_fixture(gee_hash): assert len(gee_hash) == 32 +@pytest.mark.skipif("EARTHENGINE_TOKEN" not in os.environ, reason="requires EARTHENGINE_TOKEN") +def test_gee_init_from_token(): + """Test the init_ee_from_token function.""" + credentials_filepath = Path(ee.oauth.get_credentials_path()) + existing = False + + try: + # Reset credentials to force the initialization + # It can be initiated from different imports + ee.data._credentials = None + + # Get the credentials path + + # Remove the credentials file if it exists + if credentials_filepath.exists(): + existing = True + credentials_filepath.rename(credentials_filepath.with_suffix(".json.bak")) + + # Act: Earthengine token should be created + pytest_gee.init_ee_from_token() + + assert credentials_filepath.exists() + + # read the back up and remove the "project_id" key + credentials = json.loads(credentials_filepath.with_suffix(".json.bak").read_text()) + + ## 2. Assert when there's no a project associated + # remove the project_id key if it exists + credentials.pop("project_id", None) + credentials.pop("project", None) + if "EARTHENGINE_PROJECT" in os.environ: + del os.environ["EARTHENGINE_PROJECT"] + + # write the new credentials + credentials_filepath.write_text(json.dumps(credentials)) + + with pytest.raises(NameError) as e: + pytest_gee.init_ee_from_token() + + # Access the exception message via `e.value` + error_message = str(e.value) + assert "The project name cannot be detected" in error_message + + finally: + # restore the file + if existing: + credentials_filepath.with_suffix(".json.bak").rename(credentials_filepath) + + # check that no error is raised + pytest_gee.init_ee_from_token() + + def test_gee_init(): """Test the init_ee_from_token function.""" assert ee.Number(1).getInfo() == 1