def setSubst(sheet, cols, rows): if not rows: warning('no %s selected' % sheet.rowtype) return modified = 'column' if len(cols) == 1 else 'columns' rex = vd.input("transform %s by regex: " % modified, type="regex-subst") setValuesFromRegex(cols, rows, rex)
def copyCells(sheet, col, rows): vd.clipcells = [col.getDisplayValue(r) for r in rows] if not rows: warning('no %s selected; clipboard emptied' % sheet.rowtype) return status('copied %d %s.%s to clipboard' % (len(rows), sheet.rowtype, col.name))
def gen_identify_duplicates(sheet): """ Takes a sheet, and returns a generator yielding a tuple for each row encountered. The tuple's structure is `(row_object, is_dupe)`, where is_dupe is True/False. See note in Usage section above regarding how duplicates are determined. """ keyCols = sheet.keyCols cols_to_check = None if len(keyCols) == 0: warning("No key cols specified. Using all columns.") cols_to_check = sheet.visibleCols else: cols_to_check = sheet.keyCols seen = set() for r in Progress(sheet.rows): vals = tuple(col.getValue(r) for col in cols_to_check) is_dupe = vals in seen if not is_dupe: seen.add(vals) yield (r, is_dupe)
def confirm(vd, prompt, exc=EscapeException): yn = vd.input(prompt, value='no', record=False)[:1] if not yn or yn not in 'Yy': msg = 'disconfirmed: ' + prompt if exc: raise exc(msg) warning(msg) return False return True
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 dive(self): if self.is_keyvalue: cell = self.cursorRow["value"] name = joinSheetnames(self.name, self.cursorRow["key"]) if isinstance(cell, (list, dict)): vs = self.__class__(name, source=cell) else: warning("Nothing to dive into.") return else: name = joinSheetnames(self.name, "row") vs = self.__class__(name, source=self.cursorRow) success = vs.reload() if success == False: return vd.push(vs)
def openurl_s3(p, filetype): ''' Open a sheet for an S3 path. S3 directories (prefixes) require special handling, but files (objects) can use standard VisiData "open" functions. ''' from s3fs import S3FileSystem # Non-obvious behavior here: For the default case, we don't want to send # a custom endpoint to s3fs. However, using None as a default trips up # VisiData's type detection for the endpoint option. So we use an empty # string as the default instead, and convert back to None here. endpoint = options.vds3_endpoint or None version_aware = options.vds3_version_aware # We can reuse an existing S3FileSystem as long as no relevant options # have changed since it was created. if (not S3Path.fs or S3Path.fs.version_aware != version_aware or S3Path.fs.client_kwargs.get('endpoint_url', '') != endpoint): S3Path.fs = S3FileSystem(client_kwargs={'endpoint_url': endpoint}, version_aware=version_aware) p = S3Path(p.given) if not p.is_file(): return S3DirSheet(p.name, source=p) if not filetype: filetype = p.ext or 'txt' openfunc = getGlobals().get('open_' + filetype.lower()) if not openfunc: warning(f'no loader found for {filetype} files, falling back to txt') filetype = 'txt' openfunc = open_txt vs = openfunc(p) status(f'opening {p.given} as {filetype}') return vs
def chooseMany(choices): 'Return list of `choices` elements (if list) or values (if dict).' if isinstance(choices, dict): prompt = '/'.join(choices.keys()) chosen = [] for c in vd.input(prompt + ': ', completer=CompleteKey(choices)).split(): poss = [choices[p] for p in choices if str(p).startswith(c)] if not poss: warning('invalid choice "%s"' % c) else: chosen.extend(poss) else: prompt = '/'.join(str(x) for x in choices) chosen = [] for c in vd.input(prompt + ': ', completer=CompleteKey(choices)).split(): poss = [p for p in choices if str(p).startswith(c)] if not poss: warning('invalid choice "%s"' % c) else: chosen.extend(poss) return chosen
def copyRows(sheet, rows): vd.cliprows = list((sheet, i, r) for i, r in enumerate(rows)) if not rows: warning('no %s selected; clipboard emptied' % sheet.rowtype) else: status('copied %d %s to clipboard' % (len(rows), sheet.rowtype))
def wrapper(*args, **kwargs): # ideally would include a stacktrace visidata.warning(f'{func.__name__} deprecated since v{ver}') return func(*args, **kwargs)