Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 stripe/_api_requestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ def _args_for_request_with_retries(
**params,
}

encoded_params = urlencode(list(_api_encode(params or {}, api_mode)))
encoded_params = urlencode(list(_api_encode(params or {})))

# Don't use strict form encoding by changing the square bracket control
# characters back to their literals. This is fine by the server, and
Expand Down
13 changes: 6 additions & 7 deletions stripe/_encode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import datetime
import time
from collections import OrderedDict
from typing import Generator, Optional, Tuple, Any
from typing import Generator, Tuple, Any


def _encode_datetime(dttime: datetime.datetime):
Expand All @@ -27,26 +27,25 @@ def _json_encode_date_callback(value):
return value


def _api_encode(
data, api_mode: Optional[str]
) -> Generator[Tuple[str, Any], None, None]:
def _api_encode(data) -> Generator[Tuple[str, Any], None, None]:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a breaking change? I'm assuming because it starts with a _ we're OK, but I'm not too sure how we treat that from a semver point of view

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in python, an _ prefix conventionally means "private" and most linters will at least complain if someone is trying to access a method prefixed with an _. I think this is not a breaking change here.

for key, value in data.items():
if value is None:
continue
elif hasattr(value, "stripe_id"):
yield (key, value.stripe_id)
elif isinstance(value, list) or isinstance(value, tuple):
for i, sv in enumerate(value):
encoded_key = key if api_mode == "V2" else "%s[%d]" % (key, i)
# Always use indexed format for arrays
encoded_key = "%s[%d]" % (key, i)
if isinstance(sv, dict):
subdict = _encode_nested_dict(encoded_key, sv)
for k, v in _api_encode(subdict, api_mode):
for k, v in _api_encode(subdict):
yield (k, v)
else:
yield (encoded_key, sv)
elif isinstance(value, dict):
subdict = _encode_nested_dict(key, value)
for subkey, subvalue in _api_encode(subdict, api_mode):
for subkey, subvalue in _api_encode(subdict):
yield (subkey, subvalue)
elif isinstance(value, datetime.datetime):
yield (key, _encode_datetime(value))
Expand Down
2 changes: 1 addition & 1 deletion stripe/_multipart_data_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(self, chunk_size: int = 1028):
def add_params(self, params):
# Flatten parameters first

params = dict(_api_encode(params, "V1"))
params = dict(_api_encode(params))

for key, value in params.items():
if value is None:
Expand Down
2 changes: 1 addition & 1 deletion stripe/_oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ def authorize_url(
OAuth._set_client_id(params)
if "response_type" not in params:
params["response_type"] = "code"
query = urlencode(list(_api_encode(params, "V1")))
query = urlencode(list(_api_encode(params)))
url = connect_api_base + path + "?" + query
return url

Expand Down
2 changes: 1 addition & 1 deletion stripe/_oauth_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def authorize_url(
self._set_client_id(params)
if "response_type" not in params:
params["response_type"] = "code"
query = urlencode(list(_api_encode(params, "V1")))
query = urlencode(list(_api_encode(params)))

# connect_api_base will be always set to stripe.DEFAULT_CONNECT_API_BASE
# if it is not overridden on the client explicitly.
Expand Down
4 changes: 2 additions & 2 deletions tests/test_api_requestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def test_encodes_null_values_preview(self, requestor, http_client_mock):

def test_dictionary_list_encoding(self):
params = {"foo": {"0": {"bar": "bat"}}}
encoded = list(_api_encode(params, "V1"))
encoded = list(_api_encode(params))
key, value = encoded[0]

assert key == "foo[0][bar]"
Expand All @@ -237,7 +237,7 @@ def test_ordereddict_encoding(self):
]
)
}
encoded = list(_api_encode(params, "V1"))
encoded = list(_api_encode(params))

assert encoded[0][0] == "ordered[one]"
assert encoded[1][0] == "ordered[two]"
Expand Down
10 changes: 5 additions & 5 deletions tests/test_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1176,26 +1176,26 @@ class TestAPIEncode:
def test_encode_dict(self):
body = {"foo": {"dob": {"month": 1}, "name": "bat"}}

values = [t for t in _api_encode(body, "V1")]
values = [t for t in _api_encode(body)]

assert ("foo[dob][month]", 1) in values
assert ("foo[name]", "bat") in values

def test_encode_array(self):
body = {"foo": [{"dob": {"month": 1}, "name": "bat"}]}

values = [t for t in _api_encode(body, "V1")]
values = [t for t in _api_encode(body)]

assert ("foo[0][dob][month]", 1) in values
assert ("foo[0][name]", "bat") in values

def test_encode_v2_array(self):
body = {"foo": [{"dob": {"month": 1}, "name": "bat"}]}

values = [t for t in _api_encode(body, "V2")]
values = [t for t in _api_encode(body)]

assert ("foo[dob][month]", 1) in values
assert ("foo[name]", "bat") in values
assert ("foo[0][dob][month]", 1) in values
assert ("foo[0][name]", "bat") in values


class TestHTTPXClient(ClientTestBase):
Expand Down