Skip to content

Commit e40893a

Browse files
author
Zach Banks
committed
FIX: Use POST not GET for endpoints with symbols
1 parent 3423e2f commit e40893a

File tree

3 files changed

+74
-73
lines changed

3 files changed

+74
-73
lines changed

databento/common/http.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import json
44
import warnings
55
from collections.abc import Iterable
6+
from collections.abc import Mapping
67
from io import BytesIO
78
from json.decoder import JSONDecodeError
89
from os import PathLike
@@ -94,7 +95,7 @@ async def _get_json_async(
9495
def _post(
9596
self,
9697
url: str,
97-
data: dict[str, object | None] | None = None,
98+
data: Mapping[str, object | None] | None = None,
9899
params: Iterable[tuple[str, str | None]] | None = None,
99100
basic_auth: bool = False,
100101
) -> Response:

databento/historical/api/metadata.py

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -304,22 +304,22 @@ def get_record_count(
304304
"""
305305
stype_in_valid = validate_enum(stype_in, SType, "stype_in")
306306
symbols_list = optional_symbols_list_to_list(symbols, stype_in_valid)
307-
params: list[tuple[str, str | None]] = [
308-
("dataset", validate_semantic_string(dataset, "dataset")),
309-
("symbols", ",".join(symbols_list)),
310-
("schema", str(validate_enum(schema, Schema, "schema"))),
311-
("start", optional_datetime_to_string(start)),
312-
("end", optional_datetime_to_string(end)),
313-
("stype_in", str(stype_in_valid)),
314-
]
307+
data: dict[str, str | None] = {
308+
"dataset": validate_semantic_string(dataset, "dataset"),
309+
"symbols": ",".join(symbols_list),
310+
"schema": str(validate_enum(schema, Schema, "schema")),
311+
"start": optional_datetime_to_string(start),
312+
"end": optional_datetime_to_string(end),
313+
"stype_in": str(stype_in_valid),
314+
}
315315

316316
# Optional Parameters
317317
if limit is not None:
318-
params.append(("limit", str(limit)))
318+
data["limit"] = str(limit)
319319

320-
response: Response = self._get(
320+
response: Response = self._post(
321321
url=self._base_url + ".get_record_count",
322-
params=params,
322+
data=data,
323323
basic_auth=True,
324324
)
325325

@@ -373,22 +373,22 @@ def get_billable_size(
373373
"""
374374
stype_in_valid = validate_enum(stype_in, SType, "stype_in")
375375
symbols_list = optional_symbols_list_to_list(symbols, stype_in_valid)
376-
params: list[tuple[str, str | None]] = [
377-
("dataset", validate_semantic_string(dataset, "dataset")),
378-
("start", datetime_to_string(start)),
379-
("end", optional_datetime_to_string(end)),
380-
("symbols", ",".join(symbols_list)),
381-
("schema", str(validate_enum(schema, Schema, "schema"))),
382-
("stype_in", str(stype_in_valid)),
383-
("stype_out", str(SType.INSTRUMENT_ID)),
384-
]
376+
data: dict[str, str | None] = {
377+
"dataset": validate_semantic_string(dataset, "dataset"),
378+
"start": datetime_to_string(start),
379+
"end": optional_datetime_to_string(end),
380+
"symbols": ",".join(symbols_list),
381+
"schema": str(validate_enum(schema, Schema, "schema")),
382+
"stype_in": str(stype_in_valid),
383+
"stype_out": str(SType.INSTRUMENT_ID),
384+
}
385385

386386
if limit is not None:
387-
params.append(("limit", str(limit)))
387+
data["limit"] = str(limit)
388388

389-
response: Response = self._get(
389+
response: Response = self._post(
390390
url=self._base_url + ".get_billable_size",
391-
params=params,
391+
data=data,
392392
basic_auth=True,
393393
)
394394

@@ -445,23 +445,23 @@ def get_cost(
445445
"""
446446
stype_in_valid = validate_enum(stype_in, SType, "stype_in")
447447
symbols_list = optional_symbols_list_to_list(symbols, stype_in_valid)
448-
params: list[tuple[str, str | None]] = [
449-
("dataset", validate_semantic_string(dataset, "dataset")),
450-
("start", datetime_to_string(start)),
451-
("end", optional_datetime_to_string(end)),
452-
("symbols", ",".join(symbols_list)),
453-
("schema", str(validate_enum(schema, Schema, "schema"))),
454-
("stype_in", str(stype_in_valid)),
455-
("stype_out", str(SType.INSTRUMENT_ID)),
456-
("mode", validate_enum(mode, FeedMode, "mode")),
457-
]
448+
data: dict[str, str | None] = {
449+
"dataset": validate_semantic_string(dataset, "dataset"),
450+
"start": datetime_to_string(start),
451+
"end": optional_datetime_to_string(end),
452+
"symbols": ",".join(symbols_list),
453+
"schema": str(validate_enum(schema, Schema, "schema")),
454+
"stype_in": str(stype_in_valid),
455+
"stype_out": str(SType.INSTRUMENT_ID),
456+
"mode": validate_enum(mode, FeedMode, "mode"),
457+
}
458458

459459
if limit is not None:
460-
params.append(("limit", str(limit)))
460+
data["limit"] = str(limit)
461461

462-
response: Response = self._get(
462+
response: Response = self._post(
463463
url=self._base_url + ".get_cost",
464-
params=params,
464+
data=data,
465465
basic_auth=True,
466466
)
467467

tests/test_historical_metadata.py

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def test_get_record_count_sends_expected_request(
191191
historical_client: Historical,
192192
) -> None:
193193
# Arrange
194-
monkeypatch.setattr(requests, "get", mocked_get := MagicMock())
194+
monkeypatch.setattr(requests, "post", mocked_post := MagicMock())
195195

196196
# Act
197197
historical_client.metadata.get_record_count(
@@ -204,20 +204,20 @@ def test_get_record_count_sends_expected_request(
204204
)
205205

206206
# Assert
207-
call = mocked_get.call_args.kwargs
207+
call = mocked_post.call_args.kwargs
208208
assert call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/metadata.get_record_count"
209209
assert sorted(call["headers"].keys()) == ["accept", "user-agent"]
210210
assert call["headers"]["accept"] == "application/json"
211211
assert all(v in call["headers"]["user-agent"] for v in ("Databento/", "Python/"))
212-
assert call["params"] == [
213-
("dataset", "GLBX.MDP3"),
214-
("symbols", "ESH1"),
215-
("schema", "mbo"),
216-
("start", "2020-12-28T12:00"),
217-
("end", "2020-12-29"),
218-
("stype_in", "raw_symbol"),
219-
("limit", "1000000"),
220-
]
212+
assert call["data"] == {
213+
"dataset": "GLBX.MDP3",
214+
"symbols": "ESH1",
215+
"schema": "mbo",
216+
"start": "2020-12-28T12:00",
217+
"end": "2020-12-29",
218+
"stype_in": "raw_symbol",
219+
"limit": "1000000",
220+
}
221221
assert call["timeout"] == (100, 100)
222222
assert isinstance(call["auth"], requests.auth.HTTPBasicAuth)
223223

@@ -227,7 +227,7 @@ def test_get_billable_size_sends_expected_request(
227227
historical_client: Historical,
228228
) -> None:
229229
# Arrange
230-
monkeypatch.setattr(requests, "get", mocked_get := MagicMock())
230+
monkeypatch.setattr(requests, "post", mocked_post := MagicMock())
231231

232232
# Act
233233
historical_client.metadata.get_billable_size(
@@ -240,23 +240,23 @@ def test_get_billable_size_sends_expected_request(
240240
)
241241

242242
# Assert
243-
call = mocked_get.call_args.kwargs
243+
call = mocked_post.call_args.kwargs
244244
assert (
245245
call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/metadata.get_billable_size"
246246
)
247247
assert sorted(call["headers"].keys()) == ["accept", "user-agent"]
248248
assert call["headers"]["accept"] == "application/json"
249249
assert all(v in call["headers"]["user-agent"] for v in ("Databento/", "Python/"))
250-
assert call["params"] == [
251-
("dataset", "GLBX.MDP3"),
252-
("start", "2020-12-28T12:00"),
253-
("end", "2020-12-29"),
254-
("symbols", "ESH1"),
255-
("schema", "mbo"),
256-
("stype_in", "raw_symbol"),
257-
("stype_out", "instrument_id"),
258-
("limit", "1000000"),
259-
]
250+
assert call["data"] == {
251+
"dataset": "GLBX.MDP3",
252+
"start": "2020-12-28T12:00",
253+
"end": "2020-12-29",
254+
"symbols": "ESH1",
255+
"schema": "mbo",
256+
"stype_in": "raw_symbol",
257+
"stype_out": "instrument_id",
258+
"limit": "1000000",
259+
}
260260
assert call["timeout"] == (100, 100)
261261
assert isinstance(call["auth"], requests.auth.HTTPBasicAuth)
262262

@@ -266,7 +266,7 @@ def test_get_cost_sends_expected_request(
266266
historical_client: Historical,
267267
) -> None:
268268
# Arrange
269-
monkeypatch.setattr(requests, "get", mocked_get := MagicMock())
269+
monkeypatch.setattr(requests, "post", mocked_post := MagicMock())
270270

271271
# Act
272272
historical_client.metadata.get_cost(
@@ -279,21 +279,21 @@ def test_get_cost_sends_expected_request(
279279
)
280280

281281
# Assert
282-
call = mocked_get.call_args.kwargs
282+
call = mocked_post.call_args.kwargs
283283
assert call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/metadata.get_cost"
284284
assert sorted(call["headers"].keys()) == ["accept", "user-agent"]
285285
assert call["headers"]["accept"] == "application/json"
286286
assert all(v in call["headers"]["user-agent"] for v in ("Databento/", "Python/"))
287-
assert call["params"] == [
288-
("dataset", "GLBX.MDP3"),
289-
("start", "2020-12-28T12:00"),
290-
("end", "2020-12-29"),
291-
("symbols", "ESH1"),
292-
("schema", "mbo"),
293-
("stype_in", "raw_symbol"),
294-
("stype_out", "instrument_id"),
295-
("mode", "historical-streaming"),
296-
("limit", "1000000"),
297-
]
287+
assert call["data"] == {
288+
"dataset": "GLBX.MDP3",
289+
"start": "2020-12-28T12:00",
290+
"end": "2020-12-29",
291+
"symbols": "ESH1",
292+
"schema": "mbo",
293+
"stype_in": "raw_symbol",
294+
"stype_out": "instrument_id",
295+
"mode": "historical-streaming",
296+
"limit": "1000000",
297+
}
298298
assert call["timeout"] == (100, 100)
299299
assert isinstance(call["auth"], requests.auth.HTTPBasicAuth)

0 commit comments

Comments
 (0)