Package stocks3 :: Package core :: Module config
[hide private]
[frames] | no frames]

Source Code for Module stocks3.core.config

  1  # -*- coding: utf-8 -*- 
  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  # Загрузка lxml - http://lxml.de/tutorial.html 
 39  try: 
 40    from lxml import etree 
 41    #print("running with lxml.etree") 
 42  except ImportError: 
 43    try: 
 44      # Python 2.5 
 45      import xml.etree.cElementTree as etree 
 46      #print("running with cElementTree on Python 2.5+") 
 47    except ImportError: 
 48      try: 
 49        # Python 2.5 
 50        import xml.etree.ElementTree as etree 
 51        #print("running with ElementTree on Python 2.5+") 
 52      except ImportError: 
 53        try: 
 54          # normal cElementTree install 
 55          import cElementTree as etree 
 56          #print("running with cElementTree") 
 57        except ImportError: 
 58          try: 
 59            # normal ElementTree install 
 60            import elementtree.ElementTree as etree 
 61            #print("running with ElementTree") 
 62          except ImportError: 
 63            import sys 
 64            sys.stderr.write("Failed to import ElementTree from any known place\n") 
 65            raise 
66 67 68 -def parseXML(fobj):
69 u""" 70 Разбирает входной XML-файл. Эта функция нужна лишь для того, чтобы импорт и 71 настройка парсера XML лежала в одном модуле. 72 """ 73 return etree.parse(fobj)
74
75 76 -def str_to_bool(boolString):
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
100 101 -class ConfigurationError(Exception): pass
102
103 104 -def config_check_value(func):
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
122 123 -class Configurable:
124 u""" 125 Все класс, порожденные от этого класса, тем или иным образом создаются на 126 основе конфигурации, хранящейся в XML-файле. 127 128 После инициализации объект этого класса получает в распоряжении дерево 129 XML-файла - L{Configurable.tree}. 130 """
131 - def __init__(self, tree, node):
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
140 - def makeConfig(self):
141 u""" 142 Должна быть переопределена в дочерних классах. Собственна эта функция и 143 загружает конфигурацию из переданной нам ветки self.node. 144 """ 145 return self
146
147 - def createObjects(self, factory, path, *args):
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
161 - def _get_nodes_by_path(self, path):
162 u""" 163 Возвращает список узлов по пути path. 164 """ 165 if not path: 166 return [self.node] 167 else: 168 return self.node.xpath(path)
169
170 - def _get_node_by_path(self, path):
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):
200 assert default is None or type(default) == int 201 return int(self.readString(path, attrib, default))
202 203 @config_check_value
204 - def readFloat(self, path, attrib=None, default=None):
205 assert default is None or type(default) == float 206 return float(self.readString(path, attrib, default))
207 208 @config_check_value
209 - def readBool(self, path, attrib=None, default=None):
210 assert default is None or type(default) == bool 211 r = self.readString(path, attrib, default) 212 if type(r) == bool: 213 return r 214 else: 215 return str_to_bool(r)
216
217 218 -class ConfigurableFactoryError(Exception): pass
219
220 221 -class ConfigurableFactory:
222 u""" 223 Фабрика для создания конфигурируемых объектов. 224 225 Для создания кофигурируемых объектов (L{Configurable}) достаточно иметь 226 ссылку на узел XML-файла с конфигурацией. 227 """
228 - def __init__(self):
229 self._classes = {} # словарь с классами, объекты которых может
230 # создавать фабрика 231
232 - def register(self, name, cls):
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
267 268 -def _mapActive(factory, tree, nodes, *args):
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
293 -def _check_default(path, attrib, default):
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 # FIXME: убрать параметр path отсюда 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 # Пробуем отыскать text 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