Skip to content

Commit a60ca8c

Browse files
committed
REF: Modernize to use filesystem paths
1 parent 6da3df6 commit a60ca8c

File tree

9 files changed

+79
-77
lines changed

9 files changed

+79
-77
lines changed

CHANGELOG.md

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

3+
## 0.37.0 - TBD
4+
5+
### Breaking changes
6+
- Changed the type of the `output_dir` parameter in ` HistoricalClient::BatchDownload()`
7+
to a `std::filesystem::path` and the return type to `std::filesystem::path`
8+
- Changed the type of the `file_path` parameter in
9+
`HistoricalClient::TimeseriesGetRangeToFile()` to a `std::filesystem::path`
10+
- Changed the type of the `file_path` parameter in the `DbnFileStore`, `InFileStream`,
11+
and `OutFileStream` constructors to a `std::filesystem::path`
12+
313
## 0.36.0 - 2025-05-27
414

515
This version marks the release of DBN version 3 (DBNv3), which is the new default.

include/databento/dbn_file_store.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#pragma once
22

3-
#include <string>
3+
#include <filesystem> // path
44

55
#include "databento/dbn.hpp" // DecodeMetadata
66
#include "databento/dbn_decoder.hpp" // DbnDecoder
@@ -16,8 +16,9 @@ namespace databento {
1616
// used on a given instance.
1717
class DbnFileStore {
1818
public:
19-
explicit DbnFileStore(const std::string& file_path);
20-
DbnFileStore(ILogReceiver* log_receiver, const std::string& file_path,
19+
explicit DbnFileStore(const std::filesystem::path& file_path);
20+
DbnFileStore(ILogReceiver* log_receiver,
21+
const std::filesystem::path& file_path,
2122
VersionUpgradePolicy upgrade_policy);
2223

2324
// Callback API: calling Replay consumes the input.

include/databento/file_stream.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
#pragma once
22

3-
#include <cstddef> // byte, size_t
4-
#include <fstream> // ifstream, ofstream
5-
#include <string>
3+
#include <cstddef> // byte, size_t
4+
#include <filesystem> // path
5+
#include <fstream> // ifstream, ofstream
66

77
#include "databento/ireadable.hpp"
88
#include "databento/iwritable.hpp"
99

1010
namespace databento {
1111
class InFileStream : public IReadable {
1212
public:
13-
explicit InFileStream(const std::string& file_path);
13+
explicit InFileStream(const std::filesystem::path& file_path);
1414

1515
// Read exactly `length` bytes into `buffer`.
1616
void ReadExact(std::byte* buffer, std::size_t length) override;
@@ -24,7 +24,7 @@ class InFileStream : public IReadable {
2424

2525
class OutFileStream : public IWritable {
2626
public:
27-
explicit OutFileStream(const std::string& file_path);
27+
explicit OutFileStream(const std::filesystem::path& file_path);
2828

2929
void WriteAll(const std::byte* buffer, std::size_t length) override;
3030

include/databento/historical.hpp

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <cstdint>
4+
#include <filesystem>
45
#include <map> // multimap
56
#include <string>
67
#include <vector>
@@ -75,12 +76,12 @@ class Historical {
7576
// Lists all files associated with a batch job.
7677
std::vector<BatchFileDesc> BatchListFiles(const std::string& job_id);
7778
// Returns the paths of the downloaded files.
78-
std::vector<std::string> BatchDownload(const std::string& output_dir,
79-
const std::string& job_id);
79+
std::vector<std::filesystem::path> BatchDownload(
80+
const std::filesystem::path& output_dir, const std::string& job_id);
8081
// Returns the path of the downloaded file.
81-
std::string BatchDownload(const std::string& output_dir,
82-
const std::string& job_id,
83-
const std::string& filename_to_download);
82+
std::filesystem::path BatchDownload(const std::filesystem::path& output_dir,
83+
const std::string& job_id,
84+
const std::string& filename_to_download);
8485

8586
/*
8687
* Metadata API
@@ -206,30 +207,33 @@ class Historical {
206207
const std::string& dataset,
207208
const DateTimeRange<UnixNanos>& datetime_range,
208209
const std::vector<std::string>& symbols, Schema schema,
209-
const std::string& file_path);
210+
const std::filesystem::path& file_path);
210211
DbnFileStore TimeseriesGetRangeToFile(
211212
const std::string& dataset,
212213
const DateTimeRange<std::string>& datetime_range,
213214
const std::vector<std::string>& symbols, Schema schema,
214-
const std::string& file_path);
215+
const std::filesystem::path& file_path);
215216
DbnFileStore TimeseriesGetRangeToFile(
216217
const std::string& dataset,
217218
const DateTimeRange<UnixNanos>& datetime_range,
218219
const std::vector<std::string>& symbols, Schema schema, SType stype_in,
219-
SType stype_out, std::uint64_t limit, const std::string& file_path);
220+
SType stype_out, std::uint64_t limit,
221+
const std::filesystem::path& file_path);
220222
DbnFileStore TimeseriesGetRangeToFile(
221223
const std::string& dataset,
222224
const DateTimeRange<std::string>& datetime_range,
223225
const std::vector<std::string>& symbols, Schema schema, SType stype_in,
224-
SType stype_out, std::uint64_t limit, const std::string& file_path);
226+
SType stype_out, std::uint64_t limit,
227+
const std::filesystem::path& file_path);
225228

226229
private:
227230
using HttplibParams = std::multimap<std::string, std::string>;
228231

229232
BatchJob BatchSubmitJob(const HttplibParams& params);
230233
void StreamToFile(const std::string& url_path, const HttplibParams& params,
231-
const std::string& file_path);
232-
void DownloadFile(const std::string& url, const std::string& output_path);
234+
const std::filesystem::path& file_path);
235+
void DownloadFile(const std::string& url,
236+
const std::filesystem::path& output_path);
233237
std::vector<BatchJob> BatchListJobs(const HttplibParams& params);
234238
std::vector<DatasetConditionDetail> MetadataGetDatasetCondition(
235239
const HttplibParams& params);
@@ -240,7 +244,7 @@ class Historical {
240244
const MetadataCallback& metadata_callback,
241245
const RecordCallback& record_callback);
242246
DbnFileStore TimeseriesGetRangeToFile(const HttplibParams& params,
243-
const std::string& file_path);
247+
const std::filesystem::path& file_path);
244248

245249
ILogReceiver* log_receiver_;
246250
const std::string key_;

src/dbn_file_store.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
using databento::DbnFileStore;
1010

11-
DbnFileStore::DbnFileStore(const std::string& file_path)
11+
DbnFileStore::DbnFileStore(const std::filesystem::path& file_path)
1212
: decoder_{ILogReceiver::Default(), InFileStream{file_path}} {}
1313

1414
DbnFileStore::DbnFileStore(ILogReceiver* log_receiver,
15-
const std::string& file_path,
15+
const std::filesystem::path& file_path,
1616
VersionUpgradePolicy upgrade_policy)
1717
: decoder_{log_receiver, std::make_unique<InFileStream>(file_path),
1818
upgrade_policy} {}

src/file_stream.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77

88
using databento::InFileStream;
99

10-
InFileStream::InFileStream(const std::string& file_path)
10+
InFileStream::InFileStream(const std::filesystem::path& file_path)
1111
: stream_{file_path, std::ios::binary} {
1212
if (stream_.fail()) {
13-
throw InvalidArgumentError{"InFileStream", "file_path",
14-
"Non-existent or invalid file at " + file_path};
13+
throw InvalidArgumentError{
14+
"InFileStream", "file_path",
15+
"Non-existent or invalid file at " + file_path.string()};
1516
}
1617
}
1718

@@ -33,7 +34,7 @@ std::size_t InFileStream::ReadSome(std::byte* buffer, std::size_t max_length) {
3334

3435
using databento::OutFileStream;
3536

36-
OutFileStream::OutFileStream(const std::string& file_path)
37+
OutFileStream::OutFileStream(const std::filesystem::path& file_path)
3738
: stream_{file_path, std::ios::binary} {
3839
if (stream_.fail()) {
3940
throw InvalidArgumentError{"OutFileStream", "file_path",

src/historical.cpp

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -117,16 +117,6 @@ void TryCreateDir(const std::filesystem::path& dir_name) {
117117
throw databento::Exception{"Unable to create directory "s +
118118
dir_name.generic_string() + ": " + ec.message()};
119119
}
120-
121-
std::string PathJoin(const std::string& dir, const std::string& path) {
122-
if (dir.empty()) {
123-
return path;
124-
}
125-
if (dir[dir.length() - 1] == '/') {
126-
return dir + path;
127-
}
128-
return dir + '/' + path;
129-
}
130120
} // namespace
131121

132122
Historical::Historical(ILogReceiver* log_receiver, std::string key,
@@ -285,25 +275,25 @@ std::vector<databento::BatchFileDesc> Historical::BatchListFiles(
285275
return files;
286276
}
287277

288-
std::vector<std::string> Historical::BatchDownload(
289-
const std::string& output_dir, const std::string& job_id) {
278+
std::vector<std::filesystem::path> Historical::BatchDownload(
279+
const std::filesystem::path& output_dir, const std::string& job_id) {
290280
TryCreateDir(output_dir);
291-
const std::string job_dir = PathJoin(output_dir, job_id);
281+
const std::filesystem::path job_dir = output_dir / job_id;
292282
TryCreateDir(job_dir);
293283
const auto file_descs = BatchListFiles(job_id);
294-
std::vector<std::string> paths;
284+
std::vector<std::filesystem::path> paths;
295285
for (const auto& file_desc : file_descs) {
296-
std::string output_path = PathJoin(job_dir, file_desc.filename);
286+
std::filesystem::path output_path = job_dir / file_desc.filename;
297287
DownloadFile(file_desc.https_url, output_path);
298288
paths.emplace_back(std::move(output_path));
299289
}
300290
return paths;
301291
}
302-
std::string Historical::BatchDownload(const std::string& output_dir,
303-
const std::string& job_id,
304-
const std::string& filename_to_download) {
292+
std::filesystem::path Historical::BatchDownload(
293+
const std::filesystem::path& output_dir, const std::string& job_id,
294+
const std::string& filename_to_download) {
305295
TryCreateDir(output_dir);
306-
const std::string job_dir = PathJoin(output_dir, job_id);
296+
const std::filesystem::path job_dir = output_dir / job_id;
307297
TryCreateDir(job_dir);
308298
const auto file_descs = BatchListFiles(job_id);
309299
const auto file_desc_it =
@@ -316,14 +306,14 @@ std::string Historical::BatchDownload(const std::string& output_dir,
316306
"filename_to_download",
317307
"Filename not found for batch job " + job_id};
318308
}
319-
std::string output_path = PathJoin(job_dir, file_desc_it->filename);
309+
std::filesystem::path output_path = job_dir / file_desc_it->filename;
320310
DownloadFile(file_desc_it->https_url, output_path);
321311
return output_path;
322312
}
323313

324314
void Historical::StreamToFile(const std::string& url_path,
325315
const HttplibParams& params,
326-
const std::string& file_path) {
316+
const std::filesystem::path& file_path) {
327317
OutFileStream out_file{file_path};
328318
this->client_.GetRawStream(
329319
url_path, params, [&out_file](const char* data, std::size_t length) {
@@ -333,7 +323,7 @@ void Historical::StreamToFile(const std::string& url_path,
333323
}
334324

335325
void Historical::DownloadFile(const std::string& url,
336-
const std::string& output_path) {
326+
const std::filesystem::path& output_path) {
337327
static const std::string kEndpoint = "Historical::DownloadFile";
338328
// extract path from URL
339329
const auto protocol_divider = url.find("://");
@@ -870,7 +860,7 @@ static const std::string kTimeseriesGetRangeToFileEndpoint =
870860
databento::DbnFileStore Historical::TimeseriesGetRangeToFile(
871861
const std::string& dataset, const DateTimeRange<UnixNanos>& datetime_range,
872862
const std::vector<std::string>& symbols, Schema schema,
873-
const std::string& file_path) {
863+
const std::filesystem::path& file_path) {
874864
return this->TimeseriesGetRangeToFile(dataset, datetime_range, symbols,
875865
schema, kDefaultSTypeIn,
876866
kDefaultSTypeOut, {}, file_path);
@@ -879,15 +869,16 @@ databento::DbnFileStore Historical::TimeseriesGetRangeToFile(
879869
const std::string& dataset,
880870
const DateTimeRange<std::string>& datetime_range,
881871
const std::vector<std::string>& symbols, Schema schema,
882-
const std::string& file_path) {
872+
const std::filesystem::path& file_path) {
883873
return this->TimeseriesGetRangeToFile(dataset, datetime_range, symbols,
884874
schema, kDefaultSTypeIn,
885875
kDefaultSTypeOut, {}, file_path);
886876
}
887877
databento::DbnFileStore Historical::TimeseriesGetRangeToFile(
888878
const std::string& dataset, const DateTimeRange<UnixNanos>& datetime_range,
889879
const std::vector<std::string>& symbols, Schema schema, SType stype_in,
890-
SType stype_out, std::uint64_t limit, const std::string& file_path) {
880+
SType stype_out, std::uint64_t limit,
881+
const std::filesystem::path& file_path) {
891882
httplib::Params params{
892883
{"dataset", dataset},
893884
{"encoding", "dbn"},
@@ -906,7 +897,8 @@ databento::DbnFileStore Historical::TimeseriesGetRangeToFile(
906897
const std::string& dataset,
907898
const DateTimeRange<std::string>& datetime_range,
908899
const std::vector<std::string>& symbols, Schema schema, SType stype_in,
909-
SType stype_out, std::uint64_t limit, const std::string& file_path) {
900+
SType stype_out, std::uint64_t limit,
901+
const std::filesystem::path& file_path) {
910902
httplib::Params params{
911903
{"dataset", dataset},
912904
{"encoding", "dbn"},
@@ -922,7 +914,7 @@ databento::DbnFileStore Historical::TimeseriesGetRangeToFile(
922914
return this->TimeseriesGetRangeToFile(params, file_path);
923915
}
924916
databento::DbnFileStore Historical::TimeseriesGetRangeToFile(
925-
const HttplibParams& params, const std::string& file_path) {
917+
const HttplibParams& params, const std::filesystem::path& file_path) {
926918
StreamToFile(kTimeseriesGetRangePath, params, file_path);
927919
return DbnFileStore{log_receiver_, file_path,
928920
VersionUpgradePolicy::UpgradeToV3};

tests/include/temp_file.hpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,12 @@ namespace databento {
1616
// goes out of scope.
1717
class TempFile {
1818
public:
19-
explicit TempFile(const std::filesystem::path& path)
20-
: TempFile{path.string()} {}
21-
explicit TempFile(std::string path) : path_{std::move(path)} {
19+
explicit TempFile(std::filesystem::path path) : path_{std::move(path)} {
2220
std::ifstream f{path_};
2321
if (Exists()) {
2422
throw InvalidArgumentError{
2523
"TempFile::TempFile", "path",
26-
"File at path " + path_ + " shouldn't already exist"};
24+
"File at path " + path_.string() + " shouldn't already exist"};
2725
}
2826
}
2927
TempFile(const TempFile&) = delete;
@@ -36,14 +34,14 @@ class TempFile {
3634
<< ::strerror(errno);
3735
}
3836

39-
const std::string& Path() const { return path_; }
37+
const std::filesystem::path& Path() const { return path_; }
4038

4139
bool Exists() const {
4240
std::ifstream f{path_};
4341
return f.good();
4442
}
4543

4644
private:
47-
std::string path_;
45+
std::filesystem::path path_;
4846
};
4947
} // namespace databento

tests/src/historical_tests.cpp

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -244,19 +244,17 @@ TEST_F(HistoricalTests, TestBatchDownloadAll) {
244244
static_cast<std::uint16_t>(port)};
245245
ASSERT_FALSE(temp_metadata_file.Exists());
246246
ASSERT_FALSE(temp_dbn_file.Exists());
247-
const std::vector<std::string> paths =
248-
target.BatchDownload(tmp_path_.string(), kJobId);
247+
const std::vector<std::filesystem::path> paths =
248+
target.BatchDownload(tmp_path_, kJobId);
249249
EXPECT_TRUE(temp_metadata_file.Exists());
250250
EXPECT_TRUE(temp_dbn_file.Exists());
251251
ASSERT_EQ(paths.size(), 2);
252-
EXPECT_NE(
253-
std::find_if(paths.begin(), paths.end(),
254-
[&temp_metadata_file](const auto& path) {
255-
return std::filesystem::path{path}.lexically_normal() ==
256-
std::filesystem::path{temp_metadata_file.Path()}
257-
.lexically_normal();
258-
}),
259-
paths.end());
252+
EXPECT_NE(std::find_if(paths.begin(), paths.end(),
253+
[&temp_metadata_file](const auto& path) {
254+
return path.lexically_normal() ==
255+
temp_metadata_file.Path().lexically_normal();
256+
}),
257+
paths.end());
260258
EXPECT_NE(
261259
std::find_if(paths.begin(), paths.end(),
262260
[&temp_dbn_file](const auto& path) {
@@ -278,12 +276,11 @@ TEST_F(HistoricalTests, TestBatchDownloadSingle) {
278276
databento::Historical target{logger_.get(), kApiKey, "localhost",
279277
static_cast<std::uint16_t>(port)};
280278
ASSERT_FALSE(temp_metadata_file.Exists());
281-
const std::string path =
282-
target.BatchDownload(tmp_path_.string(), kJobId, "test_metadata.json");
279+
const std::filesystem::path path =
280+
target.BatchDownload(tmp_path_, kJobId, "test_metadata.json");
283281
EXPECT_TRUE(temp_metadata_file.Exists());
284-
EXPECT_EQ(
285-
std::filesystem::path{path}.lexically_normal(),
286-
std::filesystem::path{temp_metadata_file.Path()}.lexically_normal());
282+
EXPECT_EQ(path.lexically_normal(),
283+
temp_metadata_file.Path().lexically_normal());
287284
}
288285

289286
TEST_F(HistoricalTests, TestBatchDownloadSingleInvalidFile) {
@@ -294,9 +291,8 @@ TEST_F(HistoricalTests, TestBatchDownloadSingleInvalidFile) {
294291

295292
databento::Historical target{logger_.get(), kApiKey, "localhost",
296293
static_cast<std::uint16_t>(port)};
297-
ASSERT_THROW(
298-
target.BatchDownload(tmp_path_.string(), kJobId, "test_metadata.js"),
299-
InvalidArgumentError);
294+
ASSERT_THROW(target.BatchDownload(tmp_path_, kJobId, "test_metadata.js"),
295+
InvalidArgumentError);
300296
}
301297

302298
TEST_F(HistoricalTests, TestMetadataListPublishers) {

0 commit comments

Comments
 (0)