Skip to content

Commit

Permalink
Validate pyarrow's version at runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
robomics committed Oct 20, 2024
1 parent 185c02b commit d645ec6
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 4 deletions.
83 changes: 81 additions & 2 deletions src/include/hictkpy/nanobind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,94 @@ HICTKPY_DISABLE_WARNING_USELESS_CAST
HICTKPY_DISABLE_WARNING_POP
// clang-format on

#include <cassert>
#include <mutex>
#include <string>

inline nanobind::module_ import_module_checked(const std::string& module_name) {
try {
return nanobind::module_::import_(module_name.c_str());
} catch (nanobind::python_error& e) {
// NOLINTNEXTLINE(*-pro-type-vararg)
// NOLINTNEXTLINE(*-vararg)
nanobind::raise_from(e, PyExc_ModuleNotFoundError,
"To enable %s support, please install %s with: pip install 'hictkpy[%s]'",
"To enable %s support, please install %s with: pip install 'hictkpy[%s]'\n"
"Alternatively, you can install hictkpy with all its dependencies by "
"running: pip install 'hictkpy[all]'",
module_name.c_str(), module_name.c_str(), module_name.c_str());
}
}

// NOLINTNEXTLINE(*-avoid-magic-numbers)
inline nanobind::module_ import_pyarrow_checked(int min_version_major = 16,
int min_version_minor = 0,
int min_version_patch = 0) {
assert(min_version_major >= 0);
assert(min_version_minor >= 0);
assert(min_version_patch >= 0);

static bool version_ok{false};
static std::mutex mtx{};

auto pa = import_module_checked("pyarrow");

[[maybe_unused]] const auto lck = std::scoped_lock(mtx);
if (version_ok) {
return pa;
}

static std::string error_msg{};
error_msg.clear();
try {
auto metadata = nanobind::module_::import_("importlib.metadata");

const auto version = nanobind::cast<std::vector<std::string>>(
metadata.attr("version")("pyarrow").attr("split")("."));
if (version.size() < 3) {
throw nanobind::import_error(
"unable to detect pyarrow version: assuming pyarrow's version is not compatible: please "
"install a compatible version of pyarrow with: pip install 'hictkpy[pyarrow]'");
}

const auto major_version_found = std::stoi(version[0]);
const auto minor_version_found = std::stoi(version[1]);
const auto patch_version_found = std::stoi(version[2]);

version_ok = major_version_found >= min_version_major;
version_ok |=
major_version_found == min_version_major && minor_version_found >= min_version_minor;
version_ok |= major_version_found == min_version_major &&
minor_version_found == min_version_minor &&
patch_version_found >= min_version_patch;

if (!version_ok) {
// Poor man's formatting
error_msg = "pyarrow ";
for (const auto& tok : version) {
error_msg += tok + ".";
}
if (version.size() > 1) {
error_msg.pop_back();
}
error_msg +=
" is too old to be used with hictkpy: please "
"install a compatible version with: pip install 'hictkpy[pyarrow]'";
throw nanobind::import_error(error_msg.c_str());
}
} catch (const nanobind::builtin_exception&) {
throw;
} catch (const std::exception& e) {
error_msg = "unable to parse pyarrow version: ";
error_msg += e.what();
error_msg +=
". Assuming pyarrow's version is not compatible: please "
"install a compatible version of pyarrow with: pip install 'hictkpy[pyarrow]'";
throw nanobind::import_error(error_msg.c_str());
} catch (...) {
throw nanobind::import_error(
"unable to parse pyarrow version: Assuming pyarrow's version is not compatible: please "
"install a compatible version of pyarrow with: pip install 'hictkpy[pyarrow]'");
}

assert(version_ok);
return pa;
}
2 changes: 1 addition & 1 deletion src/pixel_selector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ template <typename N, typename PixelSelector>
}

nb::object PixelSelector::to_arrow(std::string_view span) const {
std::ignore = import_module_checked("pyarrow");
std::ignore = import_pyarrow_checked();

const auto query_span = parse_span(span);
auto table = std::visit(
Expand Down
2 changes: 1 addition & 1 deletion src/to_pyarrow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ static void release_arrow_array_streamPyCapsule(PyObject* capsule) {
nb::object export_pyarrow_table(std::shared_ptr<arrow::Table> arrow_table) {
assert(arrow_table);

const auto pa = import_module_checked("pyarrow");
const auto pa = import_pyarrow_checked();

std::vector<nb::object> columns_py(static_cast<std::size_t>(arrow_table->num_columns()));
std::vector<std::shared_ptr<arrow::ChunkedArray>> columns(columns_py.size());
Expand Down

0 comments on commit d645ec6

Please sign in to comment.