From b9882c1fdff36ffdbe16810f9f2a477df5b39cbb Mon Sep 17 00:00:00 2001 From: andher1802 Date: Wed, 24 Apr 2024 13:23:00 -0500 Subject: [PATCH 01/30] draft workspace mixin --- tests/test_main.py | 4 ++-- up42/auth.py | 15 ++++++------ up42/main.py | 60 +++++++++++++++++++++++++++++++++++++--------- 3 files changed, 59 insertions(+), 20 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index cc7edb3f4..0ef8fddda 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -7,7 +7,7 @@ @pytest.fixture(autouse=True) def setup_auth_mock(auth_mock): - main._auth = auth_mock # pylint: disable=protected-access + main.workspace._auth = auth_mock # pylint: disable=protected-access yield @@ -18,7 +18,7 @@ def test_get_credits_balance(): def test_fails_to_get_auth_safely_if_unauthenticated(): - main._auth = None # pylint: disable=protected-access + main.workspace.auth = None # pylint: disable=protected-access with pytest.raises(ValueError): main.get_auth_safely() diff --git a/up42/auth.py b/up42/auth.py index afa1fe28b..9697435ff 100644 --- a/up42/auth.py +++ b/up42/auth.py @@ -1,6 +1,7 @@ """ UP42 authentication mechanism and base requests functionality """ + import json import pathlib from typing import Callable, Dict, List, Optional, Union @@ -51,10 +52,10 @@ def __init__( username: The username for the UP42 account (email UP42 console). password: Password for the UP42 console login. """ - self.workspace_id: Optional[str] = None + # self.workspace_id: Optional[str] = None credential_sources = get_credential_sources(cfg_file, username, password) self._client = create_client(credential_sources, host.endpoint("/oauth/token")) - self._get_workspace() + # self._get_workspace() logger.info("Authentication with UP42 successful!") @property @@ -65,11 +66,11 @@ def token(self) -> str: def session(self) -> requests.Session: return self._client.session - def _get_workspace(self) -> None: - """Get user id belonging to authenticated account.""" - url = host.endpoint("/users/me") - resp = self.request("GET", url) - self.workspace_id = resp["data"]["id"] + # def _get_workspace(self) -> None: + # """Get user id belonging to authenticated account.""" + # url = host.endpoint("/users/me") + # resp = self.request("GET", url) + # self.workspace_id = resp["data"]["id"] # pylint: disable=dangerous-default-value def _request_helper( diff --git a/up42/main.py b/up42/main.py index 359cfe13b..32a015992 100644 --- a/up42/main.py +++ b/up42/main.py @@ -11,7 +11,52 @@ warnings.simplefilter(action="ignore", category=FutureWarning) -_auth: Optional[up42_auth.Auth] = None +# _auth: Optional[up42_auth.Auth] = None + + +class __Workspace: # pylint: disable=invalid-name + _auth: Optional[up42_auth.Auth] = None + + @property + def auth(self): + if self._auth: + return self._auth + raise ValueError("User not authenticated.") + + @auth.setter + def auth(self, value): + self._auth = value + + @property + def workspace_id(self): + """Get user id belonging to authenticated account.""" + url = host.endpoint("/users/me") + resp = self.auth.request("GET", url) + return resp["data"]["id"] + + def authenticate( + self, + cfg_file: Optional[Union[str, pathlib.Path]] = None, + username: Optional[str] = None, + password: Optional[str] = None, + ): + """ + Authenticate with UP42, either using account credentials or a config JSON file + containing the corresponding credentials. + + Args: + cfg_file: File path to the cfg.json with {username: "...", password: "..."}. + username: The username for the UP42 account (email UP42 console). + password: Password for the UP42 console login. + """ + self._auth = up42_auth.Auth( + cfg_file=cfg_file, + username=username, + password=password, + ) + + +workspace = __Workspace() def authenticate( @@ -29,18 +74,11 @@ def authenticate( username: The username for the UP42 account (email UP42 console). password: Password for the UP42 console login. """ - global _auth - _auth = up42_auth.Auth( - cfg_file=cfg_file, - username=username, - password=password, - ) + workspace.authenticate(cfg_file=cfg_file, username=username, password=password) def get_auth_safely() -> up42_auth.Auth: - if _auth: - return _auth - raise ValueError("User not authenticated.") + return workspace.auth def check_auth(func): @@ -51,7 +89,7 @@ def check_auth(func): @functools.wraps(func) # required for mkdocstrings def inner(*args, **kwargs): - if _auth is None: + if workspace.auth is None: raise RuntimeError("Not authenticated, call up42.authenticate() first") return func(*args, **kwargs) From 728e72adea1ad94fbbf0b31d073f12079f3db42a Mon Sep 17 00:00:00 2001 From: andher1802 Date: Wed, 24 Apr 2024 14:46:39 -0500 Subject: [PATCH 02/30] passing pylint --- tests/test_main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 0ef8fddda..6e387b2ea 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -7,7 +7,7 @@ @pytest.fixture(autouse=True) def setup_auth_mock(auth_mock): - main.workspace._auth = auth_mock # pylint: disable=protected-access + main.workspace.auth = auth_mock yield @@ -18,7 +18,7 @@ def test_get_credits_balance(): def test_fails_to_get_auth_safely_if_unauthenticated(): - main.workspace.auth = None # pylint: disable=protected-access + main.workspace.auth = None with pytest.raises(ValueError): main.get_auth_safely() From fcacf086924b5bbb78eea7f6aaa233bc23225cea Mon Sep 17 00:00:00 2001 From: andher1802 Date: Tue, 30 Apr 2024 11:14:58 +0200 Subject: [PATCH 03/30] adding workspace_id to workspace --- tests/test_auth.py | 2 +- tests/test_main.py | 2 +- up42/__init__.py | 4 +-- up42/initialization.py | 18 ++++-------- up42/main.py | 67 ++++++++---------------------------------- up42/order.py | 7 +++-- 6 files changed, 27 insertions(+), 73 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index 4ac54baea..59f476c51 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -96,7 +96,7 @@ def create_auth(requests_mock: req_mock.Mocker): class TestAuth: def test_should_authenticate_when_created(self, requests_mock: req_mock.Mocker): auth = create_auth(requests_mock) - assert auth.workspace_id == constants.WORKSPACE_ID + # assert auth.workspace_id == constants.WORKSPACE_ID assert auth.token == constants.TOKEN assert auth.session == session diff --git a/tests/test_main.py b/tests/test_main.py index 6e387b2ea..905ed2f2c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -20,7 +20,7 @@ def test_get_credits_balance(): def test_fails_to_get_auth_safely_if_unauthenticated(): main.workspace.auth = None with pytest.raises(ValueError): - main.get_auth_safely() + _ = main.workspace.auth def test_get_webhook_events(requests_mock): diff --git a/up42/__init__.py b/up42/__init__.py index 5f1200580..a68761127 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -29,7 +29,7 @@ initialize_tasking, initialize_webhook, ) -from up42.main import authenticate, create_webhook, get_credits_balance, get_webhook_events, get_webhooks +from up42.main import create_webhook, get_credits_balance, get_webhook_events, get_webhooks from up42.order import Order from up42.storage import Storage from up42.tasking import Tasking @@ -57,10 +57,10 @@ initialize_order, initialize_asset, initialize_webhook, - authenticate, get_webhooks, create_webhook, get_webhook_events, get_credits_balance, ] + if hasattr(obj, "__name__") ] diff --git a/up42/initialization.py b/up42/initialization.py index 11d13cd07..3f31f6e2e 100644 --- a/up42/initialization.py +++ b/up42/initialization.py @@ -8,61 +8,55 @@ INITIALIZED_MSG = "Initialized %s" -@main.check_auth def initialize_catalog() -> catalog.Catalog: """ Returns a Catalog object for using the catalog search. """ - return catalog.Catalog(auth=main.get_auth_safely()) + return catalog.Catalog(auth=main.workspace.auth) -@main.check_auth def initialize_tasking() -> "tasking.Tasking": """ Returns a Tasking object for creating satellite tasking orders. """ - return tasking.Tasking(auth=main.get_auth_safely()) + return tasking.Tasking(auth=main.workspace.auth) -@main.check_auth def initialize_storage() -> storage.Storage: """ Returns a Storage object to list orders and assets. """ - return storage.Storage(auth=main.get_auth_safely()) + return storage.Storage(auth=main.workspace.auth) -@main.check_auth def initialize_order(order_id: str) -> order.Order: """ Returns an Order object (has to exist on UP42). Args: order_id: The UP42 order_id """ - up42_order = order.Order(auth=main.get_auth_safely(), order_id=order_id) + up42_order = order.Order(auth=main.workspace.auth, order_id=order_id) logger.info(INITIALIZED_MSG, up42_order) return up42_order -@main.check_auth def initialize_asset(asset_id: str) -> asset.Asset: """ Returns an Asset object (has to exist on UP42). Args: asset_id: The UP42 asset_id """ - up42_asset = asset.Asset(auth=main.get_auth_safely(), asset_id=asset_id) + up42_asset = asset.Asset(auth=main.workspace.auth, asset_id=asset_id) logger.info(INITIALIZED_MSG, up42_asset) return up42_asset -@main.check_auth def initialize_webhook(webhook_id: str) -> webhooks.Webhook: """ Returns a Webhook object (has to exist on UP42). Args: webhook_id: The UP42 webhook_id """ - webhook = webhooks.Webhook(auth=main.get_auth_safely(), webhook_id=webhook_id) + webhook = webhooks.Webhook(auth=main.workspace.auth, webhook_id=webhook_id) logger.info(INITIALIZED_MSG, webhook) return webhook diff --git a/up42/main.py b/up42/main.py index 32a015992..165f465b7 100644 --- a/up42/main.py +++ b/up42/main.py @@ -1,4 +1,3 @@ -import functools import logging import pathlib import warnings @@ -11,11 +10,10 @@ warnings.simplefilter(action="ignore", category=FutureWarning) -# _auth: Optional[up42_auth.Auth] = None - class __Workspace: # pylint: disable=invalid-name _auth: Optional[up42_auth.Auth] = None + workspace_id: Optional[str] = None @property def auth(self): @@ -27,13 +25,6 @@ def auth(self): def auth(self, value): self._auth = value - @property - def workspace_id(self): - """Get user id belonging to authenticated account.""" - url = host.endpoint("/users/me") - resp = self.auth.request("GET", url) - return resp["data"]["id"] - def authenticate( self, cfg_file: Optional[Union[str, pathlib.Path]] = None, @@ -49,54 +40,23 @@ def authenticate( username: The username for the UP42 account (email UP42 console). password: Password for the UP42 console login. """ + self._set_workspace_id() self._auth = up42_auth.Auth( cfg_file=cfg_file, username=username, password=password, ) + def _set_workspace_id(self): + """Get user id belonging to authenticated account.""" + url = host.endpoint("/users/me") + resp = self.auth.request("GET", url) + self.workspace_id = resp["data"]["id"] -workspace = __Workspace() - - -def authenticate( - cfg_file: Optional[Union[str, pathlib.Path]] = None, - username: Optional[str] = None, - password: Optional[str] = None, -): - """ - Authenticate with UP42, either using account credentials or a config JSON file - containing the corresponding credentials. - Also see the documentation https://sdk.up42.com/authentication/ - - Args: - cfg_file: File path to the cfg.json with {username: "...", password: "..."}. - username: The username for the UP42 account (email UP42 console). - password: Password for the UP42 console login. - """ - workspace.authenticate(cfg_file=cfg_file, username=username, password=password) - - -def get_auth_safely() -> up42_auth.Auth: - return workspace.auth - - -def check_auth(func): - """ - Some functionality of the up42 import object can theoretically be used - before authentication with UP42, so the auth needs to be checked first. - """ - - @functools.wraps(func) # required for mkdocstrings - def inner(*args, **kwargs): - if workspace.auth is None: - raise RuntimeError("Not authenticated, call up42.authenticate() first") - return func(*args, **kwargs) - return inner +workspace = __Workspace() -@check_auth def get_webhooks(return_json: bool = False) -> List[webhooks.Webhook]: """ Gets all registered webhooks for this workspace. @@ -106,10 +66,9 @@ def get_webhooks(return_json: bool = False) -> List[webhooks.Webhook]: Returns: A list of the registered webhooks for this workspace. """ - return webhooks.Webhooks(auth=get_auth_safely()).get_webhooks(return_json=return_json) + return webhooks.Webhooks(auth=workspace.auth).get_webhooks(return_json=return_json) -@check_auth def create_webhook( name: str, url: str, @@ -129,12 +88,11 @@ def create_webhook( Returns: A dict with details of the registered webhook. """ - return webhooks.Webhooks(auth=get_auth_safely()).create_webhook( + return webhooks.Webhooks(auth=workspace.auth).create_webhook( name=name, url=url, events=events, active=active, secret=secret ) -@check_auth def get_webhook_events() -> dict: """ Gets all available webhook events. @@ -142,10 +100,9 @@ def get_webhook_events() -> dict: Returns: A dict of the available webhook events. """ - return webhooks.Webhooks(auth=get_auth_safely()).get_webhook_events() + return webhooks.Webhooks(auth=workspace.auth).get_webhook_events() -@check_auth def get_credits_balance() -> dict: """ Display the overall credits available in your account. @@ -154,5 +111,5 @@ def get_credits_balance() -> dict: A dict with the balance of credits available in your account. """ endpoint_url = host.endpoint("/accounts/me/credits/balance") - response_json = get_auth_safely().request(request_type="GET", url=endpoint_url) + response_json = workspace.auth.request(request_type="GET", url=endpoint_url) return response_json["data"] diff --git a/up42/order.py b/up42/order.py index 96f53f206..7856805b0 100644 --- a/up42/order.py +++ b/up42/order.py @@ -2,6 +2,7 @@ import time from typing import Any, Dict, List, Optional, TypedDict +import up42.main from up42 import asset, asset_searcher from up42 import auth as up42_auth from up42 import host, utils @@ -140,7 +141,7 @@ def place(cls, auth: up42_auth.Auth, order_parameters: dict) -> "Order": Returns: Order: The placed order. """ - url = host.endpoint(f"/v2/orders?workspaceId={auth.workspace_id}") + url = host.endpoint(f"/v2/orders?workspaceId={up42.main.workspace.workspace_id}") response_json = auth.request( request_type="POST", url=url, @@ -175,7 +176,9 @@ def estimate(auth: up42_auth.Auth, order_parameters: OrderParams) -> int: ) estimated_credits: int = response_json["summary"]["totalCredits"] logger.info( - "Order is estimated to cost %s UP42 credits (order_parameters: %s)", estimated_credits, order_parameters + "Order is estimated to cost %s UP42 credits (order_parameters: %s)", + estimated_credits, + order_parameters, ) return estimated_credits From 709b631159e86213864436a07653d8997b4cdd08 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Tue, 30 Apr 2024 11:23:22 +0200 Subject: [PATCH 04/30] modeling user not authenticated error. --- up42/main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/up42/main.py b/up42/main.py index 165f465b7..af6c963e3 100644 --- a/up42/main.py +++ b/up42/main.py @@ -11,6 +11,10 @@ warnings.simplefilter(action="ignore", category=FutureWarning) +class UserNotAuthenticated(ValueError): + pass + + class __Workspace: # pylint: disable=invalid-name _auth: Optional[up42_auth.Auth] = None workspace_id: Optional[str] = None @@ -19,7 +23,7 @@ class __Workspace: # pylint: disable=invalid-name def auth(self): if self._auth: return self._auth - raise ValueError("User not authenticated.") + raise UserNotAuthenticated("User not authenticated.") @auth.setter def auth(self, value): From 41376c69f0fd4fbc552b950ad3fe407eb814cb70 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Tue, 30 Apr 2024 11:32:31 +0200 Subject: [PATCH 05/30] removing from auth the workspace code. --- up42/auth.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/up42/auth.py b/up42/auth.py index 9697435ff..79dec0c8a 100644 --- a/up42/auth.py +++ b/up42/auth.py @@ -52,10 +52,8 @@ def __init__( username: The username for the UP42 account (email UP42 console). password: Password for the UP42 console login. """ - # self.workspace_id: Optional[str] = None credential_sources = get_credential_sources(cfg_file, username, password) self._client = create_client(credential_sources, host.endpoint("/oauth/token")) - # self._get_workspace() logger.info("Authentication with UP42 successful!") @property @@ -66,12 +64,6 @@ def token(self) -> str: def session(self) -> requests.Session: return self._client.session - # def _get_workspace(self) -> None: - # """Get user id belonging to authenticated account.""" - # url = host.endpoint("/users/me") - # resp = self.request("GET", url) - # self.workspace_id = resp["data"]["id"] - # pylint: disable=dangerous-default-value def _request_helper( self, From 287d9c55074275d3c1e367528af12f12073b6918 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 2 May 2024 13:07:28 +0200 Subject: [PATCH 06/30] addressing comments and fix tests --- tests/fixtures/fixtures_auth.py | 4 +++- tests/fixtures/fixtures_webhook.py | 12 ++++++------ tests/test_initialization.py | 12 ++++++------ tests/test_order.py | 4 ++-- tests/test_storage.py | 4 ++-- up42/__init__.py | 3 ++- up42/catalog.py | 3 ++- up42/main.py | 6 ++---- up42/order.py | 5 ++--- up42/storage.py | 18 ++++++++++++------ up42/webhooks.py | 5 +++-- 11 files changed, 42 insertions(+), 34 deletions(-) diff --git a/tests/fixtures/fixtures_auth.py b/tests/fixtures/fixtures_auth.py index fda1ea1f1..7814cc5fd 100644 --- a/tests/fixtures/fixtures_auth.py +++ b/tests/fixtures/fixtures_auth.py @@ -1,6 +1,7 @@ import pytest import requests_mock as req_mock +import up42.main from up42 import auth as up42_auth from . import fixtures_globals as constants @@ -24,4 +25,5 @@ def auth_mock(requests_mock: req_mock.Mocker) -> up42_auth.Auth: url=url_get_credits_balance, json=constants.JSON_BALANCE, ) - return up42_auth.Auth(username=constants.USER_EMAIL, password=constants.PASSWORD) + up42.main.workspace.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) + return up42.main.workspace.auth diff --git a/tests/fixtures/fixtures_webhook.py b/tests/fixtures/fixtures_webhook.py index 726cd9cbe..cf9c0c9b4 100644 --- a/tests/fixtures/fixtures_webhook.py +++ b/tests/fixtures/fixtures_webhook.py @@ -8,11 +8,11 @@ @pytest.fixture def webhook_mock(auth_mock, requests_mock): # webhook info - url_webhook_info = f"{constants.API_HOST}/workspaces/{auth_mock.workspace_id}/webhooks/{constants.WEBHOOK_ID}" + url_webhook_info = f"{constants.API_HOST}/workspaces/{constants.WORKSPACE_ID}/webhooks/{constants.WEBHOOK_ID}" requests_mock.get(url=url_webhook_info, json=constants.JSON_WEBHOOK) # test event - url_test_event = f"{constants.API_HOST}/workspaces/{auth_mock.workspace_id}/webhooks/{constants.WEBHOOK_ID}/tests" + url_test_event = f"{constants.API_HOST}/workspaces/{constants.WORKSPACE_ID}/webhooks/{constants.WEBHOOK_ID}/tests" json_test_event = { "data": { "startedAt": "2022-06-20T04:33:48.770826Z", @@ -23,11 +23,11 @@ def webhook_mock(auth_mock, requests_mock): requests_mock.post(url=url_test_event, json=json_test_event) # update - url_update = f"{constants.API_HOST}/workspaces/{auth_mock.workspace_id}/webhooks/{constants.WEBHOOK_ID}" + url_update = f"{constants.API_HOST}/workspaces/{constants.WORKSPACE_ID}/webhooks/{constants.WEBHOOK_ID}" requests_mock.put(url=url_update, json=constants.JSON_WEBHOOK) # delete - url_delete = f"{constants.API_HOST}/workspaces/{auth_mock.workspace_id}/webhooks/{constants.WEBHOOK_ID}" + url_delete = f"{constants.API_HOST}/workspaces/{constants.WORKSPACE_ID}/webhooks/{constants.WEBHOOK_ID}" requests_mock.delete(url=url_delete) return webhooks.Webhook(auth=auth_mock, webhook_id=constants.WEBHOOK_ID) @@ -41,7 +41,7 @@ def webhooks_mock(auth_mock, requests_mock): requests_mock.get(url=url_events, json=events_json) # get webhooks - url_webhooks = f"{constants.API_HOST}/workspaces/{auth_mock.workspace_id}/webhooks" + url_webhooks = f"{constants.API_HOST}/workspaces/{constants.WORKSPACE_ID}/webhooks" webhooks_json = { "data": [ { @@ -70,7 +70,7 @@ def webhooks_mock(auth_mock, requests_mock): requests_mock.get(url=url_webhooks, json=webhooks_json) # create webhook - url_create_webhook = f"{constants.API_HOST}/workspaces/{auth_mock.workspace_id}/webhooks" + url_create_webhook = f"{constants.API_HOST}/workspaces/{constants.WORKSPACE_ID}/webhooks" requests_mock.post(url=url_create_webhook, json=constants.JSON_WEBHOOK) return webhooks.Webhooks(auth=auth_mock) diff --git a/tests/test_initialization.py b/tests/test_initialization.py index 5345da5fb..8eb021520 100644 --- a/tests/test_initialization.py +++ b/tests/test_initialization.py @@ -7,15 +7,15 @@ def test_initialize_object_without_auth_raises(): - main._auth = None # pylint: disable=protected-access + main.workspace.auth = None # pylint: disable=protected-access - with pytest.raises(RuntimeError): + with pytest.raises(main.UserNotAuthenticated): up42.initialize_catalog() - with pytest.raises(RuntimeError): + with pytest.raises(main.UserNotAuthenticated): up42.initialize_storage() - with pytest.raises(RuntimeError): + with pytest.raises(main.UserNotAuthenticated): up42.initialize_order(order_id=constants.ORDER_ID) - with pytest.raises(RuntimeError): + with pytest.raises(main.UserNotAuthenticated): up42.initialize_asset(asset_id=constants.ASSET_ID) @@ -24,7 +24,7 @@ def test_global_auth_initialize_objects( order_mock, asset_mock, ): - up42.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) + up42.main.workspace.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) catalog_obj = up42.initialize_catalog() assert isinstance(catalog_obj, catalog.Catalog) storage_obj = up42.initialize_storage() diff --git a/tests/test_order.py b/tests/test_order.py index f004cd4c9..0c67e96a1 100644 --- a/tests/test_order.py +++ b/tests/test_order.py @@ -111,7 +111,7 @@ def test_place_order(catalog_order_parameters, auth_mock, order_mock, requests_m "errors": [], }, ) - order_placed = order.Order.place(auth_mock, catalog_order_parameters) + order_placed = order.Order.place(auth_mock, catalog_order_parameters, constants.WORKSPACE_ID) assert order_placed == order_mock assert order_placed.order_id == constants.ORDER_ID assert order_placed.order_parameters == catalog_order_parameters @@ -127,7 +127,7 @@ def test_place_order_fails_if_response_contains_error(catalog_order_parameters, }, ) with pytest.raises(ValueError) as err: - order.Order.place(auth_mock, catalog_order_parameters) + order.Order.place(auth_mock, catalog_order_parameters, constants.WORKSPACE_ID) assert error_content in str(err.value) diff --git a/tests/test_storage.py b/tests/test_storage.py index d1929fb17..36bc736a7 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -272,7 +272,7 @@ def test_get_orders_v2_endpoint_params(auth_mock, requests_mock, params, expecte url_params = "&".join( [ "sort=createdAt%2Cdesc", - f"workspaceId={constants.WORKSPACE_ID}" if params["workspace_orders"] else "", + (f"workspaceId={constants.WORKSPACE_ID}" if params["workspace_orders"] else ""), f"""displayName={params["name"]}""" if params["name"] else "", *[f"status={status}" for status in endpoint_statuses], "size=50", @@ -328,7 +328,7 @@ def test_get_orders_pagination(auth_mock, requests_mock): # assets pages url_storage_orders_paginated = ( - f"{constants.API_HOST}/v2/orders?sort=createdAt,asc&workspaceId={auth_mock.workspace_id}&size=50" + f"{constants.API_HOST}/v2/orders?sort=createdAt,asc&workspaceId={constants.WORKSPACE_ID}&size=50" ) requests_mock.get(url=url_storage_orders_paginated, json=json_orders_paginated) diff --git a/up42/__init__.py b/up42/__init__.py index a68761127..4f89ee9aa 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -29,7 +29,7 @@ initialize_tasking, initialize_webhook, ) -from up42.main import create_webhook, get_credits_balance, get_webhook_events, get_webhooks +from up42.main import authenticate, create_webhook, get_credits_balance, get_webhook_events, get_webhooks from up42.order import Order from up42.storage import Storage from up42.tasking import Tasking @@ -61,6 +61,7 @@ create_webhook, get_webhook_events, get_credits_balance, + authenticate, ] if hasattr(obj, "__name__") ] diff --git a/up42/catalog.py b/up42/catalog.py index d9753f553..2d2096aed 100644 --- a/up42/catalog.py +++ b/up42/catalog.py @@ -11,6 +11,7 @@ import tqdm from shapely import geometry as geom # type: ignore +import up42.main from up42 import auth as up42_auth from up42 import host, order, utils @@ -150,7 +151,7 @@ def place_order( warnings.warn(message, DeprecationWarning, stacklevel=2) elif order_parameters is None: raise ValueError("Please provide the 'order_parameters' parameter!") - placed_order = order.Order.place(self.auth, order_parameters) # type: ignore + placed_order = order.Order.place(self.auth, order_parameters, up42.main.workspace.workspace_id) # type: ignore if track_status: placed_order.track_status(report_time) return placed_order diff --git a/up42/main.py b/up42/main.py index af6c963e3..b9e25618c 100644 --- a/up42/main.py +++ b/up42/main.py @@ -44,15 +44,11 @@ def authenticate( username: The username for the UP42 account (email UP42 console). password: Password for the UP42 console login. """ - self._set_workspace_id() self._auth = up42_auth.Auth( cfg_file=cfg_file, username=username, password=password, ) - - def _set_workspace_id(self): - """Get user id belonging to authenticated account.""" url = host.endpoint("/users/me") resp = self.auth.request("GET", url) self.workspace_id = resp["data"]["id"] @@ -60,6 +56,8 @@ def _set_workspace_id(self): workspace = __Workspace() +authenticate = workspace.authenticate + def get_webhooks(return_json: bool = False) -> List[webhooks.Webhook]: """ diff --git a/up42/order.py b/up42/order.py index 7856805b0..9638fec89 100644 --- a/up42/order.py +++ b/up42/order.py @@ -2,7 +2,6 @@ import time from typing import Any, Dict, List, Optional, TypedDict -import up42.main from up42 import asset, asset_searcher from up42 import auth as up42_auth from up42 import host, utils @@ -130,7 +129,7 @@ def get_assets(self) -> List[asset.Asset]: raise ValueError(f"Order {self.order_id} is not FULFILLED! Current status is {self.status}") @classmethod - def place(cls, auth: up42_auth.Auth, order_parameters: dict) -> "Order": + def place(cls, auth: up42_auth.Auth, order_parameters: dict, workspace_id: str) -> "Order": """ Places an order. @@ -141,7 +140,7 @@ def place(cls, auth: up42_auth.Auth, order_parameters: dict) -> "Order": Returns: Order: The placed order. """ - url = host.endpoint(f"/v2/orders?workspaceId={up42.main.workspace.workspace_id}") + url = host.endpoint(f"/v2/orders?workspaceId={workspace_id}") response_json = auth.request( request_type="POST", url=url, diff --git a/up42/storage.py b/up42/storage.py index 03c95717b..cb18635df 100644 --- a/up42/storage.py +++ b/up42/storage.py @@ -8,9 +8,8 @@ import geopandas # type: ignore from shapely import geometry as shp_geometry # type: ignore -from up42 import asset, asset_searcher -from up42 import auth as up42_auth -from up42 import host, order, stac_client, utils +import up42.main +from up42 import asset, asset_searcher, host, order, stac_client, utils logger = utils.get_logger(__name__) @@ -39,9 +38,9 @@ class Storage: ``` """ - def __init__(self, auth: up42_auth.Auth): + def __init__(self, auth: up42.Auth): self.auth = auth - self.workspace_id = auth.workspace_id + self.workspace_id = up42.main.workspace.workspace_id def __repr__(self): return f"Storage(workspace_id: {self.workspace_id})" @@ -59,7 +58,14 @@ def get_assets( acquired_after: Optional[Union[str, datetime.datetime]] = None, acquired_before: Optional[Union[str, datetime.datetime]] = None, geometry: Optional[ - Union[dict, geojson.Feature, geojson.FeatureCollection, list, geopandas.GeoDataFrame, shp_geometry.Polygon] + Union[ + dict, + geojson.Feature, + geojson.FeatureCollection, + list, + geopandas.GeoDataFrame, + shp_geometry.Polygon, + ] ] = None, workspace_id: Optional[str] = None, collection_names: Optional[List[str]] = None, diff --git a/up42/webhooks.py b/up42/webhooks.py index 5d8c1d984..072b6e459 100644 --- a/up42/webhooks.py +++ b/up42/webhooks.py @@ -1,5 +1,6 @@ from typing import List, Optional +import up42.main from up42 import auth as up42_auth from up42 import host, utils @@ -19,7 +20,7 @@ class Webhook: def __init__(self, auth: up42_auth.Auth, webhook_id: str, webhook_info: Optional[dict] = None): self.auth = auth - self.workspace_id = auth.workspace_id + self.workspace_id = up42.main.workspace.workspace_id self.webhook_id = webhook_id if webhook_info is not None: self._info = webhook_info @@ -116,7 +117,7 @@ class Webhooks: def __init__(self, auth: up42_auth.Auth): self.auth = auth - self.workspace_id = auth.workspace_id + self.workspace_id = up42.main.workspace.workspace_id def get_webhook_events(self) -> dict: """ From 5c2b95efef8bf1b3150df20cd9a5963171fce7a5 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 2 May 2024 13:09:20 +0200 Subject: [PATCH 07/30] removing asseet workspace_id from test_auth --- tests/test_auth.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index 59f476c51..819c6ef36 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -96,7 +96,6 @@ def create_auth(requests_mock: req_mock.Mocker): class TestAuth: def test_should_authenticate_when_created(self, requests_mock: req_mock.Mocker): auth = create_auth(requests_mock) - # assert auth.workspace_id == constants.WORKSPACE_ID assert auth.token == constants.TOKEN assert auth.session == session From 84c4970465398a7af9af378f5ee73e8af98aaa66 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 2 May 2024 13:13:43 +0200 Subject: [PATCH 08/30] restoring authenticate on test initialization and error type fix in test main --- tests/test_initialization.py | 2 +- tests/test_main.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_initialization.py b/tests/test_initialization.py index 8eb021520..bea531c26 100644 --- a/tests/test_initialization.py +++ b/tests/test_initialization.py @@ -24,7 +24,7 @@ def test_global_auth_initialize_objects( order_mock, asset_mock, ): - up42.main.workspace.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) + up42.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) catalog_obj = up42.initialize_catalog() assert isinstance(catalog_obj, catalog.Catalog) storage_obj = up42.initialize_storage() diff --git a/tests/test_main.py b/tests/test_main.py index 905ed2f2c..f27d15069 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -19,7 +19,7 @@ def test_get_credits_balance(): def test_fails_to_get_auth_safely_if_unauthenticated(): main.workspace.auth = None - with pytest.raises(ValueError): + with pytest.raises(main.UserNotAuthenticated): _ = main.workspace.auth From e53b9ce76b25c5e9c8cff8db9a63ee5f5daedd90 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 2 May 2024 13:28:58 +0200 Subject: [PATCH 09/30] removing innecessary fixture from test_main --- tests/test_main.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index f27d15069..1b7f744bd 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -5,13 +5,7 @@ from .fixtures import fixtures_globals as constants -@pytest.fixture(autouse=True) -def setup_auth_mock(auth_mock): - main.workspace.auth = auth_mock - yield - - -def test_get_credits_balance(): +def test_get_credits_balance(auth_mock): # pylint: disable=unused-argument balance = main.get_credits_balance() assert isinstance(balance, dict) assert "balance" in balance @@ -23,7 +17,7 @@ def test_fails_to_get_auth_safely_if_unauthenticated(): _ = main.workspace.auth -def test_get_webhook_events(requests_mock): +def test_get_webhook_events(requests_mock, auth_mock): # pylint: disable=unused-argument url_webhook_events = f"{constants.API_HOST}/webhooks/events" events = ["some-event"] requests_mock.get( From 16eede65259007ffe8c7ec452320ea32fc51c262 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 2 May 2024 13:48:15 +0200 Subject: [PATCH 10/30] updating changelog and version --- CHANGELOG.md | 7 +++++++ pyproject.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e843711f..9e24ac03b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,13 @@ You can check your current version with the following command: ``` For more information, see [UP42 Python package description](https://pypi.org/project/up42-py/). +## 1.1.0a1 + +**May 2, 2024** + +- Adding __Workspace hidden class and worskspace instance as a singleton class in `main.py` +- Changing use of Auth Class for the workspace.auth property where required. + ## 1.0.0 **Apr 17, 2024** diff --git a/pyproject.toml b/pyproject.toml index c67965ca4..f234b4e6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "up42-py" -version = "1.0.0" +version = "1.1.0a1" description = "Python SDK for UP42, the geospatial marketplace and developer platform." authors = ["UP42 GmbH "] license = "https://github.com/up42/up42-py/blob/master/LICENSE" From 4ab4befb120874596ee715d6bb1b719013df489d Mon Sep 17 00:00:00 2001 From: andher1802 Date: Mon, 20 May 2024 18:05:29 +0200 Subject: [PATCH 11/30] fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9be8d366..dce533937 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ For more information, see [UP42 Python package description](https://pypi.org/pro **May 21, 2024** -- Adding __Workspace hidden class and worskspace instance as a singleton class in `main.py` +- Adding __Workspace hidden class and workspace instance as a singleton class in `main.py` - Changing use of Auth Class for the workspace.auth property where required. From 08b02d9164380f34d14627488fa8dd6904b8c417 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Tue, 21 May 2024 08:53:48 +0200 Subject: [PATCH 12/30] updating naming workspace class --- up42/catalog.py | 2 +- up42/main.py | 8 ++++---- up42/storage.py | 7 +++---- up42/webhooks.py | 7 +++---- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/up42/catalog.py b/up42/catalog.py index 2d2096aed..dab730c5a 100644 --- a/up42/catalog.py +++ b/up42/catalog.py @@ -151,7 +151,7 @@ def place_order( warnings.warn(message, DeprecationWarning, stacklevel=2) elif order_parameters is None: raise ValueError("Please provide the 'order_parameters' parameter!") - placed_order = order.Order.place(self.auth, order_parameters, up42.main.workspace.workspace_id) # type: ignore + placed_order = order.Order.place(self.auth, order_parameters, up42.main.workspace.id) # type: ignore if track_status: placed_order.track_status(report_time) return placed_order diff --git a/up42/main.py b/up42/main.py index b9e25618c..17f0112ee 100644 --- a/up42/main.py +++ b/up42/main.py @@ -15,9 +15,9 @@ class UserNotAuthenticated(ValueError): pass -class __Workspace: # pylint: disable=invalid-name +class _Workspace: _auth: Optional[up42_auth.Auth] = None - workspace_id: Optional[str] = None + id: Optional[str] = None @property def auth(self): @@ -51,10 +51,10 @@ def authenticate( ) url = host.endpoint("/users/me") resp = self.auth.request("GET", url) - self.workspace_id = resp["data"]["id"] + self.id = resp["data"]["id"] -workspace = __Workspace() +workspace = _Workspace() authenticate = workspace.authenticate diff --git a/up42/storage.py b/up42/storage.py index cb18635df..3da01d2ea 100644 --- a/up42/storage.py +++ b/up42/storage.py @@ -8,8 +8,7 @@ import geopandas # type: ignore from shapely import geometry as shp_geometry # type: ignore -import up42.main -from up42 import asset, asset_searcher, host, order, stac_client, utils +from up42 import Auth, asset, asset_searcher, host, main, order, stac_client, utils logger = utils.get_logger(__name__) @@ -38,9 +37,9 @@ class Storage: ``` """ - def __init__(self, auth: up42.Auth): + def __init__(self, auth: Auth): self.auth = auth - self.workspace_id = up42.main.workspace.workspace_id + self.workspace_id = main.workspace.id def __repr__(self): return f"Storage(workspace_id: {self.workspace_id})" diff --git a/up42/webhooks.py b/up42/webhooks.py index 072b6e459..8ba768946 100644 --- a/up42/webhooks.py +++ b/up42/webhooks.py @@ -1,8 +1,7 @@ from typing import List, Optional -import up42.main from up42 import auth as up42_auth -from up42 import host, utils +from up42 import host, main, utils logger = utils.get_logger(__name__) @@ -20,7 +19,7 @@ class Webhook: def __init__(self, auth: up42_auth.Auth, webhook_id: str, webhook_info: Optional[dict] = None): self.auth = auth - self.workspace_id = up42.main.workspace.workspace_id + self.workspace_id = main.workspace.id self.webhook_id = webhook_id if webhook_info is not None: self._info = webhook_info @@ -117,7 +116,7 @@ class Webhooks: def __init__(self, auth: up42_auth.Auth): self.auth = auth - self.workspace_id = up42.main.workspace.workspace_id + self.workspace_id = main.workspace.id def get_webhook_events(self) -> dict: """ From 3fbf44c2082fe8a49775f19d376f1856050b8c94 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Wed, 22 May 2024 13:32:03 +0200 Subject: [PATCH 13/30] cleaning test auth for workspace class creation --- tests/test_auth.py | 21 ++++++++------------- tests/test_initialization.py | 2 +- tests/test_main.py | 14 ++++++++------ up42/catalog.py | 5 ++--- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index 819c6ef36..708306fdb 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -13,7 +13,6 @@ CONFIG_FILE = "some-config-file" TOKEN_ENDPOINT = constants.API_HOST + "/oauth/token" -WORKSPACE_ENDPOINT = constants.API_HOST + "/users/me" URL = constants.API_HOST + "/some-url" RESPONSE_TEXT = "some-response-text" ERROR = {"some": "error"} @@ -65,17 +64,13 @@ def test_should_collect_credentials(self): session.headers = cast(MutableMapping[str, Union[str, bytes]], REQUEST_HEADERS) -def create_auth(requests_mock: req_mock.Mocker): +def create_auth(): credential_sources = [{"some": "credentials"}] get_sources = mock.MagicMock(return_value=credential_sources) create_client = mock.MagicMock() create_client.return_value.token = constants.TOKEN create_client.return_value.session = session - requests_mock.get( - WORKSPACE_ENDPOINT, - json={"data": {"id": constants.WORKSPACE_ID}}, - ) auth = up42_auth.Auth( cfg_file=CONFIG_FILE, username=constants.USER_EMAIL, @@ -94,8 +89,8 @@ def create_auth(requests_mock: req_mock.Mocker): class TestAuth: - def test_should_authenticate_when_created(self, requests_mock: req_mock.Mocker): - auth = create_auth(requests_mock) + def test_should_authenticate_when_created(self): + auth = create_auth() assert auth.token == constants.TOKEN assert auth.session == session @@ -114,7 +109,7 @@ def test_should_pass_dict_for_json_response( expected: dict, requests_mock: req_mock.Mocker, ): - auth = create_auth(requests_mock) + auth = create_auth() requests_mock.request( http_method, URL, @@ -127,7 +122,7 @@ def test_should_pass_dict_for_json_response( def test_should_pass_text_for_text_response( self, http_method: str, request_data: dict, requests_mock: req_mock.Mocker ): - auth = create_auth(requests_mock) + auth = create_auth() requests_mock.request( http_method, URL, @@ -138,7 +133,7 @@ def test_should_pass_text_for_text_response( assert auth.request(http_method, URL, request_data) == RESPONSE_TEXT def test_should_pass_response(self, http_method: str, request_data: dict, requests_mock: req_mock.Mocker): - auth = create_auth(requests_mock) + auth = create_auth() requests_mock.request( http_method, URL, @@ -151,7 +146,7 @@ def test_should_pass_response(self, http_method: str, request_data: dict, reques assert response.text == RESPONSE_TEXT def test_fails_if_v1_api_request_fails(self, http_method: str, request_data: dict, requests_mock: req_mock.Mocker): - auth = create_auth(requests_mock) + auth = create_auth() requests_mock.request( http_method, @@ -175,7 +170,7 @@ def test_fails_if_status_code_is_bad( error: Optional[Dict], requests_mock: req_mock.Mocker, ): - auth = create_auth(requests_mock) + auth = create_auth() requests_mock.request( http_method, URL, diff --git a/tests/test_initialization.py b/tests/test_initialization.py index bea531c26..7d1452046 100644 --- a/tests/test_initialization.py +++ b/tests/test_initialization.py @@ -7,7 +7,7 @@ def test_initialize_object_without_auth_raises(): - main.workspace.auth = None # pylint: disable=protected-access + main.workspace.auth = None with pytest.raises(main.UserNotAuthenticated): up42.initialize_catalog() diff --git a/tests/test_main.py b/tests/test_main.py index 1b7f744bd..749339b2a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -6,17 +6,12 @@ def test_get_credits_balance(auth_mock): # pylint: disable=unused-argument + main.workspace.auth = auth_mock balance = main.get_credits_balance() assert isinstance(balance, dict) assert "balance" in balance -def test_fails_to_get_auth_safely_if_unauthenticated(): - main.workspace.auth = None - with pytest.raises(main.UserNotAuthenticated): - _ = main.workspace.auth - - def test_get_webhook_events(requests_mock, auth_mock): # pylint: disable=unused-argument url_webhook_events = f"{constants.API_HOST}/webhooks/events" events = ["some-event"] @@ -40,3 +35,10 @@ def test_get_webhooks(webhooks_mock, return_json): for hook, expected_hook in zip(webhooks, expected): assert hook.webhook_id == expected_hook.webhook_id assert hook._info == expected_hook._info # pylint: disable=protected-access + + +class TestWorkspace: + def test_fails_to_get_auth_safely_if_workspace_not_authenticated(self): + main.workspace.auth = None + with pytest.raises(main.UserNotAuthenticated): + _ = main.workspace.auth diff --git a/up42/catalog.py b/up42/catalog.py index dab730c5a..715aaaee8 100644 --- a/up42/catalog.py +++ b/up42/catalog.py @@ -11,9 +11,8 @@ import tqdm from shapely import geometry as geom # type: ignore -import up42.main from up42 import auth as up42_auth -from up42 import host, order, utils +from up42 import host, main, order, utils logger = utils.get_logger(__name__) @@ -151,7 +150,7 @@ def place_order( warnings.warn(message, DeprecationWarning, stacklevel=2) elif order_parameters is None: raise ValueError("Please provide the 'order_parameters' parameter!") - placed_order = order.Order.place(self.auth, order_parameters, up42.main.workspace.id) # type: ignore + placed_order = order.Order.place(self.auth, order_parameters, main.workspace.id) # type: ignore if track_status: placed_order.track_status(report_time) return placed_order From b3244aa78a6f0dcad16ce905792492434988b647 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Wed, 22 May 2024 13:47:09 +0200 Subject: [PATCH 14/30] fixing auth import pylint --- up42/storage.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/up42/storage.py b/up42/storage.py index 3da01d2ea..fd50166c2 100644 --- a/up42/storage.py +++ b/up42/storage.py @@ -8,7 +8,9 @@ import geopandas # type: ignore from shapely import geometry as shp_geometry # type: ignore -from up42 import Auth, asset, asset_searcher, host, main, order, stac_client, utils +from up42 import asset, asset_searcher +from up42 import auth as up42_auth +from up42 import host, main, order, stac_client, utils logger = utils.get_logger(__name__) @@ -37,7 +39,7 @@ class Storage: ``` """ - def __init__(self, auth: Auth): + def __init__(self, auth: up42_auth.Auth): self.auth = auth self.workspace_id = main.workspace.id From b19da3701f8c541e21bb32007bcb369a952c14b5 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 23 May 2024 14:12:46 +0200 Subject: [PATCH 15/30] restoring __init__.py --- tests/test_main.py | 24 ++++++++++++++++-------- up42/__init__.py | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 749339b2a..00a47c4c5 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -5,13 +5,6 @@ from .fixtures import fixtures_globals as constants -def test_get_credits_balance(auth_mock): # pylint: disable=unused-argument - main.workspace.auth = auth_mock - balance = main.get_credits_balance() - assert isinstance(balance, dict) - assert "balance" in balance - - def test_get_webhook_events(requests_mock, auth_mock): # pylint: disable=unused-argument url_webhook_events = f"{constants.API_HOST}/webhooks/events" events = ["some-event"] @@ -38,7 +31,22 @@ def test_get_webhooks(webhooks_mock, return_json): class TestWorkspace: - def test_fails_to_get_auth_safely_if_workspace_not_authenticated(self): + @pytest.fixture(autouse=True) + def setup_auth_mock(self, auth_mock): + main.workspace.auth = auth_mock + yield + + def test_authenticate_success(self, auth_mock): + main.workspace.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) + assert main.workspace.id == constants.WORKSPACE_ID + assert main.workspace.auth.token == auth_mock.token + + def test_fails_auth_property_without_authentication(self): main.workspace.auth = None with pytest.raises(main.UserNotAuthenticated): _ = main.workspace.auth + + def test_get_credits_balance(self): + balance = main.get_credits_balance() + assert isinstance(balance, dict) + assert "balance" in balance diff --git a/up42/__init__.py b/up42/__init__.py index 4f89ee9aa..c4e8e4a61 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -57,11 +57,11 @@ initialize_order, initialize_asset, initialize_webhook, + authenticate, get_webhooks, create_webhook, get_webhook_events, get_credits_balance, - authenticate, ] if hasattr(obj, "__name__") ] From 6b0e9f7b9c58199d8d466ae137c0558d8de2504c Mon Sep 17 00:00:00 2001 From: Andres Hernandez Date: Thu, 23 May 2024 14:16:23 +0200 Subject: [PATCH 16/30] Update __init__.py --- up42/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/up42/__init__.py b/up42/__init__.py index 4f89ee9aa..5f1200580 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -57,11 +57,10 @@ initialize_order, initialize_asset, initialize_webhook, + authenticate, get_webhooks, create_webhook, get_webhook_events, get_credits_balance, - authenticate, ] - if hasattr(obj, "__name__") ] From 660dc7c50d9cbd907cd6ef024ff419c6f64eb043 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 23 May 2024 15:22:34 +0200 Subject: [PATCH 17/30] adding validation to __init__.py --- up42/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/up42/__init__.py b/up42/__init__.py index 5f1200580..c4e8e4a61 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -63,4 +63,5 @@ get_webhook_events, get_credits_balance, ] + if hasattr(obj, "__name__") ] From bab32021e08e85f313e0a989cbd858ed806d8ed6 Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 23 May 2024 16:43:35 +0200 Subject: [PATCH 18/30] merge master branch --- tests/test_auth.py | 1 - tests/test_main.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index f62b97427..3b9667a06 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -91,7 +91,6 @@ def create_auth(): class TestAuth: def test_should_authenticate_when_created(self): auth = create_auth() - assert auth.token == constants.TOKEN assert auth.session == session @pytest.mark.parametrize( diff --git a/tests/test_main.py b/tests/test_main.py index 00a47c4c5..5e5838a1c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -5,7 +5,7 @@ from .fixtures import fixtures_globals as constants -def test_get_webhook_events(requests_mock, auth_mock): # pylint: disable=unused-argument +def test_get_webhook_events(requests_mock): # pylint: disable=unused-argument url_webhook_events = f"{constants.API_HOST}/webhooks/events" events = ["some-event"] requests_mock.get( @@ -36,10 +36,9 @@ def setup_auth_mock(self, auth_mock): main.workspace.auth = auth_mock yield - def test_authenticate_success(self, auth_mock): + def test_authenticate_success(self): main.workspace.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) assert main.workspace.id == constants.WORKSPACE_ID - assert main.workspace.auth.token == auth_mock.token def test_fails_auth_property_without_authentication(self): main.workspace.auth = None From 6801a6d0ed1bf7fdfc4f52fd0a971f484c99766b Mon Sep 17 00:00:00 2001 From: andher1802 Date: Thu, 23 May 2024 19:48:18 +0200 Subject: [PATCH 19/30] test __init__ --- up42/__init__.py | 9 +++++++-- up42/main.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/up42/__init__.py b/up42/__init__.py index c4e8e4a61..3810bdb1f 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -49,6 +49,12 @@ Storage, Tasking, Webhook, + ] +] + +__all__.extend( + obj.__name__ + for obj in [ get_example_aoi, read_vector_file, initialize_catalog, @@ -63,5 +69,4 @@ get_webhook_events, get_credits_balance, ] - if hasattr(obj, "__name__") -] +) diff --git a/up42/main.py b/up42/main.py index 17f0112ee..e21e70f4f 100644 --- a/up42/main.py +++ b/up42/main.py @@ -34,7 +34,7 @@ def authenticate( cfg_file: Optional[Union[str, pathlib.Path]] = None, username: Optional[str] = None, password: Optional[str] = None, - ): + ) -> None: """ Authenticate with UP42, either using account credentials or a config JSON file containing the corresponding credentials. From a6c1891ebe19a25aa88c389f06da490dcc322b7a Mon Sep 17 00:00:00 2001 From: andher1802 Date: Fri, 24 May 2024 09:02:36 +0200 Subject: [PATCH 20/30] updating changelog date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0512d12c4..00cb814fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,7 @@ You can check your current version with the following command: For more information, see [UP42 Python package description](https://pypi.org/project/up42-py/). ## 1.1.0a1 -**May 21, 2024** +**May 24, 2024** - Adding __Workspace hidden class and workspace instance as a singleton class in `main.py` - Changing use of Auth Class for the workspace.auth property where required. From 65b2fbacf4b0f0d4d4bd4ad183ec525866e6aafe Mon Sep 17 00:00:00 2001 From: andher1802 Date: Fri, 24 May 2024 09:35:44 +0200 Subject: [PATCH 21/30] merge master branch --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2ff43468..0094236a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ For more information, see [UP42 Python package description](https://pypi.org/pro **May 24, 2024** -- Adding __Workspace hidden class and workspace instance as a singleton class in `main.py` +- Adding _Workspace hidden class and workspace instance as a singleton class in `main.py` - Changing use of Auth Class for the workspace.auth property where required. From 85cd8261d46b07fa5336756e6c5bbda95328be00 Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 09:39:11 +0200 Subject: [PATCH 22/30] Simplify test_auth setup --- tests/test_auth.py | 59 ++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/tests/test_auth.py b/tests/test_auth.py index 3b9667a06..36ef53b88 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -66,32 +66,29 @@ def test_should_collect_credentials(self): client.session = session -def create_auth(): - credential_sources = [{"some": "credentials"}] - get_sources = mock.MagicMock(return_value=credential_sources) - create_client = mock.MagicMock(return_value=client) - - auth = up42_auth.Auth( - cfg_file=CONFIG_FILE, - username=constants.USER_EMAIL, - password=constants.PASSWORD, - get_credential_sources=get_sources, - create_client=create_client, - ) - - get_sources.assert_called_once_with( - CONFIG_FILE, - constants.USER_EMAIL, - constants.PASSWORD, - ) - create_client.assert_called_once_with(credential_sources, TOKEN_ENDPOINT) - return auth +class TestAuth: + def setup_method(self, _): + credential_sources = [{"some": "credentials"}] + get_sources = mock.MagicMock(return_value=credential_sources) + create_client = mock.MagicMock(return_value=client) + + self.auth = up42_auth.Auth( + cfg_file=CONFIG_FILE, + username=constants.USER_EMAIL, + password=constants.PASSWORD, + get_credential_sources=get_sources, + create_client=create_client, + ) + get_sources.assert_called_once_with( + CONFIG_FILE, + constants.USER_EMAIL, + constants.PASSWORD, + ) + create_client.assert_called_once_with(credential_sources, TOKEN_ENDPOINT) -class TestAuth: def test_should_authenticate_when_created(self): - auth = create_auth() - assert auth.session == session + assert self.auth.session == session @pytest.mark.parametrize( "expected", @@ -108,7 +105,6 @@ def test_should_pass_dict_for_json_response( expected: dict, requests_mock: req_mock.Mocker, ): - auth = create_auth() requests_mock.request( http_method, URL, @@ -116,12 +112,11 @@ def test_should_pass_dict_for_json_response( json=expected, additional_matcher=match_request_body(request_data), ) - assert auth.request(http_method, URL, request_data) == expected + assert self.auth.request(http_method, URL, request_data) == expected def test_should_pass_text_for_text_response( self, http_method: str, request_data: dict, requests_mock: req_mock.Mocker ): - auth = create_auth() requests_mock.request( http_method, URL, @@ -129,10 +124,9 @@ def test_should_pass_text_for_text_response( text=RESPONSE_TEXT, additional_matcher=match_request_body(request_data), ) - assert auth.request(http_method, URL, request_data) == RESPONSE_TEXT + assert self.auth.request(http_method, URL, request_data) == RESPONSE_TEXT def test_should_pass_response(self, http_method: str, request_data: dict, requests_mock: req_mock.Mocker): - auth = create_auth() requests_mock.request( http_method, URL, @@ -140,13 +134,11 @@ def test_should_pass_response(self, http_method: str, request_data: dict, reques text=RESPONSE_TEXT, additional_matcher=match_request_body(request_data), ) - response = auth.request(http_method, URL, request_data, return_text=False) + response = self.auth.request(http_method, URL, request_data, return_text=False) assert isinstance(response, requests.Response) assert response.text == RESPONSE_TEXT def test_fails_if_v1_api_request_fails(self, http_method: str, request_data: dict, requests_mock: req_mock.Mocker): - auth = create_auth() - requests_mock.request( http_method, URL, @@ -155,7 +147,7 @@ def test_fails_if_v1_api_request_fails(self, http_method: str, request_data: dic additional_matcher=match_request_body(request_data), ) with pytest.raises(ValueError) as exc_info: - auth.request(http_method, URL, request_data) + self.auth.request(http_method, URL, request_data) assert str(exc_info.value) == str(ERROR) @@ -169,7 +161,6 @@ def test_fails_if_status_code_is_bad( error: Optional[Dict], requests_mock: req_mock.Mocker, ): - auth = create_auth() requests_mock.request( http_method, URL, @@ -179,5 +170,5 @@ def test_fails_if_status_code_is_bad( additional_matcher=match_request_body(request_data), ) with pytest.raises(requests.HTTPError) as exc_info: - auth.request(http_method, URL, request_data, return_text=return_text) + self.auth.request(http_method, URL, request_data, return_text=return_text) assert str(exc_info.value) == (json.dumps(error) if error else "") From 275fc2ff328d1c4dcaa72798469ce2301eb61e84 Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 12:01:20 +0200 Subject: [PATCH 23/30] Simplify auth fixtures and workspace properties --- tests/fixtures/fixtures_auth.py | 14 +------------- tests/test_catalog.py | 8 ++++++++ tests/test_initialization.py | 2 -- up42/main.py | 12 +++++++----- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/tests/fixtures/fixtures_auth.py b/tests/fixtures/fixtures_auth.py index 7814cc5fd..4d670646d 100644 --- a/tests/fixtures/fixtures_auth.py +++ b/tests/fixtures/fixtures_auth.py @@ -1,7 +1,6 @@ import pytest import requests_mock as req_mock -import up42.main from up42 import auth as up42_auth from . import fixtures_globals as constants @@ -15,15 +14,4 @@ def auth_mock(requests_mock: req_mock.Mocker) -> up42_auth.Auth: "token_type": "bearer", } requests_mock.post("https://api.up42.com/oauth/token", json=json_get_token) - requests_mock.get( - url="https://api.up42.com/users/me", - json={"data": {"id": constants.WORKSPACE_ID}}, - ) - # get_credits_balance - url_get_credits_balance = f"{constants.API_HOST}/accounts/me/credits/balance" - requests_mock.get( - url=url_get_credits_balance, - json=constants.JSON_BALANCE, - ) - up42.main.workspace.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) - return up42.main.workspace.auth + return up42_auth.Auth(username=constants.USER_EMAIL, password=constants.PASSWORD) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 866ea44f7..79d339b97 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -1,6 +1,7 @@ import json import pathlib import tempfile +from unittest import mock import geopandas as gpd # type: ignore import pytest @@ -16,6 +17,13 @@ mock_search_parameters = json.load(json_file) +@pytest.fixture(autouse=True) +def mock_workspace_id(): + with mock.patch("up42.main.workspace") as mock_workspace: + mock_workspace.id = constants.WORKSPACE_ID + yield + + def test_get_collections(catalog_mock): collections = catalog_mock.get_collections() assert isinstance(collections, list) diff --git a/tests/test_initialization.py b/tests/test_initialization.py index 7d1452046..86ab81493 100644 --- a/tests/test_initialization.py +++ b/tests/test_initialization.py @@ -7,8 +7,6 @@ def test_initialize_object_without_auth_raises(): - main.workspace.auth = None - with pytest.raises(main.UserNotAuthenticated): up42.initialize_catalog() with pytest.raises(main.UserNotAuthenticated): diff --git a/up42/main.py b/up42/main.py index e21e70f4f..f7892fb66 100644 --- a/up42/main.py +++ b/up42/main.py @@ -17,7 +17,7 @@ class UserNotAuthenticated(ValueError): class _Workspace: _auth: Optional[up42_auth.Auth] = None - id: Optional[str] = None + _id: Optional[str] = None @property def auth(self): @@ -25,9 +25,11 @@ def auth(self): return self._auth raise UserNotAuthenticated("User not authenticated.") - @auth.setter - def auth(self, value): - self._auth = value + @property + def id(self): + if self._id: + return self._id + raise UserNotAuthenticated("User not authenticated.") def authenticate( self, @@ -51,7 +53,7 @@ def authenticate( ) url = host.endpoint("/users/me") resp = self.auth.request("GET", url) - self.id = resp["data"]["id"] + self._id = resp["data"]["id"] workspace = _Workspace() From 595ec2a08f70af4e7e4b7143d01b089e1449d983 Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 13:50:33 +0200 Subject: [PATCH 24/30] Test improvements --- tests/fixtures/fixtures_auth.py | 4 +- tests/test_initialization.py | 51 +++++++++---------- tests/test_main.py | 89 +++++++++++++++++++-------------- up42/main.py | 16 +++--- 4 files changed, 86 insertions(+), 74 deletions(-) diff --git a/tests/fixtures/fixtures_auth.py b/tests/fixtures/fixtures_auth.py index 4d670646d..19ffbabc5 100644 --- a/tests/fixtures/fixtures_auth.py +++ b/tests/fixtures/fixtures_auth.py @@ -8,10 +8,10 @@ @pytest.fixture def auth_mock(requests_mock: req_mock.Mocker) -> up42_auth.Auth: - json_get_token = { + token_payload = { "data": {"accessToken": constants.TOKEN}, "access_token": constants.TOKEN, "token_type": "bearer", } - requests_mock.post("https://api.up42.com/oauth/token", json=json_get_token) + requests_mock.post("https://api.up42.com/oauth/token", json=token_payload) return up42_auth.Auth(username=constants.USER_EMAIL, password=constants.PASSWORD) diff --git a/tests/test_initialization.py b/tests/test_initialization.py index 86ab81493..6b328e5a4 100644 --- a/tests/test_initialization.py +++ b/tests/test_initialization.py @@ -1,12 +1,14 @@ +from unittest import mock + import pytest import up42 -from up42 import catalog, main, tasking +from up42 import catalog, main, storage, tasking from .fixtures import fixtures_globals as constants -def test_initialize_object_without_auth_raises(): +def test_fails_to_initialize_if_not_authenticated(): with pytest.raises(main.UserNotAuthenticated): up42.initialize_catalog() with pytest.raises(main.UserNotAuthenticated): @@ -17,32 +19,25 @@ def test_initialize_object_without_auth_raises(): up42.initialize_asset(asset_id=constants.ASSET_ID) -def test_global_auth_initialize_objects( - storage_mock, +def test_should_initialize_objects( + auth_mock, order_mock, asset_mock, ): - up42.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) - catalog_obj = up42.initialize_catalog() - assert isinstance(catalog_obj, catalog.Catalog) - storage_obj = up42.initialize_storage() - assert storage_obj.workspace_id == storage_mock.workspace_id - order_obj = up42.initialize_order(order_id=constants.ORDER_ID) - assert order_obj.info == order_mock.info - asset_obj = up42.initialize_asset(asset_id=constants.ASSET_ID) - assert asset_obj.info == asset_mock.info - - -@pytest.fixture(autouse=True) -def setup_workspace(requests_mock): - requests_mock.post("https://api.up42.com/oauth/token", json={"access_token": constants.TOKEN}) - requests_mock.get( - url="https://api.up42.com/users/me", - json={"data": {"id": constants.WORKSPACE_ID}}, - ) - - -def test_should_initialize_tasking(): - up42.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) - result = up42.initialize_tasking() - assert isinstance(result, tasking.Tasking) + with mock.patch("up42.main.workspace") as workspace_mock: + workspace_mock.id = constants.WORKSPACE_ID + workspace_mock.auth = auth_mock + + catalog_obj = up42.initialize_catalog() + assert isinstance(catalog_obj, catalog.Catalog) + + storage_obj = up42.initialize_storage() + assert isinstance(storage_obj, storage.Storage) + assert storage_obj.workspace_id == constants.WORKSPACE_ID + + order_obj = up42.initialize_order(order_id=constants.ORDER_ID) + assert order_obj.info == order_mock.info + asset_obj = up42.initialize_asset(asset_id=constants.ASSET_ID) + assert asset_obj.info == asset_mock.info + result = up42.initialize_tasking() + assert isinstance(result, tasking.Tasking) diff --git a/tests/test_main.py b/tests/test_main.py index 5e5838a1c..c427b8e39 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,3 +1,5 @@ +from unittest import mock + import pytest from up42 import main @@ -5,47 +7,60 @@ from .fixtures import fixtures_globals as constants -def test_get_webhook_events(requests_mock): # pylint: disable=unused-argument - url_webhook_events = f"{constants.API_HOST}/webhooks/events" - events = ["some-event"] - requests_mock.get( - url=url_webhook_events, - json={ - "data": events, - "error": {}, - }, - ) - assert main.get_webhook_events() == events - +class TestWorkspace: + def test_fails_to_provide_properties_if_not_authenticated(self): + with pytest.raises(main.UserNotAuthenticated): + _ = main.workspace.auth + with pytest.raises(main.UserNotAuthenticated): + _ = main.workspace.id -@pytest.mark.parametrize("return_json", [False, True]) -def test_get_webhooks(webhooks_mock, return_json): - webhooks = main.get_webhooks(return_json=return_json) - expected = webhooks_mock.get_webhooks(return_json=return_json) - if return_json: - assert webhooks == expected - else: - for hook, expected_hook in zip(webhooks, expected): - assert hook.webhook_id == expected_hook.webhook_id - assert hook._info == expected_hook._info # pylint: disable=protected-access + def test_should_authenticate(self, requests_mock): + requests_mock.post("https://api.up42.com/oauth/token", json={"access_token": constants.TOKEN}) + requests_mock.get( + url="https://api.up42.com/users/me", + json={"data": {"id": constants.WORKSPACE_ID}}, + ) + main.workspace.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) + assert main.workspace.id == constants.WORKSPACE_ID -class TestWorkspace: +# TODO: these tests to be moved to test_initialization +class TestNonWorkspace: @pytest.fixture(autouse=True) - def setup_auth_mock(self, auth_mock): - main.workspace.auth = auth_mock - yield + def workspace(self, auth_mock): + with mock.patch("up42.main.workspace") as workspace_mock: + workspace_mock.auth = auth_mock + workspace_mock.id = constants.WORKSPACE_ID + yield - def test_authenticate_success(self): - main.workspace.authenticate(username=constants.USER_EMAIL, password=constants.PASSWORD) - assert main.workspace.id == constants.WORKSPACE_ID + def test_get_webhook_events(self, requests_mock): + url_webhook_events = f"{constants.API_HOST}/webhooks/events" + events = ["some-event"] + requests_mock.get( + url=url_webhook_events, + json={ + "data": events, + "error": {}, + }, + ) + assert main.get_webhook_events() == events - def test_fails_auth_property_without_authentication(self): - main.workspace.auth = None - with pytest.raises(main.UserNotAuthenticated): - _ = main.workspace.auth + @pytest.mark.parametrize("return_json", [False, True]) + def test_get_webhooks(self, webhooks_mock, return_json): + webhooks = main.get_webhooks(return_json=return_json) + expected = webhooks_mock.get_webhooks(return_json=return_json) + if return_json: + assert webhooks == expected + else: + for hook, expected_hook in zip(webhooks, expected): + assert hook.webhook_id == expected_hook.webhook_id + assert hook._info == expected_hook._info # pylint: disable=protected-access + + def test_get_credits_balance(self, requests_mock): + balance_url = f"{constants.API_HOST}/accounts/me/credits/balance" + requests_mock.get( + url=balance_url, + json=constants.JSON_BALANCE, + ) - def test_get_credits_balance(self): - balance = main.get_credits_balance() - assert isinstance(balance, dict) - assert "balance" in balance + assert main.get_credits_balance() == constants.JSON_BALANCE diff --git a/up42/main.py b/up42/main.py index f7892fb66..5b53122c8 100644 --- a/up42/main.py +++ b/up42/main.py @@ -1,7 +1,7 @@ import logging import pathlib import warnings -from typing import List, Optional, Union +from typing import Any, List, Optional, Union from up42 import auth as up42_auth from up42 import host, utils, webhooks @@ -15,21 +15,23 @@ class UserNotAuthenticated(ValueError): pass +def _authenticated(value: Any): + if value: + return value + raise UserNotAuthenticated("User not authenticated.") + + class _Workspace: _auth: Optional[up42_auth.Auth] = None _id: Optional[str] = None @property def auth(self): - if self._auth: - return self._auth - raise UserNotAuthenticated("User not authenticated.") + return _authenticated(self._auth) @property def id(self): - if self._id: - return self._id - raise UserNotAuthenticated("User not authenticated.") + return _authenticated(self._id) def authenticate( self, From ef098a32385cc90342daa6841e818e39cfe72d38 Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 14:06:55 +0200 Subject: [PATCH 25/30] Authenticate module export --- up42/__init__.py | 17 ++++++++--------- up42/main.py | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/up42/__init__.py b/up42/__init__.py index 3810bdb1f..44552ee83 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -17,6 +17,9 @@ ``` """ +import typing +from typing import Type, Union, cast + # pylint: disable=only-importing-modules-is-allowed from up42.asset import Asset from up42.auth import Auth @@ -38,9 +41,11 @@ from up42.webhooks import Webhook __version__ = get_up42_py_version() - __all__ = [ - obj.__name__ + cast( + Union[Type, typing.Callable], + obj, + ).__name__ for obj in [ Asset, Auth, @@ -49,12 +54,6 @@ Storage, Tasking, Webhook, - ] -] - -__all__.extend( - obj.__name__ - for obj in [ get_example_aoi, read_vector_file, initialize_catalog, @@ -69,4 +68,4 @@ get_webhook_events, get_credits_balance, ] -) +] diff --git a/up42/main.py b/up42/main.py index 5b53122c8..3542ee850 100644 --- a/up42/main.py +++ b/up42/main.py @@ -38,7 +38,7 @@ def authenticate( cfg_file: Optional[Union[str, pathlib.Path]] = None, username: Optional[str] = None, password: Optional[str] = None, - ) -> None: + ): """ Authenticate with UP42, either using account credentials or a config JSON file containing the corresponding credentials. From 165267f9065a28b2e2dc1140dec70a0c8338006f Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 14:25:02 +0200 Subject: [PATCH 26/30] Improve workspace id injection --- tests/fixtures/fixtures_catalog.py | 6 +++--- tests/fixtures/fixtures_globals.py | 2 -- tests/fixtures/fixtures_storage.py | 2 +- tests/fixtures/fixtures_tasking.py | 6 +++--- tests/fixtures/fixtures_webhook.py | 8 ++++++-- tests/test_catalog.py | 2 +- tests/test_main.py | 6 +++--- tests/test_storage.py | 6 +++--- up42/catalog.py | 11 ++++++----- up42/initialization.py | 8 ++++---- up42/main.py | 6 +++--- up42/storage.py | 6 +++--- up42/tasking.py | 5 +++-- up42/webhooks.py | 18 +++++++++++++----- 14 files changed, 52 insertions(+), 40 deletions(-) diff --git a/tests/fixtures/fixtures_catalog.py b/tests/fixtures/fixtures_catalog.py index 0e0c023ae..8e1e24fdb 100644 --- a/tests/fixtures/fixtures_catalog.py +++ b/tests/fixtures/fixtures_catalog.py @@ -42,7 +42,7 @@ def catalog_mock(auth_mock, requests_mock): json_data_product_schema = json.load(json_file) requests_mock.get(url=url_data_product_schema, json=json_data_product_schema) - return catalog.Catalog(auth=auth_mock) + return catalog.Catalog(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) @pytest.fixture() @@ -77,7 +77,7 @@ def catalog_pagination_mock(auth_mock, requests_mock): [{"json": search_response_json}, {"json": pagination_response_json}], ) - return catalog.Catalog(auth=auth_mock) + return catalog.Catalog(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) @pytest.fixture() @@ -119,4 +119,4 @@ def catalog_usagetype_mock(auth_mock, requests_mock): ], ) - return catalog.Catalog(auth=auth_mock) + return catalog.Catalog(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) diff --git a/tests/fixtures/fixtures_globals.py b/tests/fixtures/fixtures_globals.py index ea9062bef..aba9f90aa 100644 --- a/tests/fixtures/fixtures_globals.py +++ b/tests/fixtures/fixtures_globals.py @@ -269,5 +269,3 @@ "updatedAt": "2022-06-20T04:05:31.755744Z", } } - -JSON_BALANCE = {"data": {"balance": 10693}} diff --git a/tests/fixtures/fixtures_storage.py b/tests/fixtures/fixtures_storage.py index 2d06632e8..1307d5e08 100644 --- a/tests/fixtures/fixtures_storage.py +++ b/tests/fixtures/fixtures_storage.py @@ -39,4 +39,4 @@ def storage_mock(auth_mock, requests_mock): # orders info url_order_info = f"{constants.API_HOST}/v2/orders/{constants.ORDER_ID}" requests_mock.get(url=url_order_info, json=constants.JSON_ORDER) - return storage.Storage(auth=auth_mock) + return storage.Storage(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) diff --git a/tests/fixtures/fixtures_tasking.py b/tests/fixtures/fixtures_tasking.py index 049b6dc45..30abcf99a 100644 --- a/tests/fixtures/fixtures_tasking.py +++ b/tests/fixtures/fixtures_tasking.py @@ -109,7 +109,7 @@ def tasking_mock(auth_mock, requests_mock): json=accepted_id_response_json, ) - return tasking.Tasking(auth=auth_mock) + return tasking.Tasking(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) @pytest.fixture() @@ -148,7 +148,7 @@ def tasking_get_feasibility_mock(auth_mock, requests_mock): json_data = json.load(json_file) requests_mock.get(url=get_feasibility_decision_param, json=json_data) - return tasking.Tasking(auth=auth_mock) + return tasking.Tasking(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) @pytest.fixture() @@ -168,4 +168,4 @@ def tasking_choose_feasibility_mock(auth_mock, requests_mock): "detail": {}, } requests_mock.patch(url=choose_feasibility_url, status_code=405, json=response) - return tasking.Tasking(auth=auth_mock) + return tasking.Tasking(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) diff --git a/tests/fixtures/fixtures_webhook.py b/tests/fixtures/fixtures_webhook.py index cf9c0c9b4..ff717152c 100644 --- a/tests/fixtures/fixtures_webhook.py +++ b/tests/fixtures/fixtures_webhook.py @@ -30,7 +30,11 @@ def webhook_mock(auth_mock, requests_mock): url_delete = f"{constants.API_HOST}/workspaces/{constants.WORKSPACE_ID}/webhooks/{constants.WEBHOOK_ID}" requests_mock.delete(url=url_delete) - return webhooks.Webhook(auth=auth_mock, webhook_id=constants.WEBHOOK_ID) + return webhooks.Webhook( + auth=auth_mock, + workspace_id=constants.WORKSPACE_ID, + webhook_id=constants.WEBHOOK_ID, + ) @pytest.fixture @@ -73,4 +77,4 @@ def webhooks_mock(auth_mock, requests_mock): url_create_webhook = f"{constants.API_HOST}/workspaces/{constants.WORKSPACE_ID}/webhooks" requests_mock.post(url=url_create_webhook, json=constants.JSON_WEBHOOK) - return webhooks.Webhooks(auth=auth_mock) + return webhooks.Webhooks(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 79d339b97..668b9fd1a 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -271,7 +271,7 @@ def test_construct_order_parameters(catalog_mock): # pylint: disable=unused-argument def test_estimate_order_from_catalog(catalog_order_parameters, requests_mock, auth_mock): - catalog_instance = catalog.Catalog(auth=auth_mock) + catalog_instance = catalog.Catalog(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) expected_payload = { "summary": {"totalCredits": 100, "totalSize": 0.1, "unit": "SQ_KM"}, "results": [{"index": 0, "credits": 100, "unit": "SQ_KM", "size": 0.1}], diff --git a/tests/test_main.py b/tests/test_main.py index c427b8e39..41cdc39ec 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -58,9 +58,9 @@ def test_get_webhooks(self, webhooks_mock, return_json): def test_get_credits_balance(self, requests_mock): balance_url = f"{constants.API_HOST}/accounts/me/credits/balance" + balance = {"balance": 10693} requests_mock.get( url=balance_url, - json=constants.JSON_BALANCE, + json={"data": balance}, ) - - assert main.get_credits_balance() == constants.JSON_BALANCE + assert main.get_credits_balance() == balance diff --git a/tests/test_storage.py b/tests/test_storage.py index 36bc736a7..82a835448 100644 --- a/tests/test_storage.py +++ b/tests/test_storage.py @@ -145,7 +145,7 @@ def test_get_assets_pagination(auth_mock, requests_mock): url_storage_assets_paginated = f"{constants.API_HOST}/v2/assets?sort=createdAt,asc&size=50" requests_mock.get(url=url_storage_assets_paginated, json=json_assets_paginated) - storage_results = storage.Storage(auth=auth_mock) + storage_results = storage.Storage(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) assets = storage_results.get_assets(limit=74, sortby="createdAt", descending=False) assert len(assets) == 74 assert isinstance(assets[0], asset.Asset) @@ -291,7 +291,7 @@ def test_get_orders_v2_endpoint_params(auth_mock, requests_mock, params, expecte ) for output in expected_results ] - storage_results = storage.Storage(auth=auth_mock) + storage_results = storage.Storage(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) orders = storage_results.get_orders(**params) assert orders == expected_results @@ -332,7 +332,7 @@ def test_get_orders_pagination(auth_mock, requests_mock): ) requests_mock.get(url=url_storage_orders_paginated, json=json_orders_paginated) - storage_results = storage.Storage(auth=auth_mock) + storage_results = storage.Storage(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) orders = storage_results.get_orders(limit=74, sortby="createdAt", descending=False) assert len(orders) == 74 assert isinstance(orders[0], order.Order) diff --git a/up42/catalog.py b/up42/catalog.py index 715aaaee8..d8e58f420 100644 --- a/up42/catalog.py +++ b/up42/catalog.py @@ -12,7 +12,7 @@ from shapely import geometry as geom # type: ignore from up42 import auth as up42_auth -from up42 import host, main, order, utils +from up42 import host, order, utils logger = utils.get_logger(__name__) @@ -22,8 +22,9 @@ class CatalogBase: The base for Catalog and Tasking class, shared functionality. """ - def __init__(self, auth: up42_auth.Auth): + def __init__(self, auth: up42_auth.Auth, workspace_id: str): self.auth = auth + self.workspace_id = workspace_id self.type: Optional[str] = None def get_data_products(self, basic: bool = True) -> Union[Dict, List[Dict]]: @@ -150,7 +151,7 @@ def place_order( warnings.warn(message, DeprecationWarning, stacklevel=2) elif order_parameters is None: raise ValueError("Please provide the 'order_parameters' parameter!") - placed_order = order.Order.place(self.auth, order_parameters, main.workspace.id) # type: ignore + placed_order = order.Order.place(self.auth, order_parameters, self.workspace_id) # type: ignore if track_status: placed_order.track_status(report_time) return placed_order @@ -170,8 +171,8 @@ class Catalog(CatalogBase): [CatalogBase](catalogbase-reference.md) class. """ - def __init__(self, auth: up42_auth.Auth): - super().__init__(auth) + def __init__(self, auth: up42_auth.Auth, workspace_id: str): + super().__init__(auth, workspace_id) self.quicklooks: Optional[List[str]] = None self.type: str = "ARCHIVE" self.data_products: Optional[Dict] = None diff --git a/up42/initialization.py b/up42/initialization.py index 3f31f6e2e..5fd00c8c4 100644 --- a/up42/initialization.py +++ b/up42/initialization.py @@ -12,21 +12,21 @@ def initialize_catalog() -> catalog.Catalog: """ Returns a Catalog object for using the catalog search. """ - return catalog.Catalog(auth=main.workspace.auth) + return catalog.Catalog(auth=main.workspace.auth, workspace_id=main.workspace.id) def initialize_tasking() -> "tasking.Tasking": """ Returns a Tasking object for creating satellite tasking orders. """ - return tasking.Tasking(auth=main.workspace.auth) + return tasking.Tasking(auth=main.workspace.auth, workspace_id=main.workspace.id) def initialize_storage() -> storage.Storage: """ Returns a Storage object to list orders and assets. """ - return storage.Storage(auth=main.workspace.auth) + return storage.Storage(auth=main.workspace.auth, workspace_id=main.workspace.id) def initialize_order(order_id: str) -> order.Order: @@ -57,6 +57,6 @@ def initialize_webhook(webhook_id: str) -> webhooks.Webhook: Args: webhook_id: The UP42 webhook_id """ - webhook = webhooks.Webhook(auth=main.workspace.auth, webhook_id=webhook_id) + webhook = webhooks.Webhook(auth=main.workspace.auth, workspace_id=main.workspace.id, webhook_id=webhook_id) logger.info(INITIALIZED_MSG, webhook) return webhook diff --git a/up42/main.py b/up42/main.py index 3542ee850..648945931 100644 --- a/up42/main.py +++ b/up42/main.py @@ -72,7 +72,7 @@ def get_webhooks(return_json: bool = False) -> List[webhooks.Webhook]: Returns: A list of the registered webhooks for this workspace. """ - return webhooks.Webhooks(auth=workspace.auth).get_webhooks(return_json=return_json) + return webhooks.Webhooks(auth=workspace.auth, workspace_id=workspace.id).get_webhooks(return_json=return_json) def create_webhook( @@ -94,7 +94,7 @@ def create_webhook( Returns: A dict with details of the registered webhook. """ - return webhooks.Webhooks(auth=workspace.auth).create_webhook( + return webhooks.Webhooks(auth=workspace.auth, workspace_id=workspace.id).create_webhook( name=name, url=url, events=events, active=active, secret=secret ) @@ -106,7 +106,7 @@ def get_webhook_events() -> dict: Returns: A dict of the available webhook events. """ - return webhooks.Webhooks(auth=workspace.auth).get_webhook_events() + return webhooks.Webhooks(auth=workspace.auth, workspace_id=workspace.id).get_webhook_events() def get_credits_balance() -> dict: diff --git a/up42/storage.py b/up42/storage.py index b7d8ae35a..848e48003 100644 --- a/up42/storage.py +++ b/up42/storage.py @@ -10,7 +10,7 @@ from up42 import asset, asset_searcher from up42 import auth as up42_auth -from up42 import host, main, order, utils +from up42 import host, order, utils logger = utils.get_logger(__name__) @@ -39,9 +39,9 @@ class Storage: ``` """ - def __init__(self, auth: up42_auth.Auth): + def __init__(self, auth: up42_auth.Auth, workspace_id: str): self.auth = auth - self.workspace_id = main.workspace.id + self.workspace_id = workspace_id def __repr__(self): return f"Storage(workspace_id: {self.workspace_id})" diff --git a/up42/tasking.py b/up42/tasking.py index 032015faf..8f3209bd6 100644 --- a/up42/tasking.py +++ b/up42/tasking.py @@ -1,6 +1,7 @@ """ Tasking functionality """ + import datetime from typing import List, Optional, Union @@ -24,8 +25,8 @@ class Tasking(catalog.CatalogBase): ``` """ - def __init__(self, auth: up42_auth.Auth): - super().__init__(auth) + def __init__(self, auth: up42_auth.Auth, workspace_id: str): + super().__init__(auth, workspace_id) self.type = "TASKING" def construct_order_parameters( diff --git a/up42/webhooks.py b/up42/webhooks.py index 8ba768946..9c8b2c673 100644 --- a/up42/webhooks.py +++ b/up42/webhooks.py @@ -1,7 +1,7 @@ from typing import List, Optional from up42 import auth as up42_auth -from up42 import host, main, utils +from up42 import host, utils logger = utils.get_logger(__name__) @@ -17,9 +17,15 @@ class Webhook: ``` """ - def __init__(self, auth: up42_auth.Auth, webhook_id: str, webhook_info: Optional[dict] = None): + def __init__( + self, + auth: up42_auth.Auth, + workspace_id: str, + webhook_id: str, + webhook_info: Optional[dict] = None, + ): self.auth = auth - self.workspace_id = main.workspace.id + self.workspace_id = workspace_id self.webhook_id = webhook_id if webhook_info is not None: self._info = webhook_info @@ -114,9 +120,9 @@ class Webhooks: ``` """ - def __init__(self, auth: up42_auth.Auth): + def __init__(self, auth: up42_auth.Auth, workspace_id: str): self.auth = auth - self.workspace_id = main.workspace.id + self.workspace_id = workspace_id def get_webhook_events(self) -> dict: """ @@ -147,6 +153,7 @@ def get_webhooks(self, return_json: bool = False) -> List[Webhook]: webhooks = [ Webhook( auth=self.auth, + workspace_id=self.workspace_id, webhook_id=webhook_info["id"], webhook_info=webhook_info, ) @@ -186,6 +193,7 @@ def create_webhook( response_json = self.auth.request(request_type="POST", url=url_post, data=input_parameters) webhook = Webhook( auth=self.auth, + workspace_id=self.workspace_id, webhook_id=response_json["data"]["id"], webhook_info=response_json["data"], ) From 099947cb42bf0064884e013239573d9deba0b729 Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 14:31:37 +0200 Subject: [PATCH 27/30] Clean up --- CHANGELOG.md | 4 ++-- tests/test_asset.py | 1 + tests/test_catalog.py | 9 --------- up42/__init__.py | 5 ++--- 4 files changed, 5 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0094236a0..be62f8a18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,8 +33,8 @@ For more information, see [UP42 Python package description](https://pypi.org/pro **May 24, 2024** -- Adding _Workspace hidden class and workspace instance as a singleton class in `main.py` -- Changing use of Auth Class for the workspace.auth property where required. +- Added workspace singleton in `main.py`, encapsulating global state (auth, workspace id). +- Inject auth and workspace id instead of passing a containing object. ## 1.0.4a1 diff --git a/tests/test_asset.py b/tests/test_asset.py index f6fda83d1..5eb10c39b 100644 --- a/tests/test_asset.py +++ b/tests/test_asset.py @@ -71,6 +71,7 @@ def test_asset_info(asset_mock): assert asset_mock.info["name"] == constants.JSON_ASSET["name"] +@pytest.mark.skip(reason="tempo") class TestStacMetadata: def test_should_get_stac_items_with_retries(self, auth_mock: up42_auth.Auth, requests_mock: req_mock.Mocker): requests_mock.get(constants.URL_STAC_CATALOG, json=constants.STAC_CATALOG_RESPONSE) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 668b9fd1a..f28effdd9 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -1,13 +1,11 @@ import json import pathlib import tempfile -from unittest import mock import geopandas as gpd # type: ignore import pytest from up42 import catalog, order - from .fixtures import fixtures_globals as constants with open( @@ -17,13 +15,6 @@ mock_search_parameters = json.load(json_file) -@pytest.fixture(autouse=True) -def mock_workspace_id(): - with mock.patch("up42.main.workspace") as mock_workspace: - mock_workspace.id = constants.WORKSPACE_ID - yield - - def test_get_collections(catalog_mock): collections = catalog_mock.get_collections() assert isinstance(collections, list) diff --git a/up42/__init__.py b/up42/__init__.py index 44552ee83..02f5ce823 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -17,8 +17,7 @@ ``` """ -import typing -from typing import Type, Union, cast +from typing import Type, Union, cast, Callable # pylint: disable=only-importing-modules-is-allowed from up42.asset import Asset @@ -43,7 +42,7 @@ __version__ = get_up42_py_version() __all__ = [ cast( - Union[Type, typing.Callable], + Union[Type, Callable], obj, ).__name__ for obj in [ From 5379f517cb6de39144a245d4340261fc8904512f Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 14:35:15 +0200 Subject: [PATCH 28/30] Apply hooks --- tests/test_asset.py | 1 - tests/test_catalog.py | 1 + up42/__init__.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_asset.py b/tests/test_asset.py index 5eb10c39b..f6fda83d1 100644 --- a/tests/test_asset.py +++ b/tests/test_asset.py @@ -71,7 +71,6 @@ def test_asset_info(asset_mock): assert asset_mock.info["name"] == constants.JSON_ASSET["name"] -@pytest.mark.skip(reason="tempo") class TestStacMetadata: def test_should_get_stac_items_with_retries(self, auth_mock: up42_auth.Auth, requests_mock: req_mock.Mocker): requests_mock.get(constants.URL_STAC_CATALOG, json=constants.STAC_CATALOG_RESPONSE) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index f28effdd9..cc7fcc491 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -6,6 +6,7 @@ import pytest from up42 import catalog, order + from .fixtures import fixtures_globals as constants with open( diff --git a/up42/__init__.py b/up42/__init__.py index 02f5ce823..aa363107d 100644 --- a/up42/__init__.py +++ b/up42/__init__.py @@ -17,7 +17,7 @@ ``` """ -from typing import Type, Union, cast, Callable +from typing import Callable, Type, Union, cast # pylint: disable=only-importing-modules-is-allowed from up42.asset import Asset From 4d0df363ba7c62e937f9e61c2fc8722c33a93c14 Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 14:38:08 +0200 Subject: [PATCH 29/30] Version fix --- CHANGELOG.md | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be62f8a18..758a023fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,7 +29,7 @@ You can check your current version with the following command: ``` For more information, see [UP42 Python package description](https://pypi.org/project/up42-py/). -## 1.1.0a1 +## 1.0.4a2 **May 24, 2024** diff --git a/pyproject.toml b/pyproject.toml index 30636fd3b..203eb89cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "up42-py" -version = "1.1.0a1" +version = "1.0.4a2" description = "Python SDK for UP42, the geospatial marketplace and developer platform." authors = ["UP42 GmbH "] license = "https://github.com/up42/up42-py/blob/master/LICENSE" From c5cb44aa3621c78d66ae6d0cecdd03ea3eae2eac Mon Sep 17 00:00:00 2001 From: Javid Gafar-zada Date: Fri, 24 May 2024 17:24:11 +0200 Subject: [PATCH 30/30] Unused argument precision --- tests/test_catalog.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_catalog.py b/tests/test_catalog.py index cc7fcc491..65d383cb3 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -261,7 +261,6 @@ def test_construct_order_parameters(catalog_mock): assert order_parameters["params"]["acquisitionMode"] is None -# pylint: disable=unused-argument def test_estimate_order_from_catalog(catalog_order_parameters, requests_mock, auth_mock): catalog_instance = catalog.Catalog(auth=auth_mock, workspace_id=constants.WORKSPACE_ID) expected_payload = { @@ -278,7 +277,7 @@ def test_estimate_order_from_catalog(catalog_order_parameters, requests_mock, au def test_order_from_catalog( order_parameters, - order_mock, + order_mock, # pylint: disable=unused-argument catalog_mock, requests_mock, ):