File: parser.py

package info (click to toggle)
galileo 0.5.1-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 392 kB
  • ctags: 578
  • sloc: python: 3,462; xml: 23; makefile: 14
file content (120 lines) | stat: -rw-r--r-- 2,943 bytes parent folder | download | duplicates (2)
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
"""\
This is a custom implementation of the yaml parser in order to prevent an
extra dependency in the PyYAML module. This implementation will be used when
the PyYAML module will not be found.

The configurability of galileo should not be based on the possibility of this
parser. This parser should be adapted to allow the correct configuration.

Known limitations:
- Only spaces, no tabs
- Blank lines in the middle of an indented block is pretty bad ...
"""

from __future__ import print_function  # for the __main__ block

import json
import textwrap

def _stripcomment(line):
    s = []
    for c in line:
        if c == '#':
            break
        s.append(c)
    # And we strip the trailing spaces
    return ''.join(s).rstrip()


def _getident(line):
    i = 0
    for c in line:
        if c != ' ':
            break
        i += 1
    return i


def _addKey(d, key):
    if d is None and key:
        d = {}
    d[key] = None
    return d


def unJSONize(s):
    """ json is not good enough ...
    "'a'" doesn't get decoded,
    even worst, "a" neither """
    try:
        return json.loads(s)
    except ValueError:
        s = s.strip()
        if s[0] == "'" and s[-1] == "'":
            return s[1:-1]
        return s


def _dedent(lines, start):
    res = [lines[start]]
    idx = start + 1
    minident = _getident(lines[start])
    while idx < len(lines):
        curident = _getident(lines[idx])
        if curident < minident:
            break
        res.append(lines[idx])
        idx += 1
    return res


def loads(s):
    res = None
    current_key = None
    lines = s.split('\n')
    i = 0
    while i < len(lines):
        line = _stripcomment(lines[i])
        i += 1
        if not line: continue
        if _getident(line) == 0:
            if line.startswith('-'):
                if res is None:
                    res = []
                line = line[1:].strip()
                if line:
                    res.append(loads(line))
                elif i == len(lines):
                    res.append(None)
            elif ':' in line:
                current_key = None
                k, v = line.split(':')
                res = _addKey(res, k)
                if not v:
                    current_key = k
                else:
                    res[k] = unJSONize(v)
            else:
                return unJSONize(line)
        else:
            subblock = _dedent(lines, i-1)
            subres = loads(textwrap.dedent('\n'.join(subblock)))
            if isinstance(res, dict):
                res[current_key] = subres
            elif isinstance(res, list):
                res.append(subres)
            else:
                raise ValueError(res, subres)
            i += len(subblock) - 1

    return res


def load(f):
    return loads(f.read())

if __name__ == "__main__":
    import sys
    # For fun and quick test
    with open(sys.argv[1], 'rt') as f:
        print(load(f))