pax_global_header00006660000000000000000000000064141677756050014534gustar00rootroot0000000000000052 comment=1727c0b4c4127276f9a7e10fdc926ad71c00f095 pybind11_json-0.2.12/000077500000000000000000000000001416777560500142765ustar00rootroot00000000000000pybind11_json-0.2.12/.github/000077500000000000000000000000001416777560500156365ustar00rootroot00000000000000pybind11_json-0.2.12/.github/workflows/000077500000000000000000000000001416777560500176735ustar00rootroot00000000000000pybind11_json-0.2.12/.github/workflows/main.yml000066400000000000000000000030731416777560500213450ustar00rootroot00000000000000name: Tests on: push: branches: - master pull_request: branches: - master jobs: run: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] python-version: [3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v1 - name: Setup conda uses: s-weigand/setup-conda@v1 with: update-conda: true conda-channels: conda-forge - name: Conda install dependencies run: conda install python=${{ matrix.python-version }}*=*_cpython cmake=3.17 nlohmann_json pybind11 - name: Unix, install if: matrix.os != 'windows-latest' run: | mkdir build cd build $CONDA/bin/cmake -D CMAKE_INSTALL_PREFIX=$CONDA -D DOWNLOAD_GTEST=ON -D PYTHON_EXECUTABLE=$CONDA/bin/python -D CMAKE_INSTALL_LIBDIR=lib .. make install -j2 - name: Windows, install if: matrix.os == 'windows-latest' shell: cmd run: | call "c:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat" mkdir build cd build %CONDA%/Library/bin/cmake -G "NMake Makefiles" -D CMAKE_INSTALL_PREFIX=%CONDA% -D DOWNLOAD_GTEST=ON -D PYTHON_EXECUTABLE=%CONDA%/python.exe -Dgtest_force_shared_crt=ON -DCMAKE_CXX_FLAGS=/D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING .. nmake install - name: Run tests shell: bash run: | export PYTHONHOME=$CONDA cd build ./test/test_pybind11_json pybind11_json-0.2.12/.gitignore000066400000000000000000000000101416777560500162550ustar00rootroot00000000000000build/* pybind11_json-0.2.12/CMakeLists.txt000066400000000000000000000117061416777560500170430ustar00rootroot00000000000000############################################################################ # Copyright (c) 2019, Martin Renou # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ cmake_minimum_required(VERSION 3.4.3) project(pybind11_json) set(PYBIND11_JSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) set(${PROJECT_NAME}_VERSION_MAJOR 0) set(${PROJECT_NAME}_VERSION_MINOR 2) set(${PROJECT_NAME}_VERSION_PATCH 12) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}) ################ # Dependencies # ################ set(pybind11_REQUIRED_VERSION 2.2.4) set(nlohmann_json_REQUIRED_VERSION 3.2.0) if (NOT TARGET pybind11::headers) find_package(pybind11 ${pybind11_REQUIRED_VERSION} REQUIRED) endif() if (NOT TARGET nlohmann_json) find_package(nlohmann_json ${nlohmann_json_REQUIRED_VERSION} REQUIRED) endif() ########## # Target # ########## include(GNUInstallDirs) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib; ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set(PYBIND11_JSON_HEADERS include/pybind11_json/pybind11_json.hpp ) add_library(${PROJECT_NAME} INTERFACE) target_include_directories(${PROJECT_NAME} INTERFACE ${PYTHON_INCLUDE_DIRS} $ $) # The PUBLIC_HEADER property can be set for an INTERFACE library # as of cmake 3.15 if(NOT (CMAKE_VERSION VERSION_LESS 3.15)) # CMake >= 3.15 set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${PYBIND11_JSON_HEADERS}") endif() ######### # Tests # ######### OPTION(BUILD_TESTS "pybind11_json test suite" OFF) OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) set(BUILD_TESTS ON) endif() if(BUILD_TESTS) add_subdirectory(test) endif() ################ # Installation # ################ include(CMakePackageConfigHelpers) set(PYBIND11_JSON_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}" CACHE STRING "install path for pybind11_jsonConfig.cmake") # Install pybind11_json if(CMAKE_VERSION VERSION_LESS 3.15) # CMake < 3.15 install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets) else() install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}-targets PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) endif() # Makes the project importable from the build directory export(EXPORT ${PROJECT_NAME}-targets FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") if(CMAKE_VERSION VERSION_LESS 3.15) # CMake < 3.15 install(FILES ${PYBIND11_JSON_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}) endif() # Configure 'pybind11_jsonConfig.cmake' for a build tree set(PYBIND11_JSON_CONFIG_CODE "####### Expanded from \@PYBIND11_JSON_CONFIG_CODE\@ #######\n") set(PYBIND11_JSON_CONFIG_CODE "${PYBIND11_JSON_CONFIG_CODE}set(CMAKE_MODULE_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/cmake;\${CMAKE_MODULE_PATH}\")\n") set(PYBIND11_JSON_CONFIG_CODE "${PYBIND11_JSON_CONFIG_CODE}##################################################") configure_package_config_file(${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${PROJECT_BINARY_DIR}) # Configure 'pybind11_jsonConfig.cmake' for an install tree set(PYBIND11_JSON_CONFIG_CODE "") configure_package_config_file(${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}Config.cmake" INSTALL_DESTINATION ${PYBIND11_JSON_CMAKECONFIG_INSTALL_DIR}) # ARCH_INDEPENDENT feature was introduced in cmake 3.14 if (${CMAKE_VERSION} VERSION_LESS "3.14.0") write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${${PROJECT_NAME}_VERSION} COMPATIBILITY AnyNewerVersion) else () write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${${PROJECT_NAME}_VERSION} COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT) endif () install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${PYBIND11_JSON_CMAKECONFIG_INSTALL_DIR}) install(EXPORT ${PROJECT_NAME}-targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${PYBIND11_JSON_CMAKECONFIG_INSTALL_DIR}) pybind11_json-0.2.12/LICENSE000066400000000000000000000027331416777560500153100ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2019, All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pybind11_json-0.2.12/README.md000066400000000000000000000077521416777560500155700ustar00rootroot00000000000000![Tests](https://github.com/pybind/pybind11_json/workflows/Tests/badge.svg) # pybind11_json `pybind11_json` is an `nlohmann::json` to `pybind11` bridge, it allows you to automatically convert `nlohmann::json` to `py::object` and the other way around. Simply include the header, and the automatic conversion will be enabled. ## C++ API: Automatic conversion between `nlohmann::json` and `pybind11` Python objects ```cpp #include "pybind11_json/pybind11_json.hpp" #include "nlohmann/json.hpp" #include "pybind11/pybind11.h" namespace py = pybind11; namespace nl = nlohmann; using namespace pybind11::literals; py::dict obj = py::dict("number"_a=1234, "hello"_a="world"); // Automatic py::dict->nl::json conversion nl::json j = obj; // Automatic nl::json->py::object conversion py::object result1 = j; // Automatic nl::json->py::dict conversion py::dict result2 = j; ``` ## Making bindings You can easily make bindings for C++ classes/functions that make use of `nlohmann::json`. For example, making a binding for the following two functions is automatic, thanks to `pybind11_json` ```cpp void take_json(const nlohmann::json& json) { std::cout << "This function took an nlohmann::json instance as argument: " << s << std::endl; } nlohmann::json return_json() { nlohmann::json j = {{"value", 1}}; std::cout << "This function returns an nlohmann::json instance: " << j << std::endl; return j; } ``` Bindings: ```cpp PYBIND11_MODULE(my_module, m) { m.doc() = "My awesome module"; m.def("take_json", &take_json, "pass py::object to a C++ function that takes an nlohmann::json"); m.def("return_json", &return_json, "return py::object from a C++ function that returns an nlohmann::json"); } ``` You can then use your functions Python side: ```python import my_module my_module.take_json({"value": 2}) j = my_module.return_json() print(j) ``` ### Example You can find an example of simple Python bindings using pybind11_json here: https://github.com/martinRenou/xjson # Installation ## Using conda You can install `pybind11_json` using conda ```bash conda install -c conda-forge pybind11 nlohmann_json pybind11_json ``` ## From sources We encourage you to use conda for installing dependencies, but it is not a requirement for `pybind11_json` to work ```bash conda install cmake nlohmann_json pybind11 -c conda-forge ``` Then you can install the sources ```bash cmake -D CMAKE_INSTALL_PREFIX=your_conda_path make install ``` ## Header only usage Download the "pybind11_json.hpp" single file into your project, and install/download `pybind11` and `nlohmann_json` or use as git submodule. ## Run tests You can compile and run tests locally doing ```bash cmake -D CMAKE_INSTALL_PREFIX=$CONDA_PREFIX -D DOWNLOAD_GTEST=ON .. make ./test/test_pybind11_json ``` # Dependencies ``pybind11_json`` depends on - [pybind11](https://github.com/pybind/pybind11) - [nlohmann_json](https://github.com/nlohmann/json) | `pybind11_json`| `nlohmann_json` | `pybind11` | |----------------|-----------------|-----------------| | master | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.12 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.11 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.10 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.9 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.8 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.7 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.6 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.5 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.4 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.3 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.2 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.1 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | | 0.2.0 | >=3.2.0,<4.0 | >=2.2.4,<3.0 | # License We use a shared copyright model that enables all contributors to maintain the copyright on their contributions. This software is licensed under the BSD-3-Clause license. See the [LICENSE](LICENSE) file for details. pybind11_json-0.2.12/include/000077500000000000000000000000001416777560500157215ustar00rootroot00000000000000pybind11_json-0.2.12/include/pybind11_json/000077500000000000000000000000001416777560500204015ustar00rootroot00000000000000pybind11_json-0.2.12/include/pybind11_json/pybind11_json.hpp000066400000000000000000000160631416777560500236000ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2019, Martin Renou * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef PYBIND11_JSON_HPP #define PYBIND11_JSON_HPP #include #include #include "nlohmann/json.hpp" #include "pybind11/pybind11.h" namespace py = pybind11; namespace nl = nlohmann; namespace pyjson { inline py::object from_json(const nl::json& j) { if (j.is_null()) { return py::none(); } else if (j.is_boolean()) { return py::bool_(j.get()); } else if (j.is_number_integer()) { return py::int_(j.get()); } else if (j.is_number_unsigned()) { return py::int_(j.get()); } else if (j.is_number_float()) { return py::float_(j.get()); } else if (j.is_string()) { return py::str(j.get()); } else if (j.is_array()) { py::list obj(j.size()); for (std::size_t i = 0; i < j.size(); i++) { obj[i] = from_json(j[i]); } return std::move(obj); } else // Object { py::dict obj; for (nl::json::const_iterator it = j.cbegin(); it != j.cend(); ++it) { obj[py::str(it.key())] = from_json(it.value()); } return std::move(obj); } } inline nl::json to_json(const py::handle& obj) { if (obj.ptr() == nullptr || obj.is_none()) { return nullptr; } if (py::isinstance(obj)) { return obj.cast(); } if (py::isinstance(obj)) { try { nl::json::number_integer_t s = obj.cast(); if (py::int_(s).equal(obj)) { return s; } } catch (...) { } try { nl::json::number_unsigned_t u = obj.cast(); if (py::int_(u).equal(obj)) { return u; } } catch (...) { } throw std::runtime_error("to_json received an integer out of range for both nl::json::number_integer_t and nl::json::number_unsigned_t type: " + py::repr(obj).cast()); } if (py::isinstance(obj)) { return obj.cast(); } if (py::isinstance(obj)) { py::module base64 = py::module::import("base64"); return base64.attr("b64encode")(obj).attr("decode")("utf-8").cast(); } if (py::isinstance(obj)) { return obj.cast(); } if (py::isinstance(obj) || py::isinstance(obj)) { auto out = nl::json::array(); for (const py::handle value : obj) { out.push_back(to_json(value)); } return out; } if (py::isinstance(obj)) { auto out = nl::json::object(); for (const py::handle key : obj) { out[py::str(key).cast()] = to_json(obj[key]); } return out; } throw std::runtime_error("to_json not implemented for this type of object: " + py::repr(obj).cast()); } } // nlohmann_json serializers namespace nlohmann { #define MAKE_NLJSON_SERIALIZER_DESERIALIZER(T) \ template <> \ struct adl_serializer \ { \ inline static void to_json(json& j, const T& obj) \ { \ j = pyjson::to_json(obj); \ } \ \ inline static T from_json(const json& j) \ { \ return pyjson::from_json(j); \ } \ } #define MAKE_NLJSON_SERIALIZER_ONLY(T) \ template <> \ struct adl_serializer \ { \ inline static void to_json(json& j, const T& obj) \ { \ j = pyjson::to_json(obj); \ } \ } MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::object); MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::bool_); MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::int_); MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::float_); MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::str); MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::list); MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::tuple); MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::dict); MAKE_NLJSON_SERIALIZER_ONLY(py::handle); MAKE_NLJSON_SERIALIZER_ONLY(py::detail::item_accessor); MAKE_NLJSON_SERIALIZER_ONLY(py::detail::list_accessor); MAKE_NLJSON_SERIALIZER_ONLY(py::detail::tuple_accessor); MAKE_NLJSON_SERIALIZER_ONLY(py::detail::sequence_accessor); MAKE_NLJSON_SERIALIZER_ONLY(py::detail::str_attr_accessor); MAKE_NLJSON_SERIALIZER_ONLY(py::detail::obj_attr_accessor); #undef MAKE_NLJSON_SERIALIZER #undef MAKE_NLJSON_SERIALIZER_ONLY } // pybind11 caster namespace pybind11 { namespace detail { template <> struct type_caster { public: PYBIND11_TYPE_CASTER(nl::json, _("json")); bool load(handle src, bool) { try { value = pyjson::to_json(src); return true; } catch (...) { return false; } } static handle cast(nl::json src, return_value_policy /* policy */, handle /* parent */) { object obj = pyjson::from_json(src); return obj.release(); } }; } } #endif pybind11_json-0.2.12/pybind11_jsonConfig.cmake.in000066400000000000000000000022751416777560500215210ustar00rootroot00000000000000############################################################################ # Copyright (c) 2019, Martin Renou # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ # pybind11_json cmake module # This module sets the following variables in your project:: # # pybind11_json_FOUND - true if pybind11_json found on the system # pybind11_json_INCLUDE_DIRS - the directory containing pybind11_json headers # pybind11_json_LIBRARY - empty @PACKAGE_INIT@ @PYBIND11_JSON_CONFIG_CODE@ include(CMakeFindDependencyMacro) find_dependency(pybind11 @pybind11_REQUIRED_VERSION@) find_dependency(nlohmann_json @nlohmann_json_REQUIRED_VERSION@) if(NOT TARGET pybind11_json) include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") get_target_property(@PROJECT_NAME@_INCLUDE_DIRS pybind11_json INTERFACE_INCLUDE_DIRECTORIES) endif() pybind11_json-0.2.12/test/000077500000000000000000000000001416777560500152555ustar00rootroot00000000000000pybind11_json-0.2.12/test/CMakeLists.txt000066400000000000000000000065611416777560500200250ustar00rootroot00000000000000############################################################################ # Copyright (c) 2019, Martin Renou # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ cmake_minimum_required(VERSION 3.4.3) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) project(pybind11_json-test) enable_testing() find_package(pybind11_json REQUIRED CONFIG) endif () message(STATUS "Forcing tests build type to Release") set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) include(CheckCXXCompilerFlag) string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE) if(CMAKE_CXX_COMPILER_ID MATCHES Clang OR CMAKE_CXX_COMPILER_ID MATCHES GNU OR CMAKE_CXX_COMPILER_ID MATCHES Intel) add_compile_options(-Wunused-parameter -Wextra -Wreorder -Wconversion -Wsign-conversion) CHECK_CXX_COMPILER_FLAG(-march=native HAS_MARCH_NATIVE) if (HAS_MARCH_NATIVE) add_compile_options(-march=native) endif() endif() if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) add_compile_options(/EHsc /MP /bigobj) set(CMAKE_EXE_LINKER_FLAGS /MANIFEST:NO) endif() if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) if(DOWNLOAD_GTEST) # Download and unpack googletest at configure time configure_file(downloadGTest.cmake.in googletest-download/CMakeLists.txt) else() # Copy local source of googletest at configure time configure_file(copyGTest.cmake.in googletest-download/CMakeLists.txt) endif() execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) if(result) message(FATAL_ERROR "CMake step for googletest failed: ${result}") endif() execute_process(COMMAND ${CMAKE_COMMAND} --build . RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) if(result) message(FATAL_ERROR "Build step for googletest failed: ${result}") endif() # Add googletest directly to our build. This defines # the gtest and gtest_main targets. add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src ${CMAKE_CURRENT_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL) set(GTEST_INCLUDE_DIRS "${gtest_SOURCE_DIR}/include") set(GTEST_BOTH_LIBRARIES gtest_main gtest) else() find_package(GTest REQUIRED) endif() include_directories(${GTEST_INCLUDE_DIRS} SYSTEM) set(PYBIND11_JSON_TESTS test_pybind11_json.cpp ) add_executable(test_pybind11_json ${PYBIND11_JSON_TESTS}) if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) add_dependencies(test_pybind11_json gtest_main) endif() include_directories(${PYTHON_INCLUDE_DIRS}) target_link_libraries(test_pybind11_json ${PYTHON_LIBRARIES} ${GTEST_BOTH_LIBRARIES} pybind11::embed nlohmann_json::nlohmann_json) target_include_directories(test_pybind11_json PRIVATE ${PYBIND11_JSON_INCLUDE_DIR}) add_custom_target(tests COMMAND test_pybind11_json DEPENDS test_pybind11_json) pybind11_json-0.2.12/test/copyGTest.cmake.in000066400000000000000000000016661416777560500206160ustar00rootroot00000000000000############################################################################ # Copyright (c) 2019, Martin Renou # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ cmake_minimum_required(VERSION 2.8.2) project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest URL "${GTEST_SRC_DIR}" SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) pybind11_json-0.2.12/test/downloadGTest.cmake.in000066400000000000000000000017601416777560500214460ustar00rootroot00000000000000############################################################################ # Copyright (c) 2019, Martin Renou # # # # Distributed under the terms of the BSD 3-Clause License. # # # # The full license is in the file LICENSE, distributed with this software. # ############################################################################ cmake_minimum_required(VERSION 2.8.2) project(googletest-download NONE) include(ExternalProject) ExternalProject_Add(googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG release-1.8.0 SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" TEST_COMMAND "" ) pybind11_json-0.2.12/test/test_pybind11_json.cpp000066400000000000000000000277541416777560500215170ustar00rootroot00000000000000/*************************************************************************** * Copyright (c) 2019, Martin Renou * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #include #include #include #include #include "gtest/gtest.h" #include "pybind11_json/pybind11_json.hpp" #include "pybind11/embed.h" namespace py = pybind11; namespace nl = nlohmann; using namespace pybind11::literals; TEST(nljson_serializers_tojson, none) { py::scoped_interpreter guard; py::object obj1; py::object obj2 = py::none(); nl::json j1 = obj1; nl::json j2 = obj2; ASSERT_TRUE(j1.is_null()); ASSERT_TRUE(j2.is_null()); } TEST(nljson_serializers_tojson, bool_) { py::scoped_interpreter guard; py::bool_ obj(false); nl::json j = obj; ASSERT_TRUE(j.is_boolean()); ASSERT_FALSE(j.get()); } TEST(nljson_serializers_tojson, integer) { py::scoped_interpreter guard; py::int_ obj(36); nl::json j = obj; ASSERT_TRUE(j.is_number_integer()); ASSERT_EQ(j.get(), 36); py::int_ obj_integer_min(std::numeric_limits::min()); nl::json j_integer_min = obj_integer_min; ASSERT_TRUE(j_integer_min.is_number_integer()); ASSERT_EQ(j_integer_min.get(), std::numeric_limits::min()); py::int_ obj_unsigned_max(std::numeric_limits::max()); nl::json j_unsigned_max = obj_unsigned_max; ASSERT_TRUE(j_unsigned_max.is_number_unsigned()); ASSERT_EQ(j_unsigned_max.get(), std::numeric_limits::max()); py::int_ obj_integer_border = py::int_(std::numeric_limits::max()).attr("__add__")(1); nl::json j_integer_border = obj_integer_border; ASSERT_TRUE(j_integer_border.is_number_unsigned()); ASSERT_EQ(j_integer_min.get(), (nl::json::number_unsigned_t)(std::numeric_limits::max()) + 1); py::int_ obj_small_outside = obj_integer_min.attr("__sub__")(1); ASSERT_THROW(nl::json j_small_outside = obj_small_outside, std::runtime_error); py::int_ obj_large_outside=obj_unsigned_max.attr("__add__")(1); ASSERT_THROW(nl::json j_large_outside = obj_large_outside, std::runtime_error); } TEST(nljson_serializers_tojson, float_) { py::float_ obj(36.37); nl::json j = obj; ASSERT_TRUE(j.is_number_float()); ASSERT_EQ(j.get(), 36.37); py::float_ obj_inf(INFINITY); nl::json j_inf = obj_inf; ASSERT_TRUE(j_inf.is_number_float()); ASSERT_EQ(j_inf.get(), INFINITY); py::float_ obj_nan(NAN); nl::json j_nan = obj_nan; ASSERT_TRUE(j_nan.is_number_float()); ASSERT_TRUE(isnan(j_nan.get())); } TEST(nljson_serializers_tojson, string) { py::scoped_interpreter guard; py::str obj("Hello"); nl::json j = obj; ASSERT_TRUE(j.is_string()); ASSERT_EQ(j.get(), "Hello"); } TEST(nljson_serializers_tojson, list) { py::scoped_interpreter guard; py::list obj; obj.append(py::int_(36)); obj.append(py::str("Hello World")); obj.append(py::bool_(false)); nl::json j = obj; ASSERT_TRUE(j.is_array()); ASSERT_EQ(j[0].get(), 36); ASSERT_EQ(j[1].get(), "Hello World"); ASSERT_EQ(j[2].get(), false); } TEST(nljson_serializers_tojson, empty_list) { py::scoped_interpreter guard; py::list obj; nl::json j = obj; ASSERT_TRUE(j.is_array()); ASSERT_TRUE(j.empty()); } TEST(nljson_serializers_tojson, tuple) { py::scoped_interpreter guard; py::tuple obj = py::make_tuple(1234, "hello", false); nl::json j = obj; ASSERT_TRUE(j.is_array()); ASSERT_EQ(j[0].get(), 1234); ASSERT_EQ(j[1].get(), "hello"); ASSERT_EQ(j[2].get(), false); } TEST(nljson_serializers_tojson, dict) { py::scoped_interpreter guard; py::dict obj("number"_a=1234, "hello"_a="world"); nl::json j = obj; ASSERT_TRUE(j.is_object()); ASSERT_EQ(j["number"].get(), 1234); ASSERT_EQ(j["hello"].get(), "world"); } TEST(nljson_serializers_tojson, empty_dict) { py::scoped_interpreter guard; py::dict obj; nl::json j = obj; ASSERT_TRUE(j.is_object()); ASSERT_TRUE(j.empty()); } TEST(nljson_serializers_tojson, nested) { py::scoped_interpreter guard; py::dict obj( "list"_a=py::make_tuple(1234, "hello", false), "dict"_a=py::dict("a"_a=12, "b"_a=13), "hello"_a="world", "world"_a=py::none() ); nl::json j = obj; ASSERT_TRUE(j.is_object()); ASSERT_EQ(j["list"][0].get(), 1234); ASSERT_EQ(j["list"][1].get(), "hello"); ASSERT_EQ(j["list"][2].get(), false); ASSERT_EQ(j["dict"]["a"].get(), 12); ASSERT_EQ(j["dict"]["b"].get(), 13); ASSERT_EQ(j["world"], nullptr); } TEST(nljson_serializers_tojson, handle) { py::scoped_interpreter guard; py::list obj; obj.append(py::make_tuple(1234, "hello", false)); obj.append(py::dict("a"_a=12, "b"_a=13)); obj.append("world"); obj.append(py::none()); for (py::handle handle : obj) { nl::json j = handle; ASSERT_TRUE(j.is_array() || j.is_object() || j.is_string() || j.is_null()); } } TEST(nljson_serializers_tojson, list_accessor) { py::scoped_interpreter guard; py::list obj; obj.append(py::make_tuple(1234, "hello", false)); obj.append(py::dict("a"_a=12, "b"_a=13)); obj.append("world"); obj.append(py::none()); nl::json j = obj[0]; ASSERT_TRUE(j.is_array()); j = obj[1]; ASSERT_TRUE(j.is_object()); j = py::make_tuple(1234, "hello", false)[0]; ASSERT_TRUE(j.is_number_integer()); ASSERT_EQ(j.get(), 1234); } TEST(nljson_serializers_tojson, tuple_accessor) { py::scoped_interpreter guard; py::tuple obj = py::make_tuple(1234, "hello", false); nl::json j = obj[0]; ASSERT_TRUE(j.is_number_integer()); ASSERT_EQ(j.get(), 1234); j = obj[1]; ASSERT_TRUE(j.is_string()); ASSERT_EQ(j.get(), "hello"); } TEST(nljson_serializers_tojson, item_accessor) { py::scoped_interpreter guard; py::dict obj = py::dict("a"_a=12, "b"_a="hello"); nl::json j = obj["a"]; ASSERT_TRUE(j.is_number()); ASSERT_EQ(j.get(), 12); j = obj["b"]; ASSERT_TRUE(j.is_string()); ASSERT_EQ(j.get(), "hello"); } TEST(nljson_serializers_tojson, str_attr_accessor) { py::scoped_interpreter guard; py::module sys = py::module::import("sys"); nl::json j = sys.attr("base_prefix"); ASSERT_TRUE(j.is_string()); } TEST(nljson_serializers_tojson, obj_attr_accessor) { py::scoped_interpreter guard; py::module sys = py::module::import("sys"); py::str base_prefix = "base_prefix"; nl::json j = sys.attr(base_prefix); ASSERT_TRUE(j.is_string()); } TEST(nljson_serializers_fromjson, none) { py::scoped_interpreter guard; nl::json j = "null"_json; py::object obj = j; ASSERT_TRUE(obj.is_none()); } TEST(nljson_serializers_fromjson, bool_) { py::scoped_interpreter guard; nl::json j = "false"_json; py::object obj = j; ASSERT_TRUE(py::isinstance(obj)); ASSERT_FALSE(obj.cast()); py::bool_ obj2 = j; ASSERT_FALSE(obj2.cast()); } TEST(nljson_serializers_fromjson, integer) { py::scoped_interpreter guard; nl::json j = "36"_json; py::object obj = j; ASSERT_TRUE(py::isinstance(obj)); ASSERT_EQ(obj.cast(), 36); py::int_ obj2 = j; ASSERT_EQ(obj2.cast(), 36); } TEST(nljson_serializers_fromjson, float_) { nl::json j = "36.2"_json; py::object obj = j; ASSERT_TRUE(py::isinstance(obj)); ASSERT_EQ(obj.cast(), 36.2); py::float_ f_obj = j; ASSERT_EQ(f_obj.cast(), 36.2); nl::json j_inf(INFINITY); py::object obj_inf = j_inf; ASSERT_TRUE(py::isinstance(obj_inf)); ASSERT_EQ(obj_inf.cast(), INFINITY); py::float_ f_obj_inf = j_inf; ASSERT_EQ(f_obj_inf.cast(), INFINITY); nl::json j_nan(NAN); py::object obj_nan = j_nan; ASSERT_TRUE(py::isinstance(obj_nan)); ASSERT_TRUE(isnan(obj_nan.cast())); py::float_ f_obj_nan = j_nan; ASSERT_TRUE(isnan(f_obj_nan.cast())); } TEST(nljson_serializers_fromjson, string) { py::scoped_interpreter guard; nl::json j = "\"Hello World!\""_json; py::object obj = j; ASSERT_TRUE(py::isinstance(obj)); ASSERT_EQ(obj.cast(), "Hello World!"); py::str obj2 = j; ASSERT_EQ(obj2.cast(), "Hello World!"); } TEST(nljson_serializers_fromjson, list) { py::scoped_interpreter guard; nl::json j = "[1234, \"Hello World!\", false]"_json; py::object obj = j; ASSERT_TRUE(py::isinstance(obj)); ASSERT_EQ(py::list(obj)[0].cast(), 1234); ASSERT_EQ(py::list(obj)[1].cast(), "Hello World!"); ASSERT_EQ(py::list(obj)[2].cast(), false); py::list obj2 = j; ASSERT_EQ(py::list(obj2)[0].cast(), 1234); ASSERT_EQ(py::list(obj2)[1].cast(), "Hello World!"); ASSERT_EQ(py::list(obj2)[2].cast(), false); } TEST(nljson_serializers_fromjson, dict) { py::scoped_interpreter guard; nl::json j = "{\"a\": 1234, \"b\":\"Hello World!\", \"c\":false}"_json; py::object obj = j; ASSERT_TRUE(py::isinstance(obj)); ASSERT_EQ(py::dict(obj)["a"].cast(), 1234); ASSERT_EQ(py::dict(obj)["b"].cast(), "Hello World!"); ASSERT_EQ(py::dict(obj)["c"].cast(), false); py::dict obj2 = j; ASSERT_EQ(py::dict(obj2)["a"].cast(), 1234); ASSERT_EQ(py::dict(obj2)["b"].cast(), "Hello World!"); ASSERT_EQ(py::dict(obj2)["c"].cast(), false); } TEST(nljson_serializers_fromjson, nested) { py::scoped_interpreter guard; nl::json j = R"({ "baz": ["one", "two", "three"], "foo": 1, "bar": {"a": 36, "b": false}, "hey": null })"_json; py::object obj = j; ASSERT_TRUE(py::isinstance(obj)); ASSERT_TRUE(py::isinstance(py::dict(obj)["baz"])); ASSERT_TRUE(py::isinstance(py::dict(obj)["foo"])); py::list baz = py::dict(obj)["baz"]; py::int_ foo = py::dict(obj)["foo"]; py::dict bar = py::dict(obj)["bar"]; ASSERT_EQ(baz[0].cast(), "one"); ASSERT_EQ(baz[1].cast(), "two"); ASSERT_EQ(baz[2].cast(), "three"); ASSERT_EQ(foo.cast(), 1); ASSERT_EQ(bar["a"].cast(), 36); ASSERT_FALSE(bar["b"].cast()); ASSERT_TRUE(py::dict(obj)["hey"].is_none()); } inline const nl::json& test_fromtojson(const nl::json& json) { return json; } TEST(pybind11_caster_tojson, dict) { py::scoped_interpreter guard; py::module m("test"); m.def("to_json", &test_fromtojson); // Simulate calling this binding from Python with a dictionary as argument py::dict obj("number"_a=1234, "hello"_a="world"); nl::json j = m.attr("to_json")(obj); ASSERT_TRUE(j.is_object()); ASSERT_EQ(j["number"].get(), 1234); ASSERT_EQ(j["hello"].get(), "world"); } TEST(pybind11_caster_fromjson, dict) { py::scoped_interpreter guard; py::module m("test"); m.def("from_json", &test_fromtojson); // Simulate calling this binding from Python, getting back a py::object py::dict obj("number"_a=1234, "hello"_a="world"); py::dict j = m.attr("from_json")(obj); ASSERT_EQ(j["number"].cast(), 1234); ASSERT_EQ(j["hello"].cast(), "world"); }