From ab73e65f385dcfef429805794caadc8bd4c4d338 Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Fri, 16 Feb 2024 13:23:37 -0500 Subject: [PATCH 1/6] refactor: use token to extract project_id --- pytest_gee/__init__.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/pytest_gee/__init__.py b/pytest_gee/__init__.py index b765043..863f6ee 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,17 +31,25 @@ 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: + # Extract the project name from credentials + _credentials = json.loads(credential_file_path.read_text()) + project_id = _credentials.get("project_id", _credentials.get("project", None)) + project_id = project_id or os.environ.get( + "EARTHENGINE_PROJECT", ee.data._cloud_api_user_project + ) + + if not project_id: raise ValueError( "The project name cannot be detected." "Please set the EARTHENGINE_PROJECT environment variable." From 6613dc0dc6088530dc3eb3e7cb648ef949f67e8f Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Fri, 16 Feb 2024 15:26:14 -0500 Subject: [PATCH 2/6] refactor(__init__.py): project cannot be retreived from ee.data_cloud... if the project has not been initialized --- pytest_gee/__init__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pytest_gee/__init__.py b/pytest_gee/__init__.py index 863f6ee..140cdf0 100644 --- a/pytest_gee/__init__.py +++ b/pytest_gee/__init__.py @@ -31,7 +31,6 @@ 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. """ - credential_folder_path = Path.home() / ".config" / "earthengine" credential_file_path = credential_folder_path / "credentials" @@ -45,14 +44,13 @@ def init_ee_from_token(): # Extract the project name from credentials _credentials = json.loads(credential_file_path.read_text()) project_id = _credentials.get("project_id", _credentials.get("project", None)) - project_id = project_id or os.environ.get( - "EARTHENGINE_PROJECT", ee.data._cloud_api_user_project - ) + project_id = project_id or os.environ.get("EARTHENGINE_PROJECT", None) if not project_id: - raise ValueError( - "The project name cannot be detected." - "Please set the EARTHENGINE_PROJECT environment variable." + 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 From 4ad391419827f86c09a85d8f930f979362f4e25c Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Fri, 16 Feb 2024 16:15:10 -0500 Subject: [PATCH 3/6] feat: create a dedicated test when gee init from token --- .github/workflows/unit.yaml | 1 + tests/conftest.py | 7 ++++- tests/test_pytest_gee.py | 57 +++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) 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/tests/conftest.py b/tests/conftest.py index 9428ff7..d16e39d 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,10 @@ 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() + + 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..307c5ef 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,57 @@ def test_hash_fixture(gee_hash): assert len(gee_hash) == 32 +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 From eb854169664d9511d55e106b9f31442ddc0fb734 Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Fri, 16 Feb 2024 16:19:18 -0500 Subject: [PATCH 4/6] feat: make init with earthengine token optional as well --- tests/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index d16e39d..4dc4bbd 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,7 +13,8 @@ def pytest_configure(): if os.getenv("EARTHENGINE_SERVICE_ACCOUNT"): pytest_gee.init_ee_from_service_account() - pytest_gee.init_ee_from_token() + if os.getenv("EARTHENGINE_TOKEN"): + pytest_gee.init_ee_from_token() @pytest.fixture(scope="session") From 6e9594e6a564b32ce888b15cc8fa95ae5b7573ec Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Mon, 26 Feb 2024 16:08:16 +0100 Subject: [PATCH 5/6] feat: skip test if not earthengine token --- tests/test_pytest_gee.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_pytest_gee.py b/tests/test_pytest_gee.py index 307c5ef..7398535 100644 --- a/tests/test_pytest_gee.py +++ b/tests/test_pytest_gee.py @@ -16,6 +16,7 @@ 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()) From e1214b998e40f67cc8610a67b70801871bb94f4e Mon Sep 17 00:00:00 2001 From: dfguerrerom Date: Tue, 27 Feb 2024 10:36:22 +0100 Subject: [PATCH 6/6] feat: prioritize PROJECT env variable over credentials project --- pytest_gee/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pytest_gee/__init__.py b/pytest_gee/__init__.py index 140cdf0..ff60062 100644 --- a/pytest_gee/__init__.py +++ b/pytest_gee/__init__.py @@ -43,8 +43,9 @@ def init_ee_from_token(): # Extract the project name from credentials _credentials = json.loads(credential_file_path.read_text()) - project_id = _credentials.get("project_id", _credentials.get("project", None)) - project_id = project_id or os.environ.get("EARTHENGINE_PROJECT", None) + project_id = os.environ.get( + "EARTHENGINE_PROJECT", _credentials.get("project_id", _credentials.get("project", None)) + ) if not project_id: raise NameError(