diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 158f5f455..42997bd37 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -61,6 +61,72 @@ jobs: path: docstrings/ retention-days: 1 + + # Build and test bindings + pytest: + needs: build-docstrings + strategy: + matrix: + os: [ubuntu-latest, windows-2019, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Print home directory + run: echo Home directory inside container $HOME + + - name: Cache .hunter folder + if: matrix.os != 'windows-latest' + uses: actions/cache@v2 + with: + path: ~/.hunter/ + key: hunter-pytest-${{ matrix.os }} + - name: Cache .hunter folder + if: matrix.os == 'windows-latest' + uses: actions/cache@v2 + with: + path: C:/.hunter/ + key: hunter-pytest-${{ matrix.os }} + + - uses: actions/checkout@v2 + with: + submodules: 'recursive' + + - uses: actions/download-artifact@v2 + with: + name: 'docstrings' + path: docstrings + - name: Specify docstring to use while building the wheel + run: echo "DEPTHAI_PYTHON_DOCSTRINGS_INPUT=$PWD/docstrings/depthai_python_docstring.hpp" >> $GITHUB_ENV + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: "3.10" + + - name: Install dependencies (Ubuntu) + if: matrix.os == 'ubuntu-latest' + run: | + python -m pip install --upgrade pip + sudo apt install libusb-1.0-0-dev + + - name: Install dependencies (MacOS) + if: matrix.os == 'macos-latest' + run: | + python -m pip install --upgrade pip + brew install libusb + + - name: Install pytest + run: | + python -m pip install pytest numpy + + - name: Compile + run: | + cmake -S . -B build -D CMAKE_BUILD_TYPE=Release -D DEPTHAI_PYTHON_DOCSTRINGS_INPUT=$PWD/docstrings/depthai_python_docstring.hpp -D DEPTHAI_PYTHON_ENABLE_TESTS=ON + cmake --build build --parallel 4 + - name: Test + run: | + cmake --build build --target pytest --config Release + + # This job builds wheels for armhf arch (RPi) build-linux-armhf: needs: build-docstrings @@ -338,7 +404,7 @@ jobs: release: if: startsWith(github.ref, 'refs/tags/v') - needs: [build-linux-armhf, build-windows-x86_64, build-macos-x86_64, build-linux-x86_64, build-linux-arm64] + needs: [pytest, build-linux-armhf, build-windows-x86_64, build-macos-x86_64, build-linux-x86_64, build-linux-arm64] runs-on: ubuntu-latest steps: diff --git a/depthai-core b/depthai-core index ec14f9a98..45ac63695 160000 --- a/depthai-core +++ b/depthai-core @@ -1 +1 @@ -Subproject commit ec14f9a98670f685a2ff21f4c33eb1bc18ce836f +Subproject commit 45ac636955e1b23e648d8cdd5961f70a87a14e5c diff --git a/src/CalibrationHandlerBindings.cpp b/src/CalibrationHandlerBindings.cpp index e4a018b12..25443f349 100644 --- a/src/CalibrationHandlerBindings.cpp +++ b/src/CalibrationHandlerBindings.cpp @@ -25,8 +25,8 @@ void CalibrationHandlerBindings::bind(pybind11::module& m, void* pCallstack){ // Bindings calibrationHandler .def(py::init<>(), DOC(dai, CalibrationHandler, CalibrationHandler)) - .def(py::init(), DOC(dai, CalibrationHandler, CalibrationHandler, 2)) - .def(py::init(), DOC(dai, CalibrationHandler, CalibrationHandler, 3)) + .def(py::init(), DOC(dai, CalibrationHandler, CalibrationHandler, 2)) + .def(py::init(), DOC(dai, CalibrationHandler, CalibrationHandler, 3)) .def(py::init(), DOC(dai, CalibrationHandler, CalibrationHandler, 4)) .def("getEepromData", &CalibrationHandler::getEepromData, DOC(dai, CalibrationHandler, getEepromData)) diff --git a/src/DeviceBindings.cpp b/src/DeviceBindings.cpp index 6a2981988..02bd67f75 100644 --- a/src/DeviceBindings.cpp +++ b/src/DeviceBindings.cpp @@ -115,7 +115,7 @@ static void bindConstructors(ARG& arg){ py::gil_scoped_release release; return std::make_unique(pipeline, dev, maxUsbSpeed); }), py::arg("pipeline"), py::arg("maxUsbSpeed"), DOC(dai, DeviceBase, DeviceBase, 3)) - .def(py::init([](const Pipeline& pipeline, const std::string& pathToCmd){ + .def(py::init([](const Pipeline& pipeline, const dai::Path& pathToCmd){ auto dev = deviceSearchHelper(); py::gil_scoped_release release; return std::make_unique(pipeline, dev, pathToCmd); @@ -123,58 +123,58 @@ static void bindConstructors(ARG& arg){ .def(py::init([](const Pipeline& pipeline, const DeviceInfo& deviceInfo, bool usb2Mode){ py::gil_scoped_release release; return std::make_unique(pipeline, deviceInfo, usb2Mode); - }), py::arg("pipeline"), py::arg("devInfo"), py::arg("usb2Mode") = false, DOC(dai, DeviceBase, DeviceBase, 7)) + }), py::arg("pipeline"), py::arg("devInfo"), py::arg("usb2Mode") = false, DOC(dai, DeviceBase, DeviceBase, 6)) .def(py::init([](const Pipeline& pipeline, const DeviceInfo& deviceInfo, UsbSpeed maxUsbSpeed){ py::gil_scoped_release release; return std::make_unique(pipeline, deviceInfo, maxUsbSpeed); - }), py::arg("pipeline"), py::arg("deviceInfo"), py::arg("maxUsbSpeed"), DOC(dai, DeviceBase, DeviceBase, 8)) - .def(py::init([](const Pipeline& pipeline, const DeviceInfo& deviceInfo, std::string pathToCmd){ + }), py::arg("pipeline"), py::arg("deviceInfo"), py::arg("maxUsbSpeed"), DOC(dai, DeviceBase, DeviceBase, 7)) + .def(py::init([](const Pipeline& pipeline, const DeviceInfo& deviceInfo, dai::Path pathToCmd){ py::gil_scoped_release release; return std::make_unique(pipeline, deviceInfo, pathToCmd); - }), py::arg("pipeline"), py::arg("devInfo"), py::arg("pathToCmd"), DOC(dai, DeviceBase, DeviceBase, 9)) + }), py::arg("pipeline"), py::arg("devInfo"), py::arg("pathToCmd"), DOC(dai, DeviceBase, DeviceBase, 8)) // DeviceBase constructor - OpenVINO version .def(py::init([](OpenVINO::Version version){ auto dev = deviceSearchHelper(); py::gil_scoped_release release; return std::make_unique(version, dev); - }), py::arg("version") = OpenVINO::DEFAULT_VERSION, DOC(dai, DeviceBase, DeviceBase, 11)) + }), py::arg("version") = OpenVINO::DEFAULT_VERSION, DOC(dai, DeviceBase, DeviceBase, 10)) .def(py::init([](OpenVINO::Version version, bool usb2Mode){ auto dev = deviceSearchHelper(); py::gil_scoped_release release; return std::make_unique(version, dev, usb2Mode); - }), py::arg("version"), py::arg("usb2Mode") = false, DOC(dai, DeviceBase, DeviceBase, 13)) + }), py::arg("version"), py::arg("usb2Mode") = false, DOC(dai, DeviceBase, DeviceBase, 11)) .def(py::init([](OpenVINO::Version version, UsbSpeed maxUsbSpeed){ auto dev = deviceSearchHelper(); py::gil_scoped_release release; return std::make_unique(version, dev, maxUsbSpeed); - }), py::arg("version"), py::arg("maxUsbSpeed"), DOC(dai, DeviceBase, DeviceBase, 14)) - .def(py::init([](OpenVINO::Version version, const std::string& pathToCmd){ + }), py::arg("version"), py::arg("maxUsbSpeed"), DOC(dai, DeviceBase, DeviceBase, 12)) + .def(py::init([](OpenVINO::Version version, const dai::Path& pathToCmd){ auto dev = deviceSearchHelper(); py::gil_scoped_release release; return std::make_unique(version, dev, pathToCmd); - }), py::arg("version"), py::arg("pathToCmd"), DOC(dai, DeviceBase, DeviceBase, 15)) + }), py::arg("version"), py::arg("pathToCmd"), DOC(dai, DeviceBase, DeviceBase, 13)) .def(py::init([](OpenVINO::Version version, const DeviceInfo& deviceInfo, bool usb2Mode){ py::gil_scoped_release release; return std::make_unique(version, deviceInfo, usb2Mode); - }), py::arg("version"), py::arg("deviceDesc"), py::arg("usb2Mode") = false, DOC(dai, DeviceBase, DeviceBase, 18)) + }), py::arg("version"), py::arg("deviceDesc"), py::arg("usb2Mode") = false, DOC(dai, DeviceBase, DeviceBase, 15)) .def(py::init([](OpenVINO::Version version, const DeviceInfo& deviceInfo, UsbSpeed maxUsbSpeed){ py::gil_scoped_release release; return std::make_unique(version, deviceInfo, maxUsbSpeed); - }), py::arg("version"), py::arg("deviceInfo"), py::arg("maxUsbSpeed"), DOC(dai, DeviceBase, DeviceBase, 19)) - .def(py::init([](OpenVINO::Version version, const DeviceInfo& deviceInfo, std::string pathToCmd){ + }), py::arg("version"), py::arg("deviceInfo"), py::arg("maxUsbSpeed"), DOC(dai, DeviceBase, DeviceBase, 16)) + .def(py::init([](OpenVINO::Version version, const DeviceInfo& deviceInfo, dai::Path pathToCmd){ py::gil_scoped_release release; return std::make_unique(version, deviceInfo, pathToCmd); - }), py::arg("version"), py::arg("deviceDesc"), py::arg("pathToCmd"), DOC(dai, DeviceBase, DeviceBase, 20)) + }), py::arg("version"), py::arg("deviceDesc"), py::arg("pathToCmd"), DOC(dai, DeviceBase, DeviceBase, 17)) .def(py::init([](typename D::Config config){ auto dev = deviceSearchHelper(); py::gil_scoped_release release; return std::make_unique(config, dev); - }), py::arg("config"), DOC(dai, DeviceBase, DeviceBase, 22)) + }), py::arg("config"), DOC(dai, DeviceBase, DeviceBase, 18)) .def(py::init([](typename D::Config config, const DeviceInfo& deviceInfo){ py::gil_scoped_release release; return std::make_unique(config, deviceInfo); - }), py::arg("config"), py::arg("deviceInfo"), DOC(dai, DeviceBase, DeviceBase, 23)) + }), py::arg("config"), py::arg("deviceInfo"), DOC(dai, DeviceBase, DeviceBase, 19)) ; } diff --git a/src/DeviceBootloaderBindings.cpp b/src/DeviceBootloaderBindings.cpp index 81b2a37d9..b3ab5d59e 100644 --- a/src/DeviceBootloaderBindings.cpp +++ b/src/DeviceBootloaderBindings.cpp @@ -116,25 +116,25 @@ void DeviceBootloaderBindings::bind(pybind11::module& m, void* pCallstack){ .def_static("getFirstAvailableDevice", &DeviceBootloader::getFirstAvailableDevice, DOC(dai, DeviceBootloader, getFirstAvailableDevice)) .def_static("getAllAvailableDevices", &DeviceBootloader::getAllAvailableDevices, DOC(dai, DeviceBootloader, getAllAvailableDevices)) - .def_static("saveDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::saveDepthaiApplicationPackage), py::arg("path"), py::arg("pipeline"), py::arg("pathToCmd") = "", py::arg("compress") = false, DOC(dai, DeviceBootloader, saveDepthaiApplicationPackage)) - .def_static("saveDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::saveDepthaiApplicationPackage), py::arg("path"), py::arg("pipeline"), py::arg("compress"), DOC(dai, DeviceBootloader, saveDepthaiApplicationPackage, 2)) - .def_static("createDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::createDepthaiApplicationPackage), py::arg("pipeline"), py::arg("pathToCmd") = "", py::arg("compress") = false, DOC(dai, DeviceBootloader, createDepthaiApplicationPackage)) + .def_static("saveDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::saveDepthaiApplicationPackage), py::arg("path"), py::arg("pipeline"), py::arg("pathToCmd") = Path{}, py::arg("compress") = false, DOC(dai, DeviceBootloader, saveDepthaiApplicationPackage)) + .def_static("saveDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::saveDepthaiApplicationPackage), py::arg("path"), py::arg("pipeline"), py::arg("compress"), DOC(dai, DeviceBootloader, saveDepthaiApplicationPackage, 2)) + .def_static("createDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::createDepthaiApplicationPackage), py::arg("pipeline"), py::arg("pathToCmd") = Path{}, py::arg("compress") = false, DOC(dai, DeviceBootloader, createDepthaiApplicationPackage)) .def_static("createDepthaiApplicationPackage", py::overload_cast(&DeviceBootloader::createDepthaiApplicationPackage), py::arg("pipeline"), py::arg("compress"), DOC(dai, DeviceBootloader, createDepthaiApplicationPackage, 2)) .def_static("getEmbeddedBootloaderVersion", &DeviceBootloader::getEmbeddedBootloaderVersion, DOC(dai, DeviceBootloader, getEmbeddedBootloaderVersion)) .def_static("getEmbeddedBootloaderBinary", &DeviceBootloader::getEmbeddedBootloaderBinary, DOC(dai, DeviceBootloader, getEmbeddedBootloaderBinary)) .def(py::init(), py::arg("devInfo"), py::arg("allowFlashingBootloader") = false, DOC(dai, DeviceBootloader, DeviceBootloader)) - .def(py::init(), py::arg("devInfo"), py::arg("pathToCmd"), py::arg("allowFlashingBootloader") = false, DOC(dai, DeviceBootloader, DeviceBootloader, 2)) + .def(py::init(), py::arg("devInfo"), py::arg("pathToCmd"), py::arg("allowFlashingBootloader") = false, DOC(dai, DeviceBootloader, DeviceBootloader, 2)) .def("flash", [](DeviceBootloader& db, std::function progressCallback, const Pipeline& pipeline, bool compress) { py::gil_scoped_release release; return db.flash(progressCallback, pipeline, compress); }, py::arg("progressCallback"), py::arg("pipeline"), py::arg("compress") = false, DOC(dai, DeviceBootloader, flash)) .def("flash", [](DeviceBootloader& db, const Pipeline& pipeline, bool compress) { py::gil_scoped_release release; return db.flash(pipeline, compress); }, py::arg("pipeline"), py::arg("compress") = false, DOC(dai, DeviceBootloader, flash, 2)) .def("flashDepthaiApplicationPackage", [](DeviceBootloader& db, std::function progressCallback, std::vector package) { py::gil_scoped_release release; return db.flashDepthaiApplicationPackage(progressCallback, package); }, py::arg("progressCallback"), py::arg("package"), DOC(dai, DeviceBootloader, flashDepthaiApplicationPackage)) .def("flashDepthaiApplicationPackage", [](DeviceBootloader& db, std::vector package) { py::gil_scoped_release release; return db.flashDepthaiApplicationPackage(package); }, py::arg("package"), DOC(dai, DeviceBootloader, flashDepthaiApplicationPackage, 2)) - .def("flashBootloader", [](DeviceBootloader& db, std::function progressCallback, std::string path) { py::gil_scoped_release release; return db.flashBootloader(progressCallback, path); }, py::arg("progressCallback"), py::arg("path") = "", DOC(dai, DeviceBootloader, flashBootloader)) - .def("flashBootloader", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type, std::function progressCallback, std::string path) { py::gil_scoped_release release; return db.flashBootloader(memory, type, progressCallback, path); }, py::arg("memory"), py::arg("type"), py::arg("progressCallback"), py::arg("path") = "", DOC(dai, DeviceBootloader, flashBootloader, 2)) + .def("flashBootloader", [](DeviceBootloader& db, std::function progressCallback, const Path& path) { py::gil_scoped_release release; return db.flashBootloader(progressCallback, path); }, py::arg("progressCallback"), py::arg("path") = "", DOC(dai, DeviceBootloader, flashBootloader)) + .def("flashBootloader", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type, std::function progressCallback, dai::Path path) { py::gil_scoped_release release; return db.flashBootloader(memory, type, progressCallback, path); }, py::arg("memory"), py::arg("type"), py::arg("progressCallback"), py::arg("path") = "", DOC(dai, DeviceBootloader, flashBootloader, 2)) .def("readConfigData", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.readConfigData(memory, type); }, py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, readConfigData)) .def("flashConfigData", [](DeviceBootloader& db, nlohmann::json configData, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfigData(configData, memory, type); }, py::arg("configData"), py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfigData)) - .def("flashConfigFile", [](DeviceBootloader& db, std::string configPath, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfigFile(configPath, memory, type); }, py::arg("configData"), py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfigFile)) + .def("flashConfigFile", [](DeviceBootloader& db, dai::Path configPath, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfigFile(configPath, memory, type); }, py::arg("configData"), py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfigFile)) .def("flashConfigClear", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfigClear(memory, type); }, py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfigClear)) .def("readConfig", [](DeviceBootloader& db, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.readConfig(memory, type); }, py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, readConfig)) .def("flashConfig", [](DeviceBootloader& db, const DeviceBootloader::Config& config, DeviceBootloader::Memory memory, DeviceBootloader::Type type) { py::gil_scoped_release release; return db.flashConfig(config, memory, type); }, py::arg("config"), py::arg("memory") = DeviceBootloader::Memory::AUTO, py::arg("type") = DeviceBootloader::Type::AUTO, DOC(dai, DeviceBootloader, flashConfig)) diff --git a/src/openvino/OpenVINOBindings.cpp b/src/openvino/OpenVINOBindings.cpp index f096f72ef..29cb6da94 100644 --- a/src/openvino/OpenVINOBindings.cpp +++ b/src/openvino/OpenVINOBindings.cpp @@ -57,7 +57,7 @@ void OpenVINOBindings::bind(pybind11::module& m, void* pCallstack){ // Bind OpenVINO::Blob openvinoBlob .def(py::init>(), DOC(dai, OpenVINO, Blob, Blob)) - .def(py::init(), DOC(dai, OpenVINO, Blob, Blob, 2)) + .def(py::init(), DOC(dai, OpenVINO, Blob, Blob, 2)) .def_readwrite("version", &OpenVINO::Blob::version, DOC(dai, OpenVINO, Blob, version)) .def_readwrite("networkInputs", &OpenVINO::Blob::networkInputs, DOC(dai, OpenVINO, Blob, networkInputs)) .def_readwrite("networkOutputs", &OpenVINO::Blob::networkOutputs, DOC(dai, OpenVINO, Blob, networkOutputs)) diff --git a/src/pipeline/AssetManagerBindings.cpp b/src/pipeline/AssetManagerBindings.cpp index 72b3b29f9..40a5ddc0c 100644 --- a/src/pipeline/AssetManagerBindings.cpp +++ b/src/pipeline/AssetManagerBindings.cpp @@ -49,7 +49,7 @@ void AssetManagerBindings::bind(pybind11::module& m, void* pCallstack){ .def("addExisting", &AssetManager::addExisting, py::arg("assets"), DOC(dai, AssetManager, addExisting)) .def("set", static_cast (AssetManager::*)(Asset)>(&AssetManager::set), py::arg("asset"), DOC(dai, AssetManager, set)) .def("set", static_cast (AssetManager::*)(const std::string&, Asset)>(&AssetManager::set), py::arg("key"), py::arg("asset"), DOC(dai, AssetManager, set, 2)) - .def("set", static_cast (AssetManager::*)(const std::string& key, const std::string& path, int alignment)>(&AssetManager::set), py::arg("key"), py::arg("path"), py::arg("alignment") = 64, DOC(dai, AssetManager, set, 3)) + .def("set", static_cast (AssetManager::*)(const std::string& key, const dai::Path& path, int alignment)>(&AssetManager::set), py::arg("key"), py::arg("path"), py::arg("alignment") = 64, DOC(dai, AssetManager, set, 3)) .def("set", static_cast (AssetManager::*)(const std::string& key, const std::vector& data, int alignment)>(&AssetManager::set), py::arg("key"), py::arg("data"), py::arg("alignment") = 64, DOC(dai, AssetManager, set, 4)) .def("get", static_cast (AssetManager::*)(const std::string&) const>(&AssetManager::get), py::arg("key"), DOC(dai, AssetManager, get)) .def("get", static_cast (AssetManager::*)(const std::string&)>(&AssetManager::get), py::arg("key"), DOC(dai, AssetManager, get, 2)) diff --git a/src/pipeline/NodeBindings.cpp b/src/pipeline/NodeBindings.cpp index af5a11e39..e6c02e7a4 100644 --- a/src/pipeline/NodeBindings.cpp +++ b/src/pipeline/NodeBindings.cpp @@ -216,7 +216,7 @@ void NodeBindings::bind(pybind11::module& m, void* pCallstack){ auto edgeDetector = ADD_NODE(EdgeDetector); auto featureTracker = ADD_NODE(FeatureTracker); auto aprilTag = ADD_NODE(AprilTag); - + py::enum_ stereoDepthPresetMode(stereoDepth, "PresetMode", DOC(dai, node, StereoDepth, PresetMode)); @@ -677,7 +677,7 @@ void NodeBindings::bind(pybind11::module& m, void* pCallstack){ .def_readonly("passthrough", &NeuralNetwork::passthrough, DOC(dai, node, NeuralNetwork, passthrough)) .def("setBlobPath", [](NeuralNetwork& nn, py::object obj){ // Allows to call this function with paths as well as strings - nn.setBlobPath(py::str(obj)); + nn.setBlobPath(dai::Path(py::str(obj))); }, py::arg("path"), DOC(dai, node, NeuralNetwork, setBlobPath)) .def("setNumPoolFrames", &NeuralNetwork::setNumPoolFrames, py::arg("numFrames"), DOC(dai, node, NeuralNetwork, setNumPoolFrames)) .def("setNumInferenceThreads", &NeuralNetwork::setNumInferenceThreads, py::arg("numThreads"), DOC(dai, node, NeuralNetwork, setNumInferenceThreads)) @@ -898,20 +898,6 @@ void NodeBindings::bind(pybind11::module& m, void* pCallstack){ s.setOutputDepth(enable); HEDLEY_DIAGNOSTIC_POP }) - .def("loadCalibrationFile", [](StereoDepth& s, std::string path){ - PyErr_WarnEx(PyExc_DeprecationWarning, "loadCalibrationFile() is deprecated, Use 'Pipeline.setCalibrationData()' instead", 1); - HEDLEY_DIAGNOSTIC_PUSH - HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED - s.loadCalibrationFile(path); - HEDLEY_DIAGNOSTIC_POP - }) - .def("loadCalibrationData", [](StereoDepth& s, std::vector data){ - PyErr_WarnEx(PyExc_DeprecationWarning, "loadCalibrationData() is deprecated, Use 'Pipeline.setCalibrationData()' instead", 1); - HEDLEY_DIAGNOSTIC_PUSH - HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED - s.loadCalibrationData(data); - HEDLEY_DIAGNOSTIC_POP - }) .def("setEmptyCalibration", [](StereoDepth& s){ PyErr_WarnEx(PyExc_DeprecationWarning, "setEmptyCalibration() is deprecated, Use 'setRectification(False)' instead", 1); HEDLEY_DIAGNOSTIC_PUSH @@ -1224,8 +1210,8 @@ void NodeBindings::bind(pybind11::module& m, void* pCallstack){ .def_readonly("initialConfig", &AprilTag::initialConfig, DOC(dai, node, AprilTag, initialConfig)) .def("setWaitForConfigInput", &AprilTag::setWaitForConfigInput, py::arg("wait"), DOC(dai, node, AprilTag, setWaitForConfigInput)) ; - daiNodeModule.attr("AprilTag").attr("Properties") = aprilTagProperties; - + daiNodeModule.attr("AprilTag").attr("Properties") = aprilTagProperties; + // FeatureTracker node featureTracker .def_readonly("inputConfig", &FeatureTracker::inputConfig, DOC(dai, node, FeatureTracker, inputConfig)) diff --git a/src/pybind11_common.hpp b/src/pybind11_common.hpp index 1669cdf40..258859745 100644 --- a/src/pybind11_common.hpp +++ b/src/pybind11_common.hpp @@ -12,6 +12,7 @@ #include #include #include +#include // Include docstring file #include "docstring.hpp" @@ -24,6 +25,41 @@ namespace pybind11 { namespace detail { struct type_caster> : optional_caster> {}; }} + +namespace pybind11 { namespace detail { + template <> struct type_caster { + public: + + // This macro establishes the name 'dai::Path' in + // function signatures and declares a local variable + // 'value' of type dai::Path + PYBIND11_TYPE_CASTER(dai::Path, _("Path")); + + // Conversion part 1 (Python->C++): convert a PyObject into a dai::Path + // instance or return false upon failure. The second argument + // indicates whether implicit conversions should be applied. + bool load(handle src, bool) { + try { + str pystr = static_cast(src); + value = dai::Path(static_cast(pystr)); + return true; + } catch (...) { + return false; + } + } + + // Conversion part 2 (C++ -> Python): convert an dai::Path instance into + // a Python (string) object. The second and third arguments are used to + // indicate the return value policy and parent object (for + // ``return_value_policy::reference_internal``) and are generally + // ignored by implicit casters. + static handle cast(dai::Path src, return_value_policy /* policy */, handle /* parent */) { + return str{src.u8string()}; + } + }; +}} // namespace pybind11::detail + + namespace py = pybind11; using StackFunction = void (*)(pybind11::module &m, void *pCallstack); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c3aad2e65..15be5f6e0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ endif() set(PYBIND11_TEST_FILES "xlink_exceptions_test.cpp" + "utf8_support_test.py" ) string(REPLACE ".cpp" ".py" PYBIND11_PYTEST_FILES "${PYBIND11_TEST_FILES}") @@ -18,7 +19,10 @@ pybind11_add_module(${TARGET_TEST_MODULE} THIN_LTO ${TARGET_TEST_MODULE}.cpp ${P # A single command to compile and run the tests add_custom_target( - pytest COMMAND + pytest + COMMAND + ${CMAKE_COMMAND} -E echo "Setting PYTHONPATH env var to: $${SYS_PATH_SEPARATOR}$${SYS_PATH_SEPARATOR}$ENV{PYTHONPATH}" + COMMAND ${CMAKE_COMMAND} -E env # Python path (to find compiled modules) "PYTHONPATH=$${SYS_PATH_SEPARATOR}$${SYS_PATH_SEPARATOR}$ENV{PYTHONPATH}" diff --git a/tests/utf8_support_test.py b/tests/utf8_support_test.py new file mode 100644 index 000000000..b1d5bbf7f --- /dev/null +++ b/tests/utf8_support_test.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +import sys + +import pytest + +import depthai as dai + +def test_utf8_path_asset_manager(tmp_path): + + FILE_CONTENTS="Hello World πŸ‘" + + tmp_sneaky_file_dir = tmp_path / "UTF-8 dir πŸ™ˆπŸ™‰πŸ™‰" + tmp_sneaky_file_dir.mkdir() + tmp_sneaky_file_path = tmp_sneaky_file_dir / "sneaky πŸ‘ ΔΔ‡Ε‘Δ‘ΕΎΔ†ΔŒLpΔ‘Ε‘lčk file.txt" + tmp_sneaky_file_path.write_bytes(FILE_CONTENTS.encode("utf-8")) + + assetManager = dai.AssetManager() + asset = assetManager.set('test', tmp_sneaky_file_path) + assert(bytes(asset.data) == FILE_CONTENTS.encode("utf-8"))