MUQ  0.4.3
pybind11_json.h
Go to the documentation of this file.
1 /***************************************************************************
2 * Copyright (c) 2019, Martin Renou *
3 * *
4 * Distributed under the terms of the BSD 3-Clause License. *
5 * *
6 * The full license is in the file LICENSE, distributed with this software. *
7 ****************************************************************************/
8 
9 #ifndef PYBIND11_JSON_HPP
10 #define PYBIND11_JSON_HPP
11 
12 #include <string>
13 #include <vector>
14 
16 
17 #include "pybind11/pybind11.h"
18 
19 namespace py = pybind11;
20 namespace nl = nlohmann;
21 
22 namespace pyjson
23 {
24  inline py::object from_json(const nl::json& j)
25  {
26  if (j.is_null())
27  {
28  return py::none();
29  }
30  else if (j.is_boolean())
31  {
32  return py::bool_(j.get<bool>());
33  }
34  else if (j.is_number_integer())
35  {
36  return py::int_(j.get<nl::json::number_integer_t>());
37  }
38  else if (j.is_number_unsigned())
39  {
40  return py::int_(j.get<nl::json::number_unsigned_t>());
41  }
42  else if (j.is_number_float())
43  {
44  return py::float_(j.get<double>());
45  }
46  else if (j.is_string())
47  {
48  return py::str(j.get<std::string>());
49  }
50  else if (j.is_array())
51  {
52  py::list obj(j.size());
53  for (std::size_t i = 0; i < j.size(); i++)
54  {
55  obj[i] = from_json(j[i]);
56  }
57  return std::move(obj);
58  }
59  else // Object
60  {
61  py::dict obj;
62  for (nl::json::const_iterator it = j.cbegin(); it != j.cend(); ++it)
63  {
64  obj[py::str(it.key())] = from_json(it.value());
65  }
66  return std::move(obj);
67  }
68  }
69 
70  inline nl::json to_json(const py::handle& obj)
71  {
72  if (obj.ptr() == nullptr || obj.is_none())
73  {
74  return nullptr;
75  }
76  if (py::isinstance<py::bool_>(obj))
77  {
78  return obj.cast<bool>();
79  }
80  if (py::isinstance<py::int_>(obj))
81  {
82  try
83  {
85  if (py::int_(s).equal(obj))
86  {
87  return s;
88  }
89  }
90  catch (...)
91  {
92  }
93  try
94  {
96  if (py::int_(u).equal(obj))
97  {
98  return u;
99  }
100  }
101  catch (...)
102  {
103  }
104  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<std::string>());
105  }
106  if (py::isinstance<py::float_>(obj))
107  {
108  return obj.cast<double>();
109  }
110  if (py::isinstance<py::bytes>(obj))
111  {
112  py::module base64 = py::module::import("base64");
113  return base64.attr("b64encode")(obj).attr("decode")("utf-8").cast<std::string>();
114  }
115  if (py::isinstance<py::str>(obj))
116  {
117  return obj.cast<std::string>();
118  }
119  if (py::isinstance<py::tuple>(obj) || py::isinstance<py::list>(obj))
120  {
121  auto out = nl::json::array();
122  for (const py::handle value : obj)
123  {
124  out.push_back(to_json(value));
125  }
126  return out;
127  }
128  if (py::isinstance<py::dict>(obj))
129  {
130  auto out = nl::json::object();
131  for (const py::handle key : obj)
132  {
133  out[py::str(key).cast<std::string>()] = to_json(obj[key]);
134  }
135  return out;
136  }
137  throw std::runtime_error("to_json not implemented for this type of object: " + py::repr(obj).cast<std::string>());
138  }
139 }
140 
141 // nlohmann_json serializers
142 namespace nlohmann
143 {
144  #define MAKE_NLJSON_SERIALIZER_DESERIALIZER(T) \
145  template <> \
146  struct adl_serializer<T> \
147  { \
148  inline static void to_json(json& j, const T& obj) \
149  { \
150  j = pyjson::to_json(obj); \
151  } \
152  \
153  inline static T from_json(const json& j) \
154  { \
155  return pyjson::from_json(j); \
156  } \
157  }
158 
159  #define MAKE_NLJSON_SERIALIZER_ONLY(T) \
160  template <> \
161  struct adl_serializer<T> \
162  { \
163  inline static void to_json(json& j, const T& obj) \
164  { \
165  j = pyjson::to_json(obj); \
166  } \
167  }
168 
170 
175 
179 
181  MAKE_NLJSON_SERIALIZER_ONLY(py::detail::item_accessor);
182  MAKE_NLJSON_SERIALIZER_ONLY(py::detail::list_accessor);
183  MAKE_NLJSON_SERIALIZER_ONLY(py::detail::tuple_accessor);
184  MAKE_NLJSON_SERIALIZER_ONLY(py::detail::sequence_accessor);
185  MAKE_NLJSON_SERIALIZER_ONLY(py::detail::str_attr_accessor);
186  MAKE_NLJSON_SERIALIZER_ONLY(py::detail::obj_attr_accessor);
187 
188  #undef MAKE_NLJSON_SERIALIZER
189  #undef MAKE_NLJSON_SERIALIZER_ONLY
190 }
191 
192 // pybind11 caster
193 namespace pybind11
194 {
195  namespace detail
196  {
197  template <> struct type_caster<nl::json>
198  {
199  public:
201 
202  bool load(handle src, bool)
203  {
204  try
205  {
206  value = pyjson::to_json(src);
207  return true;
208  }
209  catch (...)
210  {
211  return false;
212  }
213  }
214 
215  static handle cast(nl::json src, return_value_policy /* policy */, handle /* parent */)
216  {
217  object obj = pyjson::from_json(src);
218  return obj.release();
219  }
220  };
221  }
222 }
223 
224 #endif
a class to store JSON values
Definition: json.h:16658
basic_json get() const
get special-case overload
Definition: json.h:19336
constexpr bool is_number_float() const noexcept
return whether value is a floating-point number
Definition: json.h:19029
NumberIntegerType number_integer_t
a type for a number (integer)
Definition: json.h:17188
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json array(initializer_list_t init={})
explicitly create an array from an initializer list
Definition: json.h:18270
const_iterator cend() const noexcept
returns a const iterator to one past the last element
Definition: json.h:21077
size_type size() const noexcept
returns the number of elements
Definition: json.h:21494
constexpr bool is_number_unsigned() const noexcept
return whether value is an unsigned integer number
Definition: json.h:19001
constexpr bool is_boolean() const noexcept
return whether value is a boolean
Definition: json.h:18914
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json object(initializer_list_t init={})
explicitly create an object from an initializer list
Definition: json.h:18314
constexpr bool is_string() const noexcept
return whether value is a string
Definition: json.h:19095
constexpr bool is_array() const noexcept
return whether value is an array
Definition: json.h:19073
constexpr bool is_number_integer() const noexcept
return whether value is an integer number
Definition: json.h:18973
NumberUnsignedType number_unsigned_t
a type for a number (unsigned)
Definition: json.h:17259
const_iterator cbegin() const noexcept
returns a const iterator to the first element
Definition: json.h:21006
iter_impl< const basic_json > const_iterator
a const iterator for a basic_json container
Definition: json.h:16787
constexpr bool is_null() const noexcept
return whether value is null
Definition: json.h:18892
namespace for Niels Lohmann
MAKE_NLJSON_SERIALIZER_ONLY(py::handle)
MAKE_NLJSON_SERIALIZER_DESERIALIZER(py::object)
nl::json to_json(const py::handle &obj)
Definition: pybind11_json.h:70
py::object from_json(const nl::json &j)
Definition: pybind11_json.h:24
static handle cast(nl::json src, return_value_policy, handle)