Commit 8ea41cf9 authored by mouadh's avatar mouadh

format docstring

parent 718df38c
...@@ -11,7 +11,7 @@ CUBE_NAME ="temp_cube" ...@@ -11,7 +11,7 @@ CUBE_NAME ="temp_cube"
class CubeGen: class CubeGen:
""" """
Benchmark olapy query execution Benchmark olapy query execution.
:param number_dimensions: number of dimensions to generate (not including fact) :param number_dimensions: number of dimensions to generate (not including fact)
:param rows_length: number of line in each dimension :param rows_length: number of line in each dimension
...@@ -28,7 +28,7 @@ class CubeGen: ...@@ -28,7 +28,7 @@ class CubeGen:
def generate_cube(self, min_val=5, max_val=100): def generate_cube(self, min_val=5, max_val=100):
""" """
Generate dimension and fact that follows star schema Generate dimension and fact that follows star schema.
:param min_val: minimal value in every dimension :param min_val: minimal value in every dimension
:param max_val: maximal value in every dimension :param max_val: maximal value in every dimension
...@@ -52,10 +52,10 @@ class CubeGen: ...@@ -52,10 +52,10 @@ class CubeGen:
@staticmethod @staticmethod
def generate_csv(tables): def generate_csv(tables):
""" """
generate csv files for the generated DataFrames Generate csv files for the generated DataFrames.
:param tables: dict of DataFrames :param tables: dict of DataFrames
""" """
cube_path = os.path.join( cube_path = os.path.join(
os.path.abspath( os.path.abspath(
os.path.join(os.path.dirname(__file__), "..")), MdxEngine.CUBE_FOLDER) os.path.join(os.path.dirname(__file__), "..")), MdxEngine.CUBE_FOLDER)
...@@ -67,9 +67,7 @@ class CubeGen: ...@@ -67,9 +67,7 @@ class CubeGen:
@staticmethod @staticmethod
def remove_temp_cube(): def remove_temp_cube():
""" """Remove the temporary cube."""
remove the temporary cube
"""
cube_path = os.path.join( cube_path = os.path.join(
os.path.abspath( os.path.abspath(
os.path.join(os.path.dirname(__file__), "..")), MdxEngine.CUBE_FOLDER) os.path.join(os.path.dirname(__file__), "..")), MdxEngine.CUBE_FOLDER)
......
...@@ -4,17 +4,15 @@ from cube_generator import CUBE_NAME ...@@ -4,17 +4,15 @@ from cube_generator import CUBE_NAME
class MicBench: class MicBench:
""" """Micro Benchmark for an mdx query."""
Micro Benchmark for an mdx query
"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
@staticmethod @staticmethod
def bench(connection, query, cube=CUBE_NAME, number=1): def bench(connection, query, cube=CUBE_NAME, number=1):
""" """
To be precise, this executes the query statement once, and To be precise, this executes the query statement once, and then returns the time it takes to execute.
then returns the time it takes to execute
:param connection: connection object :param connection: connection object
:param query: MDX query :param query: MDX query
......
...@@ -6,11 +6,12 @@ from core.services.xmla import start_server ...@@ -6,11 +6,12 @@ from core.services.xmla import start_server
def main(arg): def main(arg):
''' """
Execute xmla provider Execute xmla provider.
:param arg: -c | --console : show logs in server console :param arg: -c | --console : show logs in server console
:return: :return:
''' """
if len(arg) > 1: if len(arg) > 1:
if arg[1] in ("-c", "--console"): if arg[1] in ("-c", "--console"):
start_server(write_on_file=False) start_server(write_on_file=False)
......
...@@ -20,11 +20,14 @@ RUNNING_TOX = 'RUNNING_TOX' in os.environ ...@@ -20,11 +20,14 @@ RUNNING_TOX = 'RUNNING_TOX' in os.environ
class MdxEngine: class MdxEngine:
""" """
The principal class for executing a query The principal class for executing a query.
:param cube_name: It must be under home_directory/olapy-data/CUBE_FOLDER (example : home_directory/olapy-data/cubes/sales) :param cube_name: It must be under home_directory/olapy-data/CUBE_FOLDER (example : home_directory/olapy-data/cubes/sales)
:param cube_folder: parent cube folder name
:param mdx_query: query to execute
:param sep: separator in the csv files
""" """
CUBE_FOLDER = "cubes" CUBE_FOLDER = "cubes"
# (before instantiate MdxEngine I need to access cubes information) # (before instantiate MdxEngine I need to access cubes information)
csv_files_cubes = [] csv_files_cubes = []
...@@ -39,13 +42,6 @@ class MdxEngine: ...@@ -39,13 +42,6 @@ class MdxEngine:
cube_folder=CUBE_FOLDER, cube_folder=CUBE_FOLDER,
sep=';', sep=';',
fact_table_name="Facts"): fact_table_name="Facts"):
'''
:param cube_folder: parent cube folder name
:param mdx_query: query to execute
:param sep: separator in the csv files
'''
self.cube_folder = cube_folder self.cube_folder = cube_folder
self.cube = cube_name self.cube = cube_name
self.sep = sep self.sep = sep
...@@ -70,10 +66,7 @@ class MdxEngine: ...@@ -70,10 +66,7 @@ class MdxEngine:
@classmethod @classmethod
def get_cubes_names(cls): def get_cubes_names(cls):
''' """:return: list cubes name that exists in cubes folder (under ~/olapy-data/cubes) and postgres database (if connected)."""
:return: list cubes name that exists in cubes folder (under ~/olapy-data/cubes) and postgres database (if connected)
'''
# get csv files folders (cubes) # get csv files folders (cubes)
# toxworkdir does not expanduser properly under tox # toxworkdir does not expanduser properly under tox
if RUNNING_TOX: if RUNNING_TOX:
...@@ -121,7 +114,7 @@ class MdxEngine: ...@@ -121,7 +114,7 @@ class MdxEngine:
def _get_tables_name(self): def _get_tables_name(self):
""" """
get all tables names Get all tables names.
:return: list tables names :return: list tables names
""" """
...@@ -129,11 +122,11 @@ class MdxEngine: ...@@ -129,11 +122,11 @@ class MdxEngine:
def _load_table_config_file(self, cube_obj): def _load_table_config_file(self, cube_obj):
""" """
load tables from config file Load tables from config file.
:param cube_obj: cubes object :param cube_obj: cubes object
:return: tables dict with table name as key and DataFrame as value :return: tables dict with table name as key and DataFrame as value
""" """
tables = {} tables = {}
# just one facts table right now # just one facts table right now
self.facts = cube_obj.facts[0].table_name self.facts = cube_obj.facts[0].table_name
...@@ -159,10 +152,10 @@ class MdxEngine: ...@@ -159,10 +152,10 @@ class MdxEngine:
def _load_tables_csv_files(self): def _load_tables_csv_files(self):
""" """
load tables from csv files Load tables from csv files.
:return: tables dict with table name as key and dataframe as value :return: tables dict with table name as key and dataframe as value
""" """
tables = {} tables = {}
cube = self.get_cube() cube = self.get_cube()
for file in os.listdir(cube): for file in os.listdir(cube):
...@@ -177,10 +170,10 @@ class MdxEngine: ...@@ -177,10 +170,10 @@ class MdxEngine:
def _load_tables_db(self): def _load_tables_db(self):
""" """
load tables from database Load tables from database.
:return: tables dict with table name as key and dataframe as value :return: tables dict with table name as key and dataframe as value
""" """
tables = {} tables = {}
db = MyDB(db=self.cube) db = MyDB(db=self.cube)
cursor = db.connection.cursor() cursor = db.connection.cursor()
...@@ -198,11 +191,10 @@ class MdxEngine: ...@@ -198,11 +191,10 @@ class MdxEngine:
def load_tables(self): def load_tables(self):
""" """
load all tables { Table name : DataFrame } of the current cube instance Load all tables { Table name : DataFrame } of the current cube instance.
:return: dict with key as table name and DataFrame as value :return: dict with key as table name and DataFrame as value
""" """
config_file_parser = ConfigParser(self.cube_path) config_file_parser = ConfigParser(self.cube_path)
tables = {} tables = {}
if config_file_parser.config_file_exist( if config_file_parser.config_file_exist(
...@@ -222,10 +214,7 @@ class MdxEngine: ...@@ -222,10 +214,7 @@ class MdxEngine:
return tables return tables
def get_measures(self): def get_measures(self):
""" """:return: all numerical columns in facts table."""
:return: all numerical columns in facts table
"""
# col.lower()[-2:] != 'id' to ignore any id column # col.lower()[-2:] != 'id' to ignore any id column
return [ return [
col col
...@@ -235,12 +224,12 @@ class MdxEngine: ...@@ -235,12 +224,12 @@ class MdxEngine:
def _construct_star_schema_config_file(self, cube_name, cubes_obj): def _construct_star_schema_config_file(self, cube_name, cubes_obj):
""" """
Construct star schema DataFrame from configuration file Construct star schema DataFrame from configuration file.
:param cube_name: cube name (or database name) :param cube_name: cube name (or database name)
:param cubes_obj: cubes object :param cubes_obj: cubes object
:return: star schema DataFrame :return: star schema DataFrame
""" """
self.facts = cubes_obj.facts[0].table_name self.facts = cubes_obj.facts[0].table_name
db = MyDB(db=cube_name) db = MyDB(db=cube_name)
# load facts table # load facts table
...@@ -271,11 +260,11 @@ class MdxEngine: ...@@ -271,11 +260,11 @@ class MdxEngine:
def _construct_star_schema_csv_files(self, cube_name): def _construct_star_schema_csv_files(self, cube_name):
""" """
Construct star schema DataFrame from csv files Construct star schema DataFrame from csv files.
:param cube_name: cube name (folder name) :param cube_name: cube name (folder name)
:return: star schema DataFrame :return: star schema DataFrame
""" """
cube = self.get_cube() cube = self.get_cube()
# loading facts table # loading facts table
fusion = pd.read_csv( fusion = pd.read_csv(
...@@ -292,11 +281,11 @@ class MdxEngine: ...@@ -292,11 +281,11 @@ class MdxEngine:
def _construct_star_schema_db(self, cube_name): def _construct_star_schema_db(self, cube_name):
""" """
Construct star schema DataFrame from database Construct star schema DataFrame from database.
:param cube_name: cube name (database name) :param cube_name: cube name (database name)
:return: star schema DataFrame :return: star schema DataFrame
""" """
db = MyDB(db=cube_name) db = MyDB(db=cube_name)
# load facts table # load facts table
...@@ -319,12 +308,11 @@ class MdxEngine: ...@@ -319,12 +308,11 @@ class MdxEngine:
def get_star_schema_dataframe(self, cube_name): def get_star_schema_dataframe(self, cube_name):
""" """
merge all DataFrames as star schema Merge all DataFrames as star schema.
:param cube_name: cube name with which we want to generate a star schema model :param cube_name: cube name with which we want to generate a star schema model
:return: star schema DataFrame :return: star schema DataFrame
""" """
fusion = None fusion = None
config_file_parser = ConfigParser(self.cube_path) config_file_parser = ConfigParser(self.cube_path)
...@@ -348,7 +336,7 @@ class MdxEngine: ...@@ -348,7 +336,7 @@ class MdxEngine:
def get_all_tables_names(self, ignore_fact=False): def get_all_tables_names(self, ignore_fact=False):
""" """
get list of tables names of the cube Get list of tables names of the cube.
:param ignore_fact: return all table name with facts table name :param ignore_fact: return all table name with facts table name
:return: all tables names :return: all tables names
...@@ -359,7 +347,7 @@ class MdxEngine: ...@@ -359,7 +347,7 @@ class MdxEngine:
def get_cube(self): def get_cube(self):
""" """
get path to the cube (example /home_directory/olapy-data/cubes) Get path to the cube (example /home_directory/olapy-data/cubes).
:return: path to the cube :return: path to the cube
""" """
...@@ -369,7 +357,7 @@ class MdxEngine: ...@@ -369,7 +357,7 @@ class MdxEngine:
@staticmethod @staticmethod
def get_tuples(query, start=None, stop=None): def get_tuples(query, start=None, stop=None):
""" """
get all tuples in the mdx query Get all tuples in the mdx query.
example:: example::
...@@ -399,7 +387,6 @@ class MdxEngine: ...@@ -399,7 +387,6 @@ class MdxEngine:
:param stop: key-word in the query where we stop (examples start = ON ROWS) :param stop: key-word in the query where we stop (examples start = ON ROWS)
:return: nested list of tuples (see the example) :return: nested list of tuples (see the example)
""" """
# french characters # french characters
# or use new regex 2017.02.08 # or use new regex 2017.02.08
regex = "(\[[\w+\d ]+\](\.\[[\w+\d\.\,\s\_\-\é\ù\è\ù\û\ü\ÿ\\\à\â\æ\ç\é\è\ê\ë\ï\î" \ regex = "(\[[\w+\d ]+\](\.\[[\w+\d\.\,\s\_\-\é\ù\è\ù\û\ü\ÿ\\\à\â\æ\ç\é\è\ê\ë\ï\î" \
...@@ -422,12 +409,11 @@ class MdxEngine: ...@@ -422,12 +409,11 @@ class MdxEngine:
# TODO temporary function # TODO temporary function
def decorticate_query(self, query): def decorticate_query(self, query):
""" """
get all tuples that exists in the MDX Query by axes Get all tuples that exists in the MDX Query by axes.
:param query: MDX Query :param query: MDX Query
:return: dict of axis as key and tuples as value :return: dict of axis as key and tuples as value
""" """
tuples_on_mdx_query = self.get_tuples(query) tuples_on_mdx_query = self.get_tuples(query)
on_rows = [] on_rows = []
on_columns = [] on_columns = []
...@@ -468,7 +454,7 @@ class MdxEngine: ...@@ -468,7 +454,7 @@ class MdxEngine:
@staticmethod @staticmethod
def change_measures(tuples_on_mdx): def change_measures(tuples_on_mdx):
""" """
set measures to which exists in the query Set measures to which exists in the query.
:param tuples_on_mdx: list of tuples: :param tuples_on_mdx: list of tuples:
...@@ -478,7 +464,6 @@ class MdxEngine: ...@@ -478,7 +464,6 @@ class MdxEngine:
:return: measures column's names :return: measures column's names
""" """
return [ return [
tple[-1] for tple in tuples_on_mdx if tple[0].upper() == "MEASURES" tple[-1] for tple in tuples_on_mdx if tple[0].upper() == "MEASURES"
] ]
...@@ -486,8 +471,7 @@ class MdxEngine: ...@@ -486,8 +471,7 @@ class MdxEngine:
def get_tables_and_columns(self, tuple_as_list): def get_tables_and_columns(self, tuple_as_list):
# TODO update docstring # TODO update docstring
""" """
get used dimensions and columns in the MDX Query (useful for DataFrame -> xmla response transformation) Get used dimensions and columns in the MDX Query (useful for DataFrame -> xmla response transformation).
:param tuple_as_list: list of tuples :param tuple_as_list: list of tuples
...@@ -502,7 +486,6 @@ class MdxEngine: ...@@ -502,7 +486,6 @@ class MdxEngine:
Facts : ['Amount','Count'] Facts : ['Amount','Count']
} }
""" """
axes = {} axes = {}
# TODO optimize # TODO optimize
for axis, tuples in tuple_as_list.items(): for axis, tuples in tuple_as_list.items():
...@@ -530,9 +513,7 @@ class MdxEngine: ...@@ -530,9 +513,7 @@ class MdxEngine:
def execute_one_tuple(self, tuple_as_list, Dataframe_in, columns_to_keep): def execute_one_tuple(self, tuple_as_list, Dataframe_in, columns_to_keep):
""" """
Filter a DataFrame (Dataframe_in) with one tuple.
filter a DataFrame (Dataframe_in) with one tuple
Example :: Example ::
...@@ -591,7 +572,7 @@ class MdxEngine: ...@@ -591,7 +572,7 @@ class MdxEngine:
@staticmethod @staticmethod
def add_missed_column(dataframe1, dataframe2): def add_missed_column(dataframe1, dataframe2):
""" """
solution to fix BUG : https://github.com/pandas-dev/pandas/issues/15525 Solution to fix BUG : https://github.com/pandas-dev/pandas/issues/15525
if you want to concat two dataframes with different columns like : if you want to concat two dataframes with different columns like :
...@@ -671,7 +652,7 @@ class MdxEngine: ...@@ -671,7 +652,7 @@ class MdxEngine:
def update_columns_to_keep(self, tuple_as_list, columns_to_keep): def update_columns_to_keep(self, tuple_as_list, columns_to_keep):
""" """
if we have multiple dimensions, with many columns like: If we have multiple dimensions, with many columns like:
columns_to_keep : columns_to_keep :
...@@ -717,7 +698,6 @@ class MdxEngine: ...@@ -717,7 +698,6 @@ class MdxEngine:
:return: updated columns_to_keep :return: updated columns_to_keep
""" """
if len( if len(
tuple_as_list tuple_as_list
) == 3 and tuple_as_list[-1] in self.tables_loaded[tuple_as_list[0]].columns: ) == 3 and tuple_as_list[-1] in self.tables_loaded[tuple_as_list[0]].columns:
...@@ -731,7 +711,7 @@ class MdxEngine: ...@@ -731,7 +711,7 @@ class MdxEngine:
def execute_mdx(self): def execute_mdx(self):
""" """
execute an MDX Query Execute an MDX Query.
usage :: usage ::
...@@ -747,7 +727,6 @@ class MdxEngine: ...@@ -747,7 +727,6 @@ class MdxEngine:
} }
""" """
# use measures that exists on where or insides axes # use measures that exists on where or insides axes
query_axes = self.decorticate_query(self.mdx_query) query_axes = self.decorticate_query(self.mdx_query)
if self.change_measures(query_axes['all']): if self.change_measures(query_axes['all']):
......
...@@ -7,15 +7,12 @@ from .gen_parser.models import SelectStatement ...@@ -7,15 +7,12 @@ from .gen_parser.models import SelectStatement
class MdxParser: class MdxParser:
""" """Parse the mdx query and split it into well-defined parts."""
parse the mdx query and split it into well-defined parts
"""
START = 'MDX_statement' START = 'MDX_statement'
@staticmethod @staticmethod
def parsing_mdx_query(axis, query): def parsing_mdx_query(axis, query):
''' """Split the query into axis.
Split the query into axis
**Example**:: **Example**::
...@@ -47,7 +44,7 @@ class MdxParser: ...@@ -47,7 +44,7 @@ class MdxParser:
:param query: MDX Query :param query: MDX Query
:param axis: column | row | cube | condition | all :param axis: column | row | cube | condition | all
:return: Tuples in the axis, from the MDX query :return: Tuples in the axis, from the MDX query
''' """
model = MdxParserGen(semantics=ModelBuilderSemantics( model = MdxParserGen(semantics=ModelBuilderSemantics(
types=[SelectStatement])) types=[SelectStatement]))
ast = model.parse(query, rule_name=MdxParser.START, ignorecase=True) ast = model.parse(query, rule_name=MdxParser.START, ignorecase=True)
......
...@@ -9,7 +9,7 @@ from .models import Cube, Dimension, Facts ...@@ -9,7 +9,7 @@ from .models import Cube, Dimension, Facts
class ConfigParser: class ConfigParser:
""" """
Parse olapy config files Parse olapy config files.
Config file used if you want to show only some measures, dimensions, columns... in excel Config file used if you want to show only some measures, dimensions, columns... in excel
...@@ -114,7 +114,6 @@ class ConfigParser: ...@@ -114,7 +114,6 @@ class ConfigParser:
</cubes> </cubes>
""" """
def __init__(self, cube_path, file_name='cubes-config.xml'): def __init__(self, cube_path, file_name='cubes-config.xml'):
""" """
...@@ -126,7 +125,7 @@ class ConfigParser: ...@@ -126,7 +125,7 @@ class ConfigParser:
def config_file_exist(self): def config_file_exist(self):
""" """
check whether the config file exists or not Check whether the config file exists or not.
:return: True | False :return: True | False
""" """
...@@ -134,11 +133,10 @@ class ConfigParser: ...@@ -134,11 +133,10 @@ class ConfigParser:
def xmla_authentication(self): def xmla_authentication(self):
""" """
check if excel need authentication to access cubes or not. (xmla_authentication tag in the config file) Check if excel need authentication to access cubes or not. (xmla_authentication tag in the config file).
:return: True | False :return: True | False
""" """
with open(os.path.join(self.cube_path, self.file_name)) as config_file: with open(os.path.join(self.cube_path, self.file_name)) as config_file:
parser = etree.XMLParser() parser = etree.XMLParser()
...@@ -152,11 +150,10 @@ class ConfigParser: ...@@ -152,11 +150,10 @@ class ConfigParser:
def get_cubes_names(self): def get_cubes_names(self):
""" """
get all cubes names in the config file Get all cubes names in the config file.
:return: dict of cube name as key and cube source as value (csv or postgres) (right now only postgres is supported) :return: dict of cube name as key and cube source as value (csv or postgres) (right now only postgres is supported)
""" """
with open(os.path.join(self.cube_path, self.file_name)) as config_file: with open(os.path.join(self.cube_path, self.file_name)) as config_file:
parser = etree.XMLParser() parser = etree.XMLParser()
...@@ -172,11 +169,10 @@ class ConfigParser: ...@@ -172,11 +169,10 @@ class ConfigParser:
def construct_cubes(self): def construct_cubes(self):
""" """
construct cube (with it dimensions) and facts from the config file Construct cube (with it dimensions) and facts from the config file.
:return: list of Cubes instance :return: list of Cubes instance
""" """
if self.config_file_exist(): if self.config_file_exist():
try: try:
with open(os.path.join(self.cube_path, with open(os.path.join(self.cube_path,
......
...@@ -2,10 +2,7 @@ import psycopg2 as pg ...@@ -2,10 +2,7 @@ import psycopg2 as pg
class MyDB(object): class MyDB(object):
""" """Connect to sql database (postgres only right now)."""
Connect to sql database (postgres only right now)
"""
def __init__(self, def __init__(self,
username='postgres', username='postgres',
password='root', password='root',
......
class Facts: class Facts:
""" """Facts class used to encapsulate config file attributes."""
Facts class used to encapsulate config file attributes
"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
""" """
...@@ -23,31 +21,24 @@ class Facts: ...@@ -23,31 +21,24 @@ class Facts:
class Dimension: class Dimension:
""" """Dimension class used to encapsulate config file attributes."""
Dimension class used to encapsulate config file attributes
"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
""" """
:param kwargs: { :param kwargs: {
name : 'something', name : 'something',
displayName : 'something', displayName : 'something',
columns : columns :
{ name : 'something' } { name : 'something' }
} }
""" """
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
def __str__(self): def __str__(self):
return str(self.__dict__) return str(self.__dict__)
class Cube: class Cube:
""" """Cube class used to encapsulate config file attributes."""
Cube class used to encapsulate config file attributes
"""
def __init__(self, **kwargs): def __init__(self, **kwargs):
""" """
......
...@@ -9,9 +9,7 @@ from spyne import ComplexModel, Integer, Unicode, XmlAttribute ...@@ -9,9 +9,7 @@ from spyne import ComplexModel, Integer, Unicode, XmlAttribute
# thus xmla requests from excel can be reached # thus xmla requests from excel can be reached
class Tuple(object): class Tuple(object):
""" """Tuple description (used by spyne)."""
Tuple description (used by spyne)
"""
def __init__(self, Hierarchy, UName, Caption, LName, LNum, DisplayInfo, def __init__(self, Hierarchy, UName, Caption, LName, LNum, DisplayInfo,
PARENT_UNIQUE_NAME, HIERARCHY_UNIQUE_NAME, Value): PARENT_UNIQUE_NAME, HIERARCHY_UNIQUE_NAME, Value):
...@@ -42,9 +40,8 @@ class Tuple(object): ...@@ -42,9 +40,8 @@ class Tuple(object):
class Property(ComplexModel): class Property(ComplexModel):
""" """Property description (used by spyne)."""
Property description (used by spyne)
"""
__namespace__ = "urn:schemas-microsoft-com:xml-analysis" __namespace__ = "urn:schemas-microsoft-com:xml-analysis"
_type_info = { _type_info = {
'LocaleIdentifier': Unicode, 'LocaleIdentifier': Unicode,
...@@ -67,9 +64,8 @@ class Property(ComplexModel): ...@@ -67,9 +64,8 @@ class Property(ComplexModel):
class Restriction(ComplexModel): class Restriction(ComplexModel):
""" """Restriction description (used by spyne)."""
Restriction description (used by spyne)
"""
__namespace__ = "urn:schemas-microsoft-com:xml-analysis" __namespace__ = "urn:schemas-microsoft-com:xml-analysis"
_type_info = { _type_info = {
'CATALOG_NAME': Unicode, 'CATALOG_NAME': Unicode,
...@@ -89,50 +85,44 @@ class Restriction(ComplexModel): ...@@ -89,50 +85,44 @@ class Restriction(ComplexModel):
class Session(ComplexModel): class Session(ComplexModel):
""" """Session description (used by spyne)."""
Session description (used by spyne)
"""
__namespace__ = "urn:schemas-microsoft-com:xml-analysis" __namespace__ = "urn:schemas-microsoft-com:xml-analysis"
SessionId = XmlAttribute(Unicode) SessionId = XmlAttribute(Unicode)
class Restrictionlist(ComplexModel): class Restrictionlist(ComplexModel):
""" """Restriction description (used by spyne)."""
Restriction description (used by spyne)
"""
__namespace__ = "urn:schemas-microsoft-com:xml-analysis" __namespace__ = "urn:schemas-microsoft-com:xml-analysis"
__type_name__ = "Restrictions" __type_name__ = "Restrictions"
RestrictionList = Restriction RestrictionList = Restriction
class Propertielist(ComplexModel): class Propertielist(ComplexModel):
""" """Properties description (used by spyne)."""
Properties description (used by spyne)
"""
__namespace__ = "urn:schemas-microsoft-com:xml-analysis" __namespace__ = "urn:schemas-microsoft-com:xml-analysis"
__type_name__ = "Properties" __type_name__ = "Properties"
PropertyList = Property PropertyList = Property
class Command(ComplexModel): class Command(ComplexModel):
""" """Command description (used by spyne)."""
Command description (used by spyne)
"""
_type_info = {'Statement': Unicode,} _type_info = {'Statement': Unicode,}
class ExecuteRequest(ComplexModel): class ExecuteRequest(ComplexModel):
""" """Execute description (used by spyne)."""
Execute description (used by spyne)
"""
Command = Command Command = Command
Properties = Propertielist Properties = Propertielist
class DiscoverRequest(ComplexModel): class DiscoverRequest(ComplexModel):
""" """Discover description (used by spyne)."""
Discover description (used by spyne)
"""
RequestType = Unicode RequestType = Unicode
Restrictions = Restrictionlist Restrictions = Restrictionlist
Properties = Propertielist Properties = Propertielist
...@@ -22,24 +22,21 @@ from .xmla_execute_xsds import execute_xsd ...@@ -22,24 +22,21 @@ from .xmla_execute_xsds import execute_xsd
class XmlaProviderService(ServiceBase): class XmlaProviderService(ServiceBase):
""" """
The main class to active soap services between xmla clients and olapy.
The main class to active soap services between xmla clients and olapy IMPORTANT : all xsd and soap responses are written manually (not generated by Spyne lib)
because Spyne doesn't support encodingStyle and other namespaces required by Excel,
check it <http://stackoverflow.com/questions/25046837/the-encodingstyle-attribute-is-not-allowed-in-spyne>
""" we have to instantiate XmlaDiscoverTools and declare variables
as class variable so we can access them in Discovery and Execute functions
# IMPORTANT : all xsd and soap responses are written manually (not generated by Spyne lib) this problem is related with Spyne architecture, NO CHOICE
# because Spyne doesn't support encodingStyle and other namespaces required by Excel,
# check it <http://stackoverflow.com/questions/25046837/the-encodingstyle-attribute-is-not-allowed-in-spyne>
# we have to instantiate XmlaDiscoverTools and declare variables
# as class variable so we can access them in Discovery and Execute functions
# this problem is related with Spyne architecture, NO CHOICE
# NOTE : some variables and functions names shouldn't respect naming convention here
# because we need to create the xmla response (generated by spyne) with the same variable names,
# and then, xmla requests from excel can be reached
# thus make life easier
NOTE : some variables and functions names shouldn't respect naming convention here
because we need to create the xmla response (generated by spyne) with the same variable names,
and then, xmla requests from excel can be reached
thus make life easier.
"""
discover_tools = XmlaDiscoverTools() discover_tools = XmlaDiscoverTools()
sessio_id = discover_tools.session_id sessio_id = discover_tools.session_id
...@@ -52,7 +49,7 @@ class XmlaProviderService(ServiceBase): ...@@ -52,7 +49,7 @@ class XmlaProviderService(ServiceBase):
_throws=InvalidCredentialsError) _throws=InvalidCredentialsError)
def Discover(ctx, request): def Discover(ctx, request):
""" """
the first principle function of xmla protocol The first principle function of xmla protocol.
:param request: Discover function must take 3 argument ( JUST 3 ! ) RequestType, :param request: Discover function must take 3 argument ( JUST 3 ! ) RequestType,
Restrictions and Properties , we encapsulate them in DiscoverRequest object Restrictions and Properties , we encapsulate them in DiscoverRequest object
...@@ -62,7 +59,6 @@ class XmlaProviderService(ServiceBase): ...@@ -62,7 +59,6 @@ class XmlaProviderService(ServiceBase):
""" """
# ctx is the 'context' parameter used by Spyne # ctx is the 'context' parameter used by Spyne
# (which cause problems when we want to access xmla_provider instantiation variables) # (which cause problems when we want to access xmla_provider instantiation variables)
discover_tools = XmlaProviderService.discover_tools discover_tools = XmlaProviderService.discover_tools
ctx.out_header = Session(SessionId=str(XmlaProviderService.sessio_id)) ctx.out_header = Session(SessionId=str(XmlaProviderService.sessio_id))
...@@ -141,14 +137,13 @@ class XmlaProviderService(ServiceBase): ...@@ -141,14 +137,13 @@ class XmlaProviderService(ServiceBase):
_out_header=Session) _out_header=Session)
def Execute(ctx, request): def Execute(ctx, request):
""" """
the second principle function of xmla protocol The second principle function of xmla protocol.
:param request: Execute function must take 2 argument ( JUST 2 ! ) Command and Properties, :param request: Execute function must take 2 argument ( JUST 2 ! ) Command and Properties,
we encapsulate them in ExecuteRequest object we encapsulate them in ExecuteRequest object
:return: Execute response in xml format :return: Execute response in xml format
""" """
ctx.out_header = Session(SessionId=str(XmlaProviderService.sessio_id)) ctx.out_header = Session(SessionId=str(XmlaProviderService.sessio_id))
if request.Command.Statement == '': if request.Command.Statement == '':
...@@ -229,7 +224,7 @@ wsgi_application = WsgiApplication(application) ...@@ -229,7 +224,7 @@ wsgi_application = WsgiApplication(application)
def start_server(write_on_file=False): def start_server(write_on_file=False):
""" """
start the xmla server Start the xmla server.
:param write_on_file: :param write_on_file:
- False -> server logs will be displayed on console - False -> server logs will be displayed on console
......
...@@ -19,9 +19,7 @@ from .xmla_discover_xsds import ( ...@@ -19,9 +19,7 @@ from .xmla_discover_xsds import (
# TODO clean # TODO clean
class XmlaDiscoverTools(): class XmlaDiscoverTools():
""" """XmlaDiscoverTools for generating xmla discover responses."""
XmlaDiscoverTools for generating xmla discover responses
"""
def __init__(self): def __init__(self):
# right now the catalogue_name and cube name are the same # right now the catalogue_name and cube name are the same
...@@ -36,12 +34,11 @@ class XmlaDiscoverTools(): ...@@ -36,12 +34,11 @@ class XmlaDiscoverTools():
def change_catalogue(self, new_catalogue): def change_catalogue(self, new_catalogue):
""" """
if you change the catalogue (cube) in any request, we have to instantiate the MdxEngine with the new catalogue If you change the catalogue (cube) in any request, we have to instantiate the MdxEngine with the new catalogue.
:param new_catalogue: catalogue name :param new_catalogue: catalogue name
:return: new instance of MdxEngine with new star_schema_DataFrame and other variables :return: new instance of MdxEngine with new star_schema_DataFrame and other variables
""" """
#
if self.selected_catalogue != new_catalogue: if self.selected_catalogue != new_catalogue:
self.selected_catalogue = new_catalogue self.selected_catalogue = new_catalogue
self.executer = MdxEngine(new_catalogue) self.executer = MdxEngine(new_catalogue)
......
...@@ -5,9 +5,7 @@ from collections import OrderedDict ...@@ -5,9 +5,7 @@ from collections import OrderedDict
class XmlaExecuteTools(): class XmlaExecuteTools():
""" """XmlaExecuteTools for generating xmla execute responses."""
XmlaExecuteTools for generating xmla execute responses
"""
def __init__(self, executer): def __init__(self, executer):
self.executer = executer self.executer = executer
...@@ -15,7 +13,7 @@ class XmlaExecuteTools(): ...@@ -15,7 +13,7 @@ class XmlaExecuteTools():
@staticmethod @staticmethod
def split_dataframe(mdx_execution_result): def split_dataframe(mdx_execution_result):
""" """
Split DataFrame into multiple ones by dimension Split DataFrame into multiple ones by dimension.
example:: example::
...@@ -50,7 +48,6 @@ class XmlaExecuteTools(): ...@@ -50,7 +48,6 @@ class XmlaExecuteTools():
:param mdx_execution_result: MdxEngine.execute_mdx() result :param mdx_execution_result: MdxEngine.execute_mdx() result
:return: dict with multiple DataFrame :return: dict with multiple DataFrame
""" """
# TODO new version with facts as splited df maybe # TODO new version with facts as splited df maybe
return OrderedDict( return OrderedDict(
(key, mdx_execution_result['result'].reset_index()[list(value)]) (key, mdx_execution_result['result'].reset_index()[list(value)])
...@@ -60,7 +57,7 @@ class XmlaExecuteTools(): ...@@ -60,7 +57,7 @@ class XmlaExecuteTools():
@staticmethod @staticmethod
def get_tuple_without_nan(tuple): def get_tuple_without_nan(tuple):
""" """
remove nan from tuple. Remove nan from tuple.
example: example:
...@@ -84,6 +81,7 @@ class XmlaExecuteTools(): ...@@ -84,6 +81,7 @@ class XmlaExecuteTools():
mdx_query_axis='all', mdx_query_axis='all',
axis="Axis0"): axis="Axis0"):
""" """
:param mdx_execution_result: :param mdx_execution_result:
:param splited_df: :param splited_df:
:return: :return:
...@@ -285,7 +283,7 @@ class XmlaExecuteTools(): ...@@ -285,7 +283,7 @@ class XmlaExecuteTools():
# TODO maybe fusion with generate xs0 for less iteration # TODO maybe fusion with generate xs0 for less iteration
def generate_cell_data(self, mdx_execution_result): def generate_cell_data(self, mdx_execution_result):
""" """
examle of CellData:: Examle of CellData::
<Cell CellOrdinal="0"> <Cell CellOrdinal="0">
<Value xsi:type="xsi:long">768</Value> <Value xsi:type="xsi:long">768</Value>
...@@ -338,7 +336,7 @@ class XmlaExecuteTools(): ...@@ -338,7 +336,7 @@ class XmlaExecuteTools():
def generate_axes_info_slicer(self, mdx_execution_result): def generate_axes_info_slicer(self, mdx_execution_result):
""" """
Not used dimensions Not used dimensions.
example AxisInfo:: example AxisInfo::
...@@ -365,7 +363,6 @@ class XmlaExecuteTools(): ...@@ -365,7 +363,6 @@ class XmlaExecuteTools():
:param mdx_execution_result: mdx_execute() result :param mdx_execution_result: mdx_execute() result
:return: AxisInfo as string :return: AxisInfo as string
""" """
all_dimensions_names = self.executer.get_all_tables_names( all_dimensions_names = self.executer.get_all_tables_names(
ignore_fact=True) ignore_fact=True)
all_dimensions_names.append('Measures') all_dimensions_names.append('Measures')
...@@ -413,7 +410,7 @@ class XmlaExecuteTools(): ...@@ -413,7 +410,7 @@ class XmlaExecuteTools():
mdx_query_axis='columns', mdx_query_axis='columns',
Axis='Axis0'): Axis='Axis0'):
""" """
example AxisInfo:: Example AxisInfo::
<AxesInfo> <AxesInfo>
...@@ -445,7 +442,6 @@ class XmlaExecuteTools(): ...@@ -445,7 +442,6 @@ class XmlaExecuteTools():
:param Axis: Axis0 or Axis1 (Axis0 by default) :param Axis: Axis0 or Axis1 (Axis0 by default)
:return: :return:
""" """
hierarchy_info = "" hierarchy_info = ""
# measure must be written at the top # measure must be written at the top
if self.executer.facts in mdx_execution_result['columns_desc'][mdx_query_axis].keys( if self.executer.facts in mdx_execution_result['columns_desc'][mdx_query_axis].keys(
...@@ -488,10 +484,10 @@ class XmlaExecuteTools(): ...@@ -488,10 +484,10 @@ class XmlaExecuteTools():
def generate_axes_info(self, mdx_execution_result): def generate_axes_info(self, mdx_execution_result):
""" """
:param mdx_execution_result: mdx_execute() result :param mdx_execution_result: mdx_execute() result
:return: AxisInfo as string :return: AxisInfo as string
""" """
if mdx_execution_result['columns_desc']['rows']: if mdx_execution_result['columns_desc']['rows']:
return """ return """
{0} {0}
...@@ -520,7 +516,7 @@ class XmlaExecuteTools(): ...@@ -520,7 +516,7 @@ class XmlaExecuteTools():
def generate_slicer_axis(self, mdx_execution_result): def generate_slicer_axis(self, mdx_execution_result):
""" """
example SlicerAxis:: Example SlicerAxis::
<Axis name="SlicerAxis"> <Axis name="SlicerAxis">
......
...@@ -9,19 +9,17 @@ from ..core.mdx.parser.parse import MdxParser ...@@ -9,19 +9,17 @@ from ..core.mdx.parser.parse import MdxParser
class QueryForm(Form): class QueryForm(Form):
""" """Query Form."""
Query Form
"""
mdx = TextAreaField( mdx = TextAreaField(
"MDX Query", "MDX Query",
validators=[DataRequired(message="Please enter the MDX Query")]) validators=[DataRequired(message="Please enter the MDX Query")])
def validate(self): def validate(self):
""" """Valide.
Valide
:return: :return:
""" """
parser = MdxParser() parser = MdxParser()
if self.mdx.data: if self.mdx.data:
try: try:
...@@ -39,9 +37,8 @@ class QueryForm(Form): ...@@ -39,9 +37,8 @@ class QueryForm(Form):
class LoginForm(Form): class LoginForm(Form):
""" """Loging Form."""
Loging Form
"""
username = StringField( username = StringField(
'Your username:', 'Your username:',
validators=[DataRequired(message="Please enter the Username")]) validators=[DataRequired(message="Please enter the Username")])
......
...@@ -7,9 +7,7 @@ from os.path import expanduser ...@@ -7,9 +7,7 @@ from os.path import expanduser
class Logs: class Logs:
""" """Class responsible of managing logs (users , mdx and xmla logs)."""
class responsible of managing logs (users , mdx and xmla logs)
"""
def __init__(self, file_name): def __init__(self, file_name):
self.file_name = file_name + ".log" self.file_name = file_name + ".log"
......
...@@ -4,9 +4,7 @@ import six ...@@ -4,9 +4,7 @@ import six
class IFrame(object): class IFrame(object):
""" """Frame in which we can drag and drop our columns."""
Frame in which we can drag and drop our columns
"""
iframe = """ iframe = """
<iframe <iframe
...@@ -20,7 +18,7 @@ class IFrame(object): ...@@ -20,7 +18,7 @@ class IFrame(object):
def __init__(self, src, width, height, **kwargs): def __init__(self, src, width, height, **kwargs):
""" """
IFrame Iframe
:param src: :param src:
:param width: :param width:
:param height: :param height:
...@@ -32,7 +30,7 @@ class IFrame(object): ...@@ -32,7 +30,7 @@ class IFrame(object):
self.params = kwargs self.params = kwargs
def _repr_html_(self): def _repr_html_(self):
"""return the embed iframe""" """return the embed iframe."""
if self.params: if self.params:
# try: # try:
# from urllib.parse import urlencode # Py 3 # from urllib.parse import urlencode # Py 3
...@@ -112,7 +110,7 @@ template = """ ...@@ -112,7 +110,7 @@ template = """
def pivot_ui(df, outfile_path="pivottablejs.html", width="100%", height="500"): def pivot_ui(df, outfile_path="pivottablejs.html", width="100%", height="500"):
""" """
Create pivot table html page relative to DataFrame Create pivot table html page relative to DataFrame.
:param df: the DataFrame :param df: the DataFrame
:param outfile_path: html page name (can be the path also) :param outfile_path: html page name (can be the path also)
......
...@@ -8,20 +8,17 @@ import plotly.graph_objs as go ...@@ -8,20 +8,17 @@ import plotly.graph_objs as go
class Graphs: class Graphs:
""" """Manage graphs for the web clients."""
Manage graphs for the web clients
"""
# TODO remove this , ( right know this is just a demo with sales cube ) # TODO remove this , ( right know this is just a demo with sales cube )
@staticmethod @staticmethod
def generate_graphes(dataframe): def generate_graphes(dataframe):
""" """
Generate graphs for a pandas DataFrame, if you want to add graphs, you have to do it in this function Generate graphs for a pandas DataFrame, if you want to add graphs, you have to do it in this function.
:param dataframe: the DataFrame :param dataframe: the DataFrame
:return: dict of ids as keys and json graphs as values :return: dict of ids as keys and json graphs as values
""" """
x = [] x = []
x_pie = [] x_pie = []
y = [] y = []
......
...@@ -35,9 +35,7 @@ log_mdx = Logs('mdx') ...@@ -35,9 +35,7 @@ log_mdx = Logs('mdx')
class Nod: class Nod:
""" """Class for maintaining dimensions hierarchies."""
class for maintaining dimensions hierarchies
"""
def __init__(self, text, id, parent): def __init__(self, text, id, parent):
self.text = text self.text = text
...@@ -52,7 +50,7 @@ class Nod: ...@@ -52,7 +50,7 @@ class Nod:
def generate_tree_levels(): def generate_tree_levels():
""" """
build table's levels to use them in the page's TreeView Build table's levels to use them in the page's TreeView.
:return: dict of levels :return: dict of levels
""" """
...@@ -92,7 +90,7 @@ def generate_tree_levels(): ...@@ -92,7 +90,7 @@ def generate_tree_levels():
@login_manager.user_loader @login_manager.user_loader
def load_user(userid): def load_user(userid):
""" """
load user with specific id Load user with specific id.
:param userid: user id :param userid: user id
:return: user :return: user
......
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