Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e95eb1d
chore(internal): version bump (#469)
stainless-app[bot] Jan 6, 2025
441731c
codegen metadata
stainless-app[bot] Dec 20, 2024
d23ec0e
feat(api): api update (#471)
stainless-app[bot] Dec 23, 2024
0a22350
feat(api): api update (#472)
stainless-app[bot] Dec 24, 2024
9406c9a
codegen metadata
stainless-app[bot] Dec 25, 2024
c24985f
chore(internal): codegen related update (#473)
stainless-app[bot] Jan 1, 2025
d2fb2aa
feat(api): api update (#474)
stainless-app[bot] Jan 3, 2025
f684ed4
chore(client): simplify `Optional[object]` to just `object` (#475)
stainless-app[bot] Jan 6, 2025
cafafe4
chore: add missing isclass check (#476)
stainless-app[bot] Jan 6, 2025
59c3a8b
feat(api): api update (#477)
stainless-app[bot] Jan 6, 2025
4036eca
feat(api): api update (#478)
stainless-app[bot] Jan 6, 2025
6b04dea
chore(internal): bump httpx dependency (#480)
stainless-app[bot] Jan 7, 2025
c14225c
fix(client): only call .close() when needed (#481)
stainless-app[bot] Jan 7, 2025
b8a2ce6
docs: fix typos (#482)
stainless-app[bot] Jan 8, 2025
569ad30
docs: more typo fixes (#483)
stainless-app[bot] Jan 8, 2025
a429148
chore(internal): codegen related update (#484)
stainless-app[bot] Jan 8, 2025
7a80005
fix: correctly handle deserialising `cls` fields (#485)
stainless-app[bot] Jan 10, 2025
be53793
codegen metadata
stainless-app[bot] Jan 13, 2025
4677063
chore(internal): update deps (#486)
stainless-app[bot] Jan 14, 2025
667a330
chore(internal): bump pyright dependency (#487)
stainless-app[bot] Jan 15, 2025
dd09671
release: 2.21.0
stainless-app[bot] Jan 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "2.20.0"
".": "2.21.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
configured_endpoints: 97
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-02151f7654870aee7820ee1c04659a469e6b67ac4977116334512c6b6e6a2016.yml
configured_endpoints: 101
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/orb%2Forb-1720084d65e39f50455fe3a8756afc68fedf57306a727f92e4d020c28878df87.yml
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
# Changelog

## 2.21.0 (2025-01-15)

Full Changelog: [v2.20.0...v2.21.0](https://github.com/orbcorp/orb-python/compare/v2.20.0...v2.21.0)

### Features

* **api:** api update ([#471](https://github.com/orbcorp/orb-python/issues/471)) ([d23ec0e](https://github.com/orbcorp/orb-python/commit/d23ec0e08cc5e8bd681a8c7947778a8445b81f78))
* **api:** api update ([#472](https://github.com/orbcorp/orb-python/issues/472)) ([0a22350](https://github.com/orbcorp/orb-python/commit/0a2235016cfba90da5f68e950579d0720bd40045))
* **api:** api update ([#474](https://github.com/orbcorp/orb-python/issues/474)) ([d2fb2aa](https://github.com/orbcorp/orb-python/commit/d2fb2aa50c27160a8fd386aec812e8f3ace527fe))
* **api:** api update ([#477](https://github.com/orbcorp/orb-python/issues/477)) ([59c3a8b](https://github.com/orbcorp/orb-python/commit/59c3a8bdfa3b18311e956511afd31d211c6f320d))
* **api:** api update ([#478](https://github.com/orbcorp/orb-python/issues/478)) ([4036eca](https://github.com/orbcorp/orb-python/commit/4036ecaf1d14f3c235c11ce1551490a86fab8066))


### Bug Fixes

* **client:** only call .close() when needed ([#481](https://github.com/orbcorp/orb-python/issues/481)) ([c14225c](https://github.com/orbcorp/orb-python/commit/c14225cd09e514dea91586874e851cf1933b9af5))
* correctly handle deserialising `cls` fields ([#485](https://github.com/orbcorp/orb-python/issues/485)) ([7a80005](https://github.com/orbcorp/orb-python/commit/7a80005983ff3799ea685034dd750c08c74704e7))


### Chores

* add missing isclass check ([#476](https://github.com/orbcorp/orb-python/issues/476)) ([cafafe4](https://github.com/orbcorp/orb-python/commit/cafafe4cfdfd12d1bbad5d1fce0ad0b992741993))
* **client:** simplify `Optional[object]` to just `object` ([#475](https://github.com/orbcorp/orb-python/issues/475)) ([f684ed4](https://github.com/orbcorp/orb-python/commit/f684ed42a5452933f4fe5a495b309a74267e4728))
* **internal:** bump httpx dependency ([#480](https://github.com/orbcorp/orb-python/issues/480)) ([6b04dea](https://github.com/orbcorp/orb-python/commit/6b04deaf0406eb2130ca9f159d42f84bd5ecac4a))
* **internal:** bump pyright dependency ([#487](https://github.com/orbcorp/orb-python/issues/487)) ([667a330](https://github.com/orbcorp/orb-python/commit/667a330e4074c66434a19d25fdfaf2a710f2d2c8))
* **internal:** codegen related update ([#473](https://github.com/orbcorp/orb-python/issues/473)) ([c24985f](https://github.com/orbcorp/orb-python/commit/c24985f1ff9e87de455a4b862045701f6c646bab))
* **internal:** codegen related update ([#484](https://github.com/orbcorp/orb-python/issues/484)) ([a429148](https://github.com/orbcorp/orb-python/commit/a429148a83f0e51afcb0b99d5661c706023da48f))
* **internal:** update deps ([#486](https://github.com/orbcorp/orb-python/issues/486)) ([4677063](https://github.com/orbcorp/orb-python/commit/4677063f95f37b7b982816871d8fa98871efd15f))
* **internal:** version bump ([#469](https://github.com/orbcorp/orb-python/issues/469)) ([e95eb1d](https://github.com/orbcorp/orb-python/commit/e95eb1d93a4990d3fe2d722abf05b4bfa558c745))


### Documentation

* fix typos ([#482](https://github.com/orbcorp/orb-python/issues/482)) ([b8a2ce6](https://github.com/orbcorp/orb-python/commit/b8a2ce60542927b91329a10dd2d39efac96d6d9b))
* more typo fixes ([#483](https://github.com/orbcorp/orb-python/issues/483)) ([569ad30](https://github.com/orbcorp/orb-python/commit/569ad308f81bc99620d2d08b3afc4ea95f0fe8d5))

## 2.20.0 (2024-12-19)

Full Changelog: [v2.19.0...v2.20.0](https://github.com/orbcorp/orb-python/compare/v2.19.0...v2.20.0)
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2024 Orb
Copyright 2025 Orb

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ except orb.APIStatusError as e:
print(e.response)
```

Error codes are as followed:
Error codes are as follows:

| Status Code | Error Type |
| ----------- | -------------------------- |
Expand Down Expand Up @@ -328,7 +328,7 @@ customer = response.parse() # get the object that `customers.create()` would ha
print(customer.id)
```

These methods return an [`LegacyAPIResponse`](https://github.com/orbcorp/orb-python/tree/main/src/orb/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version.
These methods return a [`LegacyAPIResponse`](https://github.com/orbcorp/orb-python/tree/main/src/orb/_legacy_response.py) object. This is a legacy class as we're changing it slightly in the next major version.

For the sync client this will mostly be the same with the exception
of `content` & `text` will be methods instead of properties. In the
Expand Down Expand Up @@ -367,8 +367,7 @@ If you need to access undocumented endpoints, params, or response properties, th
#### Undocumented endpoints

To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other
http verbs. Options on the client will be respected (such as retries) will be respected when making this
request.
http verbs. Options on the client will be respected (such as retries) when making this request.

```py
import httpx
Expand Down Expand Up @@ -440,7 +439,7 @@ with Orb() as client:
This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:

1. Changes that only affect static types, without breaking runtime behavior.
2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_.
2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_
3. Changes that we do not expect to impact the vast majority of users in practice.

We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
Expand Down
20 changes: 20 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,23 @@ Methods:
- <code title="post /alerts/subscription_id/{subscription_id}">client.alerts.<a href="./src/orb/resources/alerts.py">create_for_subscription</a>(subscription_id, \*\*<a href="src/orb/types/alert_create_for_subscription_params.py">params</a>) -> <a href="./src/orb/types/alert.py">Alert</a></code>
- <code title="post /alerts/{alert_configuration_id}/disable">client.alerts.<a href="./src/orb/resources/alerts.py">disable</a>(alert_configuration_id, \*\*<a href="src/orb/types/alert_disable_params.py">params</a>) -> <a href="./src/orb/types/alert.py">Alert</a></code>
- <code title="post /alerts/{alert_configuration_id}/enable">client.alerts.<a href="./src/orb/resources/alerts.py">enable</a>(alert_configuration_id, \*\*<a href="src/orb/types/alert_enable_params.py">params</a>) -> <a href="./src/orb/types/alert.py">Alert</a></code>

# DimensionalPriceGroups

Types:

```python
from orb.types import DimensionalPriceGroup, DimensionalPriceGroups
```

Methods:

- <code title="post /dimensional_price_groups">client.dimensional_price_groups.<a href="./src/orb/resources/dimensional_price_groups/dimensional_price_groups.py">create</a>(\*\*<a href="src/orb/types/dimensional_price_group_create_params.py">params</a>) -> <a href="./src/orb/types/dimensional_price_group.py">DimensionalPriceGroup</a></code>
- <code title="get /dimensional_price_groups/{dimensional_price_group_id}">client.dimensional_price_groups.<a href="./src/orb/resources/dimensional_price_groups/dimensional_price_groups.py">retrieve</a>(dimensional_price_group_id) -> <a href="./src/orb/types/dimensional_price_group.py">DimensionalPriceGroup</a></code>
- <code title="get /dimensional_price_groups">client.dimensional_price_groups.<a href="./src/orb/resources/dimensional_price_groups/dimensional_price_groups.py">list</a>(\*\*<a href="src/orb/types/dimensional_price_group_list_params.py">params</a>) -> <a href="./src/orb/types/dimensional_price_group.py">SyncPage[DimensionalPriceGroup]</a></code>

## ExternalDimensionalPriceGroupID

Methods:

- <code title="get /dimensional_price_groups/external_dimensional_price_group_id/{external_dimensional_price_group_id}">client.dimensional_price_groups.external_dimensional_price_group_id.<a href="./src/orb/resources/dimensional_price_groups/external_dimensional_price_group_id.py">retrieve</a>(external_dimensional_price_group_id) -> <a href="./src/orb/types/dimensional_price_group.py">DimensionalPriceGroup</a></code>
2 changes: 1 addition & 1 deletion mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ cache_fine_grained = True
# ```
# Changing this codegen to make mypy happy would increase complexity
# and would not be worth it.
disable_error_code = func-returns-value
disable_error_code = func-returns-value,overload-cannot-match

# https://github.com/python/mypy/issues/12162
[mypy.overrides]
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "orb-billing"
version = "2.20.0"
version = "2.21.0"
description = "The official Python library for the orb API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down Expand Up @@ -54,7 +54,7 @@ dev-dependencies = [
"dirty-equals>=0.6.0",
"importlib-metadata>=6.7.0",
"rich>=13.7.1",
"nest_asyncio==1.6.0"
"nest_asyncio==1.6.0",
]

[tool.rye.scripts]
Expand Down
9 changes: 4 additions & 5 deletions requirements-dev.lock
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ h11==0.14.0
# via httpcore
httpcore==1.0.2
# via httpx
httpx==0.25.2
httpx==0.28.1
# via orb-billing
# via respx
idna==3.4
Expand All @@ -48,7 +48,7 @@ markdown-it-py==3.0.0
# via rich
mdurl==0.1.2
# via markdown-it-py
mypy==1.13.0
mypy==1.14.1
mypy-extensions==1.0.0
# via mypy
nest-asyncio==1.6.0
Expand All @@ -68,15 +68,15 @@ pydantic-core==2.27.1
# via pydantic
pygments==2.18.0
# via rich
pyright==1.1.390
pyright==1.1.392.post0
pytest==8.3.3
# via pytest-asyncio
pytest-asyncio==0.24.0
python-dateutil==2.8.2
# via time-machine
pytz==2023.3.post1
# via dirty-equals
respx==0.20.2
respx==0.22.0
rich==13.7.1
ruff==0.6.9
setuptools==68.2.2
Expand All @@ -85,7 +85,6 @@ six==1.16.0
# via python-dateutil
sniffio==1.3.0
# via anyio
# via httpx
# via orb-billing
time-machine==2.9.0
tomli==2.0.2
Expand Down
3 changes: 1 addition & 2 deletions requirements.lock
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ h11==0.14.0
# via httpcore
httpcore==1.0.2
# via httpx
httpx==0.25.2
httpx==0.28.1
# via orb-billing
idna==3.4
# via anyio
Expand All @@ -36,7 +36,6 @@ pydantic-core==2.27.1
# via pydantic
sniffio==1.3.0
# via anyio
# via httpx
# via orb-billing
typing-extensions==4.12.2
# via anyio
Expand Down
6 changes: 6 additions & 0 deletions src/orb/_base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,9 @@ def __init__(self, **kwargs: Any) -> None:

class SyncHttpxClientWrapper(DefaultHttpxClient):
def __del__(self) -> None:
if self.is_closed:
return

try:
self.close()
except Exception:
Expand Down Expand Up @@ -1349,6 +1352,9 @@ def __init__(self, **kwargs: Any) -> None:

class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient):
def __del__(self) -> None:
if self.is_closed:
return

try:
# TODO(someday): support non asyncio runtimes here
asyncio.get_running_loop().create_task(self.aclose())
Expand Down
17 changes: 17 additions & 0 deletions src/orb/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
from .resources.prices import prices
from .resources.coupons import coupons
from .resources.customers import customers
from .resources.dimensional_price_groups import dimensional_price_groups

__all__ = ["Timeout", "Transport", "ProxiesTypes", "RequestOptions", "Orb", "AsyncOrb", "Client", "AsyncClient"]

Expand All @@ -67,6 +68,7 @@ class Orb(SyncAPIClient):
subscriptions: subscriptions.Subscriptions
webhooks: webhooks.Webhooks
alerts: alerts.Alerts
dimensional_price_groups: dimensional_price_groups.DimensionalPriceGroups
with_raw_response: OrbWithRawResponse
with_streaming_response: OrbWithStreamedResponse

Expand Down Expand Up @@ -148,6 +150,7 @@ def __init__(
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.with_raw_response = OrbWithRawResponse(self)
self.with_streaming_response = OrbWithStreamedResponse(self)

Expand Down Expand Up @@ -321,6 +324,7 @@ class AsyncOrb(AsyncAPIClient):
subscriptions: subscriptions.AsyncSubscriptions
webhooks: webhooks.AsyncWebhooks
alerts: alerts.AsyncAlerts
dimensional_price_groups: dimensional_price_groups.AsyncDimensionalPriceGroups
with_raw_response: AsyncOrbWithRawResponse
with_streaming_response: AsyncOrbWithStreamedResponse

Expand Down Expand Up @@ -402,6 +406,7 @@ def __init__(
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.with_raw_response = AsyncOrbWithRawResponse(self)
self.with_streaming_response = AsyncOrbWithStreamedResponse(self)

Expand Down Expand Up @@ -575,6 +580,9 @@ def __init__(self, client: Orb) -> None:
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
)


class AsyncOrbWithRawResponse:
Expand All @@ -592,6 +600,9 @@ def __init__(self, client: AsyncOrb) -> None:
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
)


class OrbWithStreamedResponse:
Expand All @@ -609,6 +620,9 @@ def __init__(self, client: Orb) -> None:
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
)


class AsyncOrbWithStreamedResponse:
Expand All @@ -628,6 +642,9 @@ def __init__(self, client: AsyncOrb) -> None:
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
)


Client = Orb
Expand Down
12 changes: 10 additions & 2 deletions src/orb/_legacy_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,9 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
if origin == LegacyAPIResponse:
raise RuntimeError("Unexpected state - cast_to is `APIResponse`")

if inspect.isclass(origin) and issubclass(origin, httpx.Response):
if inspect.isclass(
origin # pyright: ignore[reportUnknownArgumentType]
) and issubclass(origin, httpx.Response):
# Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response
# and pass that class to our request functions. We cannot change the variance to be either
# covariant or contravariant as that makes our usage of ResponseT illegal. We could construct
Expand All @@ -272,7 +274,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`")
return cast(R, response)

if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel):
if (
inspect.isclass(
origin # pyright: ignore[reportUnknownArgumentType]
)
and not issubclass(origin, BaseModel)
and issubclass(origin, pydantic.BaseModel)
):
raise TypeError("Pydantic models must subclass our base model type, e.g. `from orb import BaseModel`")

if (
Expand Down
14 changes: 9 additions & 5 deletions src/orb/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,14 @@ def __str__(self) -> str:
@classmethod
@override
def construct( # pyright: ignore[reportIncompatibleMethodOverride]
cls: Type[ModelT],
__cls: Type[ModelT],
_fields_set: set[str] | None = None,
**values: object,
) -> ModelT:
m = cls.__new__(cls)
m = __cls.__new__(__cls)
fields_values: dict[str, object] = {}

config = get_model_config(cls)
config = get_model_config(__cls)
populate_by_name = (
config.allow_population_by_field_name
if isinstance(config, _ConfigProtocol)
Expand All @@ -196,7 +196,7 @@ def construct( # pyright: ignore[reportIncompatibleMethodOverride]
if _fields_set is None:
_fields_set = set()

model_fields = get_model_fields(cls)
model_fields = get_model_fields(__cls)
for name, field in model_fields.items():
key = field.alias
if key is None or (key not in values and populate_by_name):
Expand Down Expand Up @@ -488,7 +488,11 @@ def construct_type(*, value: object, type_: object) -> object:
_, items_type = get_args(type_) # Dict[_, items_type]
return {key: construct_type(value=item, type_=items_type) for key, item in value.items()}

if not is_literal_type(type_) and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)):
if (
not is_literal_type(type_)
and inspect.isclass(origin)
and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel))
):
if is_list(value):
return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value]

Expand Down
8 changes: 7 additions & 1 deletion src/orb/_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T:
raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`")
return cast(R, response)

if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel):
if (
inspect.isclass(
origin # pyright: ignore[reportUnknownArgumentType]
)
and not issubclass(origin, BaseModel)
and issubclass(origin, pydantic.BaseModel)
):
raise TypeError("Pydantic models must subclass our base model type, e.g. `from orb import BaseModel`")

if (
Expand Down
2 changes: 1 addition & 1 deletion src/orb/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "orb"
__version__ = "2.20.0" # x-release-please-version
__version__ = "2.21.0" # x-release-please-version
Loading
Loading