class XpathVariable(XmlObject): ROOT_NAME = 'variable' name = StringField('@name') locale_id = StringField('locale/@id') xpath = NodeField('xpath', CalculatedPropertyXpath) @property def value(self): return self.locale_id or self.xpath
class QueryPrompt(DisplayNode): ROOT_NAME = 'prompt' key = StringField('@key') appearance = StringField('@appearance', required=False) receive = StringField('@receive', required=False) input_ = StringField('@input', required=False) default_value = StringField('@default', required=False) itemset = NodeField('itemset', Itemset)
class Balance(LedgerXML): """https://github.com/dimagi/commcare-core/wiki/ledgerxml#balance-transactions """ ROOT_NAME = REPORT_TYPE_BALANCE ROOT_NS = COMMTRACK_REPORT_XMLNS entity_id = StringField('@entity-id', required=True) date = DateTimeField('@date', required=True) section_id = StringField('@section-id', required=False) entry = NodeField('entry', Entry, required=True)
class Lookup(OrderedXmlObject): ROOT_NAME = 'lookup' ORDER = ('auto_launch', 'extras', 'responses', 'field') name = StringField("@name") auto_launch = SimpleBooleanField("@auto_launch", "true", "false") action = StringField("@action", required=True) image = StringField("@image") extras = NodeListField('extra', Extra) responses = NodeListField('response', Response) field = NodeField('field', Field)
class Text(XmlObject): """ <text> <!----------- Exactly one. Will be present wherever text can be defined. Contains a sequential list of string elements to be concatenated to form the text body.--> <xpath function=""> <!------------ 0 or More. An xpath function whose result is a string. References a data model if used in a context where one exists. --> <variable name=""/> <!------------ 0 or More. Variable for the localized string. Variable elements can support any child elements that <body> can. --> </xpath> <locale id=""> <!------------ 0 or More. A localized string. id can be referenced here or as a child--> <id/> <!------------ At Most One. The id of the localized string (if not provided as an attribute --> <argument key=""/> <!------------ 0 or More. Arguments for the localized string. Key is optional. Arguments can support any child elements that <body> can. --> </locale> </text> """ ROOT_NAME = 'text' xpath = NodeField('xpath', Xpath) xpath_function = XPathField('xpath/@function') locale = NodeField('locale', Locale) locale_id = StringField('locale/@id')
class TextOrDisplay(XmlObject): text = NodeField('text', Text) display = NodeField('display', LocalizedMediaDisplay) def __init__(self, node=None, context=None, custom_icon_locale_id=None, custom_icon_form=None, custom_icon_xpath=None, menu_locale_id=None, image_locale_id=None, audio_locale_id=None, media_image=None, media_audio=None, for_action_menu=False, **kwargs): super(TextOrDisplay, self).__init__(node, context, **kwargs) text = None if menu_locale_id: text = Text(locale_id=menu_locale_id) media_text = [] if media_image: media_text.append(MediaText( locale=LocaleId(locale_id=image_locale_id), form_name='image', )) if media_audio: media_text.append(MediaText( locale=LocaleId(locale_id=audio_locale_id), form_name='audio' )) if (custom_icon_locale_id or custom_icon_xpath) and custom_icon_form: media_text.append(MediaText( locale=(LocaleId(locale_id=custom_icon_locale_id) if custom_icon_locale_id else None), xpath_function=(custom_icon_xpath if custom_icon_xpath else None), form_name=custom_icon_form )) if media_text: self.display = LocalizedMediaDisplay( media_text=[text] + media_text if text else media_text ) elif for_action_menu and text: self.display = LocalizedMediaDisplay( media_text=[text] ) elif text: self.text = text
class Transfer(LedgerXML): """https://github.com/dimagi/commcare-core/wiki/ledgerxml#transfer-transactions """ ROOT_NAME = REPORT_TYPE_TRANSFER ROOT_NS = COMMTRACK_REPORT_XMLNS src = StringField('@src', required=False) dest = StringField('@dest', required=False) date = DateTimeField('@date', required=True) type = StringField('@type', required=False) section_id = StringField('@section-id', required=False) entry = NodeField('entry', Entry, required=True)
class DisplayNode(XmlObject): """Any node that has the awkward text-or-display subnode, like Command or Menu""" text = NodeField('text', Text) display = NodeField('display', Display) def __init__(self, locale_id=None, media_image=None, media_audio=None, **kwargs): super(DisplayNode, self).__init__(**kwargs) if locale_id is None: text = None else: text = Text(locale_id=locale_id) if media_image or media_audio: self.display = Display(text=text, media_image=media_image, media_audio=media_audio) else: self.text = text
class OpenRosaResponse(XmlObject): ROOT_NAME = 'OpenRosaResponse' xmlns = StringField('@xmlns') message_nature = StringField('message/@nature') message = StringField('message') auth_keys = NodeField('auth_keys', AuthKeys) def __init__(self, *args, **kwargs): super(OpenRosaResponse, self).__init__(*args, **kwargs) self.xmlns = 'http://openrosa.org/http/response' self.message_nature = 'submit_success'
class Display(XmlObject): ROOT_NAME = 'display' text = NodeField('text', Text) media_image = StringField('media/@image') media_audio = StringField('media/@audio') def __init__(self, text=None, media_image=None, media_audio=None, **kwargs): super(Display, self).__init__(text=text, **kwargs) self.media_image = media_image self.media_audio = media_audio
class GraphTemplate(Template): # TODO: Is there a way to specify a default/static value for form? form = StringField('@form', choices=['graph']) graph = NodeField('graph', Graph) @classmethod def build(cls, form, graph, locale_config=None, locale_series_config=None, locale_annotation=None): return cls( form=form, graph=Graph( type=graph.graph_type, series=[ Series( nodeset=s.data_path, x_function=s.x_function, y_function=s.y_function, radius_function=s.radius_function, configuration=ConfigurationGroup(configs=([ # TODO: It might be worth wrapping # these values in quotes (as appropriate) # to prevent the user from having to # figure out why their unquoted colors # aren't working. ConfigurationItem(id=k, xpath_function=v) for k, v in s.config.items() ] + [ ConfigurationItem( id=k, locale_id=locale_series_config(index, k)) for k, v in sorted( s.locale_specific_config.items()) ]))) for index, s in enumerate(graph.series) ], configuration=ConfigurationGroup(configs=([ ConfigurationItem(id=k, xpath_function=v) for k, v in graph.config.items() ] + [ ConfigurationItem(id=k, locale_id=locale_config(k)) for k, v in graph.locale_specific_config.items() ])), annotations=[ Annotation(x=Text(xpath_function=a.x), y=Text(xpath_function=a.y), text=Text(locale_id=locale_annotation(i))) for i, a in enumerate(graph.annotations) ]))
class Series(OrderedXmlObject): ORDER = ( "configuration", "x_function", "y_function", "radius_function", ) ROOT_NAME = 'series' nodeset = StringField('@nodeset') configuration = NodeField('configuration', ConfigurationGroup) x_function = StringField('x/@function') y_function = StringField('y/@function') radius_function = StringField("radius/@function")
class QueryPrompt(DisplayNode): ROOT_NAME = 'prompt' key = StringField('@key') appearance = StringField('@appearance', required=False) receive = StringField('@receive', required=False) hidden = BooleanField('@hidden', required=False) input_ = StringField('@input', required=False) default_value = StringField('@default', required=False) allow_blank_value = BooleanField('@allow_blank_value', required=False) exclude = StringField('@exclude', required=False) required = StringField('@required', required=False) itemset = NodeField('itemset', Itemset)
class DisplayNode(XmlObject): """ Mixin for any node that has the awkward text-or-display subnode, like Command or Menu """ text = NodeField('text', Text) display = NodeField('display', Display) def __init__(self, node=None, context=None, locale_id=None, media_image=None, media_audio=None, **kwargs): super(DisplayNode, self).__init__(node, context, **kwargs) self.set_display( locale_id=locale_id, media_image=media_image, media_audio=media_audio, ) def set_display(self, locale_id=None, media_image=None, media_audio=None): text = None if locale_id: text = Text(locale_id=locale_id) if media_image or media_audio: self.display = Display( text=text, media_image=media_image, media_audio=media_audio, ) elif text: self.text = text
class Detail(IdNode): """ <detail id=""> <title><text/></title> <variables> <__ function=""/> </variables> <field sort=""> <header form="" width=""><text/></header> <template form="" width=""><text/></template> </field> </detail> """ ROOT_NAME = 'detail' title = NodeField('title/text', Text) variables = NodeListField('variables/*', DetailVariable) fields = NodeListField('field', Field)
class ActionMixin(OrderedXmlObject): ROOT_NAME = 'action' ORDER = ('display', 'stack') stack = NodeField('stack', Stack) relevant = XPathField('@relevant')
class Locale(XmlObject): ROOT_NAME = 'locale' id = StringField('@id') child_id = NodeField('id', Id) arguments = NodeListField('argument', LocaleArgument)
class Id(XmlObject): ROOT_NAME = 'id' xpath = NodeField('xpath', Xpath)
class AbstractTemplate(XmlObject): form = StringField('@form', choices=['image', 'phone', 'address']) width = IntegerField('@width') text = NodeField('text', Text)
class MediaText(XmlObject): ROOT_NAME = 'text' form_name = StringField('@form', choices=['image', 'audio']) # Nothing XForm-y about this 'form' locale = NodeField('locale', LocaleId) xpath = NodeField('xpath', Xpath) xpath_function = XPathField('xpath/@function')
class GraphTemplate(Template): # TODO: Is there a way to specify a default/static value for form? form = StringField('@form', choices=['graph']) graph = NodeField('graph', Graph)
class ClientPortfolio(Entity): """ Клиентский портфель Т+, основная рабочая структура для фондовой секции. """ ROOT_NAME = 'portfolio_tplus' # Идентификатор клиента id = client = StringField('@client') # Фактическая обеспеченность coverage_fact = FloatField('coverage_fact') # Плановая обеспеченность coverage_plan = FloatField('coverage_plan') # Критическая обеспеченность coverage_crit = FloatField('coverage_crit') # Входящая оценка портфеля без дисконта open_equity = FloatField('open_equity') # Текущая оценка портфеля без дисконта equity = FloatField('equity') # Плановое обеспечение (оценка ликвидационной стоимости портфеля) cover = FloatField('cover') # Плановая начальная маржа (оценка портфельного риска) init_margin = FloatField('init_margin') # Прибыль/убыток по входящим позициям pnl_income = FloatField('pnl_income') # Прибыль/убыток по сделкам pnl_intraday = FloatField('pnl_intraday') # Фактическое плечо портфеля Т+ leverage = FloatField('leverage') # Фактический уровень маржи портфеля Т+ margin_level = FloatField('margin_level') class _Money(MyXmlObject): # Входящая денежная позиция open_balance = FloatField('open_balance') # Затрачено на покупки bought = FloatField('bought') # Выручено от продаж sold = FloatField('sold') # Исполнено settled = FloatField('settled') # Текущая денежная позиция balance = FloatField('balance') # Уплачено комиссии tax = FloatField('tax') class _ValuePart(MyXmlObject): # Регистр учёта register = StringField('@register') # Входящая денежная позиция open_balance = FloatField('open_balance') # Потрачено на покупки bought = FloatField('bought') # Выручка от продаж sold = FloatField('sold') # Исполнено settled = FloatField('settled') # Текущая денежная позиция balance = FloatField('balance') value_parts = NodeListField('value_part', _ValuePart) money = NodeField('money', _Money) class _Security(MyXmlObject): # Id инструмента secid = IntegerField('@secid') # Id рынка market = IntegerField('market') # Обозначение инструмента seccode = StringField('seccode') # Текущая цена price = FloatField('price') # Входящая позиция, штук open_balance = IntegerField('open_balance') # Куплено, штук bought = IntegerField('bought') # Продано, штук sold = IntegerField('sold') # Текущая позиция, штук balance = IntegerField('balance') # Заявлено купить, штук buying = IntegerField('buying') # Заявлено продать, штук selling = IntegerField('selling') # Вклад бумаги в плановое обеспечение cover = FloatField('cover') # Плановая начальная маржа (риск) init_margin = FloatField('init_margin') # Cтавка риска для лонгов riskrate_long = FloatField('riskrate_long') # Cтавка риска для шортов riskrate_short = FloatField('riskrate_short') # Прибыль/убыток по входящим позициям pnl_income = FloatField('pnl_income') # Прибыль/убыток по сделкам pnl_intraday = FloatField('pnl_intraday') # Максимальная покупка, в лотах max_buy = IntegerField('maxbuy') # Макcимальная продажа, в лотах max_sell = IntegerField('maxsell') class _ValuePart(MyXmlObject): # Входящая позиция, штук register = StringField('@register') # Входящая позиция, штук open_balance = IntegerField('open_balance') # Куплено, штук bought = IntegerField('bought') # Продано, штук sold = IntegerField('sold') # Исполнено settled = IntegerField('settled') # Текущая позиция, штук balance = IntegerField('balance') # Заявлено купить, штук buying = IntegerField('buying') # Заявлено продать, штук selling = IntegerField('selling') value_parts = NodeListField('value_part', _ValuePart) securities = NodeListField('security', _Security)
class XpathVariable(XmlObject): ROOT_NAME = 'variable' name = StringField('@name') locale_id = StringField('locale/@id') xpath = NodeField('xpath', CalculatedPropertyXpath)
class Detail(OrderedXmlObject, IdNode): """ <detail id=""> <title><text/></title> <lookup action="" image="" name=""> <extra key="" value = "" /> <response key ="" /> </lookup> <variables> <__ function=""/> </variables> <field sort=""> <header form="" width=""><text/></header> <template form="" width=""><text/></template> </field> </detail> """ ROOT_NAME = 'detail' ORDER = ('title', 'lookup', 'details', 'fields') nodeset = StringField('@nodeset') print_template = StringField('@print-template') title = NodeField('title/text', Text) lookup = NodeField('lookup', Lookup) fields = NodeListField('field', Field) actions = NodeListField('action', Action) details = NodeListField('detail', "self") _variables = NodeField('variables', DetailVariableList) relevant = StringField('@relevant') def _init_variables(self): if self._variables is None: self._variables = DetailVariableList() def get_variables(self): self._init_variables() return self._variables.variables def set_variables(self, value): self._init_variables() self._variables.variables = value variables = property(get_variables, set_variables) def get_all_xpaths(self): result = set() if self.nodeset: result.add(self.nodeset) if self._variables: for variable in self.variables: result.add(variable.function) if self.actions: for action in self.actions: for frame in action.stack.frames: result.add(frame.if_clause) for datum in getattr(frame, 'datums', []): result.add(datum.value) def _get_graph_config_xpaths(configuration): result = set() for config in configuration.configs: result.add(config.xpath_function) return result for field in self.fields: if field.template.form == 'graph': s = etree.tostring(field.template.node) template = load_xmlobject_from_string(s, xmlclass=GraphTemplate) result.update(_get_graph_config_xpaths(template.graph.configuration)) for series in template.graph.series: result.add(series.nodeset) result.update(_get_graph_config_xpaths(series.configuration)) else: result.add(field.header.text.xpath_function) result.add(field.template.text.xpath_function) for detail in self.details: result.update(detail.get_all_xpaths()) result.discard(None) return result
class Action(ActionMixin): """ For CC < 2.21 """ display = NodeField('display', Display) auto_launch = SimpleBooleanField("@auto_launch", "true", "false") redo_last = SimpleBooleanField("@redo_last", "true", "false")
class Action(ActionMixin): """ For CC < 2.21 """ display = NodeField('display', Display)
class Display(OrderedXmlObject): ROOT_NAME = 'display' ORDER = ('text', 'media_image', 'media_audio') text = NodeField('text', Text) media_image = StringField('media/@image') media_audio = StringField('media/@audio')
class MediaText(XmlObject): ROOT_NAME = 'text' form_name = StringField('@form', choices=['image', 'audio' ]) # Nothing XForm-y about this 'form' locale = NodeField('locale', LocaleId)
class ScheduleFixture(Fixture): schedule = NodeField('schedule', Schedule)
class Detail(OrderedXmlObject, IdNode): """ <detail id=""> <title><text/></title> <lookup action="" image="" name=""> <extra key="" value = "" /> <response key ="" /> </lookup> <variables> <__ function=""/> </variables> <field sort=""> <header form="" width=""><text/></header> <template form="" width=""><text/></template> </field> </detail> """ ROOT_NAME = 'detail' ORDER = ('title', 'lookup', 'details', 'fields') nodeset = StringField('@nodeset') print_template = StringField('@print-template') title = NodeField('title/text', Text) lookup = NodeField('lookup', Lookup) fields = NodeListField('field', Field) actions = NodeListField('action', Action) details = NodeListField('detail', "self") _variables = NodeField('variables', DetailVariableList) relevant = StringField('@relevant') def _init_variables(self): if self._variables is None: self._variables = DetailVariableList() def _get_variables_node(self): self._init_variables() return self._variables.variables def _set_variables_node(self, value): self._init_variables() self._variables.variables = value variables = property(_get_variables_node, _set_variables_node) def has_variables(self): # can't check len(self.variables) directly since NodeList uses an # xpath to find its children which doesn't work here since # each node has a custom name return self._variables is not None and len( self.variables.node.getchildren()) > 0 def get_variables(self): """ :returns: List of DetailVariable objects """ return [ self.variables.mapper.to_python(node) for node in self.variables.node.getchildren() ] def get_all_xpaths(self): result = set() if self.nodeset: result.add(self.nodeset) if self.has_variables(): for variable in self.get_variables(): result.add(variable.function) if self.actions: for action in self.actions: for frame in action.stack.frames: result.add(frame.if_clause) for datum in getattr(frame, 'datums', []): result.add(datum.value) def _get_graph_config_xpaths(configuration): result = set() for config in configuration.configs: result.add(config.xpath_function) return result for field in self.fields: if field.template.form == 'graph': s = etree.tostring(field.template.node) template = load_xmlobject_from_string(s, xmlclass=GraphTemplate) result.update( _get_graph_config_xpaths(template.graph.configuration)) for series in template.graph.series: result.add(series.nodeset) result.update( _get_graph_config_xpaths(series.configuration)) else: result.add(field.header.text.xpath_function) result.add(field.template.text.xpath_function) if field.template.text.xpath: for variable in field.template.text.xpath.variables: if variable.xpath: result.add(str(variable.xpath.function)) for detail in self.details: result.update(detail.get_all_xpaths()) result.discard(None) return result