visidata 3.0.2__py3-none-any.whl → 3.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- visidata/__init__.py +12 -10
- visidata/_input.py +208 -202
- visidata/_open.py +4 -1
- visidata/_types.py +4 -3
- visidata/aggregators.py +88 -39
- visidata/apps/vdsql/_ibis.py +7 -11
- visidata/apps/vdsql/clickhouse.py +2 -2
- visidata/apps/vdsql/snowflake.py +1 -1
- visidata/apps/vgit/status.py +1 -1
- visidata/basesheet.py +11 -4
- visidata/canvas.py +54 -20
- visidata/clipboard.py +13 -6
- visidata/cliptext.py +7 -6
- visidata/cmdlog.py +40 -27
- visidata/column.py +14 -49
- visidata/ddw/regex.ddw +3 -2
- visidata/deprecated.py +14 -2
- visidata/desktop/visidata.desktop +2 -2
- visidata/editor.py +1 -0
- visidata/errors.py +1 -1
- visidata/experimental/sort_selected.py +54 -0
- visidata/expr.py +69 -18
- visidata/features/change_precision.py +1 -3
- visidata/features/cmdpalette.py +17 -2
- visidata/features/colorsheet.py +1 -1
- visidata/features/dedupe.py +3 -3
- visidata/features/go_col.py +71 -0
- visidata/features/graph_seaborn.py +1 -1
- visidata/features/join.py +20 -10
- visidata/features/layout.py +16 -3
- visidata/features/ping.py +16 -12
- visidata/features/regex.py +5 -5
- visidata/features/status_source.py +3 -1
- visidata/features/sysedit.py +1 -1
- visidata/features/transpose.py +2 -1
- visidata/features/type_ipaddr.py +2 -4
- visidata/features/unfurl.py +1 -0
- visidata/form.py +2 -2
- visidata/freqtbl.py +16 -11
- visidata/fuzzymatch.py +1 -0
- visidata/graph.py +163 -12
- visidata/guide.py +57 -24
- visidata/guides/ClipboardGuide.md +48 -0
- visidata/guides/ColumnsGuide.md +52 -0
- visidata/guides/CommandsSheet.md +28 -0
- visidata/guides/DirSheet.md +34 -0
- visidata/guides/ErrorsSheet.md +17 -0
- visidata/guides/FrequencyTable.md +42 -0
- visidata/guides/GrepSheet.md +28 -0
- visidata/guides/JsonSheet.md +38 -0
- visidata/guides/MacrosSheet.md +19 -0
- visidata/guides/MeltGuide.md +52 -0
- visidata/guides/MemorySheet.md +7 -0
- visidata/guides/MenuGuide.md +26 -0
- visidata/guides/ModifyGuide.md +38 -0
- visidata/guides/PivotGuide.md +71 -0
- visidata/guides/RegexGuide.md +107 -0
- visidata/guides/SelectionGuide.md +44 -0
- visidata/guides/SlideGuide.md +26 -0
- visidata/guides/SortGuide.md +0 -0
- visidata/guides/SplitpaneGuide.md +15 -0
- visidata/guides/TypesSheet.md +43 -0
- visidata/guides/XsvGuide.md +36 -0
- visidata/help.py +6 -6
- visidata/hint.py +2 -1
- visidata/indexsheet.py +2 -2
- visidata/interface.py +13 -14
- visidata/keys.py +4 -1
- visidata/loaders/api_airtable.py +1 -1
- visidata/loaders/archive.py +1 -1
- visidata/loaders/csv.py +9 -5
- visidata/loaders/eml.py +11 -6
- visidata/loaders/f5log.py +1 -0
- visidata/loaders/fec.py +18 -42
- visidata/loaders/fixed_width.py +19 -3
- visidata/loaders/grep.py +121 -0
- visidata/loaders/html.py +1 -0
- visidata/loaders/http.py +6 -1
- visidata/loaders/json.py +22 -4
- visidata/loaders/jsonla.py +8 -2
- visidata/loaders/mailbox.py +1 -0
- visidata/loaders/markdown.py +25 -6
- visidata/loaders/msgpack.py +19 -0
- visidata/loaders/npy.py +0 -1
- visidata/loaders/odf.py +18 -4
- visidata/loaders/orgmode.py +1 -1
- visidata/loaders/rec.py +6 -4
- visidata/loaders/sas.py +11 -4
- visidata/loaders/scrape.py +0 -1
- visidata/loaders/texttables.py +2 -0
- visidata/loaders/tsv.py +24 -7
- visidata/loaders/unzip_http.py +127 -3
- visidata/loaders/vds.py +4 -0
- visidata/loaders/vdx.py +1 -1
- visidata/loaders/xlsx.py +5 -0
- visidata/loaders/xml.py +2 -1
- visidata/macros.py +14 -31
- visidata/main.py +14 -13
- visidata/mainloop.py +14 -6
- visidata/man/vd.1 +72 -39
- visidata/man/vd.txt +72 -41
- visidata/memory.py +15 -4
- visidata/menu.py +14 -3
- visidata/metasheets.py +5 -6
- visidata/modify.py +4 -4
- visidata/mouse.py +2 -0
- visidata/movement.py +14 -28
- visidata/optionssheet.py +3 -5
- visidata/path.py +59 -37
- visidata/pivot.py +8 -5
- visidata/pyobj.py +63 -9
- visidata/save.py +16 -9
- visidata/search.py +4 -4
- visidata/selection.py +10 -56
- visidata/settings.py +37 -35
- visidata/sheets.py +186 -108
- visidata/shell.py +22 -12
- visidata/sidebar.py +71 -16
- visidata/sort.py +21 -6
- visidata/statusbar.py +42 -5
- visidata/stored_list.py +5 -2
- visidata/tests/conftest.py +1 -0
- visidata/tests/test_commands.py +9 -1
- visidata/tests/test_completer.py +18 -0
- visidata/tests/test_edittext.py +3 -2
- visidata/text_source.py +7 -4
- visidata/textsheet.py +20 -6
- visidata/themes/ascii8.py +9 -6
- visidata/themes/asciimono.py +14 -4
- visidata/threads.py +13 -3
- visidata/tuiwin.py +5 -1
- visidata/type_currency.py +1 -2
- visidata/type_date.py +6 -1
- visidata/undo.py +10 -5
- visidata/utils.py +9 -3
- visidata/vdobj.py +21 -1
- visidata/wrappers.py +9 -1
- {visidata-3.0.2.data → visidata-3.1.data}/data/share/applications/visidata.desktop +2 -2
- {visidata-3.0.2.data → visidata-3.1.data}/data/share/man/man1/vd.1 +72 -39
- {visidata-3.0.2.data → visidata-3.1.data}/data/share/man/man1/visidata.1 +72 -39
- {visidata-3.0.2.dist-info → visidata-3.1.dist-info}/METADATA +24 -6
- visidata-3.1.dist-info/RECORD +284 -0
- visidata-3.0.2.dist-info/RECORD +0 -258
- {visidata-3.0.2.data → visidata-3.1.data}/scripts/vd +0 -0
- {visidata-3.0.2.data → visidata-3.1.data}/scripts/vd2to3.vdx +0 -0
- {visidata-3.0.2.dist-info → visidata-3.1.dist-info}/LICENSE.gpl3 +0 -0
- {visidata-3.0.2.dist-info → visidata-3.1.dist-info}/WHEEL +0 -0
- {visidata-3.0.2.dist-info → visidata-3.1.dist-info}/entry_points.txt +0 -0
- {visidata-3.0.2.dist-info → visidata-3.1.dist-info}/top_level.txt +0 -0
visidata/search.py
CHANGED
@@ -91,10 +91,10 @@ def moveInputRegex(sheet, action:str, type="regex", **kwargs):
|
|
91
91
|
|
92
92
|
@Sheet.api
|
93
93
|
@asyncthread
|
94
|
-
def search_expr(sheet, expr, reverse=False):
|
94
|
+
def search_expr(sheet, expr, reverse=False, curcol=None):
|
95
95
|
for i in rotateRange(len(sheet.rows), sheet.cursorRowIndex, reverse=reverse):
|
96
96
|
try:
|
97
|
-
if sheet.evalExpr(expr, sheet.rows[i]):
|
97
|
+
if sheet.evalExpr(expr, sheet.rows[i], curcol=curcol):
|
98
98
|
sheet.cursorRowIndex=i
|
99
99
|
return
|
100
100
|
except Exception as e:
|
@@ -111,8 +111,8 @@ Sheet.addCommand('N', 'searchr-next', 'vd.moveRegex(sheet, reverse=True)', 'go t
|
|
111
111
|
|
112
112
|
Sheet.addCommand('g/', 'search-cols', 'moveInputRegex("g/", backward=False, columns="visibleCols")', 'search for regex forwards over all visible columns')
|
113
113
|
Sheet.addCommand('g?', 'searchr-cols', 'moveInputRegex("g?", backward=True, columns="visibleCols")', 'search for regex backwards over all visible columns')
|
114
|
-
Sheet.addCommand('z/', 'search-expr', 'search_expr(inputExpr("search by expr: ") or fail("no expr"))', 'search by Python expression forwards in current column (with column names as variables)')
|
115
|
-
Sheet.addCommand('z?', 'searchr-expr', 'search_expr(inputExpr("searchr by expr: ") or fail("no expr"), reverse=True)', 'search by Python expression backwards in current column (with column names as variables)')
|
114
|
+
Sheet.addCommand('z/', 'search-expr', 'search_expr(inputExpr("search by expr: ") or fail("no expr"), curcol=cursorCol)', 'search by Python expression forwards in current column (with column names as variables)')
|
115
|
+
Sheet.addCommand('z?', 'searchr-expr', 'search_expr(inputExpr("searchr by expr: ") or fail("no expr"), curcol=cursorCol, reverse=True)', 'search by Python expression backwards in current column (with column names as variables)')
|
116
116
|
|
117
117
|
vd.addMenuItems('''
|
118
118
|
View > Search > current column > search-col
|
visidata/selection.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from copy import copy
|
2
|
-
from visidata import vd, Sheet, Progress, asyncthread, options, rotateRange, Fanout, undoAttrCopyFunc, RowColorizer
|
2
|
+
from visidata import vd, Sheet, Progress, asyncthread, options, rotateRange, Fanout, undoAttrCopyFunc, RowColorizer
|
3
3
|
|
4
4
|
vd.option('bulk_select_clear', False, 'clear selected rows before new bulk selections', replay=True)
|
5
5
|
vd.option('some_selected_rows', False, 'if no rows selected, if True, someSelectedRows returns all rows; if False, fails')
|
@@ -13,54 +13,6 @@ Sheet.colorizers.append( RowColorizer(2, 'color_selected_row', lambda s,c,r,v:
|
|
13
13
|
r is not None and s.isSelected(r))
|
14
14
|
)
|
15
15
|
|
16
|
-
class SelectionGuide(GuideSheet):
|
17
|
-
sheettype = Sheet
|
18
|
-
guide_text ='''# Selecting and filtering
|
19
|
-
|
20
|
-
Some commands operate only on "selected rows". For instance, a common command to filter is {help.commands.dup_selected}.
|
21
|
-
|
22
|
-
Many g-prefixed commands are like this. For example, use {help.commands.edit_cell}, but use {help.commands.setcol_input}. Search for "selected rows" in the [:onclick help-commands-all]commands list[/] or the [:onclick sysopen-help]manpage[/] for a full list.
|
23
|
-
|
24
|
-
Rows on the **Frequency Table** or **Pivot Table** reference a group of rows from the source sheet. Selecting a row on those sheets also selects the referenced rows on the underlying source sheet.
|
25
|
-
|
26
|
-
Select and unselect rows with these commands:
|
27
|
-
|
28
|
-
## One row at a time
|
29
|
-
|
30
|
-
- {help.commands.select_row}
|
31
|
-
- {help.commands.unselect_row}
|
32
|
-
- {help.commands.stoggle_row}
|
33
|
-
|
34
|
-
## All rows at the same time
|
35
|
-
|
36
|
-
- {help.commands.select_rows}
|
37
|
-
- {help.commands.unselect_rows}
|
38
|
-
- {help.commands.stoggle_rows}
|
39
|
-
|
40
|
-
## By matching patterns
|
41
|
-
|
42
|
-
- {help.commands.select_col_regex}
|
43
|
-
- {help.commands.unselect_col_regex}
|
44
|
-
- {help.commands.select_cols_regex}
|
45
|
-
- {help.commands.unselect_cols_regex}
|
46
|
-
|
47
|
-
- {help.commands.select_equal_cell}
|
48
|
-
- {help.commands.select_equal_row}
|
49
|
-
|
50
|
-
## Select by Python expression
|
51
|
-
|
52
|
-
Python expressions can use a column value by the column name, if the
|
53
|
-
column name is a valid Python identifier (with only letters, digits, and underscores).
|
54
|
-
|
55
|
-
- {help.commands.select_expr}
|
56
|
-
- {help.commands.unselect_expr}
|
57
|
-
|
58
|
-
## Options
|
59
|
-
|
60
|
-
- {help.options.bulk_select_clear}
|
61
|
-
- {help.options.some_selected_rows}
|
62
|
-
'''
|
63
|
-
|
64
16
|
@Sheet.api
|
65
17
|
def isSelected(self, row):
|
66
18
|
'Return True if *row* is selected.'
|
@@ -71,8 +23,10 @@ def isSelected(self, row):
|
|
71
23
|
def toggle(self, rows):
|
72
24
|
'Toggle selection of given *rows*. Async.'
|
73
25
|
self.addUndoSelection()
|
74
|
-
for r in Progress(rows, 'toggling', total=len(
|
75
|
-
if
|
26
|
+
for r in Progress(rows, 'toggling', total=len(rows)):
|
27
|
+
if self.isSelected(r): #1671
|
28
|
+
self.unselectRow(r)
|
29
|
+
else:
|
76
30
|
self.selectRow(r)
|
77
31
|
|
78
32
|
|
@@ -87,7 +41,9 @@ def select_row(self, row):
|
|
87
41
|
def toggle_row(self, row):
|
88
42
|
'Toggle selection of given *row*.'
|
89
43
|
self.addUndoSelection()
|
90
|
-
if
|
44
|
+
if self.isSelected(row):
|
45
|
+
self.unselectRow(row)
|
46
|
+
else:
|
91
47
|
self.selectRow(row)
|
92
48
|
|
93
49
|
|
@@ -240,8 +196,8 @@ Sheet.addCommand('g,', 'select-equal-row', 'select(gatherBy(lambda r,currow=curs
|
|
240
196
|
Sheet.addCommand('z,', 'select-exact-cell', 'select(gatherBy(lambda r,c=cursorCol,v=cursorTypedValue: c.getTypedValue(r) == v), progress=False)', 'select rows matching current cell in current column')
|
241
197
|
Sheet.addCommand('gz,', 'select-exact-row', 'select(gatherBy(lambda r,currow=cursorRow,vcols=visibleCols: all([c.getTypedValue(r) == c.getTypedValue(currow) for c in vcols])), progress=False)', 'select rows matching current row in all visible columns')
|
242
198
|
|
243
|
-
Sheet.addCommand('z|', 'select-expr', 'expr=inputExpr("select by expr: "); select(gatherBy(lambda r, sheet=sheet, expr=expr: sheet.evalExpr(expr, r)), progress=False)', 'select rows matching Python expression in any visible column')
|
244
|
-
Sheet.addCommand('z\\', 'unselect-expr', 'expr=inputExpr("unselect by expr: "); unselect(gatherBy(lambda r, sheet=sheet, expr=expr: sheet.evalExpr(expr, r)), progress=False)', 'unselect rows matching Python expression in any visible column')
|
199
|
+
Sheet.addCommand('z|', 'select-expr', 'expr=inputExpr("select by expr: "); select(gatherBy(lambda r, sheet=sheet, expr=expr, curcol=cursorCol: sheet.evalExpr(expr, r, curcol=curcol)), progress=False)', 'select rows matching Python expression in any visible column')
|
200
|
+
Sheet.addCommand('z\\', 'unselect-expr', 'expr=inputExpr("unselect by expr: "); unselect(gatherBy(lambda r, sheet=sheet, expr=expr, curcol=cursorCol: sheet.evalExpr(expr, r, curcol=curcol)), progress=False)', 'unselect rows matching Python expression in any visible column')
|
245
201
|
|
246
202
|
Sheet.addCommand(None, 'select-error-col', 'select(gatherBy(lambda r,c=cursorCol: c.isError(r)), progress=False)', 'select rows with errors in current column')
|
247
203
|
Sheet.addCommand(None, 'select-error', 'select(gatherBy(lambda r,vcols=visibleCols: isinstance(r, TypedExceptionWrapper) or any([c.isError(r) for c in vcols])), progress=False)', 'select rows with errors in any column')
|
@@ -266,5 +222,3 @@ vd.addMenuItems('''
|
|
266
222
|
Row > Toggle select > from top > stoggle-before
|
267
223
|
Row > Toggle select > to bottom > stoggle-after
|
268
224
|
''')
|
269
|
-
|
270
|
-
vd.addGuide('SelectionGuide', SelectionGuide)
|
visidata/settings.py
CHANGED
@@ -84,7 +84,7 @@ class SettingsMgr(collections.OrderedDict):
|
|
84
84
|
if d:
|
85
85
|
for m in self._mappings(obj or vd.activeSheet):
|
86
86
|
v = d.get(self.objname(m))
|
87
|
-
if v:
|
87
|
+
if v is not None:
|
88
88
|
return v
|
89
89
|
|
90
90
|
def iter(self, obj=None):
|
@@ -107,16 +107,17 @@ class SettingsMgr(collections.OrderedDict):
|
|
107
107
|
|
108
108
|
|
109
109
|
class Command:
|
110
|
-
def __init__(self, longname, execstr, helpstr='', module='', deprecated=False):
|
110
|
+
def __init__(self, longname, execstr, helpstr='', module='', replay=True, deprecated=False):
|
111
111
|
self.longname = longname
|
112
112
|
self.execstr = execstr
|
113
113
|
self.helpstr = helpstr
|
114
114
|
self.module = module
|
115
115
|
self.deprecated = deprecated
|
116
|
+
self.replayable = replay
|
116
117
|
|
117
118
|
|
118
119
|
class Option:
|
119
|
-
def __init__(self, name, value, description='', module='', help=''
|
120
|
+
def __init__(self, name, value, description='', module='', help=''):
|
120
121
|
# description gets shows on the manpage and the optionssheet; help is shown on the sidebar while editing
|
121
122
|
self.name = name
|
122
123
|
self.value = value
|
@@ -125,7 +126,6 @@ class Option:
|
|
125
126
|
self.replayable = False
|
126
127
|
self.sheettype = BaseSheet
|
127
128
|
self.module = module
|
128
|
-
self.max_help = max_help
|
129
129
|
|
130
130
|
def __str__(self):
|
131
131
|
return str(self.value)
|
@@ -299,7 +299,7 @@ def _resolve_optalias(vd, optname, optval):
|
|
299
299
|
|
300
300
|
|
301
301
|
@VisiData.api
|
302
|
-
def option(vd, name, default, description, replay=False, sheettype=BaseSheet, help:str=''
|
302
|
+
def option(vd, name, default, description, replay=False, sheettype=BaseSheet, help:str=''):
|
303
303
|
'''Declare a new option.
|
304
304
|
|
305
305
|
- `name`: name of option
|
@@ -312,7 +312,6 @@ def option(vd, name, default, description, replay=False, sheettype=BaseSheet, he
|
|
312
312
|
opt.replayable = replay
|
313
313
|
opt.sheettype=sheettype
|
314
314
|
opt.extrahelp = help
|
315
|
-
opt.max_help = max_help
|
316
315
|
return opt
|
317
316
|
|
318
317
|
|
@@ -320,12 +319,12 @@ def option(vd, name, default, description, replay=False, sheettype=BaseSheet, he
|
|
320
319
|
def theme_option(vd, name, *args, **kwargs):
|
321
320
|
if name.startswith('color_'):
|
322
321
|
kwargs.setdefault('help', vd.help_color)
|
323
|
-
return vd.option(name, *args, **kwargs
|
322
|
+
return vd.option(name, *args, **kwargs)
|
324
323
|
|
325
324
|
|
326
325
|
@BaseSheet.class_api
|
327
326
|
@classmethod
|
328
|
-
def addCommand(cls, keystrokes, longname, execstr, helpstr='', **kwargs):
|
327
|
+
def addCommand(cls, keystrokes, longname, execstr, helpstr='', replay=True, **kwargs):
|
329
328
|
'''Add a new command to *cls* sheet type.
|
330
329
|
|
331
330
|
- *keystrokes*: default keybinding, including **prefixes**.
|
@@ -333,9 +332,10 @@ def addCommand(cls, keystrokes, longname, execstr, helpstr='', **kwargs):
|
|
333
332
|
- *execstr*: Python statement to pass to `exec()`'ed when the command is executed.
|
334
333
|
- *helpstr*: help string shown in the **Commands Sheet**.
|
335
334
|
'''
|
336
|
-
|
335
|
+
cmd = Command(longname, execstr, helpstr=helpstr, module=vd.importingModule, replay=replay, **kwargs)
|
336
|
+
vd.commands.set(longname, cmd, cls)
|
337
337
|
if keystrokes:
|
338
|
-
vd.
|
338
|
+
vd.bindkey(keystrokes, longname, cls)
|
339
339
|
return longname
|
340
340
|
|
341
341
|
def _command(cls, binding, longname, helpstr, **kwargs):
|
@@ -346,12 +346,19 @@ def _command(cls, binding, longname, helpstr, **kwargs):
|
|
346
346
|
return decorator
|
347
347
|
|
348
348
|
BaseSheet.command = classmethod(_command)
|
349
|
-
globalCommand = BaseSheet.addCommand
|
349
|
+
globalCommand = BaseSheet.addCommand # to be deprecated
|
350
|
+
|
351
|
+
|
352
|
+
@VisiData.api
|
353
|
+
def bindkey(vd, keystrokes, longname, obj='BaseSheet'):
|
354
|
+
'Bind *keystrokes* to *longname* on BaseSheet and unbind more-specific bindings of keystrokes.'
|
355
|
+
vd.bindkeys.set(vd.prettykeys(keystrokes.replace(' ', '')), longname, obj)
|
350
356
|
|
351
357
|
@VisiData.api
|
352
|
-
def
|
358
|
+
def unbindkey(vd, keystrokes, obj='BaseSheet'):
|
353
359
|
'Bind *keystrokes* to *longname* on BaseSheet and unbind more-specific bindings of keystrokes.'
|
354
|
-
vd.bindkeys
|
360
|
+
vd.bindkeys.unset(vd.prettykeys(keystrokes.replace(' ', '')), obj)
|
361
|
+
|
355
362
|
|
356
363
|
@BaseSheet.class_api
|
357
364
|
@classmethod
|
@@ -360,14 +367,14 @@ def bindkey(cls, keystrokes, longname):
|
|
360
367
|
oldlongname = vd.bindkeys._get(keystrokes, cls)
|
361
368
|
if oldlongname:
|
362
369
|
vd.warning('%s was already bound to %s' % (keystrokes, oldlongname))
|
363
|
-
vd.
|
370
|
+
vd.bindkey(keystrokes, longname, cls)
|
364
371
|
|
365
372
|
@BaseSheet.class_api
|
366
373
|
@classmethod
|
367
374
|
def unbindkey(cls, keystrokes):
|
368
375
|
'''Unbind `keystrokes` on a `<SheetType>`.
|
369
376
|
May be necessary to avoid a warning when overriding a binding on the same exact class.'''
|
370
|
-
vd.
|
377
|
+
vd.unbindkey(keystrokes, cls)
|
371
378
|
|
372
379
|
@BaseSheet.api
|
373
380
|
def getCommand(sheet, cmd):
|
@@ -376,29 +383,32 @@ def getCommand(sheet, cmd):
|
|
376
383
|
return cmd
|
377
384
|
|
378
385
|
longname = cmd
|
379
|
-
while vd.bindkeys._get(longname, obj=sheet):
|
386
|
+
while vd.bindkeys._get(longname, obj=sheet) is not None:
|
380
387
|
longname = vd.bindkeys._get(longname, obj=sheet)
|
381
388
|
|
382
389
|
return vd.commands._get(longname, obj=sheet)
|
383
390
|
|
384
391
|
|
385
392
|
@VisiData.api
|
386
|
-
def loadConfigFile(vd, fn=''
|
393
|
+
def loadConfigFile(vd, fn=''):
|
387
394
|
p = visidata.Path(fn or vd.options.config)
|
388
|
-
if _globals is None:
|
389
|
-
_globals = vd.getGlobals()
|
390
395
|
if p.exists():
|
396
|
+
newdefs = {}
|
391
397
|
try:
|
392
398
|
with open(p) as fd:
|
393
399
|
code = compile(fd.read(), str(p), 'exec')
|
394
400
|
vd.importingModule = 'visidatarc'
|
395
|
-
exec(code,
|
401
|
+
exec(code, vd.getGlobals(), newdefs)
|
396
402
|
except Exception as e:
|
397
403
|
vd.exceptionCaught(e)
|
398
404
|
finally:
|
399
405
|
vd.importingModule = None
|
400
406
|
|
401
|
-
|
407
|
+
keys = newdefs.get('__all__', None)
|
408
|
+
if keys:
|
409
|
+
vd.addGlobals({k:newdefs[k] for k in keys})
|
410
|
+
else:
|
411
|
+
vd.addGlobals(newdefs)
|
402
412
|
|
403
413
|
|
404
414
|
def addOptions(parser):
|
@@ -470,17 +480,21 @@ def loadConfigAndPlugins(vd, args=AttrDict()):
|
|
470
480
|
|
471
481
|
# user customisations in config file in standard location
|
472
482
|
if vd.options.config:
|
473
|
-
vd.loadConfigFile(vd.options.config
|
483
|
+
vd.loadConfigFile(vd.options.config)
|
474
484
|
|
475
485
|
|
476
486
|
@VisiData.api
|
477
|
-
def importModule(vd, pkgname):
|
487
|
+
def importModule(vd, pkgname, symbols=[]):
|
478
488
|
'Import the given *pkgname*, setting vd.importingModule to *pkgname* before import and resetting to None after.'
|
479
489
|
modparts = pkgname.split('.')
|
480
490
|
vd.importingModule = modparts[-1]
|
481
491
|
r = importlib.import_module(pkgname)
|
482
492
|
vd.importingModule = None
|
483
493
|
vd.importedModules.append(r)
|
494
|
+
vd.addGlobals({pkgname:r})
|
495
|
+
if symbols:
|
496
|
+
vd.addGlobals({k:getattr(r, k) for k in symbols if hasattr(r, k)})
|
497
|
+
|
484
498
|
return r
|
485
499
|
|
486
500
|
|
@@ -488,24 +502,12 @@ def importModule(vd, pkgname):
|
|
488
502
|
def importSubmodules(vd, pkgname):
|
489
503
|
'Import all files below the given *pkgname*'
|
490
504
|
import pkgutil
|
491
|
-
import os.path
|
492
505
|
|
493
506
|
m = vd.importModule(pkgname)
|
494
507
|
for module in pkgutil.walk_packages(m.__path__):
|
495
508
|
vd.importModule(pkgname + '.' + module.name)
|
496
509
|
|
497
510
|
|
498
|
-
@VisiData.api
|
499
|
-
def importStar(vd, pkgname):
|
500
|
-
'Add all symbols from *pkgname* into visidata globals.'
|
501
|
-
import pkgutil
|
502
|
-
import os.path
|
503
|
-
|
504
|
-
m = vd.importModule(pkgname)
|
505
|
-
vd.addGlobals({pkgname:m})
|
506
|
-
vd.addGlobals(m.__dict__)
|
507
|
-
|
508
|
-
|
509
511
|
@VisiData.api
|
510
512
|
def importExternal(vd, modname, pipmodname=''):
|
511
513
|
pipmodname = pipmodname or modname
|