Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

""" brain-dead simple parser for ini-style files. 

(C) Ronny Pfannschmidt, Holger Krekel -- MIT licensed 

""" 

__all__ = ['IniConfig', 'ParseError'] 

 

COMMENTCHARS = "#;" 

 

 

class ParseError(Exception): 

def __init__(self, path, lineno, msg): 

Exception.__init__(self, path, lineno, msg) 

self.path = path 

self.lineno = lineno 

self.msg = msg 

 

def __str__(self): 

return "%s:%s: %s" % (self.path, self.lineno+1, self.msg) 

 

 

class SectionWrapper(object): 

def __init__(self, config, name): 

self.config = config 

self.name = name 

 

def lineof(self, name): 

return self.config.lineof(self.name, name) 

 

def get(self, key, default=None, convert=str): 

return self.config.get(self.name, key, 

convert=convert, default=default) 

 

def __getitem__(self, key): 

return self.config.sections[self.name][key] 

 

def __iter__(self): 

section = self.config.sections.get(self.name, []) 

 

def lineof(key): 

return self.config.lineof(self.name, key) 

for name in sorted(section, key=lineof): 

yield name 

 

def items(self): 

for name in self: 

yield name, self[name] 

 

 

class IniConfig(object): 

def __init__(self, path, data=None): 

self.path = str(path) # convenience 

if data is None: 

f = open(self.path) 

try: 

tokens = self._parse(iter(f)) 

finally: 

f.close() 

else: 

tokens = self._parse(data.splitlines(True)) 

 

self._sources = {} 

self.sections = {} 

 

for lineno, section, name, value in tokens: 

if section is None: 

self._raise(lineno, 'no section header defined') 

self._sources[section, name] = lineno 

if name is None: 

if section in self.sections: 

self._raise(lineno, 'duplicate section %r' % (section, )) 

self.sections[section] = {} 

else: 

if name in self.sections[section]: 

self._raise(lineno, 'duplicate name %r' % (name, )) 

self.sections[section][name] = value 

 

def _raise(self, lineno, msg): 

raise ParseError(self.path, lineno, msg) 

 

def _parse(self, line_iter): 

result = [] 

section = None 

for lineno, line in enumerate(line_iter): 

name, data = self._parseline(line, lineno) 

# new value 

if name is not None and data is not None: 

result.append((lineno, section, name, data)) 

# new section 

elif name is not None and data is None: 

if not name: 

self._raise(lineno, 'empty section name') 

section = name 

result.append((lineno, section, None, None)) 

# continuation 

elif name is None and data is not None: 

if not result: 

self._raise(lineno, 'unexpected value continuation') 

last = result.pop() 

last_name, last_data = last[-2:] 

if last_name is None: 

self._raise(lineno, 'unexpected value continuation') 

 

if last_data: 

data = '%s\n%s' % (last_data, data) 

result.append(last[:-1] + (data,)) 

return result 

 

def _parseline(self, line, lineno): 

# blank lines 

if iscommentline(line): 

line = "" 

else: 

line = line.rstrip() 

if not line: 

return None, None 

# section 

if line[0] == '[': 

realline = line 

for c in COMMENTCHARS: 

line = line.split(c)[0].rstrip() 

if line[-1] == "]": 

return line[1:-1], None 

return None, realline.strip() 

# value 

elif not line[0].isspace(): 

try: 

name, value = line.split('=', 1) 

if ":" in name: 

raise ValueError() 

except ValueError: 

try: 

name, value = line.split(":", 1) 

except ValueError: 

self._raise(lineno, 'unexpected line: %r' % line) 

return name.strip(), value.strip() 

# continuation 

else: 

return None, line.strip() 

 

def lineof(self, section, name=None): 

lineno = self._sources.get((section, name)) 

if lineno is not None: 

return lineno + 1 

 

def get(self, section, name, default=None, convert=str): 

try: 

return convert(self.sections[section][name]) 

except KeyError: 

return default 

 

def __getitem__(self, name): 

if name not in self.sections: 

raise KeyError(name) 

return SectionWrapper(self, name) 

 

def __iter__(self): 

for name in sorted(self.sections, key=self.lineof): 

yield SectionWrapper(self, name) 

 

def __contains__(self, arg): 

return arg in self.sections 

 

 

def iscommentline(line): 

c = line.lstrip()[:1] 

return c in COMMENTCHARS