Failed Conditions
Pull Request — master (#2076)
by Abdeali
02:11
created

LineParser.__extract_keys_and_value()   A

Complexity

Conditions 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 12
rs 9.4285
1
from coalib.misc.StringConverter import StringConverter
2
from coalib.parsing.StringProcessing import unescape, convert_to_raw
3
4
5
class LineParser:
6
7
    def __init__(self,
8
                 key_value_delimiters=('=',),
9
                 comment_seperators=('#',),
10
                 key_delimiters=(',', ' '),
11
                 section_name_surroundings=None,
12
                 section_override_delimiters=(".",)):
13
        """
14
        Creates a new line parser. Please note that no delimiter or seperator
15
        may be an "o" or you may encounter undefined behaviour with the
16
        escapes.
17
18
        :param key_value_delimiters:        Delimiters that delimit a key from
19
                                            a value
20
        :param comment_seperators:          Used to initiate a comment
21
        :param key_delimiters:              Delimiters between several keys
22
        :param section_name_surroundings:   Dictionary, e.g. {"[", "]"} means a
23
                                            section name is surrounded by [].
24
                                            If None, {"[": "]"} is used as
25
                                            default.
26
        :param section_override_delimiters: Delimiter for a section override.
27
                                            E.g. "." would mean that
28
                                            section.key is a possible key that
29
                                            puts the key into the section
30
                                            "section" despite of the current
31
                                            section.
32
        """
33
        section_name_surroundings = section_name_surroundings or {"[": "]"}
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable section_name_surroundings does not seem to be defined.
Loading history...
34
35
        self.key_value_delimiters = key_value_delimiters
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable key_value_delimiters does not seem to be defined.
Loading history...
36
        self.comment_seperators = comment_seperators
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable comment_seperators does not seem to be defined.
Loading history...
37
        self.key_delimiters = key_delimiters
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable key_delimiters does not seem to be defined.
Loading history...
38
        self.section_name_surroundings = section_name_surroundings
39
        self.section_override_delimiters = section_override_delimiters
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable section_override_delimiters does not seem to be defined.
Loading history...
40
41
    def parse(self, line):
42
        """
43
        Note that every value in the returned touple *besides the value* is
44
        unescaped. This is so since the value is meant to be put into a Setting
45
        later thus the escapes may be needed there.
46
47
        :param line: the line to parse
48
        :return:     section_name (empty string if it's no section name),
49
                     [(section_override, key), ...], value, comment
50
        """
51
        line, comment = self.__seperate_by_first_occurrence(
52
            line,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable line does not seem to be defined.
Loading history...
53
            self.comment_seperators)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable self does not seem to be defined.
Loading history...
54
        comment = unescape(comment)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable comment does not seem to be defined.
Loading history...
55
        if line == "":
56
            return '', [], '', comment
57
58
        section_name = unescape(self.__get_section_name(line))
59
        if section_name != '':
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable section_name does not seem to be defined.
Loading history...
60
            return section_name, [], '', comment
61
62
        # Escapes in value might be needed by the bears
63
        keys, value = self.__extract_keys_and_value(line)
64
65
        # Add all the delimiters that stored as tuples
66
        all_delimiters = self.key_value_delimiters
67
        all_delimiters += self.key_delimiters
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable all_delimiters does not seem to be defined.
Loading history...
68
        all_delimiters += self.comment_seperators
69
        all_delimiters += self.section_override_delimiters
70
        all_delimiters = "".join(all_delimiters)
71
72
        # Add all keys and values in section_name_surroundings, which is
73
        # stored as a dict
74
        all_delimiters += "".join(self.section_name_surroundings.keys())
75
        all_delimiters += "".join(self.section_name_surroundings.values())
76
77
        value = convert_to_raw(value, all_delimiters)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable value does not seem to be defined.
Loading history...
78
79
        key_touples = []
80
        for key in keys:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable keys does not seem to be defined.
Loading history...
81
            key = convert_to_raw(key, all_delimiters)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable key does not seem to be defined.
Loading history...
82
            section, key = self.__seperate_by_first_occurrence(
83
                key,
84
                self.section_override_delimiters,
85
                True,
86
                True)
87
            key_touples.append((unescape(section), unescape(key)))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable section does not seem to be defined.
Loading history...
88
89
        return '', key_touples, value, comment
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable key_touples does not seem to be defined.
Loading history...
90
91
    @staticmethod
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable staticmethod does not seem to be defined.
Loading history...
92
    def __seperate_by_first_occurrence(string,
93
                                       delimiters,
94
                                       strip_delim=False,
95
                                       return_second_part_nonempty=False):
96
        """
97
        Seperates a string by the first of all given delimiters. Any whitespace
98
        characters will be stripped away from the parts.
99
100
        :param string:                      The string to seperate.
101
        :param delimiters:                  The delimiters.
102
        :param strip_delim:                 Strips the delimiter from the
103
                                            result if true.
104
        :param return_second_part_nonempty: If no delimiter is found and this
105
                                            is true the contents of the string
106
                                            will be returned in the second part
107
                                            of the touple instead of the first
108
                                            one.
109
        :return:                            (first_part, second_part)
110
        """
111
        temp_string = string.replace("\\\\", "oo")
112
        i = temp_string.find("\\")
113
        while i != -1:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable i does not seem to be defined.
Loading history...
114
            temp_string = temp_string[:i] + "oo" + temp_string[i+2:]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable temp_string does not seem to be defined.
Loading history...
115
            i = temp_string.find("\\", i+2)
116
117
        delim_pos = len(string)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable string does not seem to be defined.
Loading history...
118
        used_delim = ""
119
        for delim in delimiters:
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable delimiters does not seem to be defined.
Loading history...
120
            pos = temp_string.find(delim)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable delim does not seem to be defined.
Loading history...
121
            if 0 <= pos < delim_pos:
122
                delim_pos = pos
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable pos does not seem to be defined.
Loading history...
123
                used_delim = delim
124
125
        if return_second_part_nonempty and delim_pos == len(string):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable return_second_part_nonempty does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable delim_pos does not seem to be defined.
Loading history...
126
            return "", string.strip(" \n")
127
128
        return (
129
            string[:delim_pos].strip(" \n"),
130
            string[delim_pos + (len(used_delim) if strip_delim else 0):].strip(
131
                " \n"))
132
133
    def __get_section_name(self, line):
134
        for begin, end in self.section_name_surroundings.items():
135
            if (line[0:len(begin)] == begin and
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable begin does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable line does not seem to be defined.
Loading history...
136
                    line[len(line) - len(end):len(line)] == end):
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable end does not seem to be defined.
Loading history...
137
                return line[len(begin):len(line) - len(end)].strip(" \n")
138
139
        return ''
140
141
    def __extract_keys_and_value(self, line):
142
        key_part, value = self.__seperate_by_first_occurrence(
143
            line,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable line does not seem to be defined.
Loading history...
144
            self.key_value_delimiters,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable self does not seem to be defined.
Loading history...
145
            True,
146
            True)
147
        keys = list(StringConverter(
148
            key_part,
149
            list_delimiters=self.key_delimiters).__iter__(
150
            remove_backslashes=False))
151
152
        return keys, value
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable keys does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable value does not seem to be defined.
Loading history...
153