1212# License for the specific language governing permissions and limitations
1313# under the License.
1414
15- """The **splunklib.data** module reads the responses from splunkd in Atom Feed
15+ """The **splunklib.data** module reads the responses from splunkd in Atom Feed
1616format, which is the format used by most of the REST API.
1717"""
1818
19- from __future__ import absolute_import
20- import sys
2119from xml .etree .ElementTree import XML
22- from splunklib import six
2320
24- __all__ = ["load" ]
21+ __all__ = ["load" , "record" ]
2522
2623# LNAME refers to element names without namespaces; XNAME is the same
2724# name, but with an XML namespace.
3633XNAME_KEY = XNAMEF_REST % LNAME_KEY
3734XNAME_LIST = XNAMEF_REST % LNAME_LIST
3835
36+
3937# Some responses don't use namespaces (eg: search/parse) so we look for
4038# both the extended and local versions of the following names.
4139
40+
4241def isdict (name ):
43- return name == XNAME_DICT or name == LNAME_DICT
42+ return name in (XNAME_DICT , LNAME_DICT )
43+
4444
4545def isitem (name ):
46- return name == XNAME_ITEM or name == LNAME_ITEM
46+ return name in (XNAME_ITEM , LNAME_ITEM )
47+
4748
4849def iskey (name ):
49- return name == XNAME_KEY or name == LNAME_KEY
50+ return name in (XNAME_KEY , LNAME_KEY )
51+
5052
5153def islist (name ):
52- return name == XNAME_LIST or name == LNAME_LIST
54+ return name in (XNAME_LIST , LNAME_LIST )
55+
5356
5457def hasattrs (element ):
5558 return len (element .attrib ) > 0
5659
60+
5761def localname (xname ):
5862 rcurly = xname .find ('}' )
59- return xname if rcurly == - 1 else xname [rcurly + 1 :]
63+ return xname if rcurly == - 1 else xname [rcurly + 1 :]
64+
6065
6166def load (text , match = None ):
62- """This function reads a string that contains the XML of an Atom Feed, then
63- returns the
64- data in a native Python structure (a ``dict`` or ``list``). If you also
65- provide a tag name or path to match, only the matching sub-elements are
67+ """This function reads a string that contains the XML of an Atom Feed, then
68+ returns the
69+ data in a native Python structure (a ``dict`` or ``list``). If you also
70+ provide a tag name or path to match, only the matching sub-elements are
6671 loaded.
6772
6873 :param text: The XML text to load.
@@ -78,30 +83,28 @@ def load(text, match=None):
7883 'names' : {}
7984 }
8085
81- # Convert to unicode encoding in only python 2 for xml parser
82- if (sys .version_info < (3 , 0 , 0 ) and isinstance (text , unicode )):
83- text = text .encode ('utf-8' )
84-
8586 root = XML (text )
8687 items = [root ] if match is None else root .findall (match )
8788 count = len (items )
88- if count == 0 :
89+ if count == 0 :
8990 return None
90- elif count == 1 :
91+ elif count == 1 :
9192 return load_root (items [0 ], nametable )
9293 else :
9394 return [load_root (item , nametable ) for item in items ]
9495
96+
9597# Load the attributes of the given element.
9698def load_attrs (element ):
9799 if not hasattrs (element ): return None
98100 attrs = record ()
99- for key , value in six . iteritems (element .attrib ):
101+ for key , value in list (element .attrib . items ()):
100102 attrs [key ] = value
101103 return attrs
102104
105+
103106# Parse a <dict> element and return a Python dict
104- def load_dict (element , nametable = None ):
107+ def load_dict (element , nametable = None ):
105108 value = record ()
106109 children = list (element )
107110 for child in children :
@@ -110,6 +113,7 @@ def load_dict(element, nametable = None):
110113 value [name ] = load_value (child , nametable )
111114 return value
112115
116+
113117# Loads the given elements attrs & value into single merged dict.
114118def load_elem (element , nametable = None ):
115119 name = localname (element .tag )
@@ -118,12 +122,12 @@ def load_elem(element, nametable=None):
118122 if attrs is None : return name , value
119123 if value is None : return name , attrs
120124 # If value is simple, merge into attrs dict using special key
121- if isinstance (value , six . string_types ):
125+ if isinstance (value , str ):
122126 attrs ["$text" ] = value
123127 return name , attrs
124128 # Both attrs & value are complex, so merge the two dicts, resolving collisions.
125129 collision_keys = []
126- for key , val in six . iteritems (attrs ):
130+ for key , val in list (attrs . items () ):
127131 if key in value and key in collision_keys :
128132 value [key ].append (val )
129133 elif key in value and key not in collision_keys :
@@ -133,6 +137,7 @@ def load_elem(element, nametable=None):
133137 value [key ] = val
134138 return name , value
135139
140+
136141# Parse a <list> element and return a Python list
137142def load_list (element , nametable = None ):
138143 assert islist (element .tag )
@@ -143,6 +148,7 @@ def load_list(element, nametable=None):
143148 value .append (load_value (child , nametable ))
144149 return value
145150
151+
146152# Load the given root element.
147153def load_root (element , nametable = None ):
148154 tag = element .tag
@@ -151,6 +157,7 @@ def load_root(element, nametable=None):
151157 k , v = load_elem (element , nametable )
152158 return Record .fromkv (k , v )
153159
160+
154161# Load the children of the given element.
155162def load_value (element , nametable = None ):
156163 children = list (element )
@@ -159,7 +166,7 @@ def load_value(element, nametable=None):
159166 # No children, assume a simple text value
160167 if count == 0 :
161168 text = element .text
162- if text is None :
169+ if text is None :
163170 return None
164171
165172 if len (text .strip ()) == 0 :
@@ -179,31 +186,32 @@ def load_value(element, nametable=None):
179186 # If we have seen this name before, promote the value to a list
180187 if name in value :
181188 current = value [name ]
182- if not isinstance (current , list ):
189+ if not isinstance (current , list ):
183190 value [name ] = [current ]
184191 value [name ].append (item )
185192 else :
186193 value [name ] = item
187194
188195 return value
189196
197+
190198# A generic utility that enables "dot" access to dicts
191199class Record (dict ):
192- """This generic utility class enables dot access to members of a Python
200+ """This generic utility class enables dot access to members of a Python
193201 dictionary.
194202
195- Any key that is also a valid Python identifier can be retrieved as a field.
196- So, for an instance of ``Record`` called ``r``, ``r.key`` is equivalent to
197- ``r['key']``. A key such as ``invalid-key`` or ``invalid.key`` cannot be
198- retrieved as a field, because ``-`` and ``.`` are not allowed in
203+ Any key that is also a valid Python identifier can be retrieved as a field.
204+ So, for an instance of ``Record`` called ``r``, ``r.key`` is equivalent to
205+ ``r['key']``. A key such as ``invalid-key`` or ``invalid.key`` cannot be
206+ retrieved as a field, because ``-`` and ``.`` are not allowed in
199207 identifiers.
200208
201- Keys of the form ``a.b.c`` are very natural to write in Python as fields. If
202- a group of keys shares a prefix ending in ``.``, you can retrieve keys as a
209+ Keys of the form ``a.b.c`` are very natural to write in Python as fields. If
210+ a group of keys shares a prefix ending in ``.``, you can retrieve keys as a
203211 nested dictionary by calling only the prefix. For example, if ``r`` contains
204212 keys ``'foo'``, ``'bar.baz'``, and ``'bar.qux'``, ``r.bar`` returns a record
205- with the keys ``baz`` and ``qux``. If a key contains multiple ``.``, each
206- one is placed into a nested dictionary, so you can write ``r.bar.qux`` or
213+ with the keys ``baz`` and ``qux``. If a key contains multiple ``.``, each
214+ one is placed into a nested dictionary, so you can write ``r.bar.qux`` or
207215 ``r['bar.qux']`` interchangeably.
208216 """
209217 sep = '.'
@@ -215,7 +223,7 @@ def __call__(self, *args):
215223 def __getattr__ (self , name ):
216224 try :
217225 return self [name ]
218- except KeyError :
226+ except KeyError :
219227 raise AttributeError (name )
220228
221229 def __delattr__ (self , name ):
@@ -235,7 +243,7 @@ def __getitem__(self, key):
235243 return dict .__getitem__ (self , key )
236244 key += self .sep
237245 result = record ()
238- for k ,v in six . iteritems (self ):
246+ for k , v in list (self . items () ):
239247 if not k .startswith (key ):
240248 continue
241249 suffix = k [len (key ):]
@@ -250,17 +258,16 @@ def __getitem__(self, key):
250258 else :
251259 result [suffix ] = v
252260 if len (result ) == 0 :
253- raise KeyError ("No key or prefix: %s" % key )
261+ raise KeyError (f "No key or prefix: { key } " )
254262 return result
255-
256263
257- def record (value = None ):
258- """This function returns a :class:`Record` instance constructed with an
264+
265+ def record (value = None ):
266+ """This function returns a :class:`Record` instance constructed with an
259267 initial value that you provide.
260-
261- :param ` value` : An initial record value.
262- :type ` value` : ``dict``
268+
269+ :param value: An initial record value.
270+ :type value: ``dict``
263271 """
264272 if value is None : value = {}
265273 return Record (value )
266-
0 commit comments