forked from duckdb/duckdb-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpath_like.cpp
More file actions
96 lines (82 loc) · 2.92 KB
/
Copy pathpath_like.cpp
File metadata and controls
96 lines (82 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include "duckdb_python/path_like.hpp"
#include "duckdb_python/pyrelation.hpp"
#include "duckdb_python/pyconnection/pyconnection.hpp"
#include "duckdb/common/string_util.hpp"
#include "duckdb_python/pyfilesystem.hpp"
#include "duckdb_python/filesystem_object.hpp"
#include "duckdb/common/optional_ptr.hpp"
namespace duckdb {
struct PathLikeProcessor {
public:
explicit PathLikeProcessor(DuckDBPyConnection &connection) : connection(connection) {
}
public:
void AddFile(const nb::object &object);
PathLike Finalize();
protected:
ModifiedMemoryFileSystem &GetFS() {
if (!object_store) {
object_store = &connection.GetObjectFileSystem();
}
return *object_store;
}
public:
DuckDBPyConnection &connection;
optional_ptr<ModifiedMemoryFileSystem> object_store;
// The list containing every file
vector<string> all_files;
// The list of files that are registered in the object_store;
vector<string> fs_files;
};
void PathLikeProcessor::AddFile(const nb::object &object) {
if (nb::isinstance<nb::str>(object)) {
all_files.push_back(nb::cast<std::string>(nb::str(object)));
return;
}
if (nb::isinstance<nb::bytes>(object) || nb::hasattr(object, "__fspath__")) {
// A bytes path or an os.PathLike object (e.g. pathlib.Path) - decode it to a string
auto fsdecode = nb::module_::import_("os").attr("fsdecode");
all_files.push_back(nb::cast<std::string>(nb::str(fsdecode(object))));
return;
}
// This is (assumed to be) a file-like object
auto generated_name =
StringUtil::Format("%s://%s", "DUCKDB_INTERNAL_OBJECTSTORE", StringUtil::GenerateRandomName());
all_files.push_back(generated_name);
fs_files.push_back(generated_name);
auto &fs = GetFS();
fs.attr("add_file")(object, generated_name);
}
PathLike PathLikeProcessor::Finalize() {
PathLike result;
if (all_files.empty()) {
throw InvalidInputException("Please provide a non-empty list of paths or file-like objects");
}
result.files = std::move(all_files);
if (fs_files.empty()) {
// No file-like objects were registered in the filesystem
// no need to make a dependency
return result;
}
// Create the dependency, which contains the logic to clean up the files in its destructor
auto &fs = GetFS();
auto dependency = make_uniq<ExternalDependency>();
auto dependency_item = PythonDependencyItem::Create(make_uniq<FileSystemObject>(fs, std::move(fs_files)));
dependency->AddDependency("file_handles", std::move(dependency_item));
result.dependency = std::move(dependency);
return result;
}
PathLike PathLike::Create(const nb::object &object, DuckDBPyConnection &connection) {
PathLikeProcessor processor(connection);
if (nb::isinstance<nb::list>(object)) {
auto list = nb::list(object);
for (auto item : list) { // nanobind list iteration yields temporary handles; bind by value (cheap handle)
processor.AddFile(nb::borrow<nb::object>(item));
}
} else {
// Single object
processor.AddFile(object);
}
return processor.Finalize();
}
} // namespace duckdb