Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
7d111d5
codegen metadata
stainless-app[bot] Mar 17, 2026
bf9f234
codegen metadata
stainless-app[bot] Mar 17, 2026
b4bde64
codegen metadata
stainless-app[bot] Mar 17, 2026
79ceac7
codegen metadata
stainless-app[bot] Mar 17, 2026
d0946ab
codegen metadata
stainless-app[bot] Mar 17, 2026
1722f23
codegen metadata
stainless-app[bot] Mar 17, 2026
8d6f7a2
codegen metadata
stainless-app[bot] Mar 17, 2026
475f25b
codegen metadata
stainless-app[bot] Mar 17, 2026
89f9e72
codegen metadata
stainless-app[bot] Mar 17, 2026
8e32619
codegen metadata
stainless-app[bot] Mar 17, 2026
6507387
codegen metadata
stainless-app[bot] Mar 17, 2026
88eaaba
codegen metadata
stainless-app[bot] Mar 17, 2026
c2b7b7f
codegen metadata
stainless-app[bot] Mar 18, 2026
810bc37
codegen metadata
stainless-app[bot] Mar 18, 2026
99d9039
codegen metadata
stainless-app[bot] Mar 18, 2026
84fd380
codegen metadata
stainless-app[bot] Mar 18, 2026
71ed5c3
codegen metadata
stainless-app[bot] Mar 18, 2026
338a713
codegen metadata
stainless-app[bot] Mar 18, 2026
577aaf5
codegen metadata
stainless-app[bot] Mar 18, 2026
9d828d9
codegen metadata
stainless-app[bot] Mar 18, 2026
c2010bc
codegen metadata
stainless-app[bot] Mar 18, 2026
349e5ab
codegen metadata
stainless-app[bot] Mar 18, 2026
8aa87a7
codegen metadata
stainless-app[bot] Mar 18, 2026
d4e86b6
codegen metadata
stainless-app[bot] Mar 18, 2026
bfa6242
codegen metadata
stainless-app[bot] Mar 18, 2026
d3bc5b1
codegen metadata
stainless-app[bot] Mar 18, 2026
260a105
codegen metadata
stainless-app[bot] Mar 18, 2026
2147d81
codegen metadata
stainless-app[bot] Mar 18, 2026
b605ceb
codegen metadata
stainless-app[bot] Mar 18, 2026
8951f88
codegen metadata
stainless-app[bot] Mar 18, 2026
b0141d9
codegen metadata
stainless-app[bot] Mar 18, 2026
b5f413c
codegen metadata
stainless-app[bot] Mar 18, 2026
3e904b6
codegen metadata
stainless-app[bot] Mar 19, 2026
3808bd4
codegen metadata
stainless-app[bot] Mar 19, 2026
9eaac56
codegen metadata
stainless-app[bot] Mar 19, 2026
c9ac87e
codegen metadata
stainless-app[bot] Mar 19, 2026
0ff9e5e
codegen metadata
stainless-app[bot] Mar 19, 2026
9c68d82
codegen metadata
stainless-app[bot] Mar 19, 2026
d03fbdb
codegen metadata
stainless-app[bot] Mar 19, 2026
026f194
codegen metadata
stainless-app[bot] Mar 19, 2026
93500f0
feat(api): api update
stainless-app[bot] Mar 19, 2026
bbcde62
codegen metadata
stainless-app[bot] Mar 19, 2026
0e4d67f
codegen metadata
stainless-app[bot] Mar 19, 2026
648aa5f
codegen metadata
stainless-app[bot] Mar 19, 2026
93ba26e
codegen metadata
stainless-app[bot] Mar 19, 2026
4050542
codegen metadata
stainless-app[bot] Mar 19, 2026
7787c99
codegen metadata
stainless-app[bot] Mar 19, 2026
2add05e
codegen metadata
stainless-app[bot] Mar 19, 2026
02d1160
codegen metadata
stainless-app[bot] Mar 19, 2026
4930918
codegen metadata
stainless-app[bot] Mar 19, 2026
4c02582
codegen metadata
stainless-app[bot] Mar 20, 2026
66a32bb
codegen metadata
stainless-app[bot] Mar 20, 2026
7931fda
fix: sanitize endpoint path params
stainless-app[bot] Mar 20, 2026
1eeb223
codegen metadata
stainless-app[bot] Mar 20, 2026
22ca4f8
codegen metadata
stainless-app[bot] Mar 20, 2026
12ad7b2
codegen metadata
stainless-app[bot] Mar 20, 2026
a88f90c
codegen metadata
stainless-app[bot] Mar 20, 2026
88837a1
codegen metadata
stainless-app[bot] Mar 20, 2026
e16924c
codegen metadata
stainless-app[bot] Mar 20, 2026
1284f6d
codegen metadata
stainless-app[bot] Mar 20, 2026
aa50e22
codegen metadata
stainless-app[bot] Mar 20, 2026
21dfba3
codegen metadata
stainless-app[bot] Mar 20, 2026
7384685
codegen metadata
stainless-app[bot] Mar 20, 2026
f827a2d
codegen metadata
stainless-app[bot] Mar 20, 2026
c3926a6
codegen metadata
stainless-app[bot] Mar 20, 2026
63a8a4a
codegen metadata
stainless-app[bot] Mar 20, 2026
800cefb
codegen metadata
stainless-app[bot] Mar 20, 2026
e868fa1
codegen metadata
stainless-app[bot] Mar 20, 2026
da1895e
codegen metadata
stainless-app[bot] Mar 21, 2026
82cbafa
codegen metadata
stainless-app[bot] Mar 21, 2026
4e8a181
codegen metadata
stainless-app[bot] Mar 21, 2026
01a4709
codegen metadata
stainless-app[bot] Mar 21, 2026
91d68a6
codegen metadata
stainless-app[bot] Mar 21, 2026
1bb03b6
codegen metadata
stainless-app[bot] Mar 21, 2026
a26c93e
codegen metadata
stainless-app[bot] Mar 21, 2026
be5d3a9
codegen metadata
stainless-app[bot] Mar 21, 2026
cacf4fb
codegen metadata
stainless-app[bot] Mar 21, 2026
e90439c
codegen metadata
stainless-app[bot] Mar 21, 2026
bafa6bb
codegen metadata
stainless-app[bot] Mar 21, 2026
b454963
codegen metadata
stainless-app[bot] Mar 21, 2026
406ad4c
codegen metadata
stainless-app[bot] Mar 22, 2026
0b9cf3a
codegen metadata
stainless-app[bot] Mar 22, 2026
abdf018
codegen metadata
stainless-app[bot] Mar 22, 2026
051f73d
codegen metadata
stainless-app[bot] Mar 22, 2026
7957398
codegen metadata
stainless-app[bot] Mar 22, 2026
36f8588
codegen metadata
stainless-app[bot] Mar 22, 2026
5b2df1a
codegen metadata
stainless-app[bot] Mar 22, 2026
28f109f
codegen metadata
stainless-app[bot] Mar 22, 2026
3a551e8
codegen metadata
stainless-app[bot] Mar 22, 2026
a35838f
codegen metadata
stainless-app[bot] Mar 22, 2026
3482958
codegen metadata
stainless-app[bot] Mar 22, 2026
376867a
codegen metadata
stainless-app[bot] Mar 22, 2026
573da19
codegen metadata
stainless-app[bot] Mar 23, 2026
4e68ed9
codegen metadata
stainless-app[bot] Mar 23, 2026
d5ad611
codegen metadata
stainless-app[bot] Mar 23, 2026
9bd8344
codegen metadata
stainless-app[bot] Mar 23, 2026
7f48043
codegen metadata
stainless-app[bot] Mar 23, 2026
64c7218
codegen metadata
stainless-app[bot] Mar 23, 2026
1b808cf
feat(api): api update
stainless-app[bot] Mar 23, 2026
c889aee
codegen metadata
stainless-app[bot] Mar 23, 2026
5f64d76
codegen metadata
stainless-app[bot] Mar 23, 2026
ff173e4
codegen metadata
stainless-app[bot] Mar 23, 2026
feb69c2
codegen metadata
stainless-app[bot] Mar 23, 2026
e77d6d3
codegen metadata
stainless-app[bot] Mar 23, 2026
d1bcc51
codegen metadata
stainless-app[bot] Mar 23, 2026
9efb591
codegen metadata
stainless-app[bot] Mar 23, 2026
6836401
codegen metadata
stainless-app[bot] Mar 23, 2026
1006a7b
codegen metadata
stainless-app[bot] Mar 23, 2026
5814b5a
codegen metadata
stainless-app[bot] Mar 23, 2026
f64bfb0
codegen metadata
stainless-app[bot] Mar 24, 2026
41f0659
codegen metadata
stainless-app[bot] Mar 24, 2026
98f9afa
codegen metadata
stainless-app[bot] Mar 24, 2026
0697f78
chore(internal): update gitignore
stainless-app[bot] Mar 24, 2026
05d3078
codegen metadata
stainless-app[bot] Mar 24, 2026
46a11ab
codegen metadata
stainless-app[bot] Mar 24, 2026
bea0f0d
codegen metadata
stainless-app[bot] Mar 24, 2026
f0a5ec0
codegen metadata
stainless-app[bot] Mar 24, 2026
6410217
codegen metadata
stainless-app[bot] Mar 24, 2026
54130d7
codegen metadata
stainless-app[bot] Mar 24, 2026
25d0a26
codegen metadata
stainless-app[bot] Mar 24, 2026
b124d48
codegen metadata
stainless-app[bot] Mar 24, 2026
56021cb
release: 0.15.0
stainless-app[bot] Mar 24, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.prism.log
.stdy.log
_dev

__pycache__
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.14.1"
".": "0.15.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 40
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sent%2Fsent-dm-2d0bb64dc84ba67ee91db6ff81424a968c5ddea4d2844ba67fc9b4b27881d60f.yml
openapi_spec_hash: 8e1d6bc2a6c6afef625e2bdcdf28ac63
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/sent%2Fsent-dm-5f6c3d993f976b15034adfa9ff9e09b175753efb9db6a37f9705438d30f16b7f.yml
openapi_spec_hash: ee8a1712abd4f6223fbc431584fc674f
config_hash: d8e8429147c4e214ff53c11e7ab2a1a6
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## 0.15.0 (2026-03-24)

Full Changelog: [v0.14.1...v0.15.0](https://github.com/sentdm/sent-dm-python/compare/v0.14.1...v0.15.0)

### Features

* **api:** api update ([1b808cf](https://github.com/sentdm/sent-dm-python/commit/1b808cf0f33936836ad7588857056d95fc18bd79))
* **api:** api update ([93500f0](https://github.com/sentdm/sent-dm-python/commit/93500f067df17cbb5ca0384b4d5a2600f699dfda))


### Bug Fixes

* sanitize endpoint path params ([7931fda](https://github.com/sentdm/sent-dm-python/commit/7931fda88ab2bfb29cf3fd9f0622e2304bccf662))


### Chores

* **internal:** update gitignore ([0697f78](https://github.com/sentdm/sent-dm-python/commit/0697f7822f07efe9479e262a4c8e5281f07ff374))

## 0.14.1 (2026-03-17)

Full Changelog: [v0.14.0...v0.14.1](https://github.com/sentdm/sent-dm-python/compare/v0.14.0...v0.14.1)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "sentdm"
version = "0.14.1"
version = "0.15.0"
description = "The official Python library for the sent-dm API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
1 change: 1 addition & 0 deletions src/sent_dm/_utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from ._path import path_template as path_template
from ._sync import asyncify as asyncify
from ._proxy import LazyProxy as LazyProxy
from ._utils import (
Expand Down
127 changes: 127 additions & 0 deletions src/sent_dm/_utils/_path.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
from __future__ import annotations

import re
from typing import (
Any,
Mapping,
Callable,
)
from urllib.parse import quote

# Matches '.' or '..' where each dot is either literal or percent-encoded (%2e / %2E).
_DOT_SEGMENT_RE = re.compile(r"^(?:\.|%2[eE]){1,2}$")

_PLACEHOLDER_RE = re.compile(r"\{(\w+)\}")


def _quote_path_segment_part(value: str) -> str:
"""Percent-encode `value` for use in a URI path segment.
Considers characters not in `pchar` set from RFC 3986 §3.3 to be unsafe.
https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
"""
# quote() already treats unreserved characters (letters, digits, and -._~)
# as safe, so we only need to add sub-delims, ':', and '@'.
# Notably, unlike the default `safe` for quote(), / is unsafe and must be quoted.
return quote(value, safe="!$&'()*+,;=:@")


def _quote_query_part(value: str) -> str:
"""Percent-encode `value` for use in a URI query string.
Considers &, = and characters not in `query` set from RFC 3986 §3.4 to be unsafe.
https://datatracker.ietf.org/doc/html/rfc3986#section-3.4
"""
return quote(value, safe="!$'()*+,;:@/?")


def _quote_fragment_part(value: str) -> str:
"""Percent-encode `value` for use in a URI fragment.
Considers characters not in `fragment` set from RFC 3986 §3.5 to be unsafe.
https://datatracker.ietf.org/doc/html/rfc3986#section-3.5
"""
return quote(value, safe="!$&'()*+,;=:@/?")


def _interpolate(
template: str,
values: Mapping[str, Any],
quoter: Callable[[str], str],
) -> str:
"""Replace {name} placeholders in `template`, quoting each value with `quoter`.
Placeholder names are looked up in `values`.
Raises:
KeyError: If a placeholder is not found in `values`.
"""
# re.split with a capturing group returns alternating
# [text, name, text, name, ..., text] elements.
parts = _PLACEHOLDER_RE.split(template)

for i in range(1, len(parts), 2):
name = parts[i]
if name not in values:
raise KeyError(f"a value for placeholder {{{name}}} was not provided")
val = values[name]
if val is None:
parts[i] = "null"
elif isinstance(val, bool):
parts[i] = "true" if val else "false"
else:
parts[i] = quoter(str(values[name]))

return "".join(parts)


def path_template(template: str, /, **kwargs: Any) -> str:
"""Interpolate {name} placeholders in `template` from keyword arguments.
Args:
template: The template string containing {name} placeholders.
**kwargs: Keyword arguments to interpolate into the template.
Returns:
The template with placeholders interpolated and percent-encoded.
Safe characters for percent-encoding are dependent on the URI component.
Placeholders in path and fragment portions are percent-encoded where the `segment`
and `fragment` sets from RFC 3986 respectively are considered safe.
Placeholders in the query portion are percent-encoded where the `query` set from
RFC 3986 §3.3 is considered safe except for = and & characters.
Raises:
KeyError: If a placeholder is not found in `kwargs`.
ValueError: If resulting path contains /./ or /../ segments (including percent-encoded dot-segments).
"""
# Split the template into path, query, and fragment portions.
fragment_template: str | None = None
query_template: str | None = None

rest = template
if "#" in rest:
rest, fragment_template = rest.split("#", 1)
if "?" in rest:
rest, query_template = rest.split("?", 1)
path_template = rest

# Interpolate each portion with the appropriate quoting rules.
path_result = _interpolate(path_template, kwargs, _quote_path_segment_part)

# Reject dot-segments (. and ..) in the final assembled path. The check
# runs after interpolation so that adjacent placeholders or a mix of static
# text and placeholders that together form a dot-segment are caught.
# Also reject percent-encoded dot-segments to protect against incorrectly
# implemented normalization in servers/proxies.
for segment in path_result.split("/"):
if _DOT_SEGMENT_RE.match(segment):
raise ValueError(f"Constructed path {path_result!r} contains dot-segment {segment!r} which is not allowed")

result = path_result
if query_template is not None:
result += "?" + _interpolate(query_template, kwargs, _quote_query_part)
if fragment_template is not None:
result += "#" + _interpolate(fragment_template, kwargs, _quote_fragment_part)

return result
2 changes: 1 addition & 1 deletion src/sent_dm/_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__ = "sent_dm"
__version__ = "0.14.1" # x-release-please-version
__version__ = "0.15.0" # x-release-please-version
14 changes: 7 additions & 7 deletions src/sent_dm/resources/contacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from ..types import contact_list_params, contact_create_params, contact_delete_params, contact_update_params
from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
from .._utils import maybe_transform, strip_not_given, async_maybe_transform
from .._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
Expand Down Expand Up @@ -133,7 +133,7 @@ def retrieve(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return self._get(
f"/v3/contacts/{id}",
path_template("/v3/contacts/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
Expand Down Expand Up @@ -189,7 +189,7 @@ def update(
**(extra_headers or {}),
}
return self._patch(
f"/v3/contacts/{id}",
path_template("/v3/contacts/{id}", id=id),
body=maybe_transform(
{
"default_channel": default_channel,
Expand Down Expand Up @@ -300,7 +300,7 @@ def delete(
extra_headers = {"Accept": "*/*", **(extra_headers or {})}
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return self._delete(
f"/v3/contacts/{id}",
path_template("/v3/contacts/{id}", id=id),
body=maybe_transform(body, contact_delete_params.ContactDeleteParams),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
Expand Down Expand Up @@ -418,7 +418,7 @@ async def retrieve(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return await self._get(
f"/v3/contacts/{id}",
path_template("/v3/contacts/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
Expand Down Expand Up @@ -474,7 +474,7 @@ async def update(
**(extra_headers or {}),
}
return await self._patch(
f"/v3/contacts/{id}",
path_template("/v3/contacts/{id}", id=id),
body=await async_maybe_transform(
{
"default_channel": default_channel,
Expand Down Expand Up @@ -585,7 +585,7 @@ async def delete(
extra_headers = {"Accept": "*/*", **(extra_headers or {})}
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return await self._delete(
f"/v3/contacts/{id}",
path_template("/v3/contacts/{id}", id=id),
body=await async_maybe_transform(body, contact_delete_params.ContactDeleteParams),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
Expand Down
10 changes: 5 additions & 5 deletions src/sent_dm/resources/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from ..types import message_send_params
from .._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given
from .._utils import maybe_transform, strip_not_given, async_maybe_transform
from .._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
Expand Down Expand Up @@ -77,7 +77,7 @@ def retrieve_activities(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return self._get(
f"/v3/messages/{id}/activities",
path_template("/v3/messages/{id}/activities", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
Expand Down Expand Up @@ -114,7 +114,7 @@ def retrieve_status(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return self._get(
f"/v3/messages/{id}",
path_template("/v3/messages/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
Expand Down Expand Up @@ -245,7 +245,7 @@ async def retrieve_activities(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return await self._get(
f"/v3/messages/{id}/activities",
path_template("/v3/messages/{id}/activities", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
Expand Down Expand Up @@ -282,7 +282,7 @@ async def retrieve_status(
raise ValueError(f"Expected a non-empty value for `id` but received {id!r}")
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return await self._get(
f"/v3/messages/{id}",
path_template("/v3/messages/{id}", id=id),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
Expand Down
6 changes: 3 additions & 3 deletions src/sent_dm/resources/numbers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import httpx

from .._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from .._utils import strip_not_given
from .._utils import path_template, strip_not_given
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import (
Expand Down Expand Up @@ -72,7 +72,7 @@ def lookup(
raise ValueError(f"Expected a non-empty value for `phone_number` but received {phone_number!r}")
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return self._get(
f"/v3/numbers/lookup/{phone_number}",
path_template("/v3/numbers/lookup/{phone_number}", phone_number=phone_number),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
Expand Down Expand Up @@ -132,7 +132,7 @@ async def lookup(
raise ValueError(f"Expected a non-empty value for `phone_number` but received {phone_number!r}")
extra_headers = {**strip_not_given({"x-profile-id": x_profile_id}), **(extra_headers or {})}
return await self._get(
f"/v3/numbers/lookup/{phone_number}",
path_template("/v3/numbers/lookup/{phone_number}", phone_number=phone_number),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
Expand Down
Loading
Loading