eric6/Globals/E5ConfigParser.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2016 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a ConfigParser wrapper for Python 2 to provide the
8 dictionary like interface of the Python 3 variant.
9 """
10
11 from __future__ import unicode_literals
12
13 try:
14 from configparser import ConfigParser as E5ConfigParser
15 except ImportError:
16 # Py2 part with the compatibility wrapper class
17 try:
18 from collections import OrderedDict as _default_dict
19 # __IGNORE_WARNING_N813__
20 except ImportError:
21 # fallback for setup.py which hasn't yet built _collections
22 _default_dict = dict
23
24 import re
25 import itertools
26 from ConfigParser import SafeConfigParser, DEFAULTSECT
27
28 class E5ConfigParser(SafeConfigParser):
29 """
30 Class implementing a wrapper of the ConfigParser class implementing
31 dictionary like special methods and some enhancements from Python 3.
32 """
33 _OPT_TMPL = r"""
34 (?P<option>.*?) # very permissive!
35 \s*(?P<vi>{delim})\s* # any number of space/tab,
36 # followed by any of the
37 # allowed delimiters,
38 # followed by any space/tab
39 (?P<value>.*)$ # everything up to eol
40 """
41 _OPT_NV_TMPL = r"""
42 (?P<option>.*?) # very permissive!
43 \s*(?: # any number of space/tab,
44 (?P<vi>{delim})\s* # optionally followed by
45 # any of the allowed
46 # delimiters, followed by any
47 # space/tab
48 (?P<value>.*))?$ # everything up to eol
49 """
50 # Compiled regular expression for matching options with typical
51 # separators
52 OPTCRE = re.compile(_OPT_TMPL.format(delim="=|:"), re.VERBOSE)
53 # Compiled regular expression for matching options with optional
54 # values delimited using typical separators
55 OPTCRE_NV = re.compile(_OPT_NV_TMPL.format(delim="=|:"), re.VERBOSE)
56
57 def __init__(self, defaults=None, dict_type=_default_dict,
58 allow_no_value=False, delimiters=('=', ':')):
59 """
60 Constructor
61 """
62 SafeConfigParser.__init__(
63 self,
64 defaults=defaults, dict_type=dict_type,
65 allow_no_value=allow_no_value)
66
67 if delimiters == ('=', ':'):
68 self._optcre = \
69 self.OPTCRE_NV if allow_no_value else self.OPTCRE
70 else:
71 d = "|".join(re.escape(d) for d in delimiters)
72 if allow_no_value:
73 self._optcre = re.compile(
74 self._OPT_NV_TMPL.format(delim=d), re.VERBOSE)
75 else:
76 self._optcre = re.compile(
77 self._OPT_TMPL.format(delim=d), re.VERBOSE)
78
79 def __getitem__(self, key):
80 """
81 Special method to get a section.
82
83 @param key name of the section
84 @type str
85 @return section for the given key
86 @rtype dict
87 @exception KeyError raised if a non-existent key is given
88 """
89 if key == DEFAULTSECT:
90 return self._defaults
91 elif self.has_section(key):
92 return self._sections[key]
93 else:
94 raise KeyError(key)
95
96 def __setitem__(self, key, values):
97 """
98 Special method to set the values of a section.
99
100 @param key name of the section
101 @type str
102 @param values value for the section
103 @type dict
104 """
105 # To conform with the mapping protocol, overwrites existing values
106 # in the section.
107 if key == DEFAULTSECT:
108 self._defaults.clear()
109 elif self.has_section(key):
110 self._sections[key].clear()
111 else:
112 self.add_section(key)
113 for subkey, value in values.items():
114 subkey = self.optionxform(str(subkey))
115 if value is not None:
116 value = str(value)
117 self.set(key, subkey, value)
118
119 def __delitem__(self, key):
120 """
121 Special method to delete a section.
122
123 @param key name of the section
124 @type str
125 @exception ValueError raised to indicate non-removal of the
126 default section
127 @exception KeyError raised to indicate a non-existent section
128 """
129 if key == DEFAULTSECT:
130 raise ValueError("Cannot remove the default section.")
131 if not self.has_section(key):
132 raise KeyError(key)
133 self.remove_section(key)
134
135 def __contains__(self, key):
136 """
137 Special method to test, if a section is contained in the config.
138
139 @param key name of the section
140 @type str
141 @return flag indicating containment
142 @rtype bool
143 """
144 return key == DEFAULTSECT or self.has_section(key)
145
146 def __len__(self):
147 """
148 Special method get the number of sections of the config.
149
150 @return number of sections
151 @rtype int
152 """
153 return len(self._sections) + 1 # the default section
154
155 def __iter__(self):
156 """
157 Special method to return an iterator of the section names starting
158 with the default section.
159
160 @return iterator of the section names contained in the config
161 @rtype iterator of str
162 """
163 return itertools.chain((DEFAULTSECT,), self._sections.keys())
164
165
166 if __name__ == "__main__":
167 # This is some test code.
168 import sys
169
170 c = E5ConfigParser()
171 c["DEFAULT"] = {'ServerAliveInterval': '45',
172 'Compression': 'yes',
173 'CompressionLevel': '9'}
174 c['bitbucket.org'] = {}
175 c['bitbucket.org']['User'] = 'hg'
176 c['topsecret.server.com'] = {}
177 topsecret = c['topsecret.server.com']
178 topsecret['Port'] = '50022'
179 topsecret['ForwardX11'] = 'no'
180 c['DEFAULT']['ForwardX11'] = 'yes'
181
182 c.write(sys.stdout)

eric ide

mercurial