Loading...
Searching...
No Matches
py_arg.h
Go to the documentation of this file.
1#ifndef _BBM_PY_ARG_H_
2#define _BBM_PY_ARG_H_
3
4#include <utility>
5#include <stdexcept>
6
8#include "python/py_cast.h"
9
10/************************************************************************/
11/*! \file py_arg.h
12 \brief Create an object with a bbm constructor (with bbm::args) from
13 py::args and py::kwargs arguments.
14*************************************************************************/
15
16namespace bbm {
17 namespace python {
18
19 /** Implementation detail for py_args_to_bbm_args ***/
20 namespace detail {
21
22 /******************************************************************/
23 /*! \brief Extract the value from py::args and py::kwargs matching a bbm::arg
24 ******************************************************************/
25 template<typename ARG, size_t IDX> requires is_arg_v<ARG>
26 inline decltype(auto) py_args_to_bbm_arg(py::args& args, py::kwargs& kwargs)
27 {
28 using arg_t = std::decay_t<ARG>;
29 using type = std::decay_t<typename arg_t::type>;
30
31 // check if name exists
32 if(kwargs.size() > 0 && kwargs.contains( arg_t::name.value ))
33 {
34 return arg_t( py_cast<type>::cast( kwargs[ arg_t::name.value ] ) );
35 }
36
37 // otherwise copy from arg if available
38 else if(args.size() > IDX)
39 {
40 return arg_t( py_cast<type>::cast(args[IDX]) );
41 }
42
43 // otherwise return default value?
44 else if constexpr (std::is_constructible_v<arg_t>)
45 {
46 return arg_t();
47 }
48
49 // else fail
50 else throw std::runtime_error(std::string("BBM: value required for argument '") + toString(arg_t::name) + "'.'");
51
52 // unreachable...
53 return arg_t(type());
54 }
55
56 /******************************************************************/
57 /*! \brief Create a bbm::args from py_args and py::kwargs
58 ******************************************************************/
59 template<typename ARGS, size_t... IDX> requires is_args_v<ARGS>
60 inline auto py_args_to_bbm_args(py::args& args, py::kwargs& kwargs, std::index_sequence<IDX...>)
61 {
62 return ARGS( py_args_to_bbm_arg< decltype(std::declval<ARGS>().template get<IDX>()), IDX >(args, kwargs)... );
63 }
64
65
66 /******************************************************************/
67 /*! \brief Check if a name is in a bbm args at runtime
68 ******************************************************************/
69 template<typename ARGS, size_t... IDX> requires is_args_v<ARGS>
70 inline bool is_valid_bbm_arg_name(const std::string& name, std::index_sequence<IDX...>)
71 {
72 return ((std::decay_t<typename ARGS::template type<IDX>>::name.value == name) || ...);
73 }
74
75 } // end detail namespace
76
77
78 /********************************************************************/
79 /*! \brief Create a bbm::arg from py:args and py::kwargs
80
81 \tparam ARGS = bbm::args type to create and fill
82 \param args = list of python arguments
83 \param kwargs = list of keyword arguments
84 ********************************************************************/
85 template<typename ARGS> requires is_args_v<ARGS>
86 inline auto py_args_to_bbm_args(py::args& args, py::kwargs& kwargs)
87 {
88 // check validity: number of py::args
89 if(args.size() > ARGS::size) throw std::runtime_error(std::string("BBM: too many arguments (") + toString(args.size()) + "given, expected maximum: " + toString(ARGS::size) + ").");
90
91 // check validity: names of py:kwargs
92 for(auto& kwarg : kwargs)
93 {
94 std::string name = py::cast<std::string>(kwarg.first);
95 if(!detail::is_valid_bbm_arg_name<ARGS>(name, std::make_index_sequence<ARGS::size>{})) throw std::runtime_error(std::string("BBM: invalid argument name '") + name + "'.");
96 }
97
98 // Extract args
99 return detail::py_args_to_bbm_args<ARGS>(args, kwargs, std::make_index_sequence<ARGS::size>{});
100 }
101
102
103 /********************************************************************/
104 /*! \brief Construct an object with a valid 'constructor_args_t' based
105 on python args and kwargs
106
107 \tparam OBJ_TYPE = object type to create
108 \param args = list of python arguments (copied to the first N attributes)
109 \param kwargs = list of keyword arguments
110
111 Attempt to create an object with with 'OBJ_TYPE' from py::args and
112 py::kwargs when 'constructor_ars_t' exists (i.e., bbm/constructor.h
113 was used to declare a constructor).
114 *********************************************************************/
115 template<typename OBJ_TYPE> requires concepts::constructor<OBJ_TYPE>
116 inline OBJ_TYPE create_object(py::args& args, py::kwargs& kwargs)
117 {
118 return OBJ_TYPE( py_args_to_bbm_args<typename OBJ_TYPE::constructor_args_t>(args, kwargs) );
119 }
120
121
122 } // end python namepace
123} // end bbm namespace
124
125#endif /* _BBM_PY_ARG_H_ */
constructor concept
Definition: constructor.h:23
bbm constructor concept
OBJ_TYPE create_object(py::args &args, py::kwargs &kwargs)
Construct an object with a valid 'constructor_args_t' based on python args and kwargs.
Definition: py_arg.h:116
auto py_args_to_bbm_args(py::args &args, py::kwargs &kwargs)
Create a bbm::arg from py:args and py::kwargs.
Definition: py_arg.h:86
Definition: aggregatebsdf.h:29
std::string toString(const T &)
toString alias
Definition: stringconvert.h:594
decltype(auto) value(T &&t)
return the value of an attribute, or if not an attribute the object
Definition: attribute_value.h:20
Wrapper around py::cast for more robust casting to attributes and to aggregate types such as vec2d,...
Forward declaration.
Definition: args.h:248
static constexpr size_t size
Definition: args.h:282
static TARGET cast(T &&t)
Definition: py_cast.h:26