Commit 578f642d authored by mouadh's avatar mouadh

remove grako parser

parent 318d06e3
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# CAVEAT UTILITOR
#
# This file was automatically generated by Grako.
#
# https://pypi.python.org/pypi/grako/
#
# Any changes you make to it will be overwritten the next time
# the file is generated.
from __future__ import (absolute_import, division, print_function,
unicode_literals)
from grako.buffering import Buffer
from grako.parsing import Parser, graken
from grako.util import RE_FLAGS, generic_main, re # noqa
__all__ = ['MdxParserGen', 'UnknownSemantics', 'main']
KEYWORDS = {}
class UnknownBuffer(Buffer):
"""
main class for parsing MDX query generated by grako
"""
def __init__(self,
text,
whitespace=None,
nameguard=None,
comments_re=None,
eol_comments_re=None,
ignorecase=None,
namechars='',
**kwargs):
super(UnknownBuffer, self).__init__(
text,
whitespace=whitespace,
nameguard=nameguard,
comments_re=comments_re,
eol_comments_re=eol_comments_re,
ignorecase=ignorecase,
namechars=namechars,
**kwargs)
class MdxParserGen(Parser):
def __init__(self,
whitespace=None,
nameguard=None,
comments_re=None,
eol_comments_re=None,
ignorecase=None,
left_recursion=False,
parseinfo=True,
keywords=None,
namechars='',
buffer_class=UnknownBuffer,
**kwargs):
if keywords is None:
keywords = KEYWORDS
super(MdxParserGen, self).__init__(
whitespace=whitespace,
nameguard=nameguard,
comments_re=comments_re,
eol_comments_re=eol_comments_re,
ignorecase=ignorecase,
left_recursion=left_recursion,
parseinfo=parseinfo,
keywords=keywords,
namechars=namechars,
buffer_class=buffer_class,
**kwargs)
@graken()
def _MDX_statement_(self):
self._select_statement_()
@graken('SelectStatement')
def _select_statement_(self):
self._token('SELECT')
self.name_last_node('name')
with self._optional():
self._axis_specification_()
self.name_last_node('axis_specification_columns')
with self._optional():
self._token(',')
self._axis_specification_()
self.name_last_node('axis_specification_rows')
self._token('FROM')
self._cube_specification_()
self.name_last_node('cube_specification')
with self._optional():
self._token('WHERE')
self._condition_specification_()
self.name_last_node('condition_specification')
self._check_eof()
self.ast._define([
'axis_specification_columns', 'axis_specification_rows',
'condition_specification', 'cube_specification', 'name'
], [])
@graken()
def _axis_specification_(self):
with self._optional():
self._left_accolade_()
with self._optional():
self._fetch_form_()
self._dim_props_place_()
self.name_last_node('@')
with self._optional():
self._right_accolade_()
self._token('ON')
self._axis_name_()
@graken()
def _dim_props_place_(self):
with self._optional():
self._left_parentheses_()
self._dim_props_type_()
self.name_last_node('@')
with self._optional():
self._right_parentheses_()
@graken()
def _dim_props_type_(self):
with self._optional():
self._left_accolade_()
with self._optional():
self._fetch_type_()
self._dim_props_op_l1_()
self.name_last_node('@')
with self._optional():
self._right_accolade_()
with self._optional():
def block1():
self._operator_()
self.name_last_node('@')
self._dim_props_type_()
self._closure(block1)
@graken()
def _dim_props_op_l1_(self):
with self._optional():
self._left_parentheses_()
self._dim_props_op_()
self.name_last_node('@')
with self._optional():
self._right_parentheses_()
@graken()
def _dim_props_op_(self):
with self._optional():
self._left_accolade_()
self._dim_props_ligne_()
self.name_last_node('@')
with self._optional():
self._right_accolade_()
with self._optional():
def block1():
self._comma_()
self.name_last_node('@')
self._dim_props_op_()
self._closure(block1)
@graken()
def _dim_props_ligne_(self):
with self._optional():
self._left_parentheses_()
self._dimension_place_()
self.name_last_node('@')
with self._optional():
self._right_parentheses_()
with self._optional():
def block1():
with self._group():
with self._choice():
with self._option():
self._comma_()
self.name_last_node('@')
with self._option():
self._dpoint_()
self.name_last_node('@')
self._error('no available options')
self._dim_props_ligne_()
self.name_last_node('@')
self._closure(block1)
@graken()
def _dimension_place_(self):
with self._choice():
with self._option():
with self._optional():
self._left_accolade_()
self._dim_props_()
self.name_last_node('@')
with self._optional():
self._point_()
self._laste_node_()
self.name_last_node('@')
with self._optional():
self._comma_()
self.name_last_node('@')
self._dim_props_()
self.name_last_node('@')
with self._optional():
self._point_()
self._laste_node_()
self.name_last_node('@')
with self._optional():
self._dpoint_()
self.name_last_node('@')
self._dim_props_()
self.name_last_node('@')
with self._optional():
self._point_()
self._laste_node_()
self.name_last_node('@')
with self._optional():
self._right_accolade_()
with self._option():
self._dimension_shortcut_()
self.name_last_node('@')
self._error('no available options')
@graken()
def _dim_props_(self):
def block0():
with self._optional():
self._point_()
with self._optional():
self._left_bracket_()
self._dimension_()
self.name_last_node('@')
with self._optional():
self._right_bracket_()
self._closure(block0)
@graken()
def _laste_node_(self):
with self._choice():
with self._option():
self._token('members')
with self._option():
self._token('children')
with self._option():
self._token('Members')
with self._option():
self._token('ALLMEMBERS')
self._error('expecting one of: ALLMEMBERS Members children members')
@graken()
def _dimension_(self):
self._pattern(r"[a-zA-Z0-9'_'' '',']*")
self.name_last_node('@')
@graken()
def _axis_name_(self):
with self._choice():
with self._option():
self._token('0')
with self._option():
self._token('1')
with self._option():
self._token('COLUMNS')
with self._option():
self._token('ROWS')
with self._option():
self._token('_ROWS')
self._error('expecting one of: 0 1 COLUMNS ROWS _ROWS')
@graken()
def _cube_specification_(self):
with self._optional():
self._left_bracket_()
self._dimension_()
with self._optional():
self._right_bracket_()
@graken()
def _condition_specification_(self):
with self._optional():
self._left_parentheses_()
def block0():
with self._optional():
self._point_()
with self._optional():
self._left_bracket_()
self._dimension_()
self.name_last_node('@')
with self._optional():
self._right_bracket_()
self._closure(block0)
with self._optional():
self._right_parentheses_()
@graken()
def _digit_(self):
with self._choice():
with self._option():
self._token('0')
with self._option():
self._token('1')
with self._option():
self._token('2')
with self._option():
self._token('3')
with self._option():
self._token('4')
with self._option():
self._token('5')
with self._option():
self._token('6')
with self._option():
self._token('7')
with self._option():
self._token('8')
with self._option():
self._token('9')
self._error('expecting one of: 0 1 2 3 4 5 6 7 8 9')
@graken()
def _fetch_type_(self):
with self._choice():
with self._option():
self._token('CROSSJOIN')
with self._option():
self._token('NONEMPTY')
with self._option():
self._token('union')
with self._option():
self._token('except')
with self._option():
self._token('extract')
self._error(
'expecting one of: CROSSJOIN NONEMPTY except extract union')
@graken()
def _dimension_shortcut_(self):
with self._choice():
with self._option():
self._token('all')
with self._option():
self._token('time')
self._error('expecting one of: all time')
@graken()
def _fetch_form_(self):
with self._choice():
with self._option():
self._token('NONEMPTY')
with self._option():
self._token('non_empty')
with self._option():
self._token('non empty')
self._error('expecting one of: NONEMPTY non empty non_empty')
@graken()
def _left_bracket_(self):
self._token('[')
@graken()
def _right_bracket_(self):
self._token(']')
@graken()
def _left_parentheses_(self):
self._token('(')
@graken()
def _right_parentheses_(self):
self._token(')')
@graken()
def _left_accolade_(self):
self._token('{')
@graken()
def _right_accolade_(self):
self._token('}')
@graken()
def _point_(self):
self._token('.')
@graken()
def _dpoint_(self):
self._token(':')
@graken()
def _comma_(self):
self._token(',')
@graken()
def _operator_(self):
with self._choice():
with self._option():
self._token('+')
with self._option():
self._token('-')
with self._option():
self._token('/')
with self._option():
self._token('*')
self._error('expecting one of: * + - /')
class UnknownSemantics(object):
def mdx_statement(self, ast):
return ast
def select_statement(self, ast):
return ast
def axis_specification(self, ast):
return ast
def dim_props_place(self, ast):
return ast
def dim_props_type(self, ast):
return ast
def dim_props_op_l1(self, ast):
return ast
def dim_props_op(self, ast):
return ast
def dim_props_ligne(self, ast):
return ast
def dimension_place(self, ast):
return ast
def dim_props(self, ast):
return ast
def laste_node(self, ast):
return ast
def dimension(self, ast):
return ast
def axis_name(self, ast):
return ast
def cube_specification(self, ast):
return ast
def condition_specification(self, ast):
return ast
def digit(self, ast):
return ast
def fetch_type(self, ast):
return ast
def dimension_shortcut(self, ast):
return ast
def fetch_form(self, ast):
return ast
def left_bracket(self, ast):
return ast
def right_bracket(self, ast):
return ast
def left_parentheses(self, ast):
return ast
def right_parentheses(self, ast):
return ast
def left_accolade(self, ast):
return ast
def right_accolade(self, ast):
return ast
def point(self, ast):
return ast
def dpoint(self, ast):
return ast
def comma(self, ast):
return ast
def operator(self, ast):
return ast
def main(filename, startrule, **kwargs):
with open(filename) as f:
text = f.read()
parser = MdxParserGen(parseinfo=False)
return parser.parse(text, startrule, filename=filename, **kwargs)
if __name__ == '__main__':
import json
ast = generic_main(main, MdxParserGen, name='Unknown')
print('AST:')
print(ast)
print()
print('JSON:')
print(json.dumps(ast, indent=2))
print()
from __future__ import absolute_import, division, print_function
class SelectStatement:
def __init__(self, select_statement):
self.select_statement = select_statement
def __str__(self):
return '{}'.format(self.select_statement)
(* The ebnf file is the translation and improvement of microsoft mdx's spec, from https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms717923%28v=vs.85%29.aspx *)
(* The ebnf conversion was guided by http://stackoverflow.com/questions/14922242/how-to-convert-bnf-to-ebnf *)
(* The generation of mdx_parser.py is as easy as: /path/to/grako bnf_mdx.ebnf -o mdx_parser.py *)
mdx_statement =
select_statement;
select_statement::SelectStatement = name:'SELECT' [axis_specification_columns:axis_specification]
[',' axis_specification_rows:axis_specification]
'FROM' cube_specification:cube_specification
['WHERE' condition_specification:condition_specification]$
;
axis_specification = [left_accolade] [fetch_form] @:dim_props_place [right_accolade] 'ON' axis_name;
dim_props_place = [left_parentheses] @:dim_props_type [right_parentheses] ;
dim_props_type = [left_accolade] [fetch_type] @:dim_props_op_l1 [right_accolade] [{@:operator dim_props_type}*];
dim_props_op_l1 = [left_parentheses] @:dim_props_op [right_parentheses];
dim_props_op = [left_accolade] @:dim_props_ligne [right_accolade] [{@:comma dim_props_op}*];
dim_props_ligne = [left_parentheses] @:dimension_place [right_parentheses] [{ (@:comma | @:dpoint ) @:dim_props_ligne}*] ;
dimension_place = [left_accolade] @:dim_props [ point @:laste_node] [ @:comma @:dim_props [ point @:laste_node ]] [@:dpoint @:dim_props [ point @:laste_node ]] [right_accolade] | @:dimension_shortcut;
dim_props = {[point] [left_bracket] @:dimension [right_bracket]}* ;
laste_node = "members" | "children" | "Members" | 'ALLMEMBERS' ;
dimension = @:/[a-zA-Z0-9'_'' '',']*/ ;
axis_name = '0' | '1' |'COLUMNS' | 'ROWS' | '_ROWS';
cube_specification = [left_bracket] dimension [right_bracket];
condition_specification = [left_parentheses] {[point] [left_bracket] @:dimension [right_bracket]}* [right_parentheses] ;
digit =
"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
fetch_type = 'CROSSJOIN' | 'NONEMPTY' | 'union' | 'except' | 'extract' ;
dimension_shortcut = 'all' | 'time' ;
fetch_form = 'NONEMPTY' | 'non_empty' | 'non empty' ;
left_bracket = '[';
right_bracket = ']';
left_parentheses = '(';
right_parentheses = ')';
left_accolade = '{';
right_accolade = '}';
point = '.' ;
dpoint = ':' ;
comma = ',' ;
operator = '+' | '-' | '/' | '*' ;
from __future__ import absolute_import, division, print_function
from grako.model import ModelBuilderSemantics
from .gen_parser.mdxparser import MdxParserGen
from .gen_parser.models import SelectStatement
class MdxParser:
"""Parse the mdx query and split it into well-defined parts."""
START = 'MDX_statement'
@staticmethod
def parsing_mdx_query(axis, query):
"""Split the query into axis.
**Example**::
SELECT
{ [Geography].[Geo].[Country].[France],
[Geography].[Geo].[Country].[Spain] } ON COLUMNS,
{ [Product].[Prod].[Company].[Crazy Development] } ON ROWS
FROM [Sales]
WHERE [Time].[Calendar].[Year].[2010]
+------------+------------------------------------------------+
| | [Geography].[Geo].[Country].[France] |
| column | |
| | [Geography].[Geo].[Country].[Spain] |
+------------+------------------------------------------------+
| row | [Product].[Prod].[Company].[Crazy Development] |
+------------+------------------------------------------------+
| cube | [Sales] |
+------------+------------------------------------------------+
| condition | [Time].[Calendar].[Year].[2010] |
+------------+------------------------------------------------+
:param query: MDX Query
:param axis: column | row | cube | condition | all
:return: Tuples in the axis, from the MDX query
"""
model = MdxParserGen(semantics=ModelBuilderSemantics(
types=[SelectStatement]))
ast = model.parse(query, rule_name=MdxParser.START, ignorecase=True)
if axis == "column":
if ast.select_statement.axis_specification_columns is not None and \
u'' in ast.select_statement.axis_specification_columns:
ast.select_statement.axis_specification_columns.remove(u'')
return ast.select_statement.axis_specification_columns
elif axis == "row":
if ast.select_statement.axis_specification_rows is not None and \
u'' in ast.select_statement.axis_specification_rows:
ast.select_statement.axis_specification_rows.remove(u'')
return ast.select_statement.axis_specification_rows
elif axis == "cube":
if ast.select_statement.cube_specification is not None and \
u'' in ast.select_statement.cube_specification:
ast.select_statement.cube_specification.remove(u'')
return ast.select_statement.cube_specification[1] if \
isinstance(ast.select_statement.cube_specification, list) \
else ast.select_statement.cube_specification
elif axis == "condition":
if ast.select_statement.condition_specification is not None and \
type(ast.select_statement.condition_specification) not in (
unicode, str) and \
u'' in ast.select_statement.condition_specification:
ast.select_statement.condition_specification.remove(u'')
return ast.select_statement.condition_specification
elif axis == "all":
return 'Operation = {} \n' \
'Columns = {} \n' \
'Rows = {} \n' \
'From = {} \n' \
'Where = {} \n'.format(ast.select_statement.name,
ast.select_statement.from_,
ast.select_statement.axis_specification_columns,
ast.select_statement.axis_specification_rows,
ast.select_statement.cube_specification,
ast.select_statement.condition_specification,
)
#
grako
#grako
pandas<1
lxml==3.6.0 #lxml 3.7 causes problems in windows
spyne<3
......
......@@ -4,7 +4,6 @@
#
# pip-compile --output-file requirements.txt requirements.in
#
grako==3.99.9
lxml==3.6.0
numpy==1.12.1 # via pandas
pandas==0.20.1
......
from __future__ import absolute_import, division, print_function
import pandas as pd
from pandas.util.testing import assert_frame_equal
from olapy.core.mdx.executor.execute import MdxEngine
from olapy.core.mdx.parser.parse import MdxParser
CUBE = 'sales'
query1 = "SELECT" \
"{[Measures].[Amount]} ON COLUMNS " \
"FROM [sales]"
query2 = """SELECT
{[Geography].[Economy].[Partnership]} ON COLUMNS
FROM [sales]"""
query3 = """SELECT
{[Measures].[Amount]} on 0,
non empty {[Geography].[Geo].[Country].members} ON COLUMNS
FROM [sales]"""
query4 = """SELECT
{[Geography].[Economy].[Partnership]} ON COLUMNS,
non empty {[Geography].[Geo].[Country].members} on 1
from [sales]"""
query5 = """select
{[Geography].[Economy].[Country]} on 0,
non empty {[Geography].[Geo].[Country].members} on 1
from [sales]"""
query6 = """select
{[Geography].[Economy].[Partnership]} on 0,
{[Product].[Prod].[Company]} on 1
from [sales]"""
query7 = """select
{[Geography].[Economy].[Partnership].[EU]} on 0,
{[Product].[Prod].[Company].[Crazy Development]} on 1
from [sales]"""
query8 = """select
{[Geography].[Economy].[Partnership].[EU],
[Geography].[Economy].[Partnership].[None],
[Geography].[Economy].[Partnership].[NAFTA]} on 0,
{[Product].[Prod].[Company].[Crazy Development],
[Product].[Prod].[Company].[Company_test],
[Product].[Prod].[Company].[test_Development]} on 1
from [sales]"""
query9 = """select
{[Geography].[Economy].[Partnership].[EU],
[Geography].[Economy].[Partnership].[None]} on 0
from [sales]"""
query10 = """select
{[Geography].[Geo].[Country].[France],
[Geography].[Geo].[Country].[Spain]} on 0,
non empty {[Measures].[Amount]} on 1
from [sales]"""
where1 = "Where [Time].[Calendar].[Day].[May 12,2010]"
where2 = "Where[Product].[olapy].[Personal]"
where3 = "Where[Time].[Calendar].[Year].[2010]"
where4 = "Where [Measures].[Count]"
where5 = "where [Count]"
query11 = """
SELECT NON EMPTY Hierarchize(AddCalculatedMembers(DrilldownMember({{DrilldownMember({{DrilldownMember({{
[Time].[Time].[Year].Members}}, {
[Time].[Time].[Year].[2010]})}}, {
[Time].[Time].[Quarter].[2010].[Q2 2010]})}}, {
[Time].[Time].[Month].[2010].[Q2 2010].[May 2010]}))) DIMENSION PROPERTIES PARENT_UNIQUE_NAME,HIERARCHY_UNIQUE_NAME
ON COLUMNS
FROM [sales] WHERE ([Measures].[Amount])
CELL PROPERTIES VALUE, FORMAT_STRING, LANGUAGE, BACK_COLOR, FORE_COLOR, FONT_FLAGS
"""
query12 = """SELECT NON EMPTY Hierarchize(AddCalculatedMembers({
[Geography].[Geography].[Continent].Members}))
DIMENSION PROPERTIES PARENT_UNIQUE_NAME,HIERARCHY_UNIQUE_NAME ON COLUMNS
FROM [sales]
WHERE ([Measures].[Amount])
CELL PROPERTIES VALUE, FORMAT_STRING, LANGUAGE, BACK_COLOR, FORE_COLOR, FONT_FLAGS"""
parser = MdxParser()
executer = MdxEngine(CUBE)
def test_parsing_query1():
assert parser.parsing_mdx_query(
'column', query=query1) == ['Measures', 'Amount']
assert parser.parsing_mdx_query('cube', query=query1) == "sales"
assert parser.parsing_mdx_query('row', query=query1) is None
query1_where = query1 + '\n' + where1
assert parser.parsing_mdx_query(
'condition',
query=query1_where) == [u'Time', u'Calendar', u'Day', u'May 12,2010']
query2_where = query1 + '\n' + where2
assert parser.parsing_mdx_query(
'condition', query=query2_where) == [u'Product', u'olapy', u'Personal']
query3_where = query1 + '\n' + where3
assert parser.parsing_mdx_query(
'condition',
query=query3_where) == [u'Time', u'Calendar', u'Year', u'2010']
def test_parsing_query2():
assert parser.parsing_mdx_query(
'column', query=query2) == [u'Geography', u'Economy', u'Partnership']
assert parser.parsing_mdx_query('cube', query=query2) == "sales"
assert parser.parsing_mdx_query('row', query=query2) is None
query1_where = query2 + '\n' + where1
assert parser.parsing_mdx_query(
'condition',
query=query1_where) == [u'Time', u'Calendar', u'Day', u'May 12,2010']
query2_where = query2 + '\n' + where2
assert parser.parsing_mdx_query(
'condition', query=query2_where) == [u'Product', u'olapy', u'Personal']
query3_where = query2 + '\n' + where3
assert parser.parsing_mdx_query(
'condition',
query=query3_where) == [u'Time', u'Calendar', u'Year', u'2010']
def test_parsing_query3():
assert parser.parsing_mdx_query(
'column', query=query3) == [u'Measures', u'Amount']
assert parser.parsing_mdx_query('cube', query=query3) == "sales"
assert parser.parsing_mdx_query(
'row', query=query3) == [u'Geography', u'Geo', u'Country', u'members']
query1_where = query3 + '\n' + where1
assert parser.parsing_mdx_query(
'condition',
query=query1_where) == [u'Time', u'Calendar', u'Day', u'May 12,2010']
query2_where = query3 + '\n' + where2
assert parser.parsing_mdx_query(
'condition', query=query2_where) == [u'Product', u'olapy', u'Personal']
query3_where = query3 + '\n' + where3
assert parser.parsing_mdx_query(
'condition',
query=query3_where) == [u'Time', u'Calendar', u'Year', u'2010']
def test_parsing_query4():
query0 = query4
assert parser.parsing_mdx_query(
'column', query=query0) == [u'Geography', u'Economy', u'Partnership']
assert parser.parsing_mdx_query('cube', query=query0) == "sales"
assert parser.parsing_mdx_query(
'row', query=query0) == [u'Geography', u'Geo', u'Country', u'members']
query1_where = query0 + '\n' + where1
assert parser.parsing_mdx_query(
'condition',
query=query1_where) == [u'Time', u'Calendar', u'Day', u'May 12,2010']
query2_where = query0 + '\n' + where2
assert parser.parsing_mdx_query(
'condition', query=query2_where) == [u'Product', u'olapy', u'Personal']
query3_where = query0 + '\n' + where3
assert parser.parsing_mdx_query(
'condition',
query=query3_where) == [u'Time', u'Calendar', u'Year', u'2010']
def test_parsing_query5():
query0 = query5
assert parser.parsing_mdx_query(
'column', query=query0) == [u'Geography', u'Economy', u'Country']
assert parser.parsing_mdx_query('cube', query=query0) == "sales"
assert parser.parsing_mdx_query(
'row', query=query0) == [u'Geography', u'Geo', u'Country', u'members']
query1_where = query0 + '\n' + where1
assert parser.parsing_mdx_query(
'condition',
query=query1_where) == [u'Time', u'Calendar', u'Day', u'May 12,2010']
query2_where = query0 + '\n' + where2
assert parser.parsing_mdx_query(
'condition', query=query2_where) == [u'Product', u'olapy', u'Personal']
query3_where = query0 + '\n' + where3
assert parser.parsing_mdx_query(
'condition',
query=query3_where) == [u'Time', u'Calendar', u'Year', u'2010']
def test_parsing_query6():
query0 = query6
assert parser.parsing_mdx_query(
'column', query=query0) == [u'Geography', u'Economy', u'Partnership']
assert parser.parsing_mdx_query('cube', query=query0) == "sales"
assert parser.parsing_mdx_query(
'row', query=query0) == [u'Product', u'Prod', u'Company']
query1_where = query0 + '\n' + where1
assert parser.parsing_mdx_query(
'condition',
query=query1_where) == [u'Time', u'Calendar', u'Day', u'May 12,2010']
query2_where = query0 + '\n' + where2
assert parser.parsing_mdx_query(
'condition', query=query2_where) == [u'Product', u'olapy', u'Personal']
query3_where = query0 + '\n' + where3
assert parser.parsing_mdx_query(
'condition',
query=query3_where) == [u'Time', u'Calendar', u'Year', u'2010']
def test_execution_query1():
executer.mdx_query = query1
assert executer.execute_mdx()['result']['Amount'][0] == 1023
executer.mdx_query = query11
assert executer.execute_mdx()['result']['Amount'][3] == 1
assert executer.execute_mdx()['result']['Amount'][4] == 2
def test_execution_query3():
df = pd.DataFrame({
'Continent': ['America', 'Europe'],
'Amount': [768, 255]
}).groupby(['Continent']).sum()
executer.mdx_query = query12
assert assert_frame_equal(df, executer.execute_mdx()['result']) is None
executer.mdx_query = query11
assert list(executer.execute_mdx()['result'][
'Amount']) == [1023, 1023, 1023, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
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