11from dataclasses import dataclass , field
2- from collections import defaultdict
2+ from typing import Optional
33from pynumaflow .proto .common import metadata_pb2
44
55"""
@@ -46,13 +46,13 @@ def keys(self, group: str) -> list[str]:
4646 """
4747 Returns the list of keys for a given group.
4848 """
49- return list (self ._data [ group ] .keys ())
49+ return list (self ._data . get ( group , {}) .keys ())
5050
51- def value (self , group : str , key : str ) -> bytes :
51+ def value (self , group : str , key : str ) -> Optional [ bytes ] :
5252 """
5353 Returns the value for a given group and key.
5454 """
55- return self ._data [ group ][ key ]
55+ return self ._data . get ( group , {}). get ( key )
5656
5757
5858@dataclass
@@ -61,49 +61,95 @@ class UserMetadata:
6161 UserMetadata wraps the user-generated metadata groups per message. It is read-write to UDFs.
6262 """
6363
64- _data : defaultdict [str , dict [str , bytes ]] = field (default_factory = lambda : defaultdict ( dict ) )
64+ _data : dict [str , dict [str , bytes ]] = field (default_factory = dict )
6565
6666 def groups (self ) -> list [str ]:
6767 """
6868 Returns the list of group names for the user metadata.
6969 """
7070 return list (self ._data .keys ())
7171
72- def keys (self , group : str ) -> list [str ]:
72+ def keys (self , group : str ) -> Optional [ list [str ] ]:
7373 """
7474 Returns the list of keys for a given group.
7575 """
76- return list (self ._data [group ].keys ())
76+ keys = self ._data .get (group )
77+ if keys is None :
78+ return None
79+ return list (keys .keys ())
7780
78- def value (self , group : str , key : str ) -> bytes :
81+ def __contains__ (self , group : str ) -> bool :
7982 """
80- Returns the value for a given group and key.
83+ Returns True if the group exists.
84+ """
85+ return group in self ._data
86+
87+ def __getitem__ (self , group : str ) -> dict [str , bytes ]:
88+ """
89+ Returns the data for a given group.
90+ Raises KeyError if the group does not exist.
91+ """
92+ return self ._data [group ]
93+
94+ def __setitem__ (self , group : str , data : dict [str , bytes ]):
95+ """
96+ Sets the data for a given group.
97+ """
98+ self ._data [group ] = data
99+
100+ def __delitem__ (self , group : str ):
101+ """
102+ Removes the group and all its keys and values.
103+ Raises KeyError if the group does not exist.
104+ """
105+ del self ._data [group ]
106+
107+ def __len__ (self ) -> int :
81108 """
82- return self ._data [group ][key ]
109+ Returns the number of groups.
110+ """
111+ return len (self ._data )
112+
113+ def value (self , group : str , key : str ) -> Optional [bytes ]:
114+ """
115+ Returns the value for a given group and key. If the group or key does not exist, returns None.
116+ """
117+ value = self ._data .get (group )
118+ if value is None :
119+ return None
120+ return value .get (key )
83121
84122 def add (self , group : str , key : str , value : bytes ):
85123 """
86124 Adds the value for a given group and key.
87125 """
88- self ._data [ group ] [key ] = value
126+ self ._data . setdefault ( group , {}) [key ] = value
89127
90128 def set_group (self , group : str , data : dict [str , bytes ]):
91129 """
92130 Sets the data for a given group.
93131 """
94132 self ._data [group ] = data
95133
96- def remove (self , group : str , key : str ):
134+ def remove (self , group : str , key : str ) -> Optional [ bytes ] :
97135 """
98- Removes the key and its value for a given group.
136+ Removes the key and its value for a given group and returns the value. If this key is the only key in the group, the group will be removed.
137+ Returns None if the group or key does not exist.
99138 """
100- del self ._data [group ][key ]
139+ group_data = self ._data .pop (group , None )
140+ if group_data is None :
141+ return None
142+ value = group_data .pop (key , None )
143+ if group_data :
144+ self ._data [group ] = group_data
145+ return value
101146
102- def remove_group (self , group : str ):
147+ def remove_group (self , group : str ) -> Optional [ dict [ str , bytes ]] :
103148 """
104- Removes the group and all its keys and values.
149+ Removes the group and all its keys and values and returns the data.
150+ Returns None if the group does not exist.
105151 """
106- del self ._data [ group ]
152+ return self ._data . pop ( group , None )
107153
108154 def clear (self ):
109155 """
0 commit comments