Reputation: 638
I can use YAML to dump a hierarchy of python objects, so:
import yaml
class C():
def __init__(self, x, y):
self.x = x
self.y = y
class D():
def __init__(self, c, d):
self.c = c
self.d = d
d = D(c=C(x=1, y='hi'),
d='bye')
print yaml.dump(d)
produces the output:
!!python/object:__main__.D
c: !!python/object:__main__.C {x: 1, y: hi}
d: bye
But I want to selectively hide some attributes. So suppose I have a function attribs_to_dump(obj)
which for any object returns the list of attribute names I want to dump, for example:
def attribs_to_dump(obj):
if obj.__class__ == C: return ['x']
if obj.__class__ == D: return ['c']
My question is, how do I hook attribs_to_dump
into yaml.dump
so that I get the following output?
!!python/object:__main__.D
c: !!python/object:__main__.C {x: 1}
There's a complicating factor: I want to achieve the effect by hooking into Yaml as it crawls over the object hierarchy rather than by pre-processing the object hierarchy myself. The reason is that not all objects in the hierarchy are easily amenable to introspection due to setattr/getattr/__dict__
magic that is present in some libraries I am using :-(...
All help much appreciated!
Upvotes: 2
Views: 1475
Reputation: 6796
This is an interesting question, I enjoyed solving it, thanks :)
from copy import deepcopy
class C(object):
def __init__(self, x, y):
self.x = x
self.y = y
class D(object):
def __init__(self, c, d):
self.c = c
self.d = d
d = D(
c=C(x=1, y='hi'),
d='bye'
)
FILTER_PARAMS = (
#(class_reference, process_recursively, ['attributes', 'on', 'whitelist'])
(D, True, ['c']),
(C, False, ['x']),
)
def attr_filter(obj, filter_params):
for attr in dir(obj):
if attr.startswith('__'):
# ignore builtins
continue
attr_val = obj.__getattribute__(attr)
# loop through filter params
for (cls, do_recursive, whitelist) in filter_params:
if isinstance(obj, cls) and attr in whitelist:
# filter class matches the current obj's class and
# current attribute is on the whitelist
if do_recursive:
# must process this attribute the same way as the parent
setattr(obj, attr, attr_filter(attr_val, filter_params))
# break will avoid the execution of the else clause meaning
# the attribute was on the white list so don't delete it
break
else:
# delete the current attribute of the instance as it was
# not on the whitelist
delattr(obj, attr)
return obj
# do a deepcopy of the object you pass in, so the original will be preserved
filtered_instance = attr_filter(deepcopy(d), FILTER_PARAMS)
print dir(filtered_instance)
print dir(filtered_instance.c)
# now pass filtered_instance to yaml's dump function
Upvotes: 1