Commit ce60e53b authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Apply pulint rules on report_objects.py.

parent fa3ebedf
...@@ -3,17 +3,17 @@ ...@@ -3,17 +3,17 @@
""" """
import json import json
import matplotlib import matplotlib
import pandas as pd
import re import re
from datetime import date, timedelta
from gluon import current from gluon import current
from gluon.dal import Field, FieldVirtual, smart_query from gluon.dal import FieldVirtual, smart_query
from gluon.storage import Storage from gluon.storage import Storage
from pandas import DataFrame, MultiIndex, to_datetime
from plugin_dbui import get_id, Store from plugin_dbui import get_id, Store
from StringIO import StringIO from StringIO import StringIO
MSG_NO_DATAINDEX = "The property dataIndex is required when eval is used." MSG_NO_DATAINDEX = "The property dataIndex is required when eval is used."
MSG_NO_XTYPE = "The property xtype is missing." MSG_NO_XTYPE = "The property xtype is missing."
...@@ -132,7 +132,8 @@ def split_dbfield(value): ...@@ -132,7 +132,8 @@ def split_dbfield(value):
return tuple(li) return tuple(li)
class ReportException(BaseException): pass class ReportException(BaseException):
pass
class BaseReport(object): class BaseReport(object):
...@@ -178,7 +179,6 @@ class BaseReport(object): ...@@ -178,7 +179,6 @@ class BaseReport(object):
q_conditions = smart_query(db.history, config.conditions) q_conditions = smart_query(db.history, config.conditions)
selector.append_query(q_conditions) selector.append_query(q_conditions)
def _do_data(self, maps): def _do_data(self, maps):
"""Build a temporarily list with the raw data for each series. """Build a temporarily list with the raw data for each series.
This method handle the "year" database field. This method handle the "year" database field.
...@@ -192,7 +192,6 @@ class BaseReport(object): ...@@ -192,7 +192,6 @@ class BaseReport(object):
""" """
data = [] data = []
config = self.config
db = self.db db = self.db
selector = self.selector selector = self.selector
...@@ -219,18 +218,17 @@ class BaseReport(object): ...@@ -219,18 +218,17 @@ class BaseReport(object):
selector.set_year(year) selector.set_year(year)
for row in db(query(db.history)).select(*dbfields): for row in db(query(db.history)).select(*dbfields):
values = [get_value(row, *map, year=year) for map in maps] values = [get_value(row, *elt, year=year) for elt in maps]
data.append(values) data.append(values)
# standard scan # standard scan
else: else:
for row in db(query(db.history)).select(*dbfields): for row in db(query(db.history)).select(*dbfields):
values = [get_value(row, *map) for map in maps] values = [get_value(row, *elt) for elt in maps]
data.append(values) data.append(values)
return data return data
def _is_year(self, maps): def _is_year(self, maps):
""" """
@type maps: list @type maps: list
...@@ -244,7 +242,6 @@ class BaseReport(object): ...@@ -244,7 +242,6 @@ class BaseReport(object):
li = [True for el in maps if el[0] == 'year'] li = [True for el in maps if el[0] == 'year']
return (True if li else False) return (True if li else False)
def to_df(self): def to_df(self):
"""Return the pandas DataFrame. """Return the pandas DataFrame.
...@@ -298,7 +295,7 @@ class Graph(BaseReport): ...@@ -298,7 +295,7 @@ class Graph(BaseReport):
report_id = get_id(db[report_type], name=report_name) report_id = get_id(db[report_type], name=report_name)
report_config = db[report_type][report_id] report_config = db[report_type][report_id]
if report_type == "lists": if report_type == "lists":
report = List(report_config, selector) report = List(report_config, selector)
elif report_type == "metrics1d": elif report_type == "metrics1d":
...@@ -315,7 +312,6 @@ class Graph(BaseReport): ...@@ -315,7 +312,6 @@ class Graph(BaseReport):
self._do_legend() self._do_legend()
self._do_tick() self._do_tick()
def _do_graph(self): def _do_graph(self):
"""Build the graph from the C{DataFrame} structure. """Build the graph from the C{DataFrame} structure.
...@@ -330,16 +326,15 @@ class Graph(BaseReport): ...@@ -330,16 +326,15 @@ class Graph(BaseReport):
# generate the plot using a specific set of columns # generate the plot using a specific set of columns
if steer.index and len(steer.index) <= len(df.columns): if steer.index and len(steer.index) <= len(df.columns):
ax = df.ix[:,steer.index].plot(**plot) ax = df.ix[:, steer.index].plot(**plot)
# generate the plot using all columns # generate the plot using all columns
else: else:
ax = df.ix[:,:].plot(**plot) ax = df.ix[:, :].plot(**plot)
# persistence # persistence
self.ax = ax self.ax = ax
def _do_labels(self): def _do_labels(self):
"""Deal with axes label. """Deal with axes label.
...@@ -353,7 +348,6 @@ class Graph(BaseReport): ...@@ -353,7 +348,6 @@ class Graph(BaseReport):
if steer.ylabel: if steer.ylabel:
ax.set_ylabel(steer.ylabel, y=1, horizontalalignment='right') ax.set_ylabel(steer.ylabel, y=1, horizontalalignment='right')
def _do_legend(self): def _do_legend(self):
"""Deal with legend. """Deal with legend.
...@@ -368,7 +362,6 @@ class Graph(BaseReport): ...@@ -368,7 +362,6 @@ class Graph(BaseReport):
fontsize=10, fontsize=10,
ncol=3) ncol=3)
def _do_tick(self): def _do_tick(self):
"""Polish the tick mark """Polish the tick mark
...@@ -379,18 +372,17 @@ class Graph(BaseReport): ...@@ -379,18 +372,17 @@ class Graph(BaseReport):
ax.tick_params(which='major', length=8) ax.tick_params(which='major', length=8)
ax.tick_params(which='minor', length=4) ax.tick_params(which='minor', length=4)
def _savefig(self, fmt):
def _savefig(self, format):
"""Save the figure as a string. """Save the figure as a string.
@type format: str @type fmt: str
@param format: possible values are pdf, png and svg. @param fmt: possible values are pdf, png and svg.
""" """
fig = self.ax.get_figure() fig = self.ax.get_figure()
fi = StringIO() fi = StringIO()
fig.savefig(fi, format=format) fig.savefig(fi, format=fmt)
data = fi.getvalue() data = fi.getvalue()
fi.close() fi.close()
...@@ -399,7 +391,6 @@ class Graph(BaseReport): ...@@ -399,7 +391,6 @@ class Graph(BaseReport):
return data return data
def to_pdf(self): def to_pdf(self):
""" """
@rtype: string @rtype: string
...@@ -416,7 +407,6 @@ class Graph(BaseReport): ...@@ -416,7 +407,6 @@ class Graph(BaseReport):
""" """
return self._savefig('png') return self._savefig('png')
def to_svg(self): def to_svg(self):
""" """
@rtype: string @rtype: string
...@@ -459,8 +449,7 @@ class List(BaseReport): ...@@ -459,8 +449,7 @@ class List(BaseReport):
# instantiate and fill the DataFrame # instantiate and fill the DataFrame
self._do_metric() self._do_metric()
def _cast_type(self, column, dbfield, xtype):
def _cast_type(self, column, map, xtype):
"""Cast the type of a dataframe column to the database field type """Cast the type of a dataframe column to the database field type
or to the grid column xtype. or to the grid column xtype.
...@@ -476,8 +465,8 @@ class List(BaseReport): ...@@ -476,8 +465,8 @@ class List(BaseReport):
@type column: str @type column: str
@param column: the index of the column in the DataFrame @param column: the index of the column in the DataFrame
@type map: tuple @type dbfield: tuple
@param map: address of the database field encoded as @param dbfield: address of the database field encoded as
(tablename, fieldname, keyname). (tablename, fieldname, keyname).
@type xtype: str @type xtype: str
...@@ -487,7 +476,7 @@ class List(BaseReport): ...@@ -487,7 +476,7 @@ class List(BaseReport):
""" """
df = self.df df = self.df
tablename, fieldname, keyname = map tablename, fieldname = dbfield[0:2]
# the dtype of column containing a mixture of type is object. # the dtype of column containing a mixture of type is object.
if (tablename == 'year') or (df[column].dtype != 'object'): if (tablename == 'year') or (df[column].dtype != 'object'):
...@@ -503,7 +492,7 @@ class List(BaseReport): ...@@ -503,7 +492,7 @@ class List(BaseReport):
df[column] = df[column].astype('bool') df[column] = df[column].astype('bool')
elif dbtype in ('date', 'datetime', 'time'): elif dbtype in ('date', 'datetime', 'time'):
df[column] = pd.to_datetime(df[column]) df[column] = to_datetime(df[column])
elif dbtype in ('double', 'integer'): elif dbtype in ('double', 'integer'):
df[column] = df[column].astype('float64') df[column] = df[column].astype('float64')
...@@ -520,12 +509,11 @@ class List(BaseReport): ...@@ -520,12 +509,11 @@ class List(BaseReport):
df[column] = df[column].astype('bool') df[column] = df[column].astype('bool')
elif xtype == 'datecolumn': elif xtype == 'datecolumn':
df[column] = pd.to_datetime(df[column]) df[column] = to_datetime(df[column])
elif xtype == 'numbercolumn': elif xtype == 'numbercolumn':
df[column] = df[column].astype('float64') df[column] = df[column].astype('float64')
def _check_column(self, column): def _check_column(self, column):
"""Check column configuration: """Check column configuration:
...@@ -554,7 +542,6 @@ class List(BaseReport): ...@@ -554,7 +542,6 @@ class List(BaseReport):
if not (column.dataIndex or xtype == "rownumberer"): if not (column.dataIndex or xtype == "rownumberer"):
column.dataIndex = column.dbfield.replace('.', '') column.dataIndex = column.dbfield.replace('.', '')
def _do_metric(self): def _do_metric(self):
"""Interface the database with the DataFrame structure. """Interface the database with the DataFrame structure.
This method handle the "year" database field. This method handle the "year" database field.
...@@ -576,11 +563,11 @@ class List(BaseReport): ...@@ -576,11 +563,11 @@ class List(BaseReport):
# protection # protection
if not data: if not data:
self.df = pd.DataFrame(columns=index) self.df = DataFrame(columns=index)
return return
# fill the DataFrame # fill the DataFrame
df = pd.DataFrame(data, columns=index) df = DataFrame(data, columns=index)
# make the data frame persistent # make the data frame persistent
self.df = df self.df = df
...@@ -598,7 +585,6 @@ class List(BaseReport): ...@@ -598,7 +585,6 @@ class List(BaseReport):
index = [el.dataIndex for el in columns if el.dataIndex] index = [el.dataIndex for el in columns if el.dataIndex]
df = df[index] df = df[index]
def _set_store_data(self): def _set_store_data(self):
""" Generate the C{Ext.data.Store.data} property. """ Generate the C{Ext.data.Store.data} property.
It is a list of dictionaries. Each of them contains the data It is a list of dictionaries. Each of them contains the data
...@@ -613,7 +599,6 @@ class List(BaseReport): ...@@ -613,7 +599,6 @@ class List(BaseReport):
# convert the JSON-string into a list # convert the JSON-string into a list
self._store.data = json.loads(data) self._store.data = json.loads(data)
def _set_store_fields(self): def _set_store_fields(self):
""" Generate the C{Ext.data.Store.fields} property. """ Generate the C{Ext.data.Store.fields} property.
It is a list of C{Ext.data.Field} configuration. It is a list of C{Ext.data.Field} configuration.
...@@ -641,7 +626,7 @@ class List(BaseReport): ...@@ -641,7 +626,7 @@ class List(BaseReport):
# the pseudo field year # the pseudo field year
if el.dbfield == 'year': if el.dbfield == 'year':
cfg.type ='int' cfg.type = 'int'
# the computed column # the computed column
elif el.eval: elif el.eval:
...@@ -686,7 +671,6 @@ class List(BaseReport): ...@@ -686,7 +671,6 @@ class List(BaseReport):
store.fields.append(cfg) store.fields.append(cfg)
def to_grid(self): def to_grid(self):
"""Build the configuration of the C{App.grid.Panel}. """Build the configuration of the C{App.grid.Panel}.
...@@ -715,11 +699,11 @@ class List(BaseReport): ...@@ -715,11 +699,11 @@ class List(BaseReport):
# reference to javascript function or the function itself # reference to javascript function or the function itself
# are surrounded by double quoted. removed them. # are surrounded by double quoted. removed them.
grid.columns = json.dumps(grid.columns) grid.columns = json.dumps(grid.columns)
grid.columns = re.sub('("renderer": *)(")(\w+)(")', r'\1\3',grid.columns) grid.columns = \
re.sub('("renderer": *)(")(\w+)(")', r'\1\3', grid.columns)
return grid return grid
def to_store(self): def to_store(self):
"""Build the configuration of the C{Ext.data.Store}. """Build the configuration of the C{Ext.data.Store}.
...@@ -787,8 +771,8 @@ class Metric1D(List): ...@@ -787,8 +771,8 @@ class Metric1D(List):
text_groupby = 'year' text_groupby = 'year'
else: else:
tu = split_dbfield(field_groupby) tu = split_dbfield(field_groupby)
index_groupby = field_groupby.replace('.', '') index_groupby = field_groupby.replace('.', '')
text_groupby = (tu[2] if tu[2] else tu[1]) text_groupby = (tu[2] if tu[2] else tu[1])
# first column contains group by information # first column contains group by information
first_column = Storage(aggregate="", first_column = Storage(aggregate="",
...@@ -812,16 +796,11 @@ class Metric1D(List): ...@@ -812,16 +796,11 @@ class Metric1D(List):
self._do_metric() self._do_metric()
def _do_metric(self): def _do_metric(self):
"""Compute the metric according to user specifications. """Compute the metric according to user specifications.
""" """
db = self.db
config = self.config
columns = self._columns columns = self._columns
field_groupby = self._field_groupby
index_groupby = self._index_groupby index_groupby = self._index_groupby
# extract columns associated to database field # extract columns associated to database field
...@@ -846,10 +825,10 @@ class Metric1D(List): ...@@ -846,10 +825,10 @@ class Metric1D(List):
# protection against empty data # protection against empty data
if not data: if not data:
indexes = (el.dataIndex for el in columns) indexes = (el.dataIndex for el in columns)
self.df = pd.DataFrame(columns=indexes) self.df = DataFrame(columns=indexes)
return return
df = pd.DataFrame(data, columns=indexes) df = DataFrame(data, columns=indexes)
# cast dataframe column type to database field or grid column types # cast dataframe column type to database field or grid column types
self.df = df self.df = df
...@@ -870,13 +849,12 @@ class Metric1D(List): ...@@ -870,13 +849,12 @@ class Metric1D(List):
df = df[index] df = df[index]
# transform year MultiIndex into Index (only for year pseudo field) # transform year MultiIndex into Index (only for year pseudo field)
if isinstance(df.index, pd.core.index.MultiIndex): if isinstance(df.index, MultiIndex):
df.index = [el[1] for el in df.index] df.index = [el[1] for el in df.index]
# make the data frame persistent # make the data frame persistent
self.df = df self.df = df
def _is_year(self, maps): def _is_year(self, maps):
"""Supersede the method of the base class. """Supersede the method of the base class.
...@@ -885,7 +863,6 @@ class Metric1D(List): ...@@ -885,7 +863,6 @@ class Metric1D(List):
""" """
return self.config.group_field == 'year' return self.config.group_field == 'year'
def _set_store_data(self): def _set_store_data(self):
"""Generate the C{Ext.data.Store.data} property. """Generate the C{Ext.data.Store.data} property.
It is a list of dictionaries. Each of them contains the data It is a list of dictionaries. Each of them contains the data
...@@ -902,7 +879,6 @@ class Metric1D(List): ...@@ -902,7 +879,6 @@ class Metric1D(List):
self._store.data.extend(data) self._store.data.extend(data)
def _set_store_fields(self): def _set_store_fields(self):
""" Generate the Ext.data.Store.fields property. """ Generate the Ext.data.Store.fields property.
The store contains four fields: group, count, sum_fte and avg_age The store contains four fields: group, count, sum_fte and avg_age
...@@ -933,7 +909,6 @@ class Metric1D(List): ...@@ -933,7 +909,6 @@ class Metric1D(List):
store.sorters = [index_groupby] store.sorters = [index_groupby]
def to_grid(self): def to_grid(self):
"""Build the configuration of the C{App.grid.Panel}. """Build the configuration of the C{App.grid.Panel}.
...@@ -943,7 +918,6 @@ class Metric1D(List): ...@@ -943,7 +918,6 @@ class Metric1D(List):
""" """
columns = self._columns columns = self._columns
index_groupby = self._index_groupby
grid = Storage(columns=[], features=[]) grid = Storage(columns=[], features=[])
...@@ -966,7 +940,6 @@ class Metric1D(List): ...@@ -966,7 +940,6 @@ class Metric1D(List):
return grid return grid
def to_store(self): def to_store(self):
"""Build the configuration of the C{Ext.data.Store}. """Build the configuration of the C{Ext.data.Store}.
...@@ -1002,7 +975,6 @@ class Metric2D(BaseReport): ...@@ -1002,7 +975,6 @@ class Metric2D(BaseReport):
# replace undefined value by 0 # replace undefined value by 0
self.df = self.df.fillna(0) self.df = self.df.fillna(0)
def _do_metric(self): def _do_metric(self):
"""Compute the metric involving two database field. """Compute the metric involving two database field.
...@@ -1023,12 +995,12 @@ class Metric2D(BaseReport): ...@@ -1023,12 +995,12 @@ class Metric2D(BaseReport):
addresses = [address_x, address_y, address_z] addresses = [address_x, address_y, address_z]
# the database field maps (tablename, fieldname, keyname) # the database field encoded as (tablename, fieldname, keyname)
map_x = split_dbfield(address_x) dbfield_x = split_dbfield(address_x)
map_y = split_dbfield(address_y) dbfield_y = split_dbfield(address_y)
map_z = split_dbfield(address_z) dbfield_z = split_dbfield(address_z)
maps = [map_x, map_y, map_z] dbfields = [dbfield_x, dbfield_y, dbfield_z]
# metric # metric
aggregate = config.aggregation_z aggregate = config.aggregation_z
...@@ -1042,28 +1014,28 @@ class Metric2D(BaseReport): ...@@ -1042,28 +1014,28 @@ class Metric2D(BaseReport):
expression = address_z expression = address_z
ref_addresses = list(addresses) ref_addresses = list(addresses)
del maps[2] del dbfields[2]
del addresses[2] del addresses[2]
i = 0 i = 0
for m in REG_DBFIELD.finditer(address_z): for m in REG_DBFIELD.finditer(address_z):
address = m.group() address = m.group()
map = split_dbfield(address) dbfield = split_dbfield(address)
tmp = "a%i" % i tmp = "a%i" % i
i += 1 i += 1