airbyte.cloud.organizations

PyAirbyte classes and methods for Airbyte Cloud organizations.

  1# Copyright (c) 2024 Airbyte, Inc., all rights reserved.
  2"""PyAirbyte classes and methods for Airbyte Cloud organizations."""
  3
  4from __future__ import annotations
  5
  6import logging
  7from typing import Any
  8
  9import requests
 10
 11from airbyte._util import api_util
 12from airbyte.cloud._credentials import _AirbyteCredentials
 13from airbyte.cloud.models import CloudOrganizationBillingInfo
 14from airbyte.exceptions import AirbyteError
 15from airbyte.secrets.base import SecretString
 16
 17
 18logger = logging.getLogger(__name__)
 19
 20
 21class CloudOrganization:
 22    """Information about an organization in Airbyte Cloud.
 23
 24    This class provides lazy loading of organization attributes including billing status.
 25    It is typically created via `CloudWorkspace.get_organization()`.
 26    """
 27
 28    def __init__(
 29        self,
 30        organization_id: str,
 31        organization_name: str | None = None,
 32        email: str | None = None,
 33        *,
 34        client_id: str | SecretString | None = None,
 35        client_secret: str | SecretString | None = None,
 36        bearer_token: str | SecretString | None = None,
 37        public_api_root: str | None = None,
 38        config_api_root: str | None = None,
 39    ) -> None:
 40        """Initialize a `CloudOrganization`."""
 41        self.organization_id = organization_id
 42        """The organization ID."""
 43
 44        self._organization_name = organization_name
 45        """Display name of the organization."""
 46
 47        self._email = email
 48        """Email associated with the organization."""
 49
 50        self._credentials = _AirbyteCredentials(
 51            client_id=SecretString(client_id) if client_id else None,
 52            client_secret=SecretString(client_secret) if client_secret else None,
 53            bearer_token=SecretString(bearer_token) if bearer_token else None,
 54            public_api_root=public_api_root or api_util.CLOUD_API_ROOT,
 55            config_api_root=config_api_root,
 56            organization_id=organization_id,
 57        )
 58        self._organization_info: dict[str, Any] | None = None
 59        self._organization_info_fetch_failed: bool = False
 60
 61    def _fetch_organization_info(self, *, force_refresh: bool = False) -> dict[str, Any]:
 62        """Fetch and cache organization info including billing status."""
 63        if force_refresh:
 64            self._organization_info_fetch_failed = False
 65
 66        if self._organization_info_fetch_failed and self._organization_info is None:
 67            return {}
 68
 69        if not force_refresh and self._organization_info is not None:
 70            return self._organization_info
 71
 72        try:
 73            self._organization_info = api_util.get_organization_info(
 74                organization_id=self.organization_id,
 75                api_root=self._credentials.public_api_root,
 76                config_api_root=self._credentials.config_api_root,
 77                client_id=self._credentials.client_id,
 78                client_secret=self._credentials.client_secret,
 79                bearer_token=self._credentials.bearer_token,
 80            )
 81        except Exception as ex:
 82            logger.debug("Failed to fetch organization info.", exc_info=ex)
 83            if self._organization_info is None:
 84                self._organization_info_fetch_failed = True
 85            return self._organization_info or {}
 86        else:
 87            return self._organization_info
 88
 89    @property
 90    def organization_name(self) -> str | None:
 91        """Display name of the organization."""
 92        if self._organization_name is not None:
 93            return self._organization_name
 94        info = self._fetch_organization_info()
 95        return info.get("organizationName")
 96
 97    @property
 98    def email(self) -> str | None:
 99        """Email associated with the organization."""
100        if self._email is not None:
101            return self._email
102        info = self._fetch_organization_info()
103        return info.get("email")
104
105    def get_billing_status(self) -> CloudOrganizationBillingInfo:
106        """Fetch billing status for the organization or raise on failure."""
107        try:
108            info = api_util.get_organization_info(
109                organization_id=self.organization_id,
110                api_root=self._credentials.public_api_root,
111                config_api_root=self._credentials.config_api_root,
112                client_id=self._credentials.client_id,
113                client_secret=self._credentials.client_secret,
114                bearer_token=self._credentials.bearer_token,
115            )
116        except (requests.RequestException, ValueError) as ex:
117            raise AirbyteError(
118                message="Failed to retrieve organization billing information.",
119                context={"organization_id": self.organization_id},
120            ) from ex
121        billing = info.get("billing")
122        if not isinstance(billing, dict):
123            raise AirbyteError(
124                message="Organization info did not include billing details.",
125                context={"organization_id": self.organization_id},
126            )
127        payment_status = billing.get("paymentStatus")
128        subscription_status = billing.get("subscriptionStatus")
129        return CloudOrganizationBillingInfo(
130            payment_status=payment_status if isinstance(payment_status, str) else None,
131            subscription_status=(
132                subscription_status if isinstance(subscription_status, str) else None
133            ),
134            is_account_locked=api_util.is_account_locked(payment_status, subscription_status),
135        )
136
137    @property
138    def payment_status(self) -> str | None:
139        """Payment status of the organization."""
140        info = self._fetch_organization_info()
141        return (info.get("billing") or {}).get("paymentStatus")
142
143    @property
144    def subscription_status(self) -> str | None:
145        """Subscription status of the organization."""
146        info = self._fetch_organization_info()
147        return (info.get("billing") or {}).get("subscriptionStatus")
148
149    @property
150    def is_account_locked(self) -> bool:
151        """Whether the account is locked due to billing issues."""
152        return api_util.is_account_locked(self.payment_status, self.subscription_status)
logger = <Logger airbyte.cloud.organizations (INFO)>
class CloudOrganization:
 22class CloudOrganization:
 23    """Information about an organization in Airbyte Cloud.
 24
 25    This class provides lazy loading of organization attributes including billing status.
 26    It is typically created via `CloudWorkspace.get_organization()`.
 27    """
 28
 29    def __init__(
 30        self,
 31        organization_id: str,
 32        organization_name: str | None = None,
 33        email: str | None = None,
 34        *,
 35        client_id: str | SecretString | None = None,
 36        client_secret: str | SecretString | None = None,
 37        bearer_token: str | SecretString | None = None,
 38        public_api_root: str | None = None,
 39        config_api_root: str | None = None,
 40    ) -> None:
 41        """Initialize a `CloudOrganization`."""
 42        self.organization_id = organization_id
 43        """The organization ID."""
 44
 45        self._organization_name = organization_name
 46        """Display name of the organization."""
 47
 48        self._email = email
 49        """Email associated with the organization."""
 50
 51        self._credentials = _AirbyteCredentials(
 52            client_id=SecretString(client_id) if client_id else None,
 53            client_secret=SecretString(client_secret) if client_secret else None,
 54            bearer_token=SecretString(bearer_token) if bearer_token else None,
 55            public_api_root=public_api_root or api_util.CLOUD_API_ROOT,
 56            config_api_root=config_api_root,
 57            organization_id=organization_id,
 58        )
 59        self._organization_info: dict[str, Any] | None = None
 60        self._organization_info_fetch_failed: bool = False
 61
 62    def _fetch_organization_info(self, *, force_refresh: bool = False) -> dict[str, Any]:
 63        """Fetch and cache organization info including billing status."""
 64        if force_refresh:
 65            self._organization_info_fetch_failed = False
 66
 67        if self._organization_info_fetch_failed and self._organization_info is None:
 68            return {}
 69
 70        if not force_refresh and self._organization_info is not None:
 71            return self._organization_info
 72
 73        try:
 74            self._organization_info = api_util.get_organization_info(
 75                organization_id=self.organization_id,
 76                api_root=self._credentials.public_api_root,
 77                config_api_root=self._credentials.config_api_root,
 78                client_id=self._credentials.client_id,
 79                client_secret=self._credentials.client_secret,
 80                bearer_token=self._credentials.bearer_token,
 81            )
 82        except Exception as ex:
 83            logger.debug("Failed to fetch organization info.", exc_info=ex)
 84            if self._organization_info is None:
 85                self._organization_info_fetch_failed = True
 86            return self._organization_info or {}
 87        else:
 88            return self._organization_info
 89
 90    @property
 91    def organization_name(self) -> str | None:
 92        """Display name of the organization."""
 93        if self._organization_name is not None:
 94            return self._organization_name
 95        info = self._fetch_organization_info()
 96        return info.get("organizationName")
 97
 98    @property
 99    def email(self) -> str | None:
100        """Email associated with the organization."""
101        if self._email is not None:
102            return self._email
103        info = self._fetch_organization_info()
104        return info.get("email")
105
106    def get_billing_status(self) -> CloudOrganizationBillingInfo:
107        """Fetch billing status for the organization or raise on failure."""
108        try:
109            info = api_util.get_organization_info(
110                organization_id=self.organization_id,
111                api_root=self._credentials.public_api_root,
112                config_api_root=self._credentials.config_api_root,
113                client_id=self._credentials.client_id,
114                client_secret=self._credentials.client_secret,
115                bearer_token=self._credentials.bearer_token,
116            )
117        except (requests.RequestException, ValueError) as ex:
118            raise AirbyteError(
119                message="Failed to retrieve organization billing information.",
120                context={"organization_id": self.organization_id},
121            ) from ex
122        billing = info.get("billing")
123        if not isinstance(billing, dict):
124            raise AirbyteError(
125                message="Organization info did not include billing details.",
126                context={"organization_id": self.organization_id},
127            )
128        payment_status = billing.get("paymentStatus")
129        subscription_status = billing.get("subscriptionStatus")
130        return CloudOrganizationBillingInfo(
131            payment_status=payment_status if isinstance(payment_status, str) else None,
132            subscription_status=(
133                subscription_status if isinstance(subscription_status, str) else None
134            ),
135            is_account_locked=api_util.is_account_locked(payment_status, subscription_status),
136        )
137
138    @property
139    def payment_status(self) -> str | None:
140        """Payment status of the organization."""
141        info = self._fetch_organization_info()
142        return (info.get("billing") or {}).get("paymentStatus")
143
144    @property
145    def subscription_status(self) -> str | None:
146        """Subscription status of the organization."""
147        info = self._fetch_organization_info()
148        return (info.get("billing") or {}).get("subscriptionStatus")
149
150    @property
151    def is_account_locked(self) -> bool:
152        """Whether the account is locked due to billing issues."""
153        return api_util.is_account_locked(self.payment_status, self.subscription_status)

Information about an organization in Airbyte Cloud.

This class provides lazy loading of organization attributes including billing status. It is typically created via CloudWorkspace.get_organization().

CloudOrganization( organization_id: str, organization_name: str | None = None, email: str | None = None, *, client_id: str | airbyte.secrets.SecretString | None = None, client_secret: str | airbyte.secrets.SecretString | None = None, bearer_token: str | airbyte.secrets.SecretString | None = None, public_api_root: str | None = None, config_api_root: str | None = None)
29    def __init__(
30        self,
31        organization_id: str,
32        organization_name: str | None = None,
33        email: str | None = None,
34        *,
35        client_id: str | SecretString | None = None,
36        client_secret: str | SecretString | None = None,
37        bearer_token: str | SecretString | None = None,
38        public_api_root: str | None = None,
39        config_api_root: str | None = None,
40    ) -> None:
41        """Initialize a `CloudOrganization`."""
42        self.organization_id = organization_id
43        """The organization ID."""
44
45        self._organization_name = organization_name
46        """Display name of the organization."""
47
48        self._email = email
49        """Email associated with the organization."""
50
51        self._credentials = _AirbyteCredentials(
52            client_id=SecretString(client_id) if client_id else None,
53            client_secret=SecretString(client_secret) if client_secret else None,
54            bearer_token=SecretString(bearer_token) if bearer_token else None,
55            public_api_root=public_api_root or api_util.CLOUD_API_ROOT,
56            config_api_root=config_api_root,
57            organization_id=organization_id,
58        )
59        self._organization_info: dict[str, Any] | None = None
60        self._organization_info_fetch_failed: bool = False

Initialize a CloudOrganization.

organization_id

The organization ID.

organization_name: str | None
90    @property
91    def organization_name(self) -> str | None:
92        """Display name of the organization."""
93        if self._organization_name is not None:
94            return self._organization_name
95        info = self._fetch_organization_info()
96        return info.get("organizationName")

Display name of the organization.

email: str | None
 98    @property
 99    def email(self) -> str | None:
100        """Email associated with the organization."""
101        if self._email is not None:
102            return self._email
103        info = self._fetch_organization_info()
104        return info.get("email")

Email associated with the organization.

def get_billing_status(self) -> airbyte.cloud.models.CloudOrganizationBillingInfo:
106    def get_billing_status(self) -> CloudOrganizationBillingInfo:
107        """Fetch billing status for the organization or raise on failure."""
108        try:
109            info = api_util.get_organization_info(
110                organization_id=self.organization_id,
111                api_root=self._credentials.public_api_root,
112                config_api_root=self._credentials.config_api_root,
113                client_id=self._credentials.client_id,
114                client_secret=self._credentials.client_secret,
115                bearer_token=self._credentials.bearer_token,
116            )
117        except (requests.RequestException, ValueError) as ex:
118            raise AirbyteError(
119                message="Failed to retrieve organization billing information.",
120                context={"organization_id": self.organization_id},
121            ) from ex
122        billing = info.get("billing")
123        if not isinstance(billing, dict):
124            raise AirbyteError(
125                message="Organization info did not include billing details.",
126                context={"organization_id": self.organization_id},
127            )
128        payment_status = billing.get("paymentStatus")
129        subscription_status = billing.get("subscriptionStatus")
130        return CloudOrganizationBillingInfo(
131            payment_status=payment_status if isinstance(payment_status, str) else None,
132            subscription_status=(
133                subscription_status if isinstance(subscription_status, str) else None
134            ),
135            is_account_locked=api_util.is_account_locked(payment_status, subscription_status),
136        )

Fetch billing status for the organization or raise on failure.

payment_status: str | None
138    @property
139    def payment_status(self) -> str | None:
140        """Payment status of the organization."""
141        info = self._fetch_organization_info()
142        return (info.get("billing") or {}).get("paymentStatus")

Payment status of the organization.

subscription_status: str | None
144    @property
145    def subscription_status(self) -> str | None:
146        """Subscription status of the organization."""
147        info = self._fetch_organization_info()
148        return (info.get("billing") or {}).get("subscriptionStatus")

Subscription status of the organization.

is_account_locked: bool
150    @property
151    def is_account_locked(self) -> bool:
152        """Whether the account is locked due to billing issues."""
153        return api_util.is_account_locked(self.payment_status, self.subscription_status)

Whether the account is locked due to billing issues.