1
2
3 u"""
4 Основные функции для работы с файлами конфигурации.
5
6 Файлы конфигурации представляют собой XML-файлы определенной структуры. Часто,
7 разные файлы конфигурации содержат одинаковые блоки. Этот модуль содержит
8 функции, для разбора частоиспользуемых блоков конфигурации.
9
10 Используемые модули:
11 - lxml - библиотека для разбора XML (установка: easy_install lxml);
12
13 К основным параметрам, которые управляют процессом импорта-экспорта относятся:
14 - Параметры времени. При импорте-экспорте следует учитывать из какого
15 источника (L{stocks3.core.source}) пришли данные о котировках и
16 корретировать время в зависимости от временной зоны источника. При этом
17 некоторые источники вообще не отсылают время (только дату), необходимо
18 обрабатывать такие случае и брать, например, время закрытия биржи или
19 текущее время.
20
21 - Параметры точности. Как при экспорте так и при импорте необходимо
22 управлять точностью значений. Увеличить точность мы не можем (упираемся в
23 точность источника), а вот уменьшить - запросто.
24
25 Всю конфигурацию можно распределить по этапам процесса обработки данных котировок:
26 - Конфигурация транспорта.
27 - Конфигурация импорта.
28 - Конфигурация экспорта.
29
30 Сейчас о конфигурации можно сказать только то, что на хранится в виде XML.
31 Каждый конкретный модуль должен сам знать, как прочитать свою конфигурацию.
32 """
33
34 __author__ = "Zasimov Alexey"
35 __email__ = "zasimov-a@yandex-team.ru"
36
37
38
39 try:
40 from lxml import etree
41
42 except ImportError:
43 try:
44
45 import xml.etree.cElementTree as etree
46
47 except ImportError:
48 try:
49
50 import xml.etree.ElementTree as etree
51
52 except ImportError:
53 try:
54
55 import cElementTree as etree
56
57 except ImportError:
58 try:
59
60 import elementtree.ElementTree as etree
61
62 except ImportError:
63 import sys
64 sys.stderr.write("Failed to import ElementTree from any known place\n")
65 raise
69 u"""
70 Разбирает входной XML-файл. Эта функция нужна лишь для того, чтобы импорт и
71 настройка парсера XML лежала в одном модуле.
72 """
73 return etree.parse(fobj)
74
77 u"""
78 Конвертируем строчку в bool-значение.
79
80 @type boolString: строка
81 @param boolString: Строка, описывающее булево значение.
82 - Истинными значениями считаются: 1, true, yes, y.
83 - Ложными значениями считаются: 0, false, no, n.
84
85 Регистр неважен.
86 @exception ValueError: Генерируется, если boolString содержит что-то
87 непотребное.
88 """
89 if not boolString:
90 return False
91
92 s = boolString.lower()
93 if s in ["true", "1", "yes", "y"]:
94 return True
95 elif s in ["false", "0", "no", "n"]:
96 return False
97 else:
98 raise ValueError("Invalid boolean value: %s" % boolString)
99
102
105 u"""
106 Оборачиваются функции, которые могут сгенерировать ValueError. Этот
107 декоратор преобразует исключение ValueError в исключение
108 ConfigurationError.
109 """
110 def new_func(self, path, attrib=None, default=None):
111 try:
112 return func(self, path, attrib, default)
113 except ValueError, e:
114 if attrib:
115 message = "Value error, node %s.%s: %s" % (path, attrib, e)
116 else:
117 message = "Value error, node %s: %s" % (path, e)
118 raise ConfigurationError(message)
119 new_func.func_name = func.func_name
120 return new_func
121
124 u"""
125 Все класс, порожденные от этого класса, тем или иным образом создаются на
126 основе конфигурации, хранящейся в XML-файле.
127
128 После инициализации объект этого класса получает в распоряжении дерево
129 XML-файла - L{Configurable.tree}.
130 """
132 u"""
133 @param tree: XML-дерево.
134 @param node: XML-узел с конфигурацией для данного объекта.
135 """
136 self.tree = tree
137 self.node = node
138 self.config = self.makeConfig()
139
141 u"""
142 Должна быть переопределена в дочерних классах. Собственна эта функция и
143 загружает конфигурацию из переданной нам ветки self.node.
144 """
145 return self
146
148 u"""
149 Создает объекты, конфигурация которых прописана в ветке path.
150
151 Например:
152 - C{source.createObjects(factories.transports,"../transports/transport")}
153
154 @type factory: L{ConfigurableFactory}
155 @param factory: Фабрика объектов.
156 @param path: Путь до узлов с конфигурацией.
157 """
158 nodes = self._get_nodes_by_path(path)
159 return _mapActive(factory, self.tree, nodes, *args)
160
162 u"""
163 Возвращает список узлов по пути path.
164 """
165 if not path:
166 return [self.node]
167 else:
168 return self.node.xpath(path)
169
171 u"""
172 Возвращает узел по его адресу.
173
174 @type path: xpath
175 @param path: Адрес узла.
176 @exception ConfigurationError: Найдено больше или меньше одного узла.
177 """
178 nodes = self._get_nodes_by_path(path)
179 if len(nodes) != 1:
180 raise ConfigurationError("Expected one %s node. Received: %s" % (path, len(nodes)))
181 return nodes[0]
182
183 - def readString(self, path, attrib=None, default=None):
184 u"""
185 Читает строку из файла конфигурации.
186
187 @type path: строка
188 @param path: Адрес узла XML-файла.
189 @type attrib: строка
190 @param attrib: Имя атрибута. Если имя атрибута не указано, то возвращается text.
191 @param default: Значение по умолчанию. Если искомый атрибут не найден и
192 указано значение по умолчанию, то возвращается оно.
193 Иначе генерируется исключение KeyError.
194 """
195 node = self._get_node_by_path(path)
196 return readAttribOrText(node, attrib, default)
197
198 @config_check_value
199 - def readInt(self, path, attrib=None, default=None):
202
203 @config_check_value
204 - def readFloat(self, path, attrib=None, default=None):
207
208 @config_check_value
209 - def readBool(self, path, attrib=None, default=None):
216
219
222 u"""
223 Фабрика для создания конфигурируемых объектов.
224
225 Для создания кофигурируемых объектов (L{Configurable}) достаточно иметь
226 ссылку на узел XML-файла с конфигурацией.
227 """
230
231
233 u"""
234 Регистрируем класс cls в фабрике под именем name.
235
236 @param name: Имя класса в фабрике.
237 @param cls: Регистрируемый класс.
238 """
239 self._classes[name] = cls
240
241 - def create(self, name, tree, configNode, *args):
242 u"""
243 Создает объект класса name.
244
245 @param name: Имя создаваемого класса.
246 @param configNode: узел XML-файла с конфигурацей создаваемого объекта.
247 """
248 try:
249 cls = self._classes[name]
250 try:
251 return cls(tree, configNode, *args)
252 except Exception, e:
253 raise ConfigurableFactoryError("Construction error for class %s: %s" % (name, e))
254 except KeyError, e:
255 raise ConfigurableFactoryError("Unknown class: %s" % name)
256
257 - def print_(self, factory_name):
258 def format_len(s, l=50):
259 if len(s) < l:
260 s += " "*(l-len(s))
261 return s
262 for name, cls in sorted(self._classes.iteritems()):
263 print "%s %s %s" % (format_len(factory_name, 12),
264 format_len(name),
265 cls.__name__)
266
269 u"""
270 Отображает узлы конфигурации nodes на объекты. Для создания объектов
271 используется фабрика factory. В результате каждому узла из nodes будет
272 сопоставлен объект.
273
274 Узлы описываются в виде тегов:
275
276 <name class="<class_name>" active="True|False" priority="<digit>"/>
277
278 @type factory: L{ConfigurableFactory}
279 @param factory: Фабрика для создания объектов.
280 @param nodes: Узлы файла конфигурации.
281 """
282 objects = []
283 for node in nodes:
284 active = str_to_bool(node.attrib.get("active", "true"))
285 if active:
286 className = node.attrib["class"]
287 priority = int(node.attrib.get("priority", 0))
288 obj = factory.create(className, tree, node, *args)
289 objects.append((priority, obj))
290
291 return map(lambda x: x[1], sorted(objects, key=lambda x: x[0]))
292
294 u"""
295 Используется из L{readAttribOrText}.
296 """
297 if not default is None:
298 return default
299 else:
300 if attrib:
301 message = "Attribute %s.%s not found." % (path, attrib)
302 else:
303 message = "Node %s not found." % path
304 raise ConfigurationError(message)
305
306
307 -def readAttribOrText(node, attrib, default, path=""):
308 u"""
309 Читает или атрибут attrib или текст узла с именем attrib.
310 """
311 if attrib:
312 try:
313 return node.attrib[attrib]
314 except KeyError, e:
315
316 textNode = node.find(attrib)
317 if not textNode is None:
318 return textNode.text
319 else:
320 return _check_default(path, attrib, default)
321 else:
322 return node.text
323