-
Notifications
You must be signed in to change notification settings - Fork 0
/
pan_file.py
104 lines (94 loc) · 3.28 KB
/
pan_file.py
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
import os
import sys
import re
class pan_exception(Exception):
'''Exception to be risen by a header processor, to indicate
something goes wrong with it'''
pass
class pan_file(object):
'''Pan file to be automatically regenerated'''
tpl_name_re = re.compile('^\w*\s*template\s+([-\w]+)\s*;$')
act_re = re.compile('^@{\s*(\S+?)\s*=\s*(.*)}$')
def __init__(self, filename, **actions):
'''Class constructor. Takes the name of the Pan file to open,
and the a dictionary with the actions registered to each
possible header.'''
self.file = open(filename, "r+")
self.actions = actions
self.body = []
self.open = True
def __iter__(self):
'''The object iterates over its header.'''
self.file.seek(0,0)
self.open = True
return self
def next(self):
if not self.open:
raise StopIteration
i = self.file.readline()
while i:
m = self.act_re.match(i)
if m:
return (m.group(1), m.group(2))
m = self.tpl_name_re.match(i)
if m:
break
i = self.file.readline()
self.open = False
raise StopIteration
def process(self):
'''Processes the header of a Pan file, performing any
registered actions'''
self.body = []
for action, args in self:
try:
f = self.actions[action]
v = f(args)
if type(v) is str:
self.body.append(v)
else:
self.body.extend(v)
except KeyError, e:
pass
def write_file(self):
'''Writes to the file, if it's needed.
If the old contents and the new ones are the same, the old
file is kept, to avoid useless recompilations. Also, if the
new body is empty, which most likely means the documentation
strings were not meant to be consumed by us, the file is kept.
Otherwise, it assumes all contents should be generated by this
processor, and destroys any previous content.'''
if not self.body:
return False
pos = self.file.tell()
new = '\n'.join(self.body)
old = ''.join(self.file)
if new == old:
return False
self.file.seek(pos, 0)
self.file.truncate()
self.file.write(new)
self.file.close()
return True
def wrap_in_variable(name):
'''Decorator function, for wrapping the return value of a function
into a Pan variable'''
rx = re.compile('\W+')
variable = rx.sub('_', name).upper()
def wrap(f):
def code_to_pan_variable(*args, **kwargs):
st = 'variable ' + variable + ' ?= '
rt = f(*args, **kwargs)
if rt.__class__ is list:
st +='list(\n' + ',\n'.join([" '%s'" % (str(x)) for x in rt])
st += ');\n'
elif rt.__class__ is dict:
st += 'nlist(\n'
st += ',\n'.join([" '%s', '%s'" % (k, str(v)) for k, v in rt.iteritems()])
st += ');\n'
else:
st += "'%s'" % rt
st += ';\n'
return st
return code_to_pan_variable
return wrap