Skip to content

Instantly share code, notes, and snippets.

@livibetter
Created February 3, 2012 22:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save livibetter/1733243 to your computer and use it in GitHub Desktop.
Save livibetter/1733243 to your computer and use it in GitHub Desktop.
Python object traversing
#!/usr/bin/env python3
# Copyright (c) 2012 Yu-Jie Lin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import re
def ot_attr(obj, key):
if hasattr(obj, key):
return getattr(obj, key)
raise KeyError
def ot_item(obj, key):
try:
return obj.__getitem__(key)
except:
raise KeyError
def ot_index_item(obj, key):
'''For list or string or something'''
try:
return obj.__getitem__(int(key))
except:
raise KeyError
def ot(obj, path, key_funcs=None):
'''ot stands for object traversing'''
if key_funcs is None:
key_funcs = (ot_attr, ot_item, ot_index_item)
keys = re.split(r'(?<!\\)\.', path)
key_idx = 0
while key_idx < len(keys):
key = keys[key_idx].replace(r'\.', '.')
key_idx += 1
for f in key_funcs:
try:
obj = f(obj, key)
break
except KeyError:
continue
else:
raise KeyError(('No key %s in object.%s' % (key, '.'.join(keys[:key_idx-1]))).rstrip('. '))
return obj
if __name__ == '__main__':
class ThisCanNotBeFound:
pass
test_dict = {'number': 123,
'boolean': True,
'tuple': (1, 2, 3),
ThisCanNotBeFound: 'Oh no!',
}
test_dict['list'] = ['number',
456,
{'foo.bar': 'It is foobar!'},
]
print(ot(test_dict, 'number'))
print(ot(test_dict, 'boolean'))
print(ot(test_dict, 'tuple.1'))
print(ot(test_dict, 'tuple.__repr__')())
print(ot(test_dict, 'list'))
print(ot(test_dict, 'list.2.foo\\.bar'))
print(ot(test_dict, 'list.2.foo\\.bar.4'))
print(ot('string', '2'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment