From c4a1a6c0b4a53711c825257f0aa2c645c581447d Mon Sep 17 00:00:00 2001 From: Teon Banek <teon.banek@memgraph.io> Date: Mon, 9 Mar 2020 10:42:07 +0100 Subject: [PATCH] Extract py::AppendToSysPath function Reviewers: mferencevic, ipaljak, llugovic Reviewed By: mferencevic Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D2714 --- src/py/py.hpp | 22 ++++++++++++++++++++-- src/query/procedure/module.cpp | 16 +++------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/py/py.hpp b/src/py/py.hpp index 642b4d5f6..da8e91ad0 100644 --- a/src/py/py.hpp +++ b/src/py/py.hpp @@ -190,7 +190,7 @@ inline std::ostream &operator<<(std::ostream &os, const Object &py_object) { /// Stores information on a raised Python exception. /// @sa FetchError -struct ExceptionInfo final { +struct [[nodiscard]] ExceptionInfo final { /// Type of the exception, if nullptr there is no exception. Object type; /// Optional value of the exception. @@ -222,7 +222,7 @@ inline std::ostream &operator<<(std::ostream &os, /// Get the current exception info and clear the current exception indicator. /// /// This is normally used to catch and handle exceptions via C API. -inline std::optional<ExceptionInfo> FetchError() { +[[nodiscard]] inline std::optional<ExceptionInfo> FetchError() { PyObject *exc_type, *exc_value, *traceback; PyErr_Fetch(&exc_type, &exc_value, &traceback); if (!exc_type) return std::nullopt; @@ -230,4 +230,22 @@ inline std::optional<ExceptionInfo> FetchError() { return ExceptionInfo{Object(exc_type), Object(exc_value), Object(traceback)}; } +/// Append `dir` to Python's `sys.path`. +/// +/// The function does not check whether the directory exists, or is readable. +/// ExceptionInfo is returned if an error occurred. +[[nodiscard]] inline std::optional<ExceptionInfo> AppendToSysPath( + const char *dir) { + CHECK(dir); + auto *py_path = PySys_GetObject("path"); + CHECK(py_path); + py::Object import_dir(PyUnicode_FromString(dir)); + if (!import_dir) return py::FetchError(); + int import_dir_in_path = PySequence_Contains(py_path, import_dir); + if (import_dir_in_path == -1) return py::FetchError(); + if (import_dir_in_path == 1) return std::nullopt; + if (PyList_Append(py_path, import_dir) == -1) return py::FetchError(); + return std::nullopt; +} + } // namespace py diff --git a/src/query/procedure/module.cpp b/src/query/procedure/module.cpp index 1b349e832..4d0ed6772 100644 --- a/src/query/procedure/module.cpp +++ b/src/query/procedure/module.cpp @@ -345,21 +345,11 @@ bool PythonModule::Load(std::filesystem::path file_path) { CHECK(!py_module_) << "Attempting to load an already loaded module..."; LOG(INFO) << "Loading module " << file_path << " ..."; auto gil = py::EnsureGIL(); - auto *py_path = PySys_GetObject("path"); - CHECK(py_path); - py::Object import_dir(PyUnicode_FromString(file_path.parent_path().c_str())); - int import_dir_in_path = PySequence_Contains(py_path, import_dir); - if (import_dir_in_path == -1) { - LOG(ERROR) << "Unexpected error when loading module " << file_path; + auto maybe_exc = py::AppendToSysPath(file_path.parent_path().c_str()); + if (maybe_exc) { + LOG(ERROR) << "Unable to load module " << file_path << "; " << *maybe_exc; return false; } - if (import_dir_in_path == 0) { - if (PyList_Append(py_path, import_dir) != 0) { - auto exc_info = py::FetchError().value(); - LOG(ERROR) << "Unable to load module " << file_path << "; " << exc_info; - return false; - } - } py_module_ = WithModuleRegistration(&procedures_, [&](auto *module_def, auto *memory) { return ImportPyModule(file_path.stem().c_str(), module_def);