Skip to content

Commit be9a1e4

Browse files
authored
chore: make OrgAPI into a base client (#2359)
1 parent 61420f2 commit be9a1e4

7 files changed

Lines changed: 54 additions & 48 deletions

File tree

cognite/client/_api/iam.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from operator import itemgetter
77
from typing import TYPE_CHECKING, Any, Literal, TypeAlias, cast, overload
88

9-
from cognite.client._api.organization import PrincipalsAPI
9+
from cognite.client._api.org_apis.principals import PrincipalsAPI
1010
from cognite.client._api.user_profiles import UserProfilesAPI
1111
from cognite.client._api_client import APIClient
1212
from cognite.client._constants import DEFAULT_LIMIT_READ

cognite/client/_api/organization.py renamed to cognite/client/_api/org_apis/principals.py

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,18 @@
11
from __future__ import annotations
22

33
import warnings
4-
from abc import ABC
54
from collections.abc import Sequence
6-
from functools import cached_property
75
from typing import overload
86
from urllib.parse import urljoin
97

10-
from cognite.client._api_client import APIClient
118
from cognite.client._constants import DEFAULT_LIMIT_READ
9+
from cognite.client._org_client import OrgAPIClient
1210
from cognite.client.data_classes.principals import Principal, PrincipalList
13-
from cognite.client.exceptions import CogniteAPIError
1411
from cognite.client.utils._identifier import PrincipalIdentifierSequence
1512
from cognite.client.utils.useful_types import SequenceNotStr
1613

1714

18-
class OrgAPI(APIClient, ABC):
19-
_auth_url = "https://auth.cognite.com"
20-
21-
def _get_base_url_with_base_path(self) -> str:
22-
"""Get base URL with base path including organization and api version if applicable"""
23-
base_path = ""
24-
if self._api_version:
25-
base_path = f"/api/{self._api_version}/orgs/{self._organization}"
26-
# The OrganizationAPi uses the auth_url as the base for these endpoints instead of the
27-
# base_url like the rest of the SDK.
28-
return urljoin(self._auth_url, base_path)
29-
30-
@cached_property
31-
def _organization(self) -> str:
32-
headers = self._configure_headers(
33-
"application/json",
34-
additional_headers=self._config.headers.copy(),
35-
api_subversion=self._api_subversion,
36-
)
37-
# This is an internal endpoint, not part of the public API
38-
full_url = urljoin(self._config.base_url, f"/api/v1/projects/{self._config.project}")
39-
response = self._http_client_with_retry.request(method="GET", url=full_url, headers=headers)
40-
if response.status_code != 200:
41-
raise CogniteAPIError(
42-
"Could not look-up organization", response.status_code, response.headers.get("x-request-id")
43-
)
44-
return response.json()["organization"]
45-
46-
47-
class PrincipalsAPI(OrgAPI):
15+
class PrincipalsAPI(OrgAPIClient):
4816
_RESOURCE_PATH = "/principals"
4917

5018
def me(self) -> Principal:
@@ -61,9 +29,10 @@ def me(self) -> Principal:
6129
>>> res = client.iam.principals.me()
6230
"""
6331
# the /me endpoint is not using the /orgs/{org} base path, so we have to construct the URL manually
64-
path = "/principals/me"
32+
path = f"{self._RESOURCE_PATH}/me"
6533
if self._api_version:
6634
path = f"/api/{self._api_version}{path}"
35+
6736
full_url = urljoin(self._auth_url, path)
6837
headers = self._configure_headers(
6938
"application/json",

cognite/client/_org_client.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from __future__ import annotations
2+
3+
from abc import ABC
4+
from functools import cached_property
5+
from urllib.parse import urljoin
6+
7+
from cognite.client._api_client import APIClient
8+
from cognite.client.exceptions import CogniteAPIError
9+
10+
11+
class OrgAPIClient(APIClient, ABC):
12+
_auth_url = "https://auth.cognite.com"
13+
14+
def _get_base_url_with_base_path(self) -> str:
15+
"""Get base URL with base path including organization and api version if applicable"""
16+
base_path = ""
17+
if self._api_version:
18+
base_path = f"/api/{self._api_version}/orgs/{self._organization}"
19+
# The OrganizationAPi uses the auth_url as the base for these endpoints instead of the
20+
# base_url like the rest of the SDK.
21+
return urljoin(self._auth_url, base_path)
22+
23+
@cached_property
24+
def _organization(self) -> str:
25+
headers = self._configure_headers(
26+
"application/json",
27+
additional_headers=self._config.headers.copy(),
28+
api_subversion=self._api_subversion,
29+
)
30+
# This is an internal endpoint, not part of the public API
31+
full_url = urljoin(self._config.base_url, f"/api/v1/projects/{self._config.project}")
32+
response = self._http_client_with_retry.request(method="GET", url=full_url, headers=headers)
33+
if response.status_code != 200:
34+
raise CogniteAPIError(
35+
"Could not look-up organization", response.status_code, response.headers.get("x-request-id")
36+
)
37+
return response.json()["organization"]

cognite/client/testing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from cognite.client._api.hosted_extractors.sources import SourcesAPI
4343
from cognite.client._api.iam import IAMAPI, GroupsAPI, SecurityCategoriesAPI, SessionsAPI, TokenAPI
4444
from cognite.client._api.labels import LabelsAPI
45-
from cognite.client._api.organization import PrincipalsAPI
45+
from cognite.client._api.org_apis.principals import PrincipalsAPI
4646
from cognite.client._api.postgres_gateway import PostgresGatewaysAPI
4747
from cognite.client._api.postgres_gateway.tables import TablesAPI as PostgresTablesAPI
4848
from cognite.client._api.postgres_gateway.users import UsersAPI as PostgresUsersAPI

docs/source/identity_and_access_management.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ Principals
1515

1616
Get the current caller's principal
1717
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18-
.. automethod:: cognite.client._api.organization.PrincipalsAPI.me
18+
.. automethod:: cognite.client._api.org_apis.principals.PrincipalsAPI.me
1919

2020
Retrieve a principal
2121
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22-
.. automethod:: cognite.client._api.organization.PrincipalsAPI.retrieve
22+
.. automethod:: cognite.client._api.org_apis.principals.PrincipalsAPI.retrieve
2323

2424
List principals
2525
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26-
.. automethod:: cognite.client._api.organization.PrincipalsAPI.list
26+
.. automethod:: cognite.client._api.org_apis.principals.PrincipalsAPI.list
2727

2828
Tokens
2929
^^^^^^
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import pytest
22

33
from cognite.client import CogniteClient
4-
from cognite.client._api.organization import OrgAPI
4+
from cognite.client._org_client import OrgAPIClient
55

66

77
@pytest.fixture(scope="session")
8-
def org_api(cognite_client_cog_idp: CogniteClient) -> OrgAPI:
8+
def org_api(cognite_client_cog_idp: CogniteClient) -> OrgAPIClient:
99
client = cognite_client_cog_idp
10-
return OrgAPI(client.config, client._API_VERSION, client)
10+
return OrgAPIClient(client.config, client._API_VERSION, client)
1111

1212

1313
class TestOrganizationAPI:
14-
def test_get_organization(self, org_api: OrgAPI) -> None:
14+
def test_get_organization(self, org_api: OrgAPIClient) -> None:
1515
organization = org_api._organization
1616
assert isinstance(organization, str)
1717
assert organization != ""
@@ -20,6 +20,6 @@ def test_get_organization(self, org_api: OrgAPI) -> None:
2020
else:
2121
pytest.skip("Organization not supported")
2222

23-
def test_get_request_org_endpoint(self, org_api: OrgAPI) -> None:
23+
def test_get_request_org_endpoint(self, org_api: OrgAPIClient) -> None:
2424
response = org_api._get("/principals")
2525
assert response.status_code == 200

tests/tests_unit/test_testing.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import pytest
22

33
from cognite.client import ClientConfig, CogniteClient
4-
from cognite.client._api.organization import OrgAPI
54
from cognite.client._api_client import APIClient
5+
from cognite.client._org_client import OrgAPIClient
66
from cognite.client.credentials import Token
77
from cognite.client.testing import CogniteClientMock, monkeypatch_cognite_client
88
from tests.utils import all_mock_children, all_subclasses, get_api_class_by_attribute
@@ -11,8 +11,8 @@
1111
def test_ensure_all_apis_are_available_on_cognite_mock():
1212
mocked_apis = all_mock_children(CogniteClientMock())
1313
available = {v.__class__ for v in mocked_apis.values()}
14-
# OrgAPI is a base API and should not mocked directly.
15-
expected = set(all_subclasses(APIClient, exclude={OrgAPI}))
14+
# OrgAPIClient is a base API and should not mocked directly.
15+
expected = set(all_subclasses(APIClient, exclude={OrgAPIClient}))
1616
# Any new APIs that have not been added to CogniteClientMock?
1717
assert not expected.difference(available), f"Missing APIs: {expected.difference(available)}"
1818
# Any removed APIs that are still available on CogniteClientMock?

0 commit comments

Comments
 (0)