diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04b083ca..196522c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,18 @@ name: CI on: push: - branches: - - main - pull_request: - branches: - - main - - next + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: timeout-minutes: 10 name: lint - runs-on: ubuntu-latest + runs-on: ${{ github.repository == 'stainless-sdks/orb-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -33,7 +33,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ubuntu-latest + runs-on: ${{ github.repository == 'stainless-sdks/orb-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index ca66de7f..911c6231 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.19.2" + ".": "3.19.3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 01082bdc..554abf5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 3.19.3 (2025-05-09) + +Full Changelog: [v3.19.2...v3.19.3](https://github.com/orbcorp/orb-python/compare/v3.19.2...v3.19.3) + +### Bug Fixes + +* **package:** support direct resource imports ([f1b3637](https://github.com/orbcorp/orb-python/commit/f1b36376d33f17c1f2e6a6233a75ea278587398e)) + + +### Chores + +* broadly detect json family of content-type headers ([3acaf7c](https://github.com/orbcorp/orb-python/commit/3acaf7c67e8d50d65b70f9e17fc5f828297a7f17)) +* **ci:** only use depot for staging repos ([3bec73f](https://github.com/orbcorp/orb-python/commit/3bec73ffde0195acc8fb8bf662f4ebaf787ff6bc)) +* **ci:** run on more branches and use depot runners ([8e10744](https://github.com/orbcorp/orb-python/commit/8e107446f9a89c01a62ef4e853ffb3f17f7e4277)) +* **internal:** avoid errors for isinstance checks on proxies ([5bbd76d](https://github.com/orbcorp/orb-python/commit/5bbd76d645f33c75a78272cd080096196c1f1407)) +* **internal:** minor formatting changes ([0e52bb3](https://github.com/orbcorp/orb-python/commit/0e52bb34ec9734c03ca0a225467c4b6d6e158b4e)) +* use lazy imports for resources ([e79a6ec](https://github.com/orbcorp/orb-python/commit/e79a6ec9eb46e1b04b0b511edaf25294e27934fc)) + ## 3.19.2 (2025-04-22) Full Changelog: [v3.19.1...v3.19.2](https://github.com/orbcorp/orb-python/compare/v3.19.1...v3.19.2) diff --git a/pyproject.toml b/pyproject.toml index 39e4bcc9..84528b52 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "orb-billing" -version = "3.19.2" +version = "3.19.3" description = "The official Python library for the orb API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/orb/__init__.py b/src/orb/__init__.py index 61ab6a9b..8e183536 100644 --- a/src/orb/__init__.py +++ b/src/orb/__init__.py @@ -1,5 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import typing as _t + from . import types from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes from ._utils import file_from_path @@ -92,6 +94,9 @@ "DefaultAsyncHttpxClient", ] +if not _t.TYPE_CHECKING: + from ._utils._resources_proxy import resources as resources + _setup_logging() # Update the __module__ attribute for exported symbols so that diff --git a/src/orb/_client.py b/src/orb/_client.py index c4b5d59c..7ff77c19 100644 --- a/src/orb/_client.py +++ b/src/orb/_client.py @@ -3,7 +3,7 @@ from __future__ import annotations import os -from typing import Any, Union, Mapping +from typing import TYPE_CHECKING, Any, Union, Mapping from typing_extensions import Self, override import httpx @@ -24,19 +24,8 @@ is_mapping, get_async_library, ) +from ._compat import cached_property from ._version import __version__ -from .resources import ( - items, - alerts, - metrics, - invoices, - webhooks, - top_level, - credit_notes, - subscriptions, - invoice_line_items, - subscription_changes, -) from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import OrbError, APIStatusError from ._base_client import ( @@ -44,36 +33,49 @@ SyncAPIClient, AsyncAPIClient, ) -from .resources.plans import plans -from .resources.events import events -from .resources.prices import prices -from .resources.coupons import coupons -from .resources.customers import customers -from .resources.dimensional_price_groups import dimensional_price_groups + +if TYPE_CHECKING: + from .resources import ( + items, + plans, + alerts, + events, + prices, + coupons, + metrics, + invoices, + webhooks, + customers, + top_level, + credit_notes, + subscriptions, + invoice_line_items, + subscription_changes, + dimensional_price_groups, + ) + from .resources.items import Items, AsyncItems + from .resources.alerts import Alerts, AsyncAlerts + from .resources.metrics import Metrics, AsyncMetrics + from .resources.invoices import Invoices, AsyncInvoices + from .resources.top_level import TopLevel, AsyncTopLevel + from .resources.plans.plans import Plans, AsyncPlans + from .resources.credit_notes import CreditNotes, AsyncCreditNotes + from .resources.events.events import Events, AsyncEvents + from .resources.prices.prices import Prices, AsyncPrices + from .resources.subscriptions import Subscriptions, AsyncSubscriptions + from .resources.coupons.coupons import Coupons, AsyncCoupons + from .resources.invoice_line_items import InvoiceLineItems, AsyncInvoiceLineItems + from .resources.customers.customers import Customers, AsyncCustomers + from .resources.subscription_changes import SubscriptionChanges, AsyncSubscriptionChanges + from .resources.dimensional_price_groups.dimensional_price_groups import ( + DimensionalPriceGroups, + AsyncDimensionalPriceGroups, + ) __all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Orb", "AsyncOrb", "Client", "AsyncClient"] class Orb(SyncAPIClient): - top_level: top_level.TopLevel - coupons: coupons.Coupons - credit_notes: credit_notes.CreditNotes - customers: customers.Customers - events: events.Events - invoice_line_items: invoice_line_items.InvoiceLineItems - invoices: invoices.Invoices - items: items.Items - metrics: metrics.Metrics - plans: plans.Plans - prices: prices.Prices - subscriptions: subscriptions.Subscriptions - webhooks: webhooks.Webhooks - alerts: alerts.Alerts - dimensional_price_groups: dimensional_price_groups.DimensionalPriceGroups - subscription_changes: subscription_changes.SubscriptionChanges - with_raw_response: OrbWithRawResponse - with_streaming_response: OrbWithStreamedResponse - # client options api_key: str webhook_secret: str | None @@ -138,24 +140,109 @@ def __init__( self._idempotency_header = "Idempotency-Key" - self.top_level = top_level.TopLevel(self) - self.coupons = coupons.Coupons(self) - self.credit_notes = credit_notes.CreditNotes(self) - self.customers = customers.Customers(self) - self.events = events.Events(self) - self.invoice_line_items = invoice_line_items.InvoiceLineItems(self) - self.invoices = invoices.Invoices(self) - self.items = items.Items(self) - self.metrics = metrics.Metrics(self) - self.plans = plans.Plans(self) - self.prices = prices.Prices(self) - self.subscriptions = subscriptions.Subscriptions(self) - self.webhooks = webhooks.Webhooks(self) - self.alerts = alerts.Alerts(self) - self.dimensional_price_groups = dimensional_price_groups.DimensionalPriceGroups(self) - self.subscription_changes = subscription_changes.SubscriptionChanges(self) - self.with_raw_response = OrbWithRawResponse(self) - self.with_streaming_response = OrbWithStreamedResponse(self) + @cached_property + def top_level(self) -> TopLevel: + from .resources.top_level import TopLevel + + return TopLevel(self) + + @cached_property + def coupons(self) -> Coupons: + from .resources.coupons import Coupons + + return Coupons(self) + + @cached_property + def credit_notes(self) -> CreditNotes: + from .resources.credit_notes import CreditNotes + + return CreditNotes(self) + + @cached_property + def customers(self) -> Customers: + from .resources.customers import Customers + + return Customers(self) + + @cached_property + def events(self) -> Events: + from .resources.events import Events + + return Events(self) + + @cached_property + def invoice_line_items(self) -> InvoiceLineItems: + from .resources.invoice_line_items import InvoiceLineItems + + return InvoiceLineItems(self) + + @cached_property + def invoices(self) -> Invoices: + from .resources.invoices import Invoices + + return Invoices(self) + + @cached_property + def items(self) -> Items: + from .resources.items import Items + + return Items(self) + + @cached_property + def metrics(self) -> Metrics: + from .resources.metrics import Metrics + + return Metrics(self) + + @cached_property + def plans(self) -> Plans: + from .resources.plans import Plans + + return Plans(self) + + @cached_property + def prices(self) -> Prices: + from .resources.prices import Prices + + return Prices(self) + + @cached_property + def subscriptions(self) -> Subscriptions: + from .resources.subscriptions import Subscriptions + + return Subscriptions(self) + + @cached_property + def alerts(self) -> Alerts: + from .resources.alerts import Alerts + + return Alerts(self) + + @cached_property + def dimensional_price_groups(self) -> DimensionalPriceGroups: + from .resources.dimensional_price_groups import DimensionalPriceGroups + + return DimensionalPriceGroups(self) + + @cached_property + def subscription_changes(self) -> SubscriptionChanges: + from .resources.subscription_changes import SubscriptionChanges + + return SubscriptionChanges(self) + + @cached_property + def webhooks(self) -> webhooks.Webhooks: + from .resources.webhooks import Webhooks + + return Webhooks(self) + + @cached_property + def with_raw_response(self) -> OrbWithRawResponse: + return OrbWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> OrbWithStreamedResponse: + return OrbWithStreamedResponse(self) @property @override @@ -313,25 +400,6 @@ def _make_status_error( class AsyncOrb(AsyncAPIClient): - top_level: top_level.AsyncTopLevel - coupons: coupons.AsyncCoupons - credit_notes: credit_notes.AsyncCreditNotes - customers: customers.AsyncCustomers - events: events.AsyncEvents - invoice_line_items: invoice_line_items.AsyncInvoiceLineItems - invoices: invoices.AsyncInvoices - items: items.AsyncItems - metrics: metrics.AsyncMetrics - plans: plans.AsyncPlans - prices: prices.AsyncPrices - subscriptions: subscriptions.AsyncSubscriptions - webhooks: webhooks.AsyncWebhooks - alerts: alerts.AsyncAlerts - dimensional_price_groups: dimensional_price_groups.AsyncDimensionalPriceGroups - subscription_changes: subscription_changes.AsyncSubscriptionChanges - with_raw_response: AsyncOrbWithRawResponse - with_streaming_response: AsyncOrbWithStreamedResponse - # client options api_key: str webhook_secret: str | None @@ -396,24 +464,109 @@ def __init__( self._idempotency_header = "Idempotency-Key" - self.top_level = top_level.AsyncTopLevel(self) - self.coupons = coupons.AsyncCoupons(self) - self.credit_notes = credit_notes.AsyncCreditNotes(self) - self.customers = customers.AsyncCustomers(self) - self.events = events.AsyncEvents(self) - self.invoice_line_items = invoice_line_items.AsyncInvoiceLineItems(self) - self.invoices = invoices.AsyncInvoices(self) - self.items = items.AsyncItems(self) - self.metrics = metrics.AsyncMetrics(self) - self.plans = plans.AsyncPlans(self) - self.prices = prices.AsyncPrices(self) - self.subscriptions = subscriptions.AsyncSubscriptions(self) - self.webhooks = webhooks.AsyncWebhooks(self) - self.alerts = alerts.AsyncAlerts(self) - self.dimensional_price_groups = dimensional_price_groups.AsyncDimensionalPriceGroups(self) - self.subscription_changes = subscription_changes.AsyncSubscriptionChanges(self) - self.with_raw_response = AsyncOrbWithRawResponse(self) - self.with_streaming_response = AsyncOrbWithStreamedResponse(self) + @cached_property + def top_level(self) -> AsyncTopLevel: + from .resources.top_level import AsyncTopLevel + + return AsyncTopLevel(self) + + @cached_property + def coupons(self) -> AsyncCoupons: + from .resources.coupons import AsyncCoupons + + return AsyncCoupons(self) + + @cached_property + def credit_notes(self) -> AsyncCreditNotes: + from .resources.credit_notes import AsyncCreditNotes + + return AsyncCreditNotes(self) + + @cached_property + def customers(self) -> AsyncCustomers: + from .resources.customers import AsyncCustomers + + return AsyncCustomers(self) + + @cached_property + def events(self) -> AsyncEvents: + from .resources.events import AsyncEvents + + return AsyncEvents(self) + + @cached_property + def invoice_line_items(self) -> AsyncInvoiceLineItems: + from .resources.invoice_line_items import AsyncInvoiceLineItems + + return AsyncInvoiceLineItems(self) + + @cached_property + def invoices(self) -> AsyncInvoices: + from .resources.invoices import AsyncInvoices + + return AsyncInvoices(self) + + @cached_property + def items(self) -> AsyncItems: + from .resources.items import AsyncItems + + return AsyncItems(self) + + @cached_property + def metrics(self) -> AsyncMetrics: + from .resources.metrics import AsyncMetrics + + return AsyncMetrics(self) + + @cached_property + def plans(self) -> AsyncPlans: + from .resources.plans import AsyncPlans + + return AsyncPlans(self) + + @cached_property + def prices(self) -> AsyncPrices: + from .resources.prices import AsyncPrices + + return AsyncPrices(self) + + @cached_property + def subscriptions(self) -> AsyncSubscriptions: + from .resources.subscriptions import AsyncSubscriptions + + return AsyncSubscriptions(self) + + @cached_property + def alerts(self) -> AsyncAlerts: + from .resources.alerts import AsyncAlerts + + return AsyncAlerts(self) + + @cached_property + def dimensional_price_groups(self) -> AsyncDimensionalPriceGroups: + from .resources.dimensional_price_groups import AsyncDimensionalPriceGroups + + return AsyncDimensionalPriceGroups(self) + + @cached_property + def subscription_changes(self) -> AsyncSubscriptionChanges: + from .resources.subscription_changes import AsyncSubscriptionChanges + + return AsyncSubscriptionChanges(self) + + @cached_property + def webhooks(self) -> webhooks.AsyncWebhooks: + from .resources.webhooks import AsyncWebhooks + + return AsyncWebhooks(self) + + @cached_property + def with_raw_response(self) -> AsyncOrbWithRawResponse: + return AsyncOrbWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncOrbWithStreamedResponse: + return AsyncOrbWithStreamedResponse(self) @property @override @@ -571,95 +724,391 @@ def _make_status_error( class OrbWithRawResponse: + _client: Orb + def __init__(self, client: Orb) -> None: - self.top_level = top_level.TopLevelWithRawResponse(client.top_level) - self.coupons = coupons.CouponsWithRawResponse(client.coupons) - self.credit_notes = credit_notes.CreditNotesWithRawResponse(client.credit_notes) - self.customers = customers.CustomersWithRawResponse(client.customers) - self.events = events.EventsWithRawResponse(client.events) - self.invoice_line_items = invoice_line_items.InvoiceLineItemsWithRawResponse(client.invoice_line_items) - self.invoices = invoices.InvoicesWithRawResponse(client.invoices) - self.items = items.ItemsWithRawResponse(client.items) - self.metrics = metrics.MetricsWithRawResponse(client.metrics) - self.plans = plans.PlansWithRawResponse(client.plans) - self.prices = prices.PricesWithRawResponse(client.prices) - self.subscriptions = subscriptions.SubscriptionsWithRawResponse(client.subscriptions) - self.alerts = alerts.AlertsWithRawResponse(client.alerts) - self.dimensional_price_groups = dimensional_price_groups.DimensionalPriceGroupsWithRawResponse( - client.dimensional_price_groups - ) - self.subscription_changes = subscription_changes.SubscriptionChangesWithRawResponse(client.subscription_changes) + self._client = client + + @cached_property + def top_level(self) -> top_level.TopLevelWithRawResponse: + from .resources.top_level import TopLevelWithRawResponse + + return TopLevelWithRawResponse(self._client.top_level) + + @cached_property + def coupons(self) -> coupons.CouponsWithRawResponse: + from .resources.coupons import CouponsWithRawResponse + + return CouponsWithRawResponse(self._client.coupons) + + @cached_property + def credit_notes(self) -> credit_notes.CreditNotesWithRawResponse: + from .resources.credit_notes import CreditNotesWithRawResponse + + return CreditNotesWithRawResponse(self._client.credit_notes) + + @cached_property + def customers(self) -> customers.CustomersWithRawResponse: + from .resources.customers import CustomersWithRawResponse + + return CustomersWithRawResponse(self._client.customers) + + @cached_property + def events(self) -> events.EventsWithRawResponse: + from .resources.events import EventsWithRawResponse + + return EventsWithRawResponse(self._client.events) + + @cached_property + def invoice_line_items(self) -> invoice_line_items.InvoiceLineItemsWithRawResponse: + from .resources.invoice_line_items import InvoiceLineItemsWithRawResponse + + return InvoiceLineItemsWithRawResponse(self._client.invoice_line_items) + + @cached_property + def invoices(self) -> invoices.InvoicesWithRawResponse: + from .resources.invoices import InvoicesWithRawResponse + + return InvoicesWithRawResponse(self._client.invoices) + + @cached_property + def items(self) -> items.ItemsWithRawResponse: + from .resources.items import ItemsWithRawResponse + + return ItemsWithRawResponse(self._client.items) + + @cached_property + def metrics(self) -> metrics.MetricsWithRawResponse: + from .resources.metrics import MetricsWithRawResponse + + return MetricsWithRawResponse(self._client.metrics) + + @cached_property + def plans(self) -> plans.PlansWithRawResponse: + from .resources.plans import PlansWithRawResponse + + return PlansWithRawResponse(self._client.plans) + + @cached_property + def prices(self) -> prices.PricesWithRawResponse: + from .resources.prices import PricesWithRawResponse + + return PricesWithRawResponse(self._client.prices) + + @cached_property + def subscriptions(self) -> subscriptions.SubscriptionsWithRawResponse: + from .resources.subscriptions import SubscriptionsWithRawResponse + + return SubscriptionsWithRawResponse(self._client.subscriptions) + + @cached_property + def alerts(self) -> alerts.AlertsWithRawResponse: + from .resources.alerts import AlertsWithRawResponse + + return AlertsWithRawResponse(self._client.alerts) + + @cached_property + def dimensional_price_groups(self) -> dimensional_price_groups.DimensionalPriceGroupsWithRawResponse: + from .resources.dimensional_price_groups import DimensionalPriceGroupsWithRawResponse + + return DimensionalPriceGroupsWithRawResponse(self._client.dimensional_price_groups) + + @cached_property + def subscription_changes(self) -> subscription_changes.SubscriptionChangesWithRawResponse: + from .resources.subscription_changes import SubscriptionChangesWithRawResponse + + return SubscriptionChangesWithRawResponse(self._client.subscription_changes) class AsyncOrbWithRawResponse: + _client: AsyncOrb + def __init__(self, client: AsyncOrb) -> None: - self.top_level = top_level.AsyncTopLevelWithRawResponse(client.top_level) - self.coupons = coupons.AsyncCouponsWithRawResponse(client.coupons) - self.credit_notes = credit_notes.AsyncCreditNotesWithRawResponse(client.credit_notes) - self.customers = customers.AsyncCustomersWithRawResponse(client.customers) - self.events = events.AsyncEventsWithRawResponse(client.events) - self.invoice_line_items = invoice_line_items.AsyncInvoiceLineItemsWithRawResponse(client.invoice_line_items) - self.invoices = invoices.AsyncInvoicesWithRawResponse(client.invoices) - self.items = items.AsyncItemsWithRawResponse(client.items) - self.metrics = metrics.AsyncMetricsWithRawResponse(client.metrics) - self.plans = plans.AsyncPlansWithRawResponse(client.plans) - self.prices = prices.AsyncPricesWithRawResponse(client.prices) - self.subscriptions = subscriptions.AsyncSubscriptionsWithRawResponse(client.subscriptions) - self.alerts = alerts.AsyncAlertsWithRawResponse(client.alerts) - self.dimensional_price_groups = dimensional_price_groups.AsyncDimensionalPriceGroupsWithRawResponse( - client.dimensional_price_groups - ) - self.subscription_changes = subscription_changes.AsyncSubscriptionChangesWithRawResponse( - client.subscription_changes - ) + self._client = client + + @cached_property + def top_level(self) -> top_level.AsyncTopLevelWithRawResponse: + from .resources.top_level import AsyncTopLevelWithRawResponse + + return AsyncTopLevelWithRawResponse(self._client.top_level) + + @cached_property + def coupons(self) -> coupons.AsyncCouponsWithRawResponse: + from .resources.coupons import AsyncCouponsWithRawResponse + + return AsyncCouponsWithRawResponse(self._client.coupons) + + @cached_property + def credit_notes(self) -> credit_notes.AsyncCreditNotesWithRawResponse: + from .resources.credit_notes import AsyncCreditNotesWithRawResponse + + return AsyncCreditNotesWithRawResponse(self._client.credit_notes) + + @cached_property + def customers(self) -> customers.AsyncCustomersWithRawResponse: + from .resources.customers import AsyncCustomersWithRawResponse + + return AsyncCustomersWithRawResponse(self._client.customers) + + @cached_property + def events(self) -> events.AsyncEventsWithRawResponse: + from .resources.events import AsyncEventsWithRawResponse + + return AsyncEventsWithRawResponse(self._client.events) + + @cached_property + def invoice_line_items(self) -> invoice_line_items.AsyncInvoiceLineItemsWithRawResponse: + from .resources.invoice_line_items import AsyncInvoiceLineItemsWithRawResponse + + return AsyncInvoiceLineItemsWithRawResponse(self._client.invoice_line_items) + + @cached_property + def invoices(self) -> invoices.AsyncInvoicesWithRawResponse: + from .resources.invoices import AsyncInvoicesWithRawResponse + + return AsyncInvoicesWithRawResponse(self._client.invoices) + + @cached_property + def items(self) -> items.AsyncItemsWithRawResponse: + from .resources.items import AsyncItemsWithRawResponse + + return AsyncItemsWithRawResponse(self._client.items) + + @cached_property + def metrics(self) -> metrics.AsyncMetricsWithRawResponse: + from .resources.metrics import AsyncMetricsWithRawResponse + + return AsyncMetricsWithRawResponse(self._client.metrics) + + @cached_property + def plans(self) -> plans.AsyncPlansWithRawResponse: + from .resources.plans import AsyncPlansWithRawResponse + + return AsyncPlansWithRawResponse(self._client.plans) + + @cached_property + def prices(self) -> prices.AsyncPricesWithRawResponse: + from .resources.prices import AsyncPricesWithRawResponse + + return AsyncPricesWithRawResponse(self._client.prices) + + @cached_property + def subscriptions(self) -> subscriptions.AsyncSubscriptionsWithRawResponse: + from .resources.subscriptions import AsyncSubscriptionsWithRawResponse + + return AsyncSubscriptionsWithRawResponse(self._client.subscriptions) + + @cached_property + def alerts(self) -> alerts.AsyncAlertsWithRawResponse: + from .resources.alerts import AsyncAlertsWithRawResponse + + return AsyncAlertsWithRawResponse(self._client.alerts) + + @cached_property + def dimensional_price_groups(self) -> dimensional_price_groups.AsyncDimensionalPriceGroupsWithRawResponse: + from .resources.dimensional_price_groups import AsyncDimensionalPriceGroupsWithRawResponse + + return AsyncDimensionalPriceGroupsWithRawResponse(self._client.dimensional_price_groups) + + @cached_property + def subscription_changes(self) -> subscription_changes.AsyncSubscriptionChangesWithRawResponse: + from .resources.subscription_changes import AsyncSubscriptionChangesWithRawResponse + + return AsyncSubscriptionChangesWithRawResponse(self._client.subscription_changes) class OrbWithStreamedResponse: + _client: Orb + def __init__(self, client: Orb) -> None: - self.top_level = top_level.TopLevelWithStreamingResponse(client.top_level) - self.coupons = coupons.CouponsWithStreamingResponse(client.coupons) - self.credit_notes = credit_notes.CreditNotesWithStreamingResponse(client.credit_notes) - self.customers = customers.CustomersWithStreamingResponse(client.customers) - self.events = events.EventsWithStreamingResponse(client.events) - self.invoice_line_items = invoice_line_items.InvoiceLineItemsWithStreamingResponse(client.invoice_line_items) - self.invoices = invoices.InvoicesWithStreamingResponse(client.invoices) - self.items = items.ItemsWithStreamingResponse(client.items) - self.metrics = metrics.MetricsWithStreamingResponse(client.metrics) - self.plans = plans.PlansWithStreamingResponse(client.plans) - self.prices = prices.PricesWithStreamingResponse(client.prices) - self.subscriptions = subscriptions.SubscriptionsWithStreamingResponse(client.subscriptions) - self.alerts = alerts.AlertsWithStreamingResponse(client.alerts) - self.dimensional_price_groups = dimensional_price_groups.DimensionalPriceGroupsWithStreamingResponse( - client.dimensional_price_groups - ) - self.subscription_changes = subscription_changes.SubscriptionChangesWithStreamingResponse( - client.subscription_changes - ) + self._client = client + + @cached_property + def top_level(self) -> top_level.TopLevelWithStreamingResponse: + from .resources.top_level import TopLevelWithStreamingResponse + + return TopLevelWithStreamingResponse(self._client.top_level) + + @cached_property + def coupons(self) -> coupons.CouponsWithStreamingResponse: + from .resources.coupons import CouponsWithStreamingResponse + + return CouponsWithStreamingResponse(self._client.coupons) + + @cached_property + def credit_notes(self) -> credit_notes.CreditNotesWithStreamingResponse: + from .resources.credit_notes import CreditNotesWithStreamingResponse + + return CreditNotesWithStreamingResponse(self._client.credit_notes) + + @cached_property + def customers(self) -> customers.CustomersWithStreamingResponse: + from .resources.customers import CustomersWithStreamingResponse + + return CustomersWithStreamingResponse(self._client.customers) + + @cached_property + def events(self) -> events.EventsWithStreamingResponse: + from .resources.events import EventsWithStreamingResponse + + return EventsWithStreamingResponse(self._client.events) + + @cached_property + def invoice_line_items(self) -> invoice_line_items.InvoiceLineItemsWithStreamingResponse: + from .resources.invoice_line_items import InvoiceLineItemsWithStreamingResponse + + return InvoiceLineItemsWithStreamingResponse(self._client.invoice_line_items) + + @cached_property + def invoices(self) -> invoices.InvoicesWithStreamingResponse: + from .resources.invoices import InvoicesWithStreamingResponse + + return InvoicesWithStreamingResponse(self._client.invoices) + + @cached_property + def items(self) -> items.ItemsWithStreamingResponse: + from .resources.items import ItemsWithStreamingResponse + + return ItemsWithStreamingResponse(self._client.items) + + @cached_property + def metrics(self) -> metrics.MetricsWithStreamingResponse: + from .resources.metrics import MetricsWithStreamingResponse + + return MetricsWithStreamingResponse(self._client.metrics) + + @cached_property + def plans(self) -> plans.PlansWithStreamingResponse: + from .resources.plans import PlansWithStreamingResponse + + return PlansWithStreamingResponse(self._client.plans) + + @cached_property + def prices(self) -> prices.PricesWithStreamingResponse: + from .resources.prices import PricesWithStreamingResponse + + return PricesWithStreamingResponse(self._client.prices) + + @cached_property + def subscriptions(self) -> subscriptions.SubscriptionsWithStreamingResponse: + from .resources.subscriptions import SubscriptionsWithStreamingResponse + + return SubscriptionsWithStreamingResponse(self._client.subscriptions) + + @cached_property + def alerts(self) -> alerts.AlertsWithStreamingResponse: + from .resources.alerts import AlertsWithStreamingResponse + + return AlertsWithStreamingResponse(self._client.alerts) + + @cached_property + def dimensional_price_groups(self) -> dimensional_price_groups.DimensionalPriceGroupsWithStreamingResponse: + from .resources.dimensional_price_groups import DimensionalPriceGroupsWithStreamingResponse + + return DimensionalPriceGroupsWithStreamingResponse(self._client.dimensional_price_groups) + + @cached_property + def subscription_changes(self) -> subscription_changes.SubscriptionChangesWithStreamingResponse: + from .resources.subscription_changes import SubscriptionChangesWithStreamingResponse + + return SubscriptionChangesWithStreamingResponse(self._client.subscription_changes) class AsyncOrbWithStreamedResponse: + _client: AsyncOrb + def __init__(self, client: AsyncOrb) -> None: - self.top_level = top_level.AsyncTopLevelWithStreamingResponse(client.top_level) - self.coupons = coupons.AsyncCouponsWithStreamingResponse(client.coupons) - self.credit_notes = credit_notes.AsyncCreditNotesWithStreamingResponse(client.credit_notes) - self.customers = customers.AsyncCustomersWithStreamingResponse(client.customers) - self.events = events.AsyncEventsWithStreamingResponse(client.events) - self.invoice_line_items = invoice_line_items.AsyncInvoiceLineItemsWithStreamingResponse( - client.invoice_line_items - ) - self.invoices = invoices.AsyncInvoicesWithStreamingResponse(client.invoices) - self.items = items.AsyncItemsWithStreamingResponse(client.items) - self.metrics = metrics.AsyncMetricsWithStreamingResponse(client.metrics) - self.plans = plans.AsyncPlansWithStreamingResponse(client.plans) - self.prices = prices.AsyncPricesWithStreamingResponse(client.prices) - self.subscriptions = subscriptions.AsyncSubscriptionsWithStreamingResponse(client.subscriptions) - self.alerts = alerts.AsyncAlertsWithStreamingResponse(client.alerts) - self.dimensional_price_groups = dimensional_price_groups.AsyncDimensionalPriceGroupsWithStreamingResponse( - client.dimensional_price_groups - ) - self.subscription_changes = subscription_changes.AsyncSubscriptionChangesWithStreamingResponse( - client.subscription_changes - ) + self._client = client + + @cached_property + def top_level(self) -> top_level.AsyncTopLevelWithStreamingResponse: + from .resources.top_level import AsyncTopLevelWithStreamingResponse + + return AsyncTopLevelWithStreamingResponse(self._client.top_level) + + @cached_property + def coupons(self) -> coupons.AsyncCouponsWithStreamingResponse: + from .resources.coupons import AsyncCouponsWithStreamingResponse + + return AsyncCouponsWithStreamingResponse(self._client.coupons) + + @cached_property + def credit_notes(self) -> credit_notes.AsyncCreditNotesWithStreamingResponse: + from .resources.credit_notes import AsyncCreditNotesWithStreamingResponse + + return AsyncCreditNotesWithStreamingResponse(self._client.credit_notes) + + @cached_property + def customers(self) -> customers.AsyncCustomersWithStreamingResponse: + from .resources.customers import AsyncCustomersWithStreamingResponse + + return AsyncCustomersWithStreamingResponse(self._client.customers) + + @cached_property + def events(self) -> events.AsyncEventsWithStreamingResponse: + from .resources.events import AsyncEventsWithStreamingResponse + + return AsyncEventsWithStreamingResponse(self._client.events) + + @cached_property + def invoice_line_items(self) -> invoice_line_items.AsyncInvoiceLineItemsWithStreamingResponse: + from .resources.invoice_line_items import AsyncInvoiceLineItemsWithStreamingResponse + + return AsyncInvoiceLineItemsWithStreamingResponse(self._client.invoice_line_items) + + @cached_property + def invoices(self) -> invoices.AsyncInvoicesWithStreamingResponse: + from .resources.invoices import AsyncInvoicesWithStreamingResponse + + return AsyncInvoicesWithStreamingResponse(self._client.invoices) + + @cached_property + def items(self) -> items.AsyncItemsWithStreamingResponse: + from .resources.items import AsyncItemsWithStreamingResponse + + return AsyncItemsWithStreamingResponse(self._client.items) + + @cached_property + def metrics(self) -> metrics.AsyncMetricsWithStreamingResponse: + from .resources.metrics import AsyncMetricsWithStreamingResponse + + return AsyncMetricsWithStreamingResponse(self._client.metrics) + + @cached_property + def plans(self) -> plans.AsyncPlansWithStreamingResponse: + from .resources.plans import AsyncPlansWithStreamingResponse + + return AsyncPlansWithStreamingResponse(self._client.plans) + + @cached_property + def prices(self) -> prices.AsyncPricesWithStreamingResponse: + from .resources.prices import AsyncPricesWithStreamingResponse + + return AsyncPricesWithStreamingResponse(self._client.prices) + + @cached_property + def subscriptions(self) -> subscriptions.AsyncSubscriptionsWithStreamingResponse: + from .resources.subscriptions import AsyncSubscriptionsWithStreamingResponse + + return AsyncSubscriptionsWithStreamingResponse(self._client.subscriptions) + + @cached_property + def alerts(self) -> alerts.AsyncAlertsWithStreamingResponse: + from .resources.alerts import AsyncAlertsWithStreamingResponse + + return AsyncAlertsWithStreamingResponse(self._client.alerts) + + @cached_property + def dimensional_price_groups(self) -> dimensional_price_groups.AsyncDimensionalPriceGroupsWithStreamingResponse: + from .resources.dimensional_price_groups import AsyncDimensionalPriceGroupsWithStreamingResponse + + return AsyncDimensionalPriceGroupsWithStreamingResponse(self._client.dimensional_price_groups) + + @cached_property + def subscription_changes(self) -> subscription_changes.AsyncSubscriptionChangesWithStreamingResponse: + from .resources.subscription_changes import AsyncSubscriptionChangesWithStreamingResponse + + return AsyncSubscriptionChangesWithStreamingResponse(self._client.subscription_changes) Client = Orb diff --git a/src/orb/_legacy_response.py b/src/orb/_legacy_response.py index cfc5a238..96cbe8bd 100644 --- a/src/orb/_legacy_response.py +++ b/src/orb/_legacy_response.py @@ -297,7 +297,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # split is required to handle cases where additional information is included # in the response, e.g. application/json; charset=utf-8 content_type, *_ = response.headers.get("content-type", "*").split(";") - if content_type != "application/json": + if not content_type.endswith("json"): if is_basemodel(cast_to): try: data = response.json() diff --git a/src/orb/_response.py b/src/orb/_response.py index 42f88f4f..2e125354 100644 --- a/src/orb/_response.py +++ b/src/orb/_response.py @@ -237,7 +237,7 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: # split is required to handle cases where additional information is included # in the response, e.g. application/json; charset=utf-8 content_type, *_ = response.headers.get("content-type", "*").split(";") - if content_type != "application/json": + if not content_type.endswith("json"): if is_basemodel(cast_to): try: data = response.json() diff --git a/src/orb/_utils/_proxy.py b/src/orb/_utils/_proxy.py index ffd883e9..0f239a33 100644 --- a/src/orb/_utils/_proxy.py +++ b/src/orb/_utils/_proxy.py @@ -46,7 +46,10 @@ def __dir__(self) -> Iterable[str]: @property # type: ignore @override def __class__(self) -> type: # pyright: ignore - proxied = self.__get_proxied__() + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) if issubclass(type(proxied), LazyProxy): return type(proxied) return proxied.__class__ diff --git a/src/orb/_utils/_resources_proxy.py b/src/orb/_utils/_resources_proxy.py new file mode 100644 index 00000000..a12180a0 --- /dev/null +++ b/src/orb/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `orb.resources` module. + + This is used so that we can lazily import `orb.resources` only when + needed *and* so that users can just import `orb` and reference `orb.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("orb.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() diff --git a/src/orb/_version.py b/src/orb/_version.py index 93e0c539..aec64c6e 100644 --- a/src/orb/_version.py +++ b/src/orb/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "orb" -__version__ = "3.19.2" # x-release-please-version +__version__ = "3.19.3" # x-release-please-version diff --git a/src/orb/types/event_deprecate_response.py b/src/orb/types/event_deprecate_response.py index 1ef11446..6e2142c7 100644 --- a/src/orb/types/event_deprecate_response.py +++ b/src/orb/types/event_deprecate_response.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["EventDeprecateResponse"] diff --git a/src/orb/types/event_update_response.py b/src/orb/types/event_update_response.py index 5c79e769..5ed59795 100644 --- a/src/orb/types/event_update_response.py +++ b/src/orb/types/event_update_response.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["EventUpdateResponse"] diff --git a/src/orb/types/top_level_ping_response.py b/src/orb/types/top_level_ping_response.py index b7ab100c..06876c86 100644 --- a/src/orb/types/top_level_ping_response.py +++ b/src/orb/types/top_level_ping_response.py @@ -1,6 +1,5 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel __all__ = ["TopLevelPingResponse"] diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py index 2aafc1f3..8b8e20c9 100644 --- a/tests/test_utils/test_proxy.py +++ b/tests/test_utils/test_proxy.py @@ -21,3 +21,14 @@ def test_recursive_proxy() -> None: assert dir(proxy) == [] assert type(proxy).__name__ == "RecursiveLazyProxy" assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" + + +def test_isinstance_does_not_error() -> None: + class AlwaysErrorProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + raise RuntimeError("Mocking missing dependency") + + proxy = AlwaysErrorProxy() + assert not isinstance(proxy, dict) + assert isinstance(proxy, LazyProxy)