mirror of
https://github.com/EttusResearch/uhd.git
synced 2026-10-25 17:36:10 +00:00
uhd: python: Make DeviceAddr behave like dict
This adds methods to the Python-bound version of device_addr_t so it
behaves like and can be used like a Python dictionary.
Specifically, it adds (including unit tests; assume a and b are of type
uhd.types.DeviceAddr):
```py
len(a)
a.keys()
a.values()
a.get('key')
a.get('key', 'default')
a.pop('key')
'key' in a
a['key']
a['key'] = 'new_val'
a == b
a != b
# These differ from Python's versions:
a.update(b)
a.update({'foo': 'bar'})
```
The update() method follows the signature of
uhd::device_addr_t::update(), not that of Python's dict.update(), see
the manual for details (the fail_on_conflict argument). All other
methods behave equivalently between Python's dict and uhd::dict.
Signed-off-by: Martin Braun <martin.braun@ettus.com>
This commit is contained in:
parent
f14ce015b9
commit
18d11d2ef8
@ -9,6 +9,7 @@
|
||||
#define INCLUDED_UHD_TYPES_PYTHON_HPP
|
||||
|
||||
#include <uhd/types/device_addr.hpp>
|
||||
#include <uhd/types/dict.hpp>
|
||||
#include <uhd/types/stream_cmd.hpp>
|
||||
#include <pybind11/stl.h>
|
||||
#include <map>
|
||||
@ -44,9 +45,82 @@ void export_types(py::module& m)
|
||||
.def("__str__", &uhd::device_addr_t::to_pp_string)
|
||||
.def("to_string", &uhd::device_addr_t::to_string)
|
||||
.def("to_pp_string", &uhd::device_addr_t::to_pp_string)
|
||||
.def("to_dict", [](uhd::device_addr_t& self) {
|
||||
return static_cast<std::map<std::string, std::string>>(self);
|
||||
});
|
||||
.def("to_dict",
|
||||
[](uhd::device_addr_t& self) {
|
||||
return static_cast<std::map<std::string, std::string>>(self);
|
||||
})
|
||||
.def("keys", [](const uhd::device_addr_t& self) { return self.keys(); })
|
||||
.def("values", [](const uhd::device_addr_t& self) { return self.vals(); })
|
||||
.def("get",
|
||||
[](const uhd::device_addr_t& self, const std::string& key) -> py::object {
|
||||
if (self.has_key(key)) {
|
||||
return py::str(self.get(key));
|
||||
}
|
||||
return py::none();
|
||||
})
|
||||
.def("get",
|
||||
[](const uhd::device_addr_t& self,
|
||||
const std::string& key,
|
||||
const std::string& other) { return self.get(key, other); })
|
||||
.def(
|
||||
"pop",
|
||||
[](uhd::device_addr_t& self,
|
||||
const std::string& key,
|
||||
const char* def) -> std::string {
|
||||
if (!self.has_key(key)) {
|
||||
if (def == nullptr) {
|
||||
throw py::key_error(key);
|
||||
}
|
||||
return std::string(def);
|
||||
}
|
||||
return self.pop(key);
|
||||
},
|
||||
py::arg("k"),
|
||||
py::arg("d") = nullptr)
|
||||
.def(
|
||||
"update",
|
||||
[](uhd::device_addr_t& self,
|
||||
const uhd::device_addr_t& new_dict,
|
||||
const bool fail_on_conflict) { self.update(new_dict, fail_on_conflict); },
|
||||
py::arg("E"),
|
||||
py::arg("fail_on_conflict") = true)
|
||||
.def(
|
||||
"update",
|
||||
[](uhd::device_addr_t& self,
|
||||
const std::map<std::string, std::string>& new_dict,
|
||||
const bool fail_on_conflict) {
|
||||
self.update(uhd::device_addr_t(new_dict), fail_on_conflict);
|
||||
},
|
||||
py::arg("E"),
|
||||
py::arg("fail_on_conflict") = true)
|
||||
.def("separate",
|
||||
[](const uhd::device_addr_t& self) {
|
||||
return uhd::separate_device_addr(self);
|
||||
})
|
||||
.def("__getitem__",
|
||||
[](const uhd::device_addr_t& self, const std::string& key) -> std::string {
|
||||
if (!self.has_key(key)) {
|
||||
throw py::key_error(key);
|
||||
}
|
||||
return self.get(key);
|
||||
})
|
||||
.def("__setitem__",
|
||||
[](uhd::device_addr_t& self, const std::string& key, const std::string& val) {
|
||||
self.set(key, val);
|
||||
})
|
||||
.def("__contains__",
|
||||
[](const uhd::device_addr_t& self, const std::string& key) {
|
||||
return self.has_key(key);
|
||||
})
|
||||
.def("__len__", [](const uhd::device_addr_t& self) { return self.size(); })
|
||||
.def("__eq__",
|
||||
[](const uhd::device_addr_t& self, const uhd::device_addr_t& other) {
|
||||
return self == other;
|
||||
})
|
||||
.def("__ne__",
|
||||
[](const uhd::device_addr_t& self, const uhd::device_addr_t& other) {
|
||||
return self != other;
|
||||
});
|
||||
// This will allow functions in Python that take a device_addr to also take
|
||||
// a string:
|
||||
py::implicitly_convertible<std::string, uhd::device_addr_t>();
|
||||
|
||||
@ -72,6 +72,7 @@ set(pytest_sources
|
||||
verify_fbs_test.py
|
||||
pychdr_parse_test.py
|
||||
uhd_image_downloader_test.py
|
||||
device_addr_test.py
|
||||
)
|
||||
|
||||
#turn each test cpp file into an executable with an int main() function
|
||||
|
||||
56
host/tests/device_addr_test.py
Normal file
56
host/tests/device_addr_test.py
Normal file
@ -0,0 +1,56 @@
|
||||
#
|
||||
# Copyright 2020 Ettus Research, a National Instruments Brand
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
"""
|
||||
Unit test for uhd.types.DeviceAddr
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from uhd.types import DeviceAddr, separate_device_addr, combine_device_addrs
|
||||
|
||||
class DeviceAddrTest(unittest.TestCase):
|
||||
""" Test Python-wrapped device_addr_t """
|
||||
|
||||
def test_device_addr_dict(self):
|
||||
"""
|
||||
Check we can use DeviceAddr like a Python dict
|
||||
"""
|
||||
dev_a = DeviceAddr("a=1,b=2,c=3")
|
||||
self.assertEqual(len(dev_a), 3)
|
||||
self.assertEqual(dev_a.to_dict(), {'a': '1', 'b': '2', 'c': '3'})
|
||||
dev_d = dev_a.to_dict()
|
||||
self.assertEqual(dev_a.keys(), list(dev_d.keys()))
|
||||
self.assertEqual(dev_a.values(), list(dev_d.values()))
|
||||
self.assertEqual(dev_a.get('a'), '1')
|
||||
self.assertEqual(dev_a.get('a', 'boo'), '1')
|
||||
self.assertEqual(dev_a.get('z'), None)
|
||||
self.assertEqual(dev_a.get('z', 'boo'), 'boo')
|
||||
self.assertEqual(dev_a['a'], '1')
|
||||
with self.assertRaises(KeyError):
|
||||
print(dev_a['z'])
|
||||
self.assertTrue('a' in dev_a)
|
||||
self.assertEqual(dev_a.pop('a'), '1')
|
||||
self.assertEqual(len(dev_a), 2)
|
||||
self.assertTrue('a' not in dev_a)
|
||||
self.assertEqual(dev_a.pop('z', 'boo'), 'boo')
|
||||
with self.assertRaises(KeyError):
|
||||
print(dev_a.pop('z'))
|
||||
dev_a.update({'a': '9'})
|
||||
self.assertEqual(dev_a.get('a'), '9')
|
||||
with self.assertRaises(RuntimeError):
|
||||
dev_a.update({'a': '12'})
|
||||
dev_a.update({'a': '12'}, False)
|
||||
self.assertEqual(dev_a.get('a'), '12')
|
||||
|
||||
def test_device_addr_separate(self):
|
||||
dev_a = DeviceAddr("addr0=192.168.40.1,addr1=192.168.40.2,time_source=external")
|
||||
self.assertEqual(len(dev_a.separate()), 2)
|
||||
self.assertEqual(len(dev_a.separate()[0]), 2)
|
||||
self.assertEqual(dev_a.separate(), separate_device_addr(dev_a))
|
||||
self.assertEqual(
|
||||
DeviceAddr(
|
||||
'addr0=192.168.40.1,time_source0=external,'
|
||||
'addr1=192.168.40.2,time_source1=external'),
|
||||
combine_device_addrs(dev_a.separate()))
|
||||
Loading…
Reference in New Issue
Block a user