Skip to content

Commit d515389

Browse files
[CIVIS-10059] FIX API calls should send all items in an array query parameter (#507)
* FIX array params in API calls * MAINT update changelog * MAINT update civis api spec * VER bump version to 2.4.3 * MAINT update changelog * ENH check for more general __iter__ and filter dict+str
1 parent 55fe7c2 commit d515389

File tree

5 files changed

+45
-2
lines changed

5 files changed

+45
-2
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1818

1919
### Security
2020

21+
## 2.4.3 - 2025-01-13
22+
23+
### Fixed
24+
- Fixed the way array query parameters are passed to a Civis API call,
25+
so that all items in an array are included in the correctly formatted URL. (#507)
26+
2127
## 2.4.2 - 2025-01-02
2228

2329
### Changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "civis"
7-
version = "2.4.2"
7+
version = "2.4.3"
88
description = "Civis API Python Client"
99
readme = "README.rst"
1010
requires-python = ">= 3.10"

src/civis/base.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,27 @@ def _build_path(self, path):
119119
return self._base_url
120120
return tostr_urljoin(self._base_url, path.strip("/"))
121121

122+
@staticmethod
123+
def _handle_array_params(params):
124+
"""Convert array-like parameters to the format that Civis API expects.
125+
126+
Different APIs expect array-like parameters in different formats.
127+
For Civis API, an array parameter `foo` needs to be passed in as `foo[]`.
128+
Related reference: https://stackoverflow.com/a/23347265
129+
"""
130+
if not params:
131+
return
132+
new_params = {}
133+
for key, value in params.items():
134+
if hasattr(value, "__iter__") and not isinstance(value, (dict, str)):
135+
new_params[f"{key}[]"] = list(value)
136+
else:
137+
new_params[key] = value
138+
return new_params
139+
122140
def _make_request(self, method, path=None, params=None, data=None, **kwargs):
123141
url = self._build_path(path)
142+
params = self._handle_array_params(params)
124143

125144
with self._lock:
126145
if self._client._retrying is None:

src/civis/resources/civis_api_spec.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/test_base.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,21 @@ def test_civis_api_error_empty_response():
4747

4848
error = CivisAPIError(response)
4949
assert error.error_message == "No Response Content from Civis API"
50+
51+
52+
@pytest.mark.parametrize(
53+
"source_params, expected_params",
54+
[
55+
({}, None),
56+
(None, None),
57+
(
58+
{"foo": 123, "bar": "hello", "baz": {"a": 1, "b": 2}},
59+
{"foo": 123, "bar": "hello", "baz": {"a": 1, "b": 2}},
60+
),
61+
({"foo": [1, 2, 3]}, {"foo[]": [1, 2, 3]}),
62+
({"foo": (1, 2, 3)}, {"foo[]": [1, 2, 3]}),
63+
({"foo": {1, 2, 3}}, {"foo[]": [1, 2, 3]}),
64+
],
65+
)
66+
def test_array_params(source_params, expected_params):
67+
assert Endpoint._handle_array_params(source_params) == expected_params

0 commit comments

Comments
 (0)