Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
tev
plugin_event
Commits
3f63bef0
Commit
3f63bef0
authored
Jan 13, 2017
by
LE GAC Renaud
Browse files
Redesign BaseReport and inherited classes.
parent
db9f1c72
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
91 additions
and
86 deletions
+91
-86
controllers/plugin_event.py
controllers/plugin_event.py
+9
-29
modules/plugin_event/report_objects.py
modules/plugin_event/report_objects.py
+74
-48
modules/plugin_event/selector.py
modules/plugin_event/selector.py
+8
-9
No files found.
controllers/plugin_event.py
View file @
3f63bef0
...
...
@@ -28,25 +28,15 @@ def graph_mpl():
"""Plot list or metric using the matplotlib library
"""
# selector and configuration
try
:
ui_table
=
virtdb
.
selector
selector
=
EvtSelector
(
ui_table
)
except
SelectorActiveItemsException
as
e
:
return
INLINE_ALERT
%
(
T
(
"Error..."
),
T
(
str
(
e
)))
config
=
db
.
graphs
[
request
.
vars
.
id_graphs
]
# build the graph
try
:
graph
=
Graph
(
config
,
selector
)
graph
=
Graph
(
db
.
graphs
,
request
.
vars
.
id_graphs
)
except
(
IndexError
,
TypeError
,
ValueError
)
as
e
:
return
INLINE_ALERT
%
(
"Error"
,
e
)
return
INLINE_ALERT
%
(
"
GRAPH
Error"
,
e
)
# build the report title
title
=
do_title
(
config
,
selector
)
title
=
do_title
(
graph
)
# extract the image
# encode special character to be used in the image URI
...
...
@@ -81,39 +71,29 @@ def grid():
The identifier is used to instantiate the proper class.
"""
try
:
ui_table
=
virtdb
.
selector
selector
=
EvtSelector
(
ui_table
)
except
SelectorActiveItemsException
as
e
:
return
INLINE_ALERT
%
(
T
(
"Error..."
),
T
(
str
(
e
)))
# extract the report configuration and the build the report
# build the report
try
:
if
"id_lists"
in
request
.
vars
:
config
=
db
.
lists
[
request
.
vars
.
id_lists
]
report
=
List
(
config
,
selector
)
report
=
List
(
db
.
lists
,
request
.
vars
.
id_lists
)
elif
"id_metrics1d"
in
request
.
vars
:
config
=
db
.
metrics1d
[
request
.
vars
.
id_metrics1d
]
report
=
Metric1D
(
config
,
selector
)
report
=
Metric1D
(
db
.
metrics1d
,
request
.
vars
.
id_metrics1d
)
elif
"id_metrics2d"
in
request
.
vars
:
config
=
db
.
metrics2d
[
request
.
vars
.
id_metrics2d
]
report
=
Metric2D
(
config
,
selector
)
report
=
Metric2D
(
db
.
metrics2d
,
request
.
vars
.
id_metrics2d
)
else
:
return
INLINE_ALERT
%
(
"Error"
,
"Report id is not defined."
)
except
(
IndexError
,
ReportException
,
TypeError
,
ValueError
)
as
e
:
return
INLINE_ALERT
%
(
"
JSON
Error..."
,
e
)
return
INLINE_ALERT
%
(
"
REPORT
Error..."
,
e
)
# extract the configurations for the Ext.data.Store and Dbui.grid.Panel.
store
=
report
.
to_store
()
grid
=
report
.
to_grid
()
# build the report title
title
=
do_title
(
config
,
select
or
)
title
=
do_title
(
rep
or
t
)
# delegate the grid rendering to the view
return
dict
(
cfg_store
=
store
,
grid
=
grid
,
title
=
title
)
...
...
modules/plugin_event/report_objects.py
View file @
3f63bef0
...
...
@@ -13,29 +13,34 @@ from pandas import DataFrame, MultiIndex, to_datetime
from
plugin_dbui
import
get_id
,
Store
from
pydal.helpers.methods
import
smart_query
from
pydal.objects
import
FieldVirtual
from
selector
import
EvtSelector
from
StringIO
import
StringIO
MSG_NO_DATAINDEX
=
"The property dataIndex is required when eval is used."
MSG_NO_EVT_ID
=
"Identifier of the event is not defined."
MSG_NO_XTYPE
=
"The property xtype is missing."
REG_DBFIELD
=
re
.
compile
(
"\w+\.\w+(?:\.\w+)?"
,
re
.
UNICODE
)
REG_EVT_ID
=
re
.
compile
(
"history\.id_events *={1,2} *(\d+)"
)
REG_PYQUERY
=
re
.
compile
(
"[\( ]*\w+\.\w+\.\w+"
)
REG_SINGLE_DBFIELD
=
re
.
compile
(
"^ *\w+\.\w+(\.\w+)? *$"
,
re
.
UNICODE
)
def
do_title
(
config
,
select
or
):
def
do_title
(
rep
or
t
):
"""Build the report title.
Args:
config (gluon.dal.Row): the list configuration parameter.
selector (EvtSelector): selector handling period of time.
report (BaseReport): the report
Returns:
str:
"""
db
=
current
.
globalenv
[
"db"
]
db
=
report
.
db
config
=
report
.
config
selector
=
report
.
selector
T
=
current
.
T
# from the configuration
...
...
@@ -150,40 +155,55 @@ class BaseReport(object):
"""Base class to build list, metric or graph reports.
Args:
config
(gluon.dal.
Row
): t
h
e con
figuration parameter
for
the
report.
select
or (
EvtSelector): the selector handling user criteria
.
table
(gluon.dal.
Table
): t
abl
e con
taining configurations
for report
s
.
id_rep
or
t
(
int): identifier of the report in the table
.
"""
def
__init__
(
self
,
config
,
select
or
):
def
__init__
(
self
,
table
,
id_rep
or
t
):
db
=
current
.
globalenv
[
"db"
]
db
=
table
.
_db
self
.
db
=
db
self
.
df
=
None
self
.
config
=
config
self
.
rows
=
None
self
.
selector
=
selector
# Extract the configuration for the report configuration
config
=
table
[
id_report
]
# Extract the event identifier located in the condition field
conditions
=
config
.
conditions
mtch
=
REG_EVT_ID
.
search
(
conditions
)
if
mtch
is
None
:
raise
ReportException
(
current
.
T
(
MSG_NO_EVT_ID
))
id_event
=
int
(
mtch
.
group
(
1
))
# Instantiate the selector
virtdb
=
current
.
globalenv
[
"virtdb"
]
selector
=
EvtSelector
(
virtdb
.
selector
,
id_event
)
# apply the condition criteria used to filter the history records
# condition can be written as a smart query: history.id_events == 7
# or like a python query: db.events.event == "People"
if
"conditions"
in
config
:
condition
=
config
.
conditions
# minimal protection to avoid injection flow
# the beginning of the python query should be like:
# db.table.field
# (db.table.field
# ((db.table.field
# ( ( db.table.field
#
if
REG_PYQUERY
.
match
(
condition
):
q_conditions
=
eval
(
condition
,
None
,
{
"db"
:
db
})
else
:
q_conditions
=
smart_query
(
db
.
history
,
config
.
conditions
)
# minimal protection to avoid injection flow
# the beginning of the python query should be like:
# db.table.field
# (db.table.field
# ((db.table.field
# ( ( db.table.field
#
if
REG_PYQUERY
.
match
(
conditions
):
q_conditions
=
eval
(
conditions
,
None
,
{
"db"
:
db
})
selector
.
append_query
(
q_conditions
)
else
:
q_conditions
=
smart_query
(
db
.
history
,
conditions
)
selector
.
append_query
(
q_conditions
)
# keep track of configuration and selector
self
.
config
=
config
self
.
selector
=
selector
def
_do_data
(
self
,
maps
):
"""Build a temporarily list with the raw data for each series.
...
...
@@ -274,19 +294,23 @@ class Graph(BaseReport):
scater plots, *etc*.
Args:
config
(gluon.dal.
Row
):
t
h
e con
figuration parameter for the graph
.
table
(gluon.dal.
Table
):
t
abl
e con
taining configurations for reports
.
select
or (
EvtSelector
):
selector handling period of tim
e.
id_rep
or
t
(
int
):
identifier of the report in the tabl
e.
backend (str):
the name of the matplotlib backend uses to produce figure.
"""
def
__init__
(
self
,
config
,
select
or
,
backend
=
"Agg"
):
def
__init__
(
self
,
table
,
id_rep
or
t
,
backend
=
"Agg"
):
BaseReport
.
__init__
(
self
,
config
,
selector
)
self
.
db
=
table
.
_db
self
.
config
=
config
=
table
[
id_report
]
self
.
df
=
None
self
.
rows
=
None
# set the matplotlib back end
#
...
...
@@ -315,18 +339,18 @@ class Graph(BaseReport):
report_type
=
config
.
report_type
report_name
=
config
.
report_name
report_id
=
get_id
(
db
[
report_type
],
name
=
report_name
)
report_config
=
db
[
report_type
][
report_id
]
if
report_type
==
"lists"
:
report
=
List
(
report_config
,
selector
)
report
=
List
(
db
.
lists
,
report_id
)
elif
report_type
==
"metrics1d"
:
report
=
Metric1D
(
report_config
,
selector
)
report
=
Metric1D
(
db
.
metrics1d
,
report_id
)
elif
report_type
==
"metrics2d"
:
report
=
Metric2D
(
report_config
,
selector
)
report
=
Metric2D
(
db
.
metrics2d
,
report_id
)
self
.
df
=
report
.
to_df
()
self
.
selector
=
report
.
selector
# build the graph from the DataFrame
self
.
_do_graph
()
...
...
@@ -458,16 +482,16 @@ class List(BaseReport):
Its configuration is returned by the method *to_store*.
Args:
config
(gluon.dal.
Row
): t
h
e con
figuration parameter for the list
.
select
or (
EvtSelector): selector handling period of tim
e.
table
(gluon.dal.
Table
): t
abl
e con
taining configurations for reports
.
id_rep
or
t
(
int): identifier of the report in the tabl
e.
"""
def
__init__
(
self
,
config
,
select
or
):
def
__init__
(
self
,
table
,
id_rep
or
t
):
BaseReport
.
__init__
(
self
,
config
,
select
or
)
BaseReport
.
__init__
(
self
,
table
,
id_rep
or
t
)
# decode column configuration
columns
=
[
Storage
(
el
)
for
el
in
json
.
loads
(
config
.
columns
)]
columns
=
[
Storage
(
el
)
for
el
in
json
.
loads
(
self
.
config
.
columns
)]
# check column configuration
# add database field map (tablename, fieldname, keyname)
...
...
@@ -789,13 +813,15 @@ class Metric1D(List):
A summary information can also be computed for each column or rows.
Args:
config
(gluon.dal.
Row
): t
h
e con
figuration parameter for the metric
.
select
or (
EvtSelector): selector handling period of tim
e.
table
(gluon.dal.
Table
): t
abl
e con
taining configurations for reports
.
id_rep
or
t
(
int): identifier of the report in the tabl
e.
"""
def
__init__
(
self
,
config
,
select
or
):
def
__init__
(
self
,
table
,
id_rep
or
t
):
BaseReport
.
__init__
(
self
,
config
,
selector
)
BaseReport
.
__init__
(
self
,
table
,
id_report
)
config
=
self
.
config
# group by attributes
field_groupby
=
config
.
group_field
...
...
@@ -1001,13 +1027,13 @@ class Metric2D(BaseReport):
In fact, all the computation methods of the ``pandas.DataFrame`` class.
Args:
config
(gluon.dal.
Row
): t
h
e con
figuration parameter for the metric
.
select
or (
EvtSelector): selector handling period of tim
e.
table
(gluon.dal.
Table
): t
abl
e con
taining configurations for reports
.
id_rep
or
t
(
int): identifier of the report in the tabl
e.
"""
def
__init__
(
self
,
config
,
select
or
):
def
__init__
(
self
,
table
,
id_rep
or
t
):
BaseReport
.
__init__
(
self
,
config
,
select
or
)
BaseReport
.
__init__
(
self
,
table
,
id_rep
or
t
)
self
.
_do_metric
()
# replace undefined value by 0
...
...
modules/plugin_event/selector.py
View file @
3f63bef0
...
...
@@ -129,7 +129,7 @@ class EvtSelector(SelectorActiveItems):
"""Main selector to build list, metric or graph according to
the user criteria:
- focus on history record
- focus on history record
and on a given event.
- Select record active during the selected period of time.
- Selection can be performed on category defined as a string.
- For each record computes virtual field: ``age``, ``coverage``,
...
...
@@ -144,8 +144,10 @@ class EvtSelector(SelectorActiveItems):
categories, year_end, year_start and year are systematically
excluded.
id_event (int): the event identifier
"""
def
__init__
(
self
,
table
,
exclude_fields
=
()):
def
__init__
(
self
,
table
,
id_event
=
0
,
exclude_fields
=
()):
li
=
[
"data"
,
"id_object_categories"
,
...
...
@@ -158,9 +160,10 @@ class EvtSelector(SelectorActiveItems):
li
.
extend
(
exclude_fields
)
SelectorActiveItems
.
__init__
(
self
,
table
,
exclude_fields
=
li
)
# add virtual fields
self
.
_db
=
db
=
current
.
globalenv
[
"db"
]
self
.
_id_event
=
id_event
# add virtual fields
history
=
db
.
history
virtual
=
Field
.
Virtual
...
...
@@ -172,13 +175,9 @@ class EvtSelector(SelectorActiveItems):
history
.
is_over
=
virtual
(
"is_over"
,
self
.
_is_over
,
ftype
=
"boolean"
)
history
.
is_start
=
virtual
(
"is_start"
,
self
.
_is_start
,
ftype
=
"boolean"
)
# keep track of the identifier of the people event
# since it is used by period_activity
self
.
_id_event_people
=
get_id
(
db
.
events
,
event
=
"People"
)
def
_active_period
(
self
,
id_people
,
id_domain
,
id_team
):
"""Determine the period when a person is active in a given
domain and team
.
domain and team
and for a given event
Args:
id_people (int):
...
...
@@ -191,7 +190,7 @@ class EvtSelector(SelectorActiveItems):
stop (datetime or None)
"""
rawsql
=
RAWSQL_ACTIVITY
%
(
self
.
_id_event
_people
,
rawsql
=
RAWSQL_ACTIVITY
%
(
self
.
_id_event
,
id_people
,
id_domain
,
id_team
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment