1
|
|
|
import re |
2
|
|
|
import validators |
3
|
|
|
from collections import Iterable, OrderedDict |
4
|
|
|
|
5
|
|
|
from coalib.misc import Constants |
6
|
|
|
from coalib.parsing.StringProcessing import ( |
7
|
|
|
unescape, unescaped_split, unescaped_strip) |
8
|
|
|
|
9
|
|
|
|
10
|
|
|
class StringConverter: |
11
|
|
|
""" |
12
|
|
|
Converts strings to other things as needed. If you need some kind of string |
13
|
|
|
conversion that is not implemented here, consider adding it so everyone |
14
|
|
|
gets something out of it. |
15
|
|
|
""" |
16
|
|
|
|
17
|
|
|
def __init__(self, |
18
|
|
|
value, |
19
|
|
|
strip_whitespaces=True, |
20
|
|
|
list_delimiters=None, |
21
|
|
|
dict_delimiter=":", |
22
|
|
|
remove_empty_iter_elements=True): |
23
|
|
|
if list_delimiters is None: |
|
|
|
|
24
|
|
|
list_delimiters = [",", ";"] |
25
|
|
|
|
26
|
|
|
if not isinstance(list_delimiters, Iterable): |
|
|
|
|
27
|
|
|
raise TypeError("list_delimiters has to be an Iterable.") |
28
|
|
|
if not isinstance(strip_whitespaces, bool): |
|
|
|
|
29
|
|
|
raise TypeError("strip_whitespaces has to be a bool parameter") |
30
|
|
|
|
31
|
|
|
self.__strip_whitespaces = strip_whitespaces |
32
|
|
|
self.__list_delimiters = list_delimiters |
33
|
|
|
self.__dict_delimiter = dict_delimiter |
|
|
|
|
34
|
|
|
self.__remove_empty_iter_elements = remove_empty_iter_elements |
|
|
|
|
35
|
|
|
|
36
|
|
|
self.__escaped_list = None |
37
|
|
|
self.__unescaped_list = None |
38
|
|
|
self.__dict = None |
39
|
|
|
self.value = value |
|
|
|
|
40
|
|
|
|
41
|
|
|
def __str__(self): |
42
|
|
|
return unescape(self.value) |
|
|
|
|
43
|
|
|
|
44
|
|
|
def __bool__(self): |
45
|
|
|
if str(self).lower() in Constants.TRUE_STRINGS: |
46
|
|
|
return True |
47
|
|
|
if str(self).lower() in Constants.FALSE_STRINGS: |
48
|
|
|
return False |
49
|
|
|
raise ValueError |
|
|
|
|
50
|
|
|
|
51
|
|
|
def __len__(self): |
52
|
|
|
return len(str(self)) |
|
|
|
|
53
|
|
|
|
54
|
|
|
def __int__(self): |
55
|
|
|
return int(str(self)) |
|
|
|
|
56
|
|
|
|
57
|
|
|
def __float__(self): |
58
|
|
|
return float(str(self)) |
|
|
|
|
59
|
|
|
|
60
|
|
|
def __url__(self): |
61
|
|
|
""" |
62
|
|
|
Determines the url validity of this setting. |
63
|
|
|
|
64
|
|
|
:return: url string |
65
|
|
|
:raises ValueError: If the url is not valid. |
66
|
|
|
""" |
67
|
|
|
strrep = str(self).strip() |
68
|
|
|
if validators.url(strrep): |
|
|
|
|
69
|
|
|
return strrep |
70
|
|
|
|
71
|
|
|
raise ValueError(repr(strrep) + " is not a valid url.") |
72
|
|
|
|
73
|
|
|
def __iter__(self, remove_backslashes=True): |
74
|
|
|
""" |
75
|
|
|
Converts the value to a list using the delimiters given at construction |
76
|
|
|
time. |
77
|
|
|
|
78
|
|
|
Note that escaped values will be unescaped and escaped list delimiters |
79
|
|
|
will be allowed in values. If you need the escapes you should not |
80
|
|
|
use this routine. |
81
|
|
|
|
82
|
|
|
:param remove_backslashes: Whether or not to remove the backslashes |
83
|
|
|
after conversion. |
84
|
|
|
:return: An iterator over all values. |
85
|
|
|
""" |
86
|
|
|
if remove_backslashes: |
|
|
|
|
87
|
|
|
return iter(self.__unescaped_list) |
|
|
|
|
88
|
|
|
else: |
89
|
|
|
return iter(self.__escaped_list) |
90
|
|
|
|
91
|
|
|
def __getitem__(self, item): |
92
|
|
|
return self.__dict.__getitem__(item) |
|
|
|
|
93
|
|
|
|
94
|
|
|
def keys(self): |
95
|
|
|
return self.__dict.keys() |
96
|
|
|
|
97
|
|
|
def __get_raw_list(self): |
98
|
|
|
pattern = ("(?:" + |
99
|
|
|
"|".join(re.escape(v) for v in self.__list_delimiters) + |
|
|
|
|
100
|
|
|
")") |
101
|
|
|
|
102
|
|
|
return list(unescaped_split(pattern, |
|
|
|
|
103
|
|
|
self.value, |
104
|
|
|
use_regex=True)) |
105
|
|
|
|
106
|
|
|
def __prepare_list(self): |
107
|
|
|
self.__escaped_list = self.__get_raw_list() |
108
|
|
|
|
109
|
|
|
if self.__strip_whitespaces: |
|
|
|
|
110
|
|
|
self.__escaped_list = [unescaped_strip(elem) |
|
|
|
|
111
|
|
|
for elem in self.__escaped_list] |
112
|
|
|
|
113
|
|
|
self.__unescaped_list = [unescape(elem) |
114
|
|
|
for elem in self.__escaped_list] |
115
|
|
|
|
116
|
|
|
if self.__remove_empty_iter_elements: |
117
|
|
|
# Need to do after stripping, cant use builtin functionality of |
118
|
|
|
# split. |
119
|
|
|
while "" in self.__unescaped_list: |
120
|
|
|
self.__unescaped_list.remove("") |
121
|
|
|
while "" in self.__escaped_list: |
122
|
|
|
self.__escaped_list.remove("") |
123
|
|
|
|
124
|
|
|
def __prepare_dict(self): |
125
|
|
|
# We must keep order here, user can drop it later. |
126
|
|
|
self.__dict = OrderedDict() |
127
|
|
|
for elem in self.__get_raw_list(): |
128
|
|
|
key_val = unescaped_split(self.__dict_delimiter, elem, max_split=1) |
|
|
|
|
129
|
|
|
|
130
|
|
|
if self.__strip_whitespaces: |
131
|
|
|
key_val = [unescaped_strip(item) for item in key_val] |
|
|
|
|
132
|
|
|
|
133
|
|
|
key_val = [unescape(item) for item in key_val] |
134
|
|
|
|
135
|
|
|
if not any(item != "" for item in key_val): |
136
|
|
|
continue |
137
|
|
|
|
138
|
|
|
if len(key_val) < 2: |
139
|
|
|
self.__dict[key_val[0]] = "" |
140
|
|
|
else: |
141
|
|
|
self.__dict[key_val[0]] = key_val[1] |
142
|
|
|
|
143
|
|
|
@property |
|
|
|
|
144
|
|
|
def value(self): |
145
|
|
|
return self.__value |
|
|
|
|
146
|
|
|
|
147
|
|
|
@value.setter |
|
|
|
|
148
|
|
|
def value(self, newval): |
149
|
|
|
self.__value = str(newval) |
|
|
|
|
150
|
|
|
if self.__strip_whitespaces: |
|
|
|
|
151
|
|
|
self.__value = unescaped_strip(self.__value) |
152
|
|
|
|
153
|
|
|
self.__prepare_list() |
154
|
|
|
self.__prepare_dict() |
155
|
|
|
|
156
|
|
|
def __eq__(self, other): |
157
|
|
|
return isinstance(other, StringConverter) and self.value == other.value |
|
|
|
|
158
|
|
|
|
159
|
|
|
def __ne__(self, other): |
160
|
|
|
return not self.__eq__(other) |
|
|
|
|
161
|
|
|
|