1
2 r"""
3 ==========================
4 Schema config management
5 ==========================
6
7 Schema config management.
8
9 :Copyright:
10
11 Copyright 2010 - 2016
12 Andr\xe9 Malo or his licensors, as applicable
13
14 :License:
15
16 Licensed under the Apache License, Version 2.0 (the "License");
17 you may not use this file except in compliance with the License.
18 You may obtain a copy of the License at
19
20 http://www.apache.org/licenses/LICENSE-2.0
21
22 Unless required by applicable law or agreed to in writing, software
23 distributed under the License is distributed on an "AS IS" BASIS,
24 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 See the License for the specific language governing permissions and
26 limitations under the License.
27
28 """
29 if __doc__:
30
31 __doc__ = __doc__.encode('ascii').decode('unicode_escape')
32 __author__ = r"Andr\xe9 Malo".encode('ascii').decode('unicode_escape')
33 __docformat__ = "restructuredtext en"
34
35 import errno as _errno
36
37 if 1:
38
39 try:
40 import ConfigParser as _config_parser
41 except ImportError:
42 import configparser as _config_parser
43
44 try:
45 from cStringIO import StringIO as _TextIO
46 except ImportError:
47 from io import StringIO as _TextIO
48
49 from . import _template
53 """
54 Schema config container
55
56 :IVariables:
57 `tables` : ``list``
58 Table list
59
60 `_lines` : sequence
61 Original config lines (or ``None``)
62 """
63
64
65
66
67 _CONFIG_TPL = _template.Template('''
68 # This is a comment. I love comments.
69 #
70 # This files contains table names, one per line
71 # Comments and empty lines are ignored
72 #
73 # If the table name contains a dot, the first part is treated as
74 # schema name.
75 #
76 # If the table variable should be treated differently, use:
77 #
78 # name = table
79 #
80 # The basename of this file (modulo .schema extension) is used as
81 # basename for the python file.
82 ''')
83
84 - def __init__(self, tables, schemas, lines=None):
85 """
86 Initialization
87
88 :Parameters:
89 `tables` : ``list``
90 Table list
91
92 `schemas` : ``dict``
93 (Alien) Schema mapping
94
95 `lines` : sequence
96 Original config lines. If omitted or ``None``, the config lines
97 are not available.
98 """
99 self.tables = tables
100 self.schemas = schemas
101 self._lines = lines
102
103 @classmethod
105 """
106 Construct from config file
107
108 :Parameters:
109 `name_or_file` : ``str`` or ``file``
110 Config filename or file pointer
111
112 :Return: New Config instance
113 :Rtype: `Config`
114
115 :Exceptions:
116 - `IOError` : Error reading the file (except for ENOENT, which
117 treats the file as empty)
118 """
119 if name_or_file is None:
120 lines = []
121 else:
122 read = getattr(name_or_file, 'read', None)
123 if read is None:
124 try:
125 fp = open(name_or_file)
126 except IOError as e:
127 if e.errno != _errno.ENOENT:
128 raise
129 lines = []
130 else:
131 try:
132 lines = fp.read().splitlines(True)
133 finally:
134 fp.close()
135 else:
136 lines = name_or_file.read().splitlines(True)
137 return cls.from_lines(lines)
138
139 @classmethod
141 """
142 Create from config lines
143
144 :Parameters:
145 `lines` : sequence
146 List of config lines
147
148 :Return: New Config instance
149 :Rtype: `Config`
150 """
151 conf_lines = ['[schemas]', '[tables]']
152 for line in lines:
153 line = line.rstrip()
154 if not line or line.lstrip().startswith('#'):
155 continue
156 if '=' in line or ('[' in line and ']' in line):
157 conf_lines.append(line)
158 else:
159 name = line
160 if '.' in name:
161 name = name.rsplit('.', 1)[1]
162 conf_lines.append('%s = %s' % (name, line))
163 if bytes is str:
164 parser = _config_parser.RawConfigParser()
165 parser.optionxform = lambda x: x
166 parser.readfp(_TextIO('\n'.join(conf_lines)))
167 else:
168 parser = _config_parser.RawConfigParser(strict=False)
169 parser.optionxform = lambda x: x
170
171 parser.read_file(_TextIO('\n'.join(conf_lines)))
172 return cls.from_parser(parser, lines=lines)
173
174 @classmethod
176 """
177 Construct from config parser
178
179 :Parameters:
180 `parser` : ``ConfigParser.RawConfigParser``
181 Configparser instance
182
183 `lines` : sequence
184 Original config lines
185
186 :Return: New Config instance
187 :Rtype: `Config`
188 """
189 tables = [(name, val) for name, val in parser.items('tables')]
190 schemas = dict((name, val) for name, val in parser.items('schemas'))
191 return cls(tables, schemas, lines=lines)
192
193 - def dump(self, fp):
194 """
195 Dump config to a file
196
197 :Parameters:
198 `fp` : ``file``
199 Stream to dump to
200 """
201 lines = self._lines
202 if not lines:
203 result = self._CONFIG_TPL.expand().splitlines(False)
204 if lines is None:
205 tables = ['%s = %s' % table for table in self.tables]
206 if tables:
207 result.append('')
208 result.extend(tables)
209 schemas = ['%s = %s' % (key, value)
210 for key, value in self.schemas.items()]
211 if schemas:
212 result.append('')
213 result.append('[schemas]')
214 result.extend(schemas)
215 else:
216 result = lines
217
218 content = '\n'.join([line.rstrip() for line in result]) + '\n'
219 try:
220 fp.write('')
221 except TypeError:
222 content = content.encode('utf-8')
223 fp.write(content)
224