19
19
import os
20
20
import time
21
21
import traceback
22
- from typing import List
22
+ from collections import OrderedDict
23
+ from itertools import chain
24
+ from typing import List , Dict , Callable
23
25
24
26
from pydictdisplayfilter .display_filters import BaseDisplayFilter , DictDisplayFilter
27
+ from pydictdisplayfilter .evaluators import Evaluator
25
28
from pydictdisplayfilter .exceptions import ParserError , EvaluationError
29
+ from pydictdisplayfilter .slicers import BasicSlicer
26
30
27
31
28
32
class TableError (Exception ):
29
33
pass
30
34
31
35
36
+ class TableColumnSizeCalculator :
37
+
38
+ @staticmethod
39
+ def calculate (data_store : List [dict ], fields : List ) -> List [int ]:
40
+ """ Calculates and returns the necessary size of each column in the data store. """
41
+ field_sizes = OrderedDict ()
42
+ for field in fields :
43
+ field_sizes [field ] = len (field )
44
+ for item in data_store :
45
+ for key in field_sizes .keys ():
46
+ if key in item :
47
+ field_sizes [key ] = max (len (str (item [key ])), field_sizes [key ])
48
+ return list (field_sizes .values ())
49
+
50
+
32
51
class Table :
33
52
""" Data store with filter capabilities and pretty table printout. """
34
53
@@ -39,22 +58,18 @@ def _make_table(self, data_store: List[dict]) -> List[str]:
39
58
""" Creates a table including header from the data store. """
40
59
if not data_store :
41
60
return []
42
- table = [self .fields ()]
43
- column_size = self ._calculate_column_size (data_store )
61
+ fields = self .fields ()
62
+ table = [fields ]
63
+ column_size = self ._calculate_column_size (data_store , fields )
44
64
format_str = ' | ' .join (["{{:<{}}}" .format (i ) for i in column_size ])
45
65
for item in data_store :
46
- table .append (item .values ())
47
- column_size = self ._calculate_column_size (data_store )
66
+ table .append ([str (item [field ]) if field in item else '' for field in fields ])
48
67
table .insert (1 , ['-' * i for i in column_size ]) # Separating line
49
68
return ["" ] + [ format_str .format (* item ) for item in table ]
50
69
51
- def _calculate_column_size (self , data_store : List [dict ]) -> List [int ]:
70
+ def _calculate_column_size (self , data_store : List [dict ], fields : List ) -> List [int ]:
52
71
""" Calculates and returns the necessary size of each column in the data store. """
53
- header = list (data_store [0 ].keys ())
54
- items = [list (item .values ()) for item in data_store ]
55
- return [
56
- max (len (str (item )) for item in column ) for column in zip (* items + [header ])
57
- ]
72
+ return TableColumnSizeCalculator .calculate (data_store , fields )
58
73
59
74
def _make_footer (self , items : List [dict ], duration : float ) -> List [str ]:
60
75
""" Creates a footer for the table which prints some statistics. """
@@ -70,7 +85,7 @@ def _make_footer(self, items: List[dict], duration: float) -> List[str]:
70
85
71
86
def fields (self ) -> List [str ]:
72
87
""" Returns the field names used in the data store. """
73
- raise NotImplementedError ()
88
+ return self . _display_filter . field_names
74
89
75
90
def filter (self , display_filter : str ) -> str :
76
91
"""
@@ -177,22 +192,29 @@ def do_exit(self, *args):
177
192
class DictTable (Table ):
178
193
""" Data store with filter capabilities and pretty table printout. """
179
194
180
- def __init__ (self , data_store : List [dict ]):
195
+ def __init__ (self ,
196
+ data_store : List [dict ],
197
+ field_names : List [str ] = None ,
198
+ functions : Dict [str , Callable ] = None ,
199
+ slicers : List [BasicSlicer ] = None ,
200
+ evaluator : Evaluator = None ):
181
201
""" Initializes the DictTable with a data store. """
182
- self . _data_store = data_store
183
- super ().__init__ (DictDisplayFilter (data_store ))
202
+ field_names = field_names or self . _extract_field_names ( data_store )
203
+ super ().__init__ (DictDisplayFilter (data_store , field_names , functions , slicers , evaluator ))
184
204
185
- def fields (self ) -> List [str ]:
186
- """ Returns the field names used in the data store. """
187
- if not self ._data_store :
188
- # No items in data store, so there are no fields to query either.
189
- return list ()
190
- return list (self ._data_store [0 ].keys ())
205
+ def _extract_field_names (self , data_store : List [dict ]) -> List [str ]:
206
+ """ Extracts the field names from the given data store. """
207
+ return sorted (set (chain .from_iterable (row .keys () for row in data_store )))
191
208
192
209
193
210
class DictDisplayFilterShell (DisplayFilterShell ):
194
211
""" A little shell for querying a list of dictionaries using the display filter. """
195
212
196
- def __init__ (self , data_store : List [dict ]):
213
+ def __init__ (self ,
214
+ data_store : List [dict ],
215
+ field_names : List [str ] = None ,
216
+ functions : Dict [str , Callable ] = None ,
217
+ slicers : List [BasicSlicer ] = None ,
218
+ evaluator : Evaluator = None ):
197
219
""" Initializes the DictDisplayFilterShell with a data store. """
198
- super ().__init__ (DictTable (data_store ))
220
+ super ().__init__ (DictTable (data_store , field_names , functions , slicers , evaluator ))
0 commit comments