33# SPDX-License-Identifier: MIT
44
55import logging
6- from typing import IO , Any , Dict , Iterator , Optional , Union
6+ from typing import IO , Any , Dict , Iterator , Optional , Tuple , Union
77
88from _libyang import ffi , lib
99from .keyed_list import KeyedList
@@ -190,13 +190,69 @@ def diff_flags(with_defaults: bool = False) -> int:
190190 return flags
191191
192192
193+ # -------------------------------------------------------------------------------------
194+ class DNodeAttrs :
195+ __slots__ = ("context" , "parent" , "cdata" , "__dict__" )
196+
197+ def __init__ (self , context : "libyang.Context" , parent : "libyang.DNode" ):
198+ self .context = context
199+ self .parent = parent
200+ self .cdata = [] # C type: "struct lyd_attr *"
201+
202+ def get (self , name : str ) -> Optional [str ]:
203+ for attr_name , attr_value in self :
204+ if attr_name == name :
205+ return attr_value
206+ return None
207+
208+ def set (self , name : str , value : str ):
209+ attrs = ffi .new ("struct lyd_attr **" )
210+ ret = lib .lyd_new_attr (
211+ self .parent .cdata ,
212+ ffi .NULL ,
213+ str2c (name ),
214+ str2c (value ),
215+ attrs ,
216+ )
217+ if ret != lib .LY_SUCCESS :
218+ raise self .context .error ("cannot create attr" )
219+ self .cdata .append (attrs [0 ])
220+
221+ def remove (self , name : str ):
222+ for attr in self .cdata :
223+ if self ._get_attr_name (attr ) == name :
224+ lib .lyd_free_attr_single (self .context .cdata , attr )
225+ self .cdata .remove (attr )
226+ break
227+
228+ def __contains__ (self , name : str ) -> bool :
229+ for attr_name , _ in self :
230+ if attr_name == name :
231+ return True
232+ return False
233+
234+ def __iter__ (self ) -> Iterator [Tuple [str , str ]]:
235+ for attr in self .cdata :
236+ name = self ._get_attr_name (attr )
237+ yield (name , c2str (attr .value ))
238+
239+ def __len__ (self ) -> int :
240+ return len (self .cdata )
241+
242+ @staticmethod
243+ def _get_attr_name (cdata ) -> str :
244+ if cdata .name .prefix != ffi .NULL :
245+ return f"{ c2str (cdata .name .prefix )} :{ c2str (cdata .name .name )} "
246+ return c2str (cdata .name .name )
247+
248+
193249# -------------------------------------------------------------------------------------
194250class DNode :
195251 """
196252 Data tree node.
197253 """
198254
199- __slots__ = ("context" , "cdata" , "free_func" , "__dict__" )
255+ __slots__ = ("context" , "cdata" , "attributes" , " free_func" , "__dict__" )
200256
201257 def __init__ (self , context : "libyang.Context" , cdata ):
202258 """
@@ -207,6 +263,7 @@ def __init__(self, context: "libyang.Context", cdata):
207263 """
208264 self .context = context
209265 self .cdata = cdata # C type: "struct lyd_node *"
266+ self .attributes = None
210267 self .free_func = None # type: Callable[DNode]
211268
212269 def meta (self ):
@@ -254,6 +311,11 @@ def new_meta(self, name: str, value: str, clear_dflt: bool = False):
254311 if ret != lib .LY_SUCCESS :
255312 raise self .context .error ("cannot create meta" )
256313
314+ def attrs (self ) -> DNodeAttrs :
315+ if not self .attributes :
316+ self .attributes = DNodeAttrs (self .context , self )
317+ return self .attributes
318+
257319 def add_defaults (
258320 self ,
259321 no_config : bool = False ,
0 commit comments