Skip to content

Commit f80db19

Browse files
author
Jouke Witteveen
committed
Add make_namespace function and tests
1 parent 721834b commit f80db19

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

docs/advanced/pycpp/object.rst

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,37 @@ Available types include :class:`handle`, :class:`object`, :class:`bool_`,
2020
Be sure to review the :ref:`pytypes_gotchas` before using this heavily in
2121
your C++ API.
2222

23+
.. _instantiating_compound_types:
24+
25+
Instantiating compound Python types from C++
26+
============================================
27+
28+
Dictionaries can be initialized in the :class:`dict` constructor:
29+
30+
.. code-block:: cpp
31+
32+
using namespace pybind11::literals; // to bring in the `_a` literal
33+
auto d = py::dict("spam"_a=py::none(), "eggs"_a=42);
34+
35+
A tuple of python objects can be instantiated using :func:`py::make_tuple`:
36+
37+
.. code-block:: cpp
38+
39+
py::tuple tup = py::make_tuple(42, py::none(), "spam");
40+
41+
Each element is converted to a supported Python type.
42+
43+
A simple namespace can be instantiated using :func:`py::make_namespace`:
44+
45+
.. code-block:: cpp
46+
47+
using namespace pybind11::literals; // to bring in the `_a` literal
48+
py::object ns = py::make_namespace("spam"_a=py::none(), "eggs"_a=42);
49+
50+
Attributes on a namespace can be modified with the :func:`py::delattr`,
51+
:func:`py::getattr`, and :func:`py::setattr` functions. Namespaces can be useful
52+
as stand-ins for class instances.
53+
2354
.. _casting_back_and_forth:
2455

2556
Casting back and forth
@@ -30,7 +61,7 @@ types to Python, which can be done using :func:`py::cast`:
3061

3162
.. code-block:: cpp
3263
33-
MyClass *cls = ..;
64+
MyClass *cls = ...;
3465
py::object obj = py::cast(cls);
3566
3667
The reverse direction uses the following syntax:

include/pybind11/cast.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,6 +1890,12 @@ template <return_value_policy policy = return_value_policy::automatic_reference,
18901890
return result;
18911891
}
18921892

1893+
template <typename... Args,
1894+
typename = detail::enable_if_t<args_are_all_keyword_or_ds<Args...>()>>
1895+
object make_namespace(Args&&... args_) {
1896+
return reinterpret_steal<object>(_PyNamespace_New(dict(std::forward<Args>(args_)...).ptr()));
1897+
}
1898+
18931899
/// \ingroup annotations
18941900
/// Annotation for arguments
18951901
struct arg {

tests/test_pytypes.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,17 @@ TEST_SUBMODULE(pytypes, m) {
7575
return dict.contains(val);
7676
});
7777

78+
// test_tuple
79+
m.def("make_tuple", []() { return py::make_tuple(42, "foo"); });
80+
81+
// test_namespace
82+
m.def("make_namespace", []() {
83+
auto ns = py::make_namespace("attr"_a=42, "x"_a="foo", "wrong"_a=1);
84+
py::delattr(ns, "wrong");
85+
py::setattr(ns, "right", py::int_(2));
86+
return ns;
87+
});
88+
7889
// test_str
7990
m.def("str_from_string", []() { return py::str(std::string("baz")); });
8091
m.def("str_from_bytes", []() { return py::str(py::bytes("boo", 3)); });

tests/test_pytypes.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,19 @@ def test_dict(capture, doc):
9898
assert m.dict_keyword_constructor() == {"x": 1, "y": 2, "z": 3}
9999

100100

101+
def test_tuple():
102+
t = m.make_tuple()
103+
assert t == (42, "foo")
104+
105+
106+
def test_namespace():
107+
ns = m.make_namespace()
108+
assert ns.attr == 42
109+
assert ns.x == "foo"
110+
assert ns.right == 2
111+
assert not hasattr(ns, "wrong")
112+
113+
101114
def test_str(doc):
102115
assert m.str_from_string().encode().decode() == "baz"
103116
assert m.str_from_bytes().encode().decode() == "boo"

0 commit comments

Comments
 (0)