Skip to content

Commit d3fd45c

Browse files
authored
VER: Release 0.15.2
See release notes.
2 parents 4d71810 + 2a32651 commit d3fd45c

File tree

9 files changed

+106
-14
lines changed

9 files changed

+106
-14
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 0.15.2 - 2023-07-19
4+
5+
#### Bug fixes
6+
- Fixed an issue where the `end` parameter in `timeseries.get_range_async` did not support a value of `None`
7+
- Fixed an issue where `timeseries.get_range` requests would begin with an invalid `path` parameter
8+
39
## 0.15.1 - 2023-07-06
410

511
#### Bug fixes
@@ -27,6 +33,7 @@
2733

2834
## 0.14.1 - 2023-06-16
2935

36+
#### Bug fixes
3037
- Fixed issue where `DBNStore.to_df()` would raise an exception if no records were present
3138
- Fixed exception message when creating a DBNStore from an empty data source
3239

@@ -101,6 +108,7 @@
101108

102109
## 0.11.0 - 2023-04-13
103110

111+
#### Bug fixes
104112
- Changed `end` and `end_date` to optional to support new forward-fill behaviour
105113
- Upgraded `zstandard` to 0.20.0
106114

databento/common/dbnstore.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
from databento.common.data import STRUCT_MAP
3838
from databento.common.error import BentoError
3939
from databento.common.symbology import InstrumentIdMappingInterval
40+
from databento.common.validation import validate_file_write_path
4041
from databento.common.validation import validate_maybe_enum
4142
from databento.live import DBNRecord
4243

@@ -227,8 +228,8 @@ def __init__(self, source: BytesIO | bytes | IO[bytes]):
227228
@property
228229
def name(self) -> str:
229230
"""
230-
Return the name of the source buffer.
231-
Equivelant to `repr` of the input.
231+
Return the name of the source buffer. Equivalent to `repr` of the
232+
input.
232233
233234
Returns
234235
-------
@@ -978,10 +979,20 @@ def to_file(self, path: Path | str) -> None:
978979
path : str
979980
The file path to write to.
980981
982+
Raises
983+
------
984+
IsADirectoryError
985+
If path is a directory.
986+
FileExistsError
987+
If path exists.
988+
PermissionError
989+
If path is not writable.
990+
981991
"""
982-
with open(path, mode="xb") as f:
992+
file_path = validate_file_write_path(path, "path")
993+
with open(file_path, mode="xb") as f:
983994
f.write(self._data_source.reader.read())
984-
self._data_source = FileDataSource(path)
995+
self._data_source = FileDataSource(file_path)
985996

986997
def to_json(
987998
self,

databento/common/validation.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import os
34
from enum import Enum
45
from os import PathLike
56
from pathlib import Path
@@ -27,6 +28,11 @@ def validate_path(value: PathLike[str] | str, param: str) -> Path:
2728
Path
2829
A valid path.
2930
31+
Raises
32+
------
33+
TypeError
34+
If value is not a valid path.
35+
3036
"""
3137
try:
3238
return Path(value)
@@ -37,6 +43,42 @@ def validate_path(value: PathLike[str] | str, param: str) -> Path:
3743
) from None
3844

3945

46+
def validate_file_write_path(value: PathLike[str] | str, param: str) -> Path:
47+
"""
48+
Validate whether the given value is a valid path to a writable file.
49+
50+
Parameters
51+
----------
52+
value: PathLike or str
53+
The value to validate.
54+
param : str
55+
The name of the parameter being validated (for any error message).
56+
57+
Returns
58+
-------
59+
Path
60+
A valid path to a writable file.
61+
62+
Raises
63+
------
64+
IsADirectoryError
65+
If path is a directory.
66+
FileExistsError
67+
If path exists.
68+
PermissionError
69+
If path is not writable.
70+
71+
"""
72+
path_valid = validate_path(value, param)
73+
if not os.access(path_valid.parent, os.W_OK):
74+
raise PermissionError(f"The file `{value}` is not writable.")
75+
if path_valid.is_dir():
76+
raise IsADirectoryError(f"The `{param}` was not a path to a file.")
77+
if path_valid.is_file():
78+
raise FileExistsError(f"The file `{value}` already exists.")
79+
return path_valid
80+
81+
4082
def validate_enum(
4183
value: object,
4284
enum: type[E],

databento/historical/api/timeseries.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from databento.common.parsing import optional_datetime_to_string
1616
from databento.common.parsing import optional_symbols_list_to_list
1717
from databento.common.validation import validate_enum
18+
from databento.common.validation import validate_file_write_path
1819
from databento.common.validation import validate_semantic_string
1920
from databento.historical.api import API_VERSION
2021
from databento.historical.http import BentoHttpAPI
@@ -79,7 +80,7 @@ def get_range(
7980
limit : int, optional
8081
The maximum number of records to return. If `None` then no limit.
8182
path : PathLike or str, optional
82-
The path to stream the data to on disk (will then return a `DBNStore`).
83+
The file path to stream the data to on disk (will then return a `DBNStore`).
8384
8485
Returns
8586
-------
@@ -102,7 +103,6 @@ def get_range(
102103
data: dict[str, object | None] = {
103104
"dataset": validate_semantic_string(dataset, "dataset"),
104105
"start": start_valid,
105-
"end": end_valid,
106106
"symbols": ",".join(symbols_list),
107107
"schema": str(schema_valid),
108108
"stype_in": str(stype_in_valid),
@@ -114,6 +114,10 @@ def get_range(
114114
# Optional Parameters
115115
if limit is not None:
116116
data["limit"] = str(limit)
117+
if end is not None:
118+
data["end"] = end_valid
119+
if path is not None:
120+
path = validate_file_write_path(path, "path")
117121

118122
return self._stream(
119123
url=self._base_url + ".get_range",
@@ -173,7 +177,7 @@ async def get_range_async(
173177
limit : int, optional
174178
The maximum number of records to return. If `None` then no limit.
175179
path : PathLike or str, optional
176-
The path to stream the data to on disk (will then return a `DBNStore`).
180+
The file path to stream the data to on disk (will then return a `DBNStore`).
177181
178182
Returns
179183
-------
@@ -196,7 +200,6 @@ async def get_range_async(
196200
data: dict[str, object | None] = {
197201
"dataset": validate_semantic_string(dataset, "dataset"),
198202
"start": start_valid,
199-
"end": end_valid,
200203
"symbols": ",".join(symbols_list),
201204
"schema": str(schema_valid),
202205
"stype_in": str(stype_in_valid),
@@ -208,6 +211,10 @@ async def get_range_async(
208211
# Optional Parameters
209212
if limit is not None:
210213
data["limit"] = str(limit)
214+
if end is not None:
215+
data["end"] = end_valid
216+
if path is not None:
217+
path = validate_file_write_path(path, "path")
211218

212219
return await self._stream_async(
213220
url=self._base_url + ".get_range",

databento/live/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,8 @@ def gateway(self) -> str | None:
193193
@property
194194
def metadata(self) -> databento_dbn.Metadata | None:
195195
"""
196-
The DBN metadata header for this session, or `None` if the
197-
metadata has not been received yet.
196+
The DBN metadata header for this session, or `None` if the metadata has
197+
not been received yet.
198198
199199
Returns
200200
-------

databento/live/protocol.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@
4141

4242
def chunk(iterable: Iterable[_C], size: int) -> Iterable[tuple[_C, ...]]:
4343
"""
44-
Break an iterable into chunks with a length of
45-
at most `size`.
44+
Break an iterable into chunks with a length of at most `size`.
4645
4746
Parameters
4847
----------

databento/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.15.1"
1+
__version__ = "0.15.2"

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "databento"
3-
version = "0.15.1"
3+
version = "0.15.2"
44
description = "Official Python client library for Databento"
55
authors = [
66
"Databento <[email protected]>",

tests/test_common_validation.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from __future__ import annotations
22

33
from enum import Enum
4+
from pathlib import Path
45
from typing import Any
56

67
import pytest
78
from databento.common.validation import validate_enum
9+
from databento.common.validation import validate_file_write_path
810
from databento.common.validation import validate_gateway
911
from databento.common.validation import validate_maybe_enum
1012
from databento.common.validation import validate_path
@@ -26,6 +28,29 @@ def test_validate_path_given_wrong_types_raises_type_error(
2628
with pytest.raises(TypeError):
2729
validate_path(value, "param")
2830

31+
def test_validate_file_write_path(
32+
tmp_path: Path,
33+
) -> None:
34+
# Arrange, Act, Assert
35+
test_file = tmp_path / "test.file"
36+
validate_file_write_path(test_file, "param")
37+
38+
def test_validate_file_write_path_is_dir(
39+
tmp_path: Path,
40+
) -> None:
41+
# Arrange, Act, Assert
42+
with pytest.raises(IsADirectoryError):
43+
validate_file_write_path(tmp_path, "param")
44+
45+
def test_validate_file_write_path_exists(
46+
tmp_path: Path,
47+
) -> None:
48+
# Arrange, Act, Assert
49+
test_file = tmp_path / "test.file"
50+
test_file.touch()
51+
with pytest.raises(FileExistsError):
52+
validate_file_write_path(test_file, "param")
53+
2954
@pytest.mark.parametrize(
3055
"value, enum",
3156
[

0 commit comments

Comments
 (0)