# coding=utf-8
"""Create a part of HTML of table."""
import os.path
from jinja2 import Template
from .nodes import get
from .utility import path_expand
from .exception import DataProcessorError
class _TableData(object):
"""Manage table data.
This class form data needed template from arguments.
Examples
--------
>>> nodelist = [{'path': '/tmp', 'children': ['/tmp/run1', '/tmp/run0']},
... {'path': '/tmp/run0', 'name': 'run0', 'comment': 'test',
... 'configure': {'nx':1}},
... {'path': '/tmp/run1', 'name': 'run1',
... 'configure': {'ny': 20}}]
>>> table_data = _TableData(nodelist[0], nodelist, "children",
... groups=[{'dict_path': ['configure']},
... {'items': ['comment', 'path'], 'name': 'node'}])
>>> table_data.table == [
... {'nx': ['1', ''], 'ny': ['', '20']},
... {'comment': ['test', ''], 'path': ['/tmp/run0', '/tmp/run1']}]
True
>>> table_data.type == 'table'
True
>>> table_data.tags == ['children']
True
>>> table_data.col_groupname == ['configure', 'node']
True
>>> table_data.row_name == ['run0', 'run1']
True
>>> table_data.col_name == [['nx', 'ny'], ['comment', 'path']]
True
>>> table_data.row_path == ['/tmp/run0', '/tmp/run1']
True
>>> table_data.path == '/tmp'
True
"""
def __init__(self, node, node_list, table_type, groups):
self.type = "table"
self.tags = [table_type]
self.table = []
self._dict_path = self.__get_dict_path(groups)
self._linked_node = self.__get_linked_node(node_list, node[table_type])
self.col_groupname = self.__get_groupname(groups, self._dict_path)
self.row_name = self.__get_valuelist(self._linked_node, "name")
self.row_path = self.__get_valuelist(self._linked_node, "path")
self.col_name = self.__get_col_name(groups, self._dict_path,
self._linked_node)
self.path = node["path"]
for idx in range(len(groups)):
tble = {}
for node in self._linked_node:
dic = self.__get_dic_from_path(node, self._dict_path[idx])
for key in self.col_name[idx]:
self.__copy_value(tble, dic, key)
self.table.append(tble)
def __get_dict_path(self, groups):
dict_path = []
for group in groups:
if not "dict_path" in group or group["dict_path"] is None:
dict_path.append([])
else:
dict_path.append(group["dict_path"])
return dict_path
def __get_groupname(self, groups, dict_path):
groupname = []
for idx in range(len(groups)):
if not "name" in groups[idx] or groups[idx]["name"] is None:
groupname.append("/".join(dict_path[idx]))
else:
groupname.append(groups[idx]["name"])
return groupname
def __get_linked_node(self, node_list, path_list):
linked_node = []
for path in sorted(path_list):
node = get(node_list, path)
if not node is None:
linked_node.append(node)
return linked_node
def __get_valuelist(self, dict_list, keyname):
value = []
for dic in dict_list:
if keyname in dic:
value.append(dic[keyname])
else:
value.append("")
return value
def __get_col_name(self, groups, dict_path, linked_node):
col_name = []
if not linked_node:
return col_name
for group in groups:
if "items" in group and group["items"] is not None:
col_name.append(group["items"])
continue
group_idx = groups.index(group)
allkeys = set([])
for node in linked_node:
dic = self.__get_dic_from_path(node, dict_path[group_idx])
allkeys = allkeys | set(dic.keys())
if not allkeys:
raise DataProcessorError(
"No any node have dic specified `dict_path`")
allkeys = sorted(list(allkeys), key=lambda x: (len(x), x))
col_name.append(allkeys)
return col_name
def __get_dic_from_path(self, node, dict_path):
dic = node
for key in dict_path:
if not key in dic:
return {}
dic = dic[key]
return dic
def __copy_value(self, dic_out, dic_in, key):
try:
value = dic_in[key]
if type(value) == str:
value = unicode(value, "utf-8")
else:
value = unicode(value)
except KeyError:
value = ""
try:
dic_out[key].append(value)
except KeyError:
dic_out[key] = [value]
[docs]class Table(object):
"""Create table widget.
Create table from dictionary in node.
If node has dictionary in its values,
also search dictionary recursively. (e.g. node[key1][key2]...[keyn])
Parameters
----------
table_type : {'children', 'parents'}, optional
Table is composed of nodes in node[`table_type`].
groups : list of dic, optional
Specify elements in table for each group.
Default is one group which get all of 'configure' key.
One group has three keys below at most.
- dict_path : list of str, optional
List of key. Default is node itself.
Search dictionary recursively by `dict_path`.
- items : list of str, optional
List of key in dictionary specified by `dict_path`.
Table has only items in `items`.
- name : str, optional
Group name. Default is "/".join(`dict_path`).
Raises
------
DataProcessorError
Occurs in three cases:
+ No path exist.
+ Node to the `path` has no `table_type` key.
+ fail to search dictionary recursively: `dict_path` is invalid.
Examples
--------
If you have following list and you call as follows,
>>> nodelist = [{'path': '/tmp', 'children': ['/tmp/run1', '/tmp/run0']},
... {'path': '/tmp/run0', 'name': 'run0', 'comment': u'testあ',
... 'configure': {'nx':1, 'ny':2}},
... {'path': '/tmp/run1', 'name': 'run1',
... 'configure': {'nx': 10, 'ny': 20}}]
>>> tble = Table('/tmp', nodelist,
... groups=[{'dict_path': ['configure']},
... {'items': ['comment', 'path'], 'name': 'node'}])
>>> html_str = tble.render()
you can get html string of following formatted table.
+------+-----------+---------------------+
| | configure | node |
| +-----+-----+---------+-----------+
| | nx | ny | comment | path |
+======+=====+=====+=========+===========+
| run0 | 1 | 2 | testあ | /tmp/run0 |
+------+-----+-----+---------+-----------+
| run1 | 10 | 20 | | /tmp/run1 |
+------+-----+-----+---------+-----------+
Another example.
>>> node_list = [{"path": "/path/to",
... "children": ["/path/to/1", "/path/to/2"]},
... {"path": "/path/to/1", "name": "n1", "val1": 1,
... "hoge1": {"hoge2": {"hoge3": {"val4": 4}}}},
... {"path": "/path/to/2", "name": "h1", "val2": 2,
... "hoge1": {"hoge2": {"hoge3": {"val3": 4}}}}]
>>> tbl = Table("/path/to", node_list,
... groups=[{"items": ["val1", "val2"], "name": "some name"},
... {"dict_path": ["hoge1", "hoge2", "hoge3"]}])
>>> html_str = tbl.render()
+---+-------------+--------------------+
| | some name | hoge1/hoge2/hoge3 |
+ +------+------+----------+---------+
| | val1 | val2 | val3 | val4 |
+===+======+======+==========+=========+
|h1 | n | 2 | 4 | |
+---+------+------+----------+---------+
|n1 | 1 | | | 4 |
+---+------+------+----------+---------+
"""
def __init__(self, path, node_list, table_type="children",
groups=[{"dict_path": ["configure"],
"items": None, "name": None},
]):
node = get(node_list, path_expand(path))
if node is None:
raise DataProcessorError("Any node don't have path: %s" % path)
if not table_type in node:
raise DataProcessorError("node has no '%s' key" % table_type)
self._table_data = _TableData(node, node_list, table_type, groups)
[docs] def render(self):
"""Get a piece of html for table.
Returns
-------
str
A piece of html composed of the parameters in constructor.
"""
template = os.path.join(os.path.dirname(__file__),
"../../template/widget_table.html")
with open(template, "r") as f:
tmpl = Template(f.read())
return tmpl.render(data=self._table_data)