Commit 3c3ecadb authored by mouadh's avatar mouadh

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	requirements.txt
parents cedc74c8 16ebd261
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
from __future__ import absolute_import, division, print_function from __future__ import absolute_import, division, print_function
import HTMLParser
import xmlwitch
import os import os
from datetime import datetime from datetime import datetime
from os.path import expanduser from os.path import expanduser
from lxml import etree
from spyne import AnyXml, Application, ServiceBase, rpc, Fault from spyne import AnyXml, Application, ServiceBase, rpc, Fault
from spyne.const.http import HTTP_200 from spyne.const.http import HTTP_200
from spyne.error import InvalidCredentialsError from spyne.error import InvalidCredentialsError
...@@ -158,11 +160,13 @@ class XmlaProviderService(ServiceBase): ...@@ -158,11 +160,13 @@ class XmlaProviderService(ServiceBase):
if request.Command.Statement == '': if request.Command.Statement == '':
# check if command contains a query # check if command contains a query
return etree.fromstring("""
<return> xml = xmlwitch.Builder()
<root xmlns="urn:schemas-microsoft-com:xml-analysis:empty"/> with xml['return']:
</return> xml.root(xmlns="urn:schemas-microsoft-com:xml-analysis:empty")
""")
return str(xml)
else: else:
XmlaProviderService.discover_tools.change_catalogue( XmlaProviderService.discover_tools.change_catalogue(
request.Properties.PropertyList.Catalog) request.Properties.PropertyList.Catalog)
...@@ -171,54 +175,45 @@ class XmlaProviderService(ServiceBase): ...@@ -171,54 +175,45 @@ class XmlaProviderService(ServiceBase):
df = executer.execute_mdx() df = executer.execute_mdx()
xmla_tools = XmlaExecuteTools(executer) xmla_tools = XmlaExecuteTools(executer)
return etree.fromstring(""" xml = xmlwitch.Builder()
<return> with xml['return']:
<root xmlns="urn:schemas-microsoft-com:xml-analysis:mddataset" with xml.root(
xmlns:xsd="http://www.w3.org/2001/XMLSchema" execute_xsd,
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> xmlns="urn:schemas-microsoft-com:xml-analysis:mddataset",
{0} **{
<OlapInfo> 'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
<CubeInfo> 'xmlns:xsi':
<Cube> 'http://www.w3.org/2001/XMLSchema-instance'
<CubeName>Sales</CubeName> }):
<LastDataUpdate with xml.OlapInfo(xmla_tools.generate_cell_info()):
xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">{7}</LastDataUpdate> with xml.CubeInfo:
<LastSchemaUpdate with xml.Cube:
xmlns="http://schemas.microsoft.com/analysisservices/2003/engine">{7}</LastSchemaUpdate> xml.CubeName('Sales')
</Cube> xml.LastDataUpdate(
</CubeInfo> datetime.now().strftime(
<AxesInfo> '%Y-%m-%dT%H:%M:%S'),
{1} xmlns="http://schemas.microsoft.com/analysisservices/2003/engine"
{2} )
</AxesInfo> xml.LastSchemaUpdate(
{3} datetime.now().strftime(
</OlapInfo> '%Y-%m-%dT%H:%M:%S'),
<Axes> xmlns="http://schemas.microsoft.com/analysisservices/2003/engine"
{4} )
{5}
</Axes> xml.AxesInfo(
<CellData> xmla_tools.generate_axes_info(df),
{6} xmla_tools.generate_axes_info_slicer(df))
</CellData>
</root> xml.Axes(
</return> xmla_tools.generate_xs0(df),
""".format(execute_xsd, xmla_tools.generate_slicer_axis(df))
xmla_tools.generate_axes_info(df),
xmla_tools.generate_axes_info_slicer(df), xml.CellData(xmla_tools.generate_cell_data(df))
xmla_tools.generate_cell_info(),
xmla_tools.generate_xs0(df), html_parser = HTMLParser.HTMLParser()
xmla_tools.generate_slicer_axis(df), xml = html_parser.unescape(str(xml)).replace('&', '&amp;')
xmla_tools.generate_cell_data(df),
datetime.now().strftime('%Y-%m-%dT%H:%M:%S')).replace( return xml
'&', '&amp;'))
# Problem:
# An XML parser returns the error “xmlParseEntityRef: noname”
#
# Cause:
# There is a stray ‘&’ (ampersand character) somewhere in the XML text eg. some text & some more text
# Solution
# .replace('&', '&amp;')
application = Application( application = Application(
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -4,6 +4,7 @@ import itertools ...@@ -4,6 +4,7 @@ import itertools
from collections import OrderedDict from collections import OrderedDict
import numpy as np import numpy as np
import xmlwitch
class XmlaExecuteTools(): class XmlaExecuteTools():
...@@ -88,7 +89,8 @@ class XmlaExecuteTools(): ...@@ -88,7 +89,8 @@ class XmlaExecuteTools():
:param splited_df: :param splited_df:
:return: :return:
""" """
axis0 = ""
xml = xmlwitch.Builder()
# only measure selected # only measure selected
if mdx_execution_result['columns_desc'][mdx_query_axis].keys() == [ if mdx_execution_result['columns_desc'][mdx_query_axis].keys() == [
self.executer.facts self.executer.facts
...@@ -128,78 +130,82 @@ class XmlaExecuteTools(): ...@@ -128,78 +130,82 @@ class XmlaExecuteTools():
] ]
first_att = 3 first_att = 3
for tupls in itertools.chain(*tuples): if tuples:
axis0 += "<Tuple>\n" with xml.Axis(name=axis):
if tupls[0][1] in self.executer.measures and len( with xml.Tuples:
self.executer.selected_measures) > 1: for tupls in itertools.chain(*tuples):
with xml.Tuple:
axis0 += """ if tupls[0][1] in self.executer.measures and len(
<Member Hierarchy="[Measures]"> self.executer.selected_measures) > 1:
<UName>[Measures].[{0}]</UName> with xml.Member(Hierarchy="[Measures]"):
<Caption>{0}</Caption> xml.UName(
<LName>[Measures]</LName> '[Measures].[{0}]'.format(tupls[0][1]))
<LNum>0</LNum> xml.Caption('{0}'.format(tupls[0][1]))
<DisplayInfo>0</DisplayInfo> xml.LName('[Measures]')
<HIERARCHY_UNIQUE_NAME>[Measures]</HIERARCHY_UNIQUE_NAME> xml.LNum('0')
</Member> xml.DisplayInfo('0')
""".format(tupls[0][1]) xml.HIERARCHY_UNIQUE_NAME('[Measures]')
if tupls[0][-1] in self.executer.measures: if tupls[0][-1] in self.executer.measures:
axis0 += "</Tuple>\n" continue
continue
for tupl in tupls:
for tupl in tupls: tuple_without_minus_1 = self.get_tuple_without_nan(
tuple_without_minus_1 = self.get_tuple_without_nan(tupl) tupl)
# french caracteres # french caracteres
# TODO encode dataframe # TODO encode dataframe
if type(tuple_without_minus_1[-1]) == unicode: if type(tuple_without_minus_1[-1]) == unicode:
tuple_without_minus_1 = [ tuple_without_minus_1 = [
x.encode('utf-8', 'replace') x.encode('utf-8', 'replace')
for x in tuple_without_minus_1 for x in tuple_without_minus_1
] ]
axis0 += """ # todo ugly !!
<Member Hierarchy="[{0}].[{0}]"> with xml.Member(Hierarchy="[{0}].[{0}]".format(
<UName>[{0}].[{0}].[{1}].{2}</UName> tuple_without_minus_1[0])):
<Caption>{3}</Caption> xml.UName('[{0}].[{0}].[{1}].{2}'.format(
<LName>[{0}].[{0}].[{1}]</LName> tuple_without_minus_1[0], splited_df[
<LNum>{4}</LNum> tuple_without_minus_1[0]].columns[
<DisplayInfo>131076</DisplayInfo>""".format( len(tuple_without_minus_1) -
tuple_without_minus_1[0], splited_df[tuple_without_minus_1[ first_att], '.'.join([
0]].columns[len(tuple_without_minus_1) - first_att], '[' + str(i) + ']'
'.'.join([ for i in
'[' + str(i) + ']' tuple_without_minus_1[
for i in tuple_without_minus_1[first_att - 1:] first_att - 1:]
]), tuple_without_minus_1[-1], ])))
len(tuple_without_minus_1) - first_att) xml.Caption('{0}'.format(
# PARENT_UNIQUE_NAME must be before HIERARCHY_UNIQUE_NAME tuple_without_minus_1[-1]))
if len(tuple_without_minus_1[first_att - 1:]) > 1: xml.LName('[{0}].[{0}].[{1}]'.format(
axis0 += """ tuple_without_minus_1[0], splited_df[
<PARENT_UNIQUE_NAME>[{0}].[{0}].[{1}].{2}</PARENT_UNIQUE_NAME>""".format( tuple_without_minus_1[0]].columns[
tuple_without_minus_1[0], len(tuple_without_minus_1) -
splited_df[tuple_without_minus_1[0]].columns[0], first_att]))
'.'.join([ xml.LNum('{0}'.format(
'[' + str(i) + ']' len(tuple_without_minus_1) -
for i in tuple_without_minus_1[first_att - 1:-1] first_att))
])) xml.DisplayInfo('131076')
axis0 += """
<HIERARCHY_UNIQUE_NAME>[{0}].[{0}]</HIERARCHY_UNIQUE_NAME> # PARENT_UNIQUE_NAME must be before HIERARCHY_UNIQUE_NAME (todo change it in xsd)
</Member> if len(tuple_without_minus_1[first_att -
""".format(tuple_without_minus_1[0]) 1:]) > 1:
xml.PARENT_UNIQUE_NAME(
axis0 += "</Tuple>\n" '[{0}].[{0}].[{1}].{2}'.format(
tuple_without_minus_1[0],
if axis0: splited_df[
axis0 = """ tuple_without_minus_1[0]]
<Axis name="{0}"> .columns[0], '.'.join([
<Tuples> '[' + str(i) + ']'
{1} for i in
</Tuples> tuple_without_minus_1[
</Axis> first_att - 1:-1]
""".format(axis, axis0) ])))
return axis0 xml.HIERARCHY_UNIQUE_NAME(
'[{0}].[{0}]'.format(
tuple_without_minus_1[0]))
return str(xml)
def generate_xs0(self, mdx_execution_result): def generate_xs0(self, mdx_execution_result):
""" """
...@@ -307,7 +313,6 @@ class XmlaExecuteTools(): ...@@ -307,7 +313,6 @@ class XmlaExecuteTools():
:param mdx_execution_result: mdx_execute() result :param mdx_execution_result: mdx_execute() result
:return: CellData as string :return: CellData as string
""" """
columns_loop = []
if ((len(mdx_execution_result['columns_desc']['columns'].keys()) == 0) if ((len(mdx_execution_result['columns_desc']['columns'].keys()) == 0)
^ ^
...@@ -331,18 +336,16 @@ class XmlaExecuteTools(): ...@@ -331,18 +336,16 @@ class XmlaExecuteTools():
index=False) index=False)
]) ])
cell_data = "" xml = xmlwitch.Builder()
index = 0 index = 0
for value in columns_loop: for value in columns_loop:
if np.isnan(value): if np.isnan(value):
value = '' value = ''
cell_data += """ with xml.Cell(CellOrdinal=str(index)):
<Cell CellOrdinal="{0}"> xml.Value(str(value), **{'xsi:type': 'xsi:long'})
<Value xsi:type="xsi:long">{1}</Value>
</Cell>
""".format(index, value)
index += 1 index += 1
return cell_data return str(xml)
def generate_axes_info_slicer(self, mdx_execution_result): def generate_axes_info_slicer(self, mdx_execution_result):
""" """
...@@ -377,43 +380,51 @@ class XmlaExecuteTools(): ...@@ -377,43 +380,51 @@ class XmlaExecuteTools():
ignore_fact=True) ignore_fact=True)
all_dimensions_names.append('Measures') all_dimensions_names.append('Measures')
hierarchy_info_slicer = "" xml = xmlwitch.Builder()
slicer_list = list( slicer_list = list(
set(all_dimensions_names) - set( set(all_dimensions_names) - set(
table_name table_name
for table_name in mdx_execution_result['columns_desc']['all'])) for table_name in mdx_execution_result['columns_desc']['all']))
# we have to write measures after dimensions ! # we have to write measures after dimensions ! (todo change xsd)
if 'Measures' in slicer_list: if 'Measures' in slicer_list:
slicer_list.insert( slicer_list.insert(
len(slicer_list), len(slicer_list),
slicer_list.pop(slicer_list.index('Measures'))) slicer_list.pop(slicer_list.index('Measures')))
for dim_diff in slicer_list: if slicer_list:
to_write = "[{0}].[{0}]".format(dim_diff) with xml.AxisInfo(name='SlicerAxis'):
if dim_diff == 'Measures': for dim_diff in slicer_list:
# if measures > 1 we don't have to write measure to_write = "[{0}].[{0}]".format(dim_diff)
if self.executer.facts in mdx_execution_result['columns_desc'][ if dim_diff == 'Measures':
'all'] and len(mdx_execution_result['columns_desc'][ # if measures > 1 we don't have to write measure
'all'][self.executer.facts]) > 1: if self.executer.facts in mdx_execution_result[
continue 'columns_desc']['all'] and len(
else: mdx_execution_result['columns_desc'][
to_write = "[Measures]" 'all'][self.executer.facts]) > 1:
hierarchy_info_slicer += """ continue
<HierarchyInfo name="{0}"> else:
<UName name="{0}.[MEMBER_UNIQUE_NAME]" type="xs:string"/> to_write = "[Measures]"
<Caption name="{0}.[MEMBER_CAPTION]" type="xs:string"/>
<LName name="{0}.[LEVEL_UNIQUE_NAME]" type="xs:string"/> with xml.HierarchyInfo(name=to_write):
<LNum name="{0}.[LEVEL_NUMBER]" type="xs:int"/> xml.UName(
<DisplayInfo name="{0}.[DISPLAY_INFO]" type="xs:unsignedInt"/> name="{0}.[MEMBER_UNIQUE_NAME]".format(to_write),
</HierarchyInfo> **{'type': 'xs:string'})
""".format(to_write) xml.Caption(
name="{0}.[MEMBER_CAPTION]".format(to_write),
if hierarchy_info_slicer: **{'type': 'xs:string'})
hierarchy_info_slicer = "<AxisInfo name='SlicerAxis'>\n" + hierarchy_info_slicer + "\n</AxisInfo>\n" xml.LName(
name="{0}.[LEVEL_UNIQUE_NAME]".format(to_write),
return hierarchy_info_slicer **{'type': 'xs:string'})
xml.LNum(
name="{0}.[LEVEL_NUMBER]".format(to_write),
**{'type': 'xs:int'})
xml.DisplayInfo(
name="{0}.[DISPLAY_INFO]".format(to_write),
**{'type': 'xs:unsignedInt'})
return str(xml)
def generate_one_axis_info(self, def generate_one_axis_info(self,
mdx_execution_result, mdx_execution_result,
...@@ -452,45 +463,72 @@ class XmlaExecuteTools(): ...@@ -452,45 +463,72 @@ class XmlaExecuteTools():
:param Axis: Axis0 or Axis1 (Axis0 by default) :param Axis: Axis0 or Axis1 (Axis0 by default)
:return: :return:
""" """
hierarchy_info = ""
# measure must be written at the top
if self.executer.facts in mdx_execution_result['columns_desc'][
mdx_query_axis].keys() and len(mdx_execution_result[
'columns_desc'][mdx_query_axis][self.executer.facts]) > 1:
hierarchy_info += """
<HierarchyInfo name="{0}">
<UName name="{0}.[MEMBER_UNIQUE_NAME]" type="xs:string"/>
<Caption name="{0}.[MEMBER_CAPTION]" type="xs:string"/>
<LName name="{0}.[LEVEL_UNIQUE_NAME]" type="xs:string"/>
<LNum name="{0}.[LEVEL_NUMBER]" type="xs:int"/>
<DisplayInfo name="{0}.[DISPLAY_INFO]" type="xs:unsignedInt"/>
<PARENT_UNIQUE_NAME name="{0}.[PARENT_UNIQUE_NAME]" type="xs:string"/>
<HIERARCHY_UNIQUE_NAME name="{0}.[HIERARCHY_UNIQUE_NAME]" type="xs:string"/>
</HierarchyInfo>
""".format('[Measures]')
for table_name in mdx_execution_result['columns_desc'][mdx_query_axis]:
if table_name != self.executer.facts:
hierarchy_info += """
<HierarchyInfo name="[{0}].[{0}]">
<UName name="[{0}].[{0}].[MEMBER_UNIQUE_NAME]" type="xs:string"/>
<Caption name="[{0}].[{0}].[MEMBER_CAPTION]" type="xs:string"/>
<LName name="[{0}].[{0}].[LEVEL_UNIQUE_NAME]" type="xs:string"/>
<LNum name="[{0}].[{0}].[LEVEL_NUMBER]" type="xs:int"/>
<DisplayInfo name="[{0}].[{0}].[DISPLAY_INFO]" type="xs:unsignedInt"/>
<PARENT_UNIQUE_NAME name="[{0}].[{0}].[PARENT_UNIQUE_NAME]" type="xs:string"/>
<HIERARCHY_UNIQUE_NAME name="[{0}].[{0}].[HIERARCHY_UNIQUE_NAME]" type="xs:string"/>
</HierarchyInfo>
""".format(table_name)
if hierarchy_info:
hierarchy_info = """
<AxisInfo name='{0}'>
{1}
</AxisInfo>
""".format(Axis, hierarchy_info)
return hierarchy_info axis_tables = mdx_execution_result['columns_desc'][mdx_query_axis]
xml = xmlwitch.Builder()
# measure must be written at the top
if axis_tables:
with xml.AxisInfo(name=Axis):
# many measures , then write this on the top
if self.executer.facts in axis_tables.keys() and len(
axis_tables[self.executer.facts]) > 1:
with xml.HierarchyInfo(name='[Measures]'):
xml.UName(
name="[Measures].[MEMBER_UNIQUE_NAME]",
**{'type': 'xs:string'})
xml.Caption(
name="[Measures].[MEMBER_CAPTION]",
**{'type': 'xs:string'})
xml.LName(
name="[Measures].[LEVEL_UNIQUE_NAME]",
**{'type': 'xs:string'})
xml.LNum(
name="[Measures].[LEVEL_NUMBER]",
**{'type': 'xs:int'})
xml.DisplayInfo(
name="[Measures].[DISPLAY_INFO]",
**{'type': 'xs:unsignedInt'})
xml.PARENT_UNIQUE_NAME(
name="[Measures].[PARENT_UNIQUE_NAME]",
**{'type': 'xs:string'})
xml.HIERARCHY_UNIQUE_NAME(
name="[Measures].[HIERARCHY_UNIQUE_NAME]",
**{'type': 'xs:string'})
for table_name in axis_tables:
if table_name != self.executer.facts:
with xml.HierarchyInfo(
name='[{0}].[{0}]'.format(table_name)):
xml.UName(
name="[{0}].[{0}].[MEMBER_UNIQUE_NAME]".format(
table_name),
**{'type': 'xs:string'})
xml.Caption(
name="[{0}].[{0}].[MEMBER_CAPTION]".format(
table_name),
**{'type': 'xs:string'})
xml.LName(
name="[{0}].[{0}].[LEVEL_UNIQUE_NAME]".format(
table_name),
**{'type': 'xs:string'})
xml.LNum(
name="[{0}].[{0}].[LEVEL_NUMBER]".format(
table_name),
**{'type': 'xs:int'})
xml.DisplayInfo(
name="[{0}].[{0}].[DISPLAY_INFO]".format(
table_name),
**{'type': 'xs:unsignedInt'})
xml.PARENT_UNIQUE_NAME(
name="[{0}].[{0}].[PARENT_UNIQUE_NAME]".format(
table_name),
**{'type': 'xs:string'})
xml.HIERARCHY_UNIQUE_NAME(
name="[{0}].[{0}].[HIERARCHY_UNIQUE_NAME]".
format(table_name),
**{'type': 'xs:string'})
return str(xml)
def generate_axes_info(self, mdx_execution_result): def generate_axes_info(self, mdx_execution_result):
""" """
...@@ -514,15 +552,16 @@ class XmlaExecuteTools(): ...@@ -514,15 +552,16 @@ class XmlaExecuteTools():
@staticmethod @staticmethod
def generate_cell_info(): def generate_cell_info():
return """ xml = xmlwitch.Builder()
<CellInfo> with xml.CellInfo:
<Value name="VALUE"/> xml.Value(name="VALUE")
<FormatString name="FORMAT_STRING" type="xs:string"/> xml.FormatString(name="FORMAT_STRING", **{'type': 'xs:string'})
<Language name="LANGUAGE" type="xs:unsignedInt"/> xml.Language(name="LANGUAGE", **{'type': 'xs:unsignedInt'})
<BackColor name="BACK_COLOR" type="xs:unsignedInt"/> xml.BackColor(name="BACK_COLOR", **{'type': 'xs:unsignedInt'})
<ForeColor name="FORE_COLOR" type="xs:unsignedInt"/> xml.ForeColor(name="FORE_COLOR", **{'type': 'xs:unsignedInt'})
<FontFlags name="FONT_FLAGS" type="xs:int"/> xml.FontFlags(name="FONT_FLAGS", **{'type': 'xs:int'})
</CellInfo>"""
return str(xml)
def generate_slicer_axis(self, mdx_execution_result): def generate_slicer_axis(self, mdx_execution_result):
""" """
...@@ -553,57 +592,51 @@ class XmlaExecuteTools(): ...@@ -553,57 +592,51 @@ class XmlaExecuteTools():
:param mdx_execution_result: mdx_execute() result :param mdx_execution_result: mdx_execute() result
:return: SlicerAxis as string :return: SlicerAxis as string
""" """
tuple = ""
# not used dimensions # not used dimensions
for dim_diff in list( unused_dimensions = list(
set(self.executer.get_all_tables_names(ignore_fact=True)) - set(self.executer.get_all_tables_names(ignore_fact=True)) - set(
set(table_name table_name
for table_name in mdx_execution_result['columns_desc'][ for table_name in mdx_execution_result['columns_desc']['all']))
'all'])): xml = xmlwitch.Builder()
if unused_dimensions:
# TODO encode dataframe with xml.Axis(name="SlicerAxis"):
# french caracteres with xml.Tuples:
if type(self.executer.tables_loaded[dim_diff].iloc[0][ with xml.Tuple:
0]) == unicode: for dim_diff in unused_dimensions:
column_attribut = self.executer.tables_loaded[dim_diff].iloc[
0][0].encode('utf-8', 'replace') # TODO encode dataframe
else: # french caracteres
column_attribut = self.executer.tables_loaded[dim_diff].iloc[ if type(self.executer.tables_loaded[dim_diff].iloc[
0][0] 0][0]) == unicode:
column_attribut = self.executer.tables_loaded[
tuple += """ dim_diff].iloc[0][0].encode('utf-8',
<Member Hierarchy="[{0}].[{0}]"> 'replace')
<UName>[{0}].[{0}].[{1}].[{2}]</UName> else:
<Caption>{2}</Caption> column_attribut = self.executer.tables_loaded[
<LName>[{0}].[{0}].[{1}]</LName> dim_diff].iloc[0][0]
<LNum>0</LNum>
<DisplayInfo>2</DisplayInfo> with xml.Member(
</Member> Hierarchy="[{0}].[{0}]".format(dim_diff)):
""".format(dim_diff, xml.UName('[{0}].[{0}].[{1}].[{2}]'.format(
self.executer.tables_loaded[dim_diff].columns[0], dim_diff, self.executer.tables_loaded[
column_attribut) dim_diff].columns[0], column_attribut))
xml.Caption(str(column_attribut))
# if we have zero on one only measures used xml.LName('[{0}].[{0}].[{1}]'.format(
if len(self.executer.selected_measures) <= 1: dim_diff, self.executer.tables_loaded[
tuple += """ dim_diff].columns[0]))
<Member Hierarchy="[Measures]"> xml.LNum('0')
<UName>[Measures].[{0}]</UName> xml.DisplayInfo('2')
<Caption>{0}</Caption>
<LName>[Measures]</LName> # if we have zero on one only measures used
<LNum>0</LNum> if len(self.executer.selected_measures) <= 1:
<DisplayInfo>0</DisplayInfo> with xml.Member(
</Member> Hierarchy="[Measures]".format(dim_diff)):
""".format(self.executer.measures[0]) xml.UName('[Measures].[{0}]'.format(
self.executer.measures[0]))
if tuple: xml.Caption(
tuple = """ '{0}'.format(self.executer.measures[0]))
<Axis name="SlicerAxis"> xml.LName('[Measures]')
<Tuples> xml.LNum('0')
<Tuple> xml.DisplayInfo('0')
{0}
</Tuple> return str(xml)
</Tuples>
</Axis>
""".format(tuple)
return tuple
...@@ -5,6 +5,7 @@ spyne<3 ...@@ -5,6 +5,7 @@ spyne<3
treelib<2 treelib<2
SQLAlchemy SQLAlchemy
psycopg2 psycopg2
xmlwitch
# Test # Test
werkzeug werkzeug
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment