Skip to content

Commit 6dc3dc1

Browse files
committed
MOD: Support form data for POST requests
1 parent d91880b commit 6dc3dc1

File tree

8 files changed

+145
-160
lines changed

8 files changed

+145
-160
lines changed

databento/common/parsing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ def datetime_to_date_string(value: pd.Timestamp | date | str | int) -> str:
233233

234234

235235
def optional_datetime_to_string(
236-
value: pd.Timestamp | date | str | int,
236+
value: pd.Timestamp | date | str | int | None,
237237
) -> str | None:
238238
"""
239239
Return a valid datetime string from the given value (if not None).

databento/historical/api/batch.py

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -119,43 +119,34 @@ def submit_job(
119119
"""
120120
stype_in_valid = validate_enum(stype_in, SType, "stype_in")
121121
symbols_list = optional_symbols_list_to_string(symbols, stype_in_valid)
122-
params: list[tuple[str, str | None]] = [
123-
("dataset", validate_semantic_string(dataset, "dataset")),
124-
("start", datetime_to_string(start)),
125-
("end", optional_datetime_to_string(end)),
126-
("symbols", str(symbols_list)),
127-
("schema", str(validate_enum(schema, Schema, "schema"))),
128-
("stype_in", str(stype_in_valid)),
129-
("stype_out", str(validate_enum(stype_out, SType, "stype_out"))),
130-
("encoding", str(validate_enum(encoding, Encoding, "encoding"))),
131-
(
132-
"compression",
133-
str(validate_enum(compression, Compression, "compression"))
134-
if compression
135-
else None,
136-
),
137-
(
138-
"split_duration",
139-
str(validate_enum(split_duration, SplitDuration, "split_duration")),
140-
),
141-
(
142-
"packaging",
143-
str(validate_enum(packaging, Packaging, "packaging"))
144-
if packaging
145-
else None,
146-
),
147-
("delivery", str(validate_enum(delivery, Delivery, "delivery"))),
148-
]
122+
data: dict[str, object | None] = {
123+
"dataset": validate_semantic_string(dataset, "dataset"),
124+
"start": datetime_to_string(start),
125+
"end": optional_datetime_to_string(end),
126+
"symbols": str(symbols_list),
127+
"schema": str(validate_enum(schema, Schema, "schema")),
128+
"stype_in": str(stype_in_valid),
129+
"stype_out": str(validate_enum(stype_out, SType, "stype_out")),
130+
"encoding": str(validate_enum(encoding, Encoding, "encoding")),
131+
"compression": str(validate_enum(compression, Compression, "compression"))
132+
if compression
133+
else None,
134+
"split_duration": str(validate_enum(split_duration, SplitDuration, "split_duration")),
135+
"packaging": str(validate_enum(packaging, Packaging, "packaging"))
136+
if packaging
137+
else None,
138+
"delivery": str(validate_enum(delivery, Delivery, "delivery")),
139+
}
149140

150141
# Optional Parameters
151142
if limit is not None:
152-
params.append(("limit", str(limit)))
143+
data["limit"] = str(limit)
153144
if split_size is not None:
154-
params.append(("split_size", str(split_size)))
145+
data["split_size"] = str(split_size)
155146

156147
return self._post(
157148
url=self._base_url + ".submit_job",
158-
params=params,
149+
data=data,
159150
basic_auth=True,
160151
).json()
161152

databento/historical/api/symbology.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def resolve(
3838
"""
3939
Request symbology mappings resolution from Databento.
4040
41-
Makes a `GET /symbology.resolve` HTTP request.
41+
Makes a `POST /symbology.resolve` HTTP request.
4242
4343
Parameters
4444
----------
@@ -66,19 +66,19 @@ def resolve(
6666
"""
6767
stype_in_valid = validate_enum(stype_in, SType, "stype_in")
6868
symbols_list = optional_symbols_list_to_string(symbols, stype_in_valid)
69-
params: list[tuple[str, str | None]] = [
70-
("dataset", validate_semantic_string(dataset, "dataset")),
71-
("symbols", symbols_list),
72-
("stype_in", str(stype_in_valid)),
73-
("stype_out", str(validate_enum(stype_out, SType, "stype_out"))),
74-
("start_date", datetime_to_date_string(start_date)),
75-
("end_date", optional_date_to_string(end_date)),
76-
("default_value", default_value),
77-
]
69+
data: dict[str, object | None] = {
70+
"dataset": validate_semantic_string(dataset, "dataset"),
71+
"symbols": symbols_list,
72+
"stype_in": str(stype_in_valid),
73+
"stype_out": str(validate_enum(stype_out, SType, "stype_out")),
74+
"start_date": datetime_to_date_string(start_date),
75+
"end_date": optional_date_to_string(end_date),
76+
"default_value": default_value,
77+
}
7878

79-
response: Response = self._get(
79+
response: Response = self._post(
8080
url=self._base_url + ".resolve",
81-
params=params,
81+
data=data,
8282
basic_auth=True,
8383
)
8484

databento/historical/api/timeseries.py

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def __init__(self, key: str, gateway: str) -> None:
3131

3232
def get_range(
3333
self,
34-
dataset: Dataset | str | None,
34+
dataset: Dataset | str,
3535
start: pd.Timestamp | date | str | int,
3636
end: pd.Timestamp | date | str | int | None = None,
3737
symbols: list[str] | str | None = None,
@@ -44,7 +44,7 @@ def get_range(
4444
"""
4545
Request a historical time series data stream from Databento.
4646
47-
Makes a `GET /timeseries.get_range` HTTP request.
47+
Makes a `POST /timeseries.get_range` HTTP request.
4848
4949
Primary method for getting historical intraday market data, daily data,
5050
instrument definitions and market status data directly into your application.
@@ -99,32 +99,32 @@ def get_range(
9999
schema_valid = validate_enum(schema, Schema, "schema")
100100
start_valid = datetime_to_string(start)
101101
end_valid = optional_datetime_to_string(end)
102-
params: list[tuple[str, str | None]] = [
103-
("dataset", validate_semantic_string(dataset, "dataset")),
104-
("start", start_valid),
105-
("end", end_valid),
106-
("symbols", symbols_list),
107-
("schema", str(schema_valid)),
108-
("stype_in", str(stype_in_valid)),
109-
("stype_out", str(validate_enum(stype_out, SType, "stype_out"))),
110-
("encoding", str(Encoding.DBN)), # Always request dbn
111-
("compression", str(Compression.ZSTD)), # Always request zstd
112-
]
102+
data: dict[str, object | None] = {
103+
"dataset": validate_semantic_string(dataset, "dataset"),
104+
"start": start_valid,
105+
"end": end_valid,
106+
"symbols": symbols_list,
107+
"schema": str(schema_valid),
108+
"stype_in": str(stype_in_valid),
109+
"stype_out": str(validate_enum(stype_out, SType, "stype_out")),
110+
"encoding": str(Encoding.DBN), # Always request dbn
111+
"compression": str(Compression.ZSTD), # Always request zstd
112+
}
113113

114114
# Optional Parameters
115115
if limit is not None:
116-
params.append(("limit", str(limit)))
116+
data["limit"] = str(limit)
117117

118118
return self._stream(
119119
url=self._base_url + ".get_range",
120-
params=params,
120+
data=data,
121121
basic_auth=True,
122122
path=path,
123123
)
124124

125125
async def get_range_async(
126126
self,
127-
dataset: Dataset | str | None,
127+
dataset: Dataset | str,
128128
start: pd.Timestamp | date | str | int,
129129
end: pd.Timestamp | date | str | int | None = None,
130130
symbols: list[str] | str | None = None,
@@ -138,7 +138,7 @@ async def get_range_async(
138138
Asynchronously request a historical time series data stream from
139139
Databento.
140140
141-
Makes a `GET /timeseries.get_range` HTTP request.
141+
Makes a `POST /timeseries.get_range` HTTP request.
142142
143143
Primary method for getting historical intraday market data, daily data,
144144
instrument definitions and market status data directly into your application.
@@ -193,25 +193,25 @@ async def get_range_async(
193193
schema_valid = validate_enum(schema, Schema, "schema")
194194
start_valid = datetime_to_string(start)
195195
end_valid = optional_datetime_to_string(end)
196-
params: list[tuple[str, str | None]] = [
197-
("dataset", validate_semantic_string(dataset, "dataset")),
198-
("start", start_valid),
199-
("end", end_valid),
200-
("symbols", symbols_list),
201-
("schema", str(schema_valid)),
202-
("stype_in", str(stype_in_valid)),
203-
("stype_out", str(validate_enum(stype_out, SType, "stype_out"))),
204-
("encoding", str(Encoding.DBN)), # Always request dbn
205-
("compression", str(Compression.ZSTD)), # Always request zstd
206-
]
196+
data: dict[str, object | None] = {
197+
"dataset": validate_semantic_string(dataset, "dataset"),
198+
"start": start_valid,
199+
"end": end_valid,
200+
"symbols": symbols_list,
201+
"schema": str(schema_valid),
202+
"stype_in": str(stype_in_valid),
203+
"stype_out": str(validate_enum(stype_out, SType, "stype_out")),
204+
"encoding": str(Encoding.DBN), # Always request dbn
205+
"compression": str(Compression.ZSTD), # Always request zstd
206+
}
207207

208208
# Optional Parameters
209209
if limit is not None:
210-
params.append(("limit", str(limit)))
210+
data["limit"] = str(limit)
211211

212212
return await self._stream_async(
213213
url=self._base_url + ".get_range",
214-
params=params,
214+
data=data,
215215
basic_auth=True,
216216
path=path,
217217
)

databento/historical/http.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from databento.version import __version__
2525

2626

27-
_32KB = 1024 * 32 # 32_768
27+
_32KIB = 1024 * 32 # 32_768
2828
WARNING_HEADER_FIELD: str = "X-Warning"
2929

3030

@@ -94,13 +94,15 @@ async def _get_json_async(
9494
def _post(
9595
self,
9696
url: str,
97+
data: dict[str, object | None] | None = None,
9798
params: Iterable[tuple[str, str | None]] | None = None,
9899
basic_auth: bool = False,
99100
) -> Response:
100101
self._check_api_key()
101102

102103
with requests.post(
103104
url=url,
105+
data=data,
104106
params=params,
105107
headers=self._headers,
106108
auth=HTTPBasicAuth(username=self._key, password="") if basic_auth else None,
@@ -113,15 +115,15 @@ def _post(
113115
def _stream(
114116
self,
115117
url: str,
116-
params: Iterable[tuple[str, str | None]],
118+
data: dict[str, object | None],
117119
basic_auth: bool,
118120
path: PathLike[str] | str | None = None,
119121
) -> DBNStore:
120122
self._check_api_key()
121123

122-
with requests.get(
124+
with requests.post(
123125
url=url,
124-
params=params,
126+
data=data,
125127
headers=self._headers,
126128
auth=HTTPBasicAuth(username=self._key, password="") if basic_auth else None,
127129
timeout=(self.TIMEOUT, self.TIMEOUT),
@@ -135,7 +137,7 @@ def _stream(
135137
else:
136138
writer = open(path, "x+b")
137139

138-
for chunk in response.iter_content(chunk_size=_32KB):
140+
for chunk in response.iter_content(chunk_size=_32KIB):
139141
writer.write(chunk)
140142

141143
if path is None:
@@ -148,16 +150,16 @@ def _stream(
148150
async def _stream_async(
149151
self,
150152
url: str,
151-
params: Iterable[tuple[str, str | None]],
153+
data: dict[str, object | None] | None,
152154
basic_auth: bool,
153155
path: PathLike[str] | str | None = None,
154156
) -> DBNStore:
155157
self._check_api_key()
156158

157159
async with aiohttp.ClientSession() as session:
158-
async with session.get(
160+
async with session.post(
159161
url=url,
160-
params=[x for x in params if x[1] is not None],
162+
data=data,
161163
headers=self._headers,
162164
auth=aiohttp.BasicAuth(login=self._key, password="", encoding="utf-8")
163165
if basic_auth

tests/test_historical_batch.py

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -77,27 +77,25 @@ def test_batch_submit_job_sends_expected_request(
7777

7878
# Assert
7979
call = mocked_post.call_args.kwargs
80-
assert (
81-
call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/batch.submit_job"
82-
)
80+
assert call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/batch.submit_job"
8381
assert sorted(call["headers"].keys()) == ["accept", "user-agent"]
8482
assert call["headers"]["accept"] == "application/json"
8583
assert all(v in call["headers"]["user-agent"] for v in ("Databento/", "Python/"))
86-
assert call["params"] == [
87-
("dataset", "GLBX.MDP3"),
88-
("start", "2020-12-28T12:00"),
89-
("end", "2020-12-29"),
90-
("symbols", "ESH1"),
91-
("schema", "trades"),
92-
("stype_in", "raw_symbol"),
93-
("stype_out", "instrument_id"),
94-
("encoding", "csv"),
95-
("compression", "zstd"),
96-
("split_duration", "day"),
97-
("packaging", "none"),
98-
("delivery", "download"),
99-
("split_size", "10000000000"),
100-
]
84+
assert call["data"] == {
85+
"dataset": "GLBX.MDP3",
86+
"start": "2020-12-28T12:00",
87+
"end": "2020-12-29",
88+
"symbols": "ESH1",
89+
"schema": "trades",
90+
"stype_in": "raw_symbol",
91+
"stype_out": "instrument_id",
92+
"encoding": "csv",
93+
"compression": "zstd",
94+
"split_duration": "day",
95+
"packaging": "none",
96+
"delivery": "download",
97+
"split_size": "10000000000",
98+
}
10199
assert call["timeout"] == (100, 100)
102100
assert isinstance(call["auth"], requests.auth.HTTPBasicAuth)
103101

@@ -114,9 +112,7 @@ def test_batch_list_jobs_sends_expected_request(
114112

115113
# Assert
116114
call = mocked_get.call_args.kwargs
117-
assert (
118-
call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/batch.list_jobs"
119-
)
115+
assert call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/batch.list_jobs"
120116
assert sorted(call["headers"].keys()) == ["accept", "user-agent"]
121117
assert call["headers"]["accept"] == "application/json"
122118
assert all(v in call["headers"]["user-agent"] for v in ("Databento/", "Python/"))
@@ -141,9 +137,7 @@ def test_batch_list_files_sends_expected_request(
141137

142138
# Assert
143139
call = mocked_get.call_args.kwargs
144-
assert (
145-
call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/batch.list_files"
146-
)
140+
assert call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/batch.list_files"
147141
assert sorted(call["headers"].keys()) == ["accept", "user-agent"]
148142
assert call["headers"]["accept"] == "application/json"
149143
assert all(v in call["headers"]["user-agent"] for v in ("Databento/", "Python/"))
@@ -174,9 +168,7 @@ def test_batch_download_single_file_sends_expected_request(
174168

175169
# Assert
176170
call = mocked_get.call_args.kwargs
177-
assert (
178-
call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/batch.list_files"
179-
)
171+
assert call["url"] == f"{historical_client.gateway}/v{db.API_VERSION}/batch.list_files"
180172
assert sorted(call["headers"].keys()) == ["accept", "user-agent"]
181173
assert call["headers"]["accept"] == "application/json"
182174
assert all(v in call["headers"]["user-agent"] for v in ("Databento/", "Python/"))

0 commit comments

Comments
 (0)