def _render_cells(self, data): """Render cell-block using given data""" cell_styles = ['' for x in self._allcolumns] # Style column if self.columnstyles: for c, s in self.columnstyles: cell_styles[self._allcolumns.index(c)] = s # Style cells if self.cellstyles: for c, d, s in self.cellstyles: f = bool_formula(d) if f(dict(zip(self._allcolumns, data))): cell_styles[self._allcolumns.index(c)] += s # formatted columns if self.formatters: data = list(data) for column, formatter in self.formatters.iteritems(): if data[column] != '': data[column] = formatter(data[column]) # Return block of rendered cells (use renderer.cell for actual # rendering) return ''.join(self.renderer.cell(self, cell_styles[k], data[k], i) for i, k in enumerate(self._displaycolumns))
def render(self, renderer): """Compile data into requested tabular form (via renderer). Params: renderer: object/module used to render data into requested form Example: >>> import datagrid.renderer.ascii >>> d = DataGrid([[1,2,3],[4,5,6]], ['col-a', 'col-b', 'col-c']) >>> renderer = datagrid.renderer.ascii.Renderer() >>> type(d.render(renderer)) <type 'str'> >>> d = DataGrid([[1,2,3],[4,5,6]]) >>> type(d.render(renderer)) <type 'str'> """ # make sure we have something to render if not len(self.data): raise NothingToRenderError() # prepare for render self._normalize() # Filter data data = (dict(zip(self._rawcolumns, x)) for x in self.data) if self.filters: for d in self.filters: f = bool_formula(d) data = ifilter(f, data) self.data = [] for r in data: row = [] for c in self._rawcolumns: row.append(r[c]) self.data.append(row) # run renderer setup logic (if we have any) self.renderer = renderer if hasattr(self.renderer, 'setup'): self.renderer.setup(self) # build table pieces and glue together head = self.renderer.head(self) # render body if we are suppressing detail on a flat set if not self.suppressdetail or self.groupby: body = self._render_body(self.data, self.groupby) else: body = '' taildata = self._add_calculated_columns( self._compile_aggregate_data(self.data)) tail = self.renderer.tail(self, self._render_cells(taildata)) # render table and return return self.renderer.table(self, head, body, tail)
def _render_row(self, data, **kargs): """Render table-row""" row_styles = [] # Style rows if self.rowstyles: for d, s in self.rowstyles: f = bool_formula(d) if f(dict(zip(self._allcolumns, data))): row_styles.append(s) return self.renderer.row(self, ' '.join(row_styles), self._render_cells(data), **kargs)
def fun(row): formatted_row = dict(zip(self._rawcolumns, row)) for f in self.post_aggregate_filters: if not bool_formula(f)(formatted_row): return False return True
def _render_body(self, data, groupby=list(), aggregate_row=None): """Render table body segment For flat data sets (unaggregated), this includes the entire body of data. Aggregated sets, however, will call _render_body for each aggregation name/value pair.""" groupby_len = len(groupby) if groupby_len: # get unique values for aggregation requested idx = self._allcolumns.index(groupby[0]) # create method to group by keyfunc = lambda x: x[idx] # group data into chunks of aggregated data output = [] data = sorted(data, key=keyfunc) for value, subdata in itertools.groupby(data, keyfunc): # we will be looking at this more than once, so we need a # concrete list (tuple), not just an iterator subdata = tuple(subdata) # format aggregate value if idx in self.formatters: fvalue = self.formatters[idx](value) else: fvalue = value # this config gets sent to renderer.row for displaying # aggregate row information (name, value, etc) rowargs = dict(name=groupby[0], value=fvalue, level=groupby_len) # build aggregate summary row rowdata = self._compile_aggregate_data(subdata, aggregate_row) rowdata[idx] = value # add calculated columns to data rowdata = self._add_calculated_columns(rowdata) # if details are suppressed, decrement out agg-level if self.suppressdetail: rowargs['level'] -= 1 # Do post aggregate filters def fun(row): formatted_row = dict(zip(self._rawcolumns, row)) for f in self.post_aggregate_filters: if not bool_formula(f)(formatted_row): return False return True if any(map(fun, subdata)): # generate aggregate row rowoutput = self._render_row(rowdata, **rowargs) # render remainder of rows beneath aggregation level if rowargs['level'] > 0: rowoutput += self._render_body(subdata, groupby[1:], rowdata) # append rendered data to output buffer output.append((rowdata, rowoutput)) # sort aggregate row sorting and return compiled string output = multi_sorted(output, self.sortby, lambda c, d: d[0][c]) return ''.join(row[1] for row in output) else: # Find calculated column values and apply formatting for given row data = [self._add_calculated_columns(row) for row in data] if self.post_aggregate_filters: for f in self.post_aggregate_filters: data = [r for r in data if bool_formula(f)( dict(zip(self._allcolumns, r)))] # sort data and display data = multi_sorted(data, self.sortby) return ''.join(self._render_row(row) for row in data)