On Wed, Oct 28, 2026 at 02:46:51PM -0700, Douglas Anderson wrote: > Add Pythonic iterator helpers on `FdtRo` to simplify walking nodes, > properties, and memory reservation entries without manual offset loops > or `-FDT_ERR_NOTFOUND` sentinel handling: > > - `subnodes(nodeoffset)`: yields the offset of each direct child subnode > of `nodeoffset`. > - `properties(nodeoffset)`: yields a `Property` object for each property > of `nodeoffset`. > - `get_mem_rsv_list()`: returns a list of `(address, size)` tuples for > all entries in the memory reservation block. > > Assisted-by: Gemini:gemini-pro-prerelease > Signed-off-by: Douglas Anderson Patches 1 & 2 are useful independent of the rest of the series. Applied, thanks. > --- > > Changes in v2: > - New patch adding FdtRo.subnodes(), FdtRo.properties(), and > FdtRo.get_mem_rsv_list() > > pylibfdt/libfdt.i | 45 +++++++++++++++++++++++++++++++++++++++++ > tests/pylibfdt_tests.py | 18 +++++++++++++++++ > 2 files changed, 63 insertions(+) > > diff --git a/pylibfdt/libfdt.i b/pylibfdt/libfdt.i > index 46f28f67290d..0db7110b4a38 100644 > --- a/pylibfdt/libfdt.i > +++ b/pylibfdt/libfdt.i > @@ -201,6 +201,23 @@ class FdtRo(object): > """ > return check_err(fdt_next_subnode(self._fdt, nodeoffset), quiet) > > + def subnodes(self, nodeoffset): > + """Iterate over the subnodes of a node > + > + Args: > + nodeoffset: Offset of parent node to check > + > + Yields: > + Node offset of each direct subnode in order > + > + Raises: > + FdtException on error (e.g. invalid nodeoffset) > + """ > + soff = self.first_subnode(nodeoffset, quiet=QUIET_NOTFOUND) > + while soff >= 0: > + yield soff > + soff = self.next_subnode(soff, quiet=QUIET_NOTFOUND) > + > def magic(self): > """Return the magic word from the header > > @@ -302,6 +319,17 @@ class FdtRo(object): > check_err(val[0], quiet) > return val[1:] > > + def get_mem_rsv_list(self): > + """Return a list of all memory reserve-map records > + > + Returns: > + List of (address, size) tuples for each memory reserve-map record > + """ > + return [ > + tuple(self.get_mem_rsv(i)) > + for i in range(self.num_mem_rsv()) > + ] > + > def address_cells(self, nodeoffset, quiet=()): > """Return the number of address cells used by a node's children > > @@ -434,6 +462,23 @@ class FdtRo(object): > return pdata[1] > return Property(pdata[0], pdata[1]) > > + def properties(self, nodeoffset): > + """Iterate over the properties of a node > + > + Args: > + nodeoffset: Offset of node to check > + > + Yields: > + Property object for each property on @nodeoffset in order > + > + Raises: > + FdtException on error (e.g. invalid nodeoffset) > + """ > + poff = self.first_property_offset(nodeoffset, quiet=QUIET_NOTFOUND) > + while poff >= 0: > + yield self.get_property_by_offset(poff) > + poff = self.next_property_offset(poff, quiet=QUIET_NOTFOUND) > + > def getprop(self, nodeoffset, prop_name, quiet=()): > """Get a property from a node > > diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py > index 1b65961491bf..2a0509c7802e 100644 > --- a/tests/pylibfdt_tests.py > +++ b/tests/pylibfdt_tests.py > @@ -243,6 +243,22 @@ class PyLibfdtBasicTests(unittest.TestCase): > node_list.append(self.fdt.get_name(node)) > node = self.fdt.next_subnode(node, QUIET_NOTFOUND) > self.assertEqual(node_list, ['subnode@1', 'subnode@2']) > + self.assertEqual( > + [self.fdt.get_name(n) for n in self.fdt.subnodes(0)], > + ['subnode@1', 'subnode@2'], > + ) > + leaf = self.fdt.path_offset('/subnode@1/ss1') > + self.assertEqual(list(self.fdt.subnodes(leaf)), []) > + > + def testPropertiesIterator(self): > + """Check that we can iterate through properties of a node""" > + node = self.fdt.path_offset('/subnode@1') > + props = list(self.fdt.properties(node)) > + self.assertEqual([p.name for p in props], > + ['compatible', 'reg', 'prop-int']) > + self.assertEqual(props[0], b'subnode1\0') > + leaf = self.fdt.path_offset('/subnode@1/ss1') > + self.assertEqual(list(self.fdt.properties(leaf)), []) > > def testFirstNextSubnodeOffsetExceptions(self): > """Check except handling for first/next subnode functions""" > @@ -410,6 +426,8 @@ class PyLibfdtBasicTests(unittest.TestCase): > self.assertEqual([ 0xdeadbeef00000000, 0x100000], > self.fdt.get_mem_rsv(0)) > self.assertEqual([123456789, 0o10000], self.fdt.get_mem_rsv(1)) > + self.assertEqual([(0xdeadbeef00000000, 0x100000), (123456789, 0o10000)], > + self.fdt.get_mem_rsv_list()) > > def testAddDelReserveMap(self): > """Test that we can add to and remove from the memory reserve map""" > -- > 2.56.0.313.g2479322e68-goog > > -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibson