def reload(self): mapping = self.source self.columns = [] self.rows = [] self.key_type = str self.size = len(mapping) if self.size == 0: return if isinstance(mapping, list): first = mapping[0] if isinstance(first, dict): colgetter = lambda x: x.keys() elif isinstance(first, list): colgetter = lambda x: list(range(len(x))) else: mapping = dict(enumerate(mapping)) self.key_type = int self.size = len(mapping) if isinstance(mapping, dict): self.is_keyvalue = True if self.size: max_key_len = max(map(len, map(str, mapping.keys()))) key_width = min(50, max(max_key_len + 2, 6)) else: key_width = None self.addColumn( ColumnItem("key", width=key_width, type=self.key_type)) self.addColumn(ColumnItem("value")) self.setKeys(self.columns[:1]) for k, v in mapping.items(): self.addRow({"key": k, "value": v}) elif isinstance(mapping, list): self.is_keyvalue = False indices = [] for item in mapping: try: cols = colgetter(item) for col in cols: if col not in indices: self.addColumn(ColumnItem(col)) indices.append(col) self.addRow(item) except Exception as e: warning( "Can't dive on lists with heterogenous item types.") return False
def reload(self): self.rows = [] for sheet in self.sources: for r in sheet.rows: self.addRow((sheet, r)) self.columns = [] self.addColumn(ColumnItem('origin_sheet', 0)) allColumns = {} for srcsheet in self.sources: for srccol in srcsheet.visibleCols: colsBySheet = allColumns.get(srccol.name, None) if colsBySheet is None: colsBySheet = {} # dict of [Sheet] -> Column allColumns[srccol.name] = colsBySheet if isinstance(srccol, ColumnExpr): combinedCol = copy(srccol) else: combinedCol = ColumnConcat(srccol.name, colsBySheet, type=srccol.type) self.addColumn(combinedCol) if srcsheet in colsBySheet: status('%s has multiple columns named "%s"' % (srcsheet.name, srccol.name)) colsBySheet[srcsheet] = srccol self.recalc( ) # to set .sheet on columns, needed if this reload becomes async
def addRow(self, row, index=None): for i in range(len(self.columns), len(row)): # no-op if already done self.addColumn(ColumnItem('', i)) self._rowtype = namedlist('tsvobj', [(c.name or '_') for c in self.columns]) if type(row) is not self._rowtype: row = self._rowtype(row) super().addRow(row, index=index)
def setCols(self, headerrows): self.columns = [] for i, _ in enumerate(itertools.zip_longest(*headerrows)): self.addColumn(ColumnItem('', i)) self.setColNames(headerrows) self._rowtype = namedlist('tsvobj', [(c.name or '_') for c in self.columns])
def addRow(self, row, index=None): super().addRow(row, index=index) if isinstance(row, dict): for k in row: if k not in self.colnames: c = ColumnItem(k, type=deduceType(row[k])) self.colnames[k] = c self.addColumn(c) return row
class StatusSheet(Sheet): precious = False rowtype = 'statuses' # rowdef: (priority, args, nrepeats) columns = [ ColumnItem('priority', 0, type=int, width=0), ColumnItem('nrepeats', 2, type=int, width=0), ColumnItem('args', 1, width=0), Column('message', getter=lambda col, row: composeStatus(row[1], row[2])), ] colorizers = [ RowColorizer(1, 'color_error', lambda s, c, r, v: r and r[0] == 3), RowColorizer(1, 'color_warning', lambda s, c, r, v: r and r[0] in [1, 2]), ] def reload(self): self.rows = self.source
class TextSheet(Sheet): 'Displays any iterable source, with linewrap if wrap set in init kwargs or options.' rowtype = 'lines' filetype = 'txt' columns = [ ColumnItem('linenum', 0, type=int, width=0), ColumnItem('text', 1), ] def iterload(self): winWidth = min(self.columns[1].width or 78, self.windowWidth-2) wrap = options.wrap for startingLine, text in enumerate(self.source): if wrap and text: for i, L in enumerate(textwrap.wrap(str(text), width=winWidth)): yield [startingLine+i+1, L] else: yield [startingLine+1, text]
def reload_sync(self): 'Perform synchronous loading of TSV file, discarding header lines.' header_lines = options.get('header', self) with self.source.open_text() as fp: # get one line anyway to determine number of columns lines = list(getlines(fp, int(header_lines) or 1)) headers = [L.split(options.delimiter) for L in lines] if header_lines <= 0: self.columns = [ ColumnItem('', i) for i in range(len(headers[0])) ] else: self.columns = [ ColumnItem('\\n'.join(x), i) for i, x in enumerate(zip(*headers[:header_lines])) ] lines = lines[header_lines:] # in case of header_lines == 0 self._rowtype = namedlist('tsvobj', [c.name for c in self.columns]) self.recalc() delim = options.delimiter self.rows = [] with Progress(total=self.source.filesize) as prog: for L in itertools.chain(lines, getlines(fp)): row = L.split(delim) ncols = self._rowtype.length() # current number of cols if len(row) > ncols: newcols = [ ColumnItem('', len(row) + i, width=8) for i in range(len(row) - ncols) ] self._rowtype = namedlist( self._rowtype.__name__, list(self._rowtype._fields) + ['_' for c in newcols]) self.addRow(self._rowtype(row)) prog.addProgress(len(L))
def reload(self): """Loading a TOML file produces a single dict. Use its keys as column headings, and populate a single row. """ self.columns = [] self.rows = [] data = tomllib.load(self.source.open_bytes()) for k, v in data.items(): self.addColumn(ColumnItem(k, type=deduceType(v))) self.addRow(data)
class StatusSheet(Sheet): precious = False rowtype = 'statuses' # rowdef: (priority, args, nrepeats) columns = [ ColumnItem('priority', 0, type=int, width=0), ColumnItem('nrepeats', 2, type=int, width=0), ColumnItem('args', 1, width=0), Column('message', getter=lambda col, row: composeStatus(row[1], row[2])), ] colorizers = [ Colorizer( 'row', 1, lambda s, c, r, v: options.color_error if r[0] == 3 else None), Colorizer( 'row', 1, lambda s, c, r, v: options.color_warning if r[0] in [1, 2] else None), ] def reload(self): self.rows = vd.statusHistory[::-1]
def reload_json(self): self.rows = [] with self.source.open_text() as fp: ret = json.load(fp) if isinstance(ret, dict): self.rows = [ret] self.columns = [] for k in self.rows[0]: self.addColumn(ColumnItem(k, type=deduceType(self.rows[0][k]))) else: self.rows = [] for row in Progress(ret): self.addRow(row)
def reload(self): sheets = self.sources # first item in joined row is the key tuple from the first sheet. # first columns are the key columns from the first sheet, using its row (0) self.columns = [] for i, c in enumerate(sheets[0].keyCols): self.addColumn( SubrowColumn(c.name, ColumnItem(c.name, i, type=c.type, width=c.width), 0)) self.setKeys(self.columns) for sheetnum, vs in enumerate(sheets): # subsequent elements are the rows from each source, in order of the source sheets ctr = collections.Counter(c.name for c in vs.nonKeyVisibleCols) for c in vs.nonKeyVisibleCols: newname = c.name if ctr[c.name] == 1 else '%s_%s' % (vs.name, c.name) self.addColumn(SubrowColumn(newname, c, sheetnum + 1)) rowsBySheetKey = {} rowsByKey = {} groupRowsByKey(sheets, rowsBySheetKey, rowsByKey) self.rows = [] with Progress(gerund='joining', total=len(rowsByKey)) as prog: for k, combinedRows in rowsByKey.items(): prog.addProgress(1) if self.jointype == 'full': # keep all rows from all sheets for combinedRow in combinedRows: self.addRow(combinedRow) elif self.jointype == 'inner': # only rows with matching key on all sheets for combinedRow in combinedRows: if all(combinedRow): self.addRow(combinedRow) elif self.jointype == 'outer': # all rows from first sheet for combinedRow in combinedRows: if combinedRow[1]: self.addRow(combinedRow) elif self.jointype == 'diff': # only rows without matching key on all sheets for combinedRow in combinedRows: if not all(combinedRow): self.addRow(combinedRow)
def newRow(self): return Sheet('', columns=[ColumnItem('', 0)], rows=[])
def set_columns_from_row(self, row): self.columns.clear() for i, name in enumerate(row.keys()): self.addColumn(ColumnItem(name))