1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
import yaml, re
def add_yaml_resolvers(classes):
for cls in classes: #only one at a time works so far?
if hasattr(cls, 'yaml_pattern') and cls not in implicit_resolved:
yaml.add_implicit_resolver(cls.yaml_tag, re.compile(cls.yaml_pattern))
implicit_resolved.append(cls)
implicit_resolved=[]
def load(string):
global implicit_resolved
tmp = yaml.load_all(string)
rval = tmp.next() #this might be tag_hack
if type(rval) == tag_hack:
other_return_value = tmp.next() #a document listing which tags to ignore comes before the real metadata
#now remove the tag_hack tags from the system
for tag in rval.tags:
rval.undo_tag_hack_for_tag(tag)
return other_return_value
else: return rval
def dump(value, filename=None):
retval = yaml.dump(value, default_flow_style=False)
if filename is not None:
f = open(filename, 'w')
f.write(retval)
else:
return retval
class FennObject(yaml.YAMLObject):
'''so i dont repeat generic yaml stuff everywhere'''
#TODO fix bad characters spaces etc
@staticmethod
def setify(var):
'''converts whatever to a set; dicts become a set of their values'''
if not hasattr(var, '__iter__'): var = set([var])
if isinstance(var, dict): var = set([var.values()]) #that's right, not keys
if isinstance(var, list): var = set(var)
return var
def overlay(self, other):
if type(other)==dict:
attrs = other.iteritems()
else:
attrs = other.__dict__.iteritems()
for (k, v) in attrs:
setattr(self, k, v)
@classmethod
def to_yaml(cls, dumper, data):
if hasattr(data, "yaml_flow_style"):
flow = data.yaml_flow_style
else: flow=None
if hasattr(data, 'yaml_repr'):
repr, tag = data.yaml_repr(), data.yaml_tag
if isinstance(repr, list) or isinstance(repr, tuple):
return dumper.represent_sequence(tag, repr, flow)
elif isinstance(repr, dict):
return dumper.represent_mapping(tag, repr, flow)
else:
return dumper.represent_scalar(tag, repr)
else:
#return the default yaml dump
if len(data.__dict__) > 0: return dumper.represent_mapping(cls.yaml_tag, data.__dict__.iteritems())
else: return dumper.represent_scalar(cls.yaml_tag, data)
@classmethod
def from_yaml(cls, loader, node):
'''see http://pyyaml.org/wiki/PyYAMLDocumentation#Constructorsrepresentersresolvers'''
if type(node)==yaml.ScalarNode:
data = loader.construct_scalar(node)
return cls(data) #assuming that the class has one positional arg
elif type(node) == yaml.MappingNode:
data = loader.construct_mapping(node, deep=True) #will this break path_resolver?
rval = cls()
#stuff data into object's attributes
for (key, value) in data.iteritems():
if value is not None:
setattr(rval, key, value)
#this isn't actually used anywhere:
if hasattr(rval, "post_init_hook"):
rval.post_init_hook()
return rval
elif type(node) == yaml.SequenceNode:
data = loader.construct_sequence(node, deep=True)
return cls(data)
else: raise ValueError, "node type must be scalar, mapping, or sequence; got: " + str(cls.yaml_type)
class Dummy(object):
def __init__(self, node):
if hasattr(node, 'iteritems'):
for (k,v) in node.iteritems(): setattr(self, k,v)
else: self = node
@staticmethod
def multi_constructor(loader, tag_suffix, node):
#if the real class is actually loaded, return it
#so search through the classes that inherit from YAMLObject and hasattr(blah,"yaml_type") and the right yaml_type
#if
# tag_hack.yaml_loader.yaml_constructors..
# return .. the correct object ..
if type(node) == yaml.ScalarNode:
data = loader.construct_scalar(node)
elif type(node) == yaml.MappingNode:
data = loader.construct_mapping(node)
elif type(node) == yaml.SequenceNode:
data = loader.construct_sequence(node)
else: raise TypeError, 'I dont know what to do with this node: ' + str(node)
return Dummy(data)
#foo = yaml.load_all('!!python/object:skdb.tag_hack \n tags: "!hello"\n---\n test: !hello\n 1234')
class tag_hack(FennObject):
'''allows loading of a template file containing tags that do not exist yet.
prepend something like this to the actual document:
!tag_hack tags: ["!one", "!two", "!three"]\n---\n'''
yaml_tag="!tag_hack"
tags=[]
def __init__(self):
pass
def __setstate__ (self, attrs):
for i in attrs['tags']:
yaml.add_multi_constructor(i, Dummy.multi_constructor)
self.tags.append(i)
def undo_tag_hack_for_tag(self, tag):
'''undoes a tag hack for a particular tag'''
#for key in yaml.YAMLObject.yaml_loader.yaml_constructors.keys():
# if key:
# if key[:1] == "!":
# print key
if tag in self.yaml_loader.yaml_multi_constructors:
self.yaml_loader.yaml_multi_constructors.pop(tag)
self.tags.remove(tag) #this might need to be indented
return
|