internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: saulpw/visidata

Issue:
SQLite databases with invalid unicode not supported
**Small description**

Opening a SQLite database will fail when a cell in a TEXT column has invalid unicode characters

**Expected result**

Either the specific cell that has invalid unicode is not imported, or it is imported but the invalid characters are stripped or slash-escaped.

**Actual result with screenshot**

![error screenshot](https://user-images.githubusercontent.com/5001092/137644252-3474128c-52be-40cb-89bb-6b13498169d7.png)

![error screenshot](https://user-images.githubusercontent.com/5001092/137644398-e3b388e3-ebfe-476e-94b3-ede0a418223f.png)

(those are errors from two different DBs that I've seen this problem on)

**Steps to reproduce with sample data and a .vd**

Here's a SQLite file that has this problem: https://hack.wesleyac.com/test.sqlite

**Additional context**

`vd --version`: `saul.pw/VisiData v2.4`

dbcli/litecli#89 is a similar issue in a different python project, which may have useful context for fixing this



Discussion:

Resolving patch:
diff --git a/visidata/loaders/sqlite.py b/visidata/loaders/sqlite.py
--- a/visidata/loaders/sqlite.py
+++ b/visidata/loaders/sqlite.py
@@ -21,7 +21,9 @@ def resolve(self):
 
     def conn(self):
         import sqlite3
-        return sqlite3.connect(str(self.resolve()))
+        con = sqlite3.connect(str(self.resolve()))
+        con.text_factory = lambda s, enc=self.options.encoding: s.decode(enc)
+        return con
 
     def execute(self, conn, sql, parms=None):
         parms = parms or []
@@ -55,10 +57,7 @@ def parse_sqlite_type(t):
                     if colkey:
                         self.setKeys([c])
 
-            try:
-                r = self.execute(conn, 'SELECT rowid, * FROM "%s"' % tblname)
-            except sqlite3.OperationalError:
-                vd.error('tables WITHOUT ROWID not supported')
+            r = self.execute(conn, 'SELECT rowid, * FROM "%s"' % tblname)
             yield from Progress(r, total=r.rowcount-1)
 
     @asyncthread
@@ -171,6 +170,7 @@ def iterload(self):
 def save_sqlite(vd, p, *vsheets):
     import sqlite3
     conn = sqlite3.connect(str(p))
+    conn.text_factory = lambda s, enc=vsheets[0].options.encoding: s.decode(enc)
     conn.row_factory = sqlite3.Row
     c = conn.cursor()
 


Test patch:
diff --git a/tests/golden/invalid_unicode_sqlite.tsv b/tests/golden/invalid_unicode_sqlite.tsv
new file mode 100644
--- /dev/null
+++ b/tests/golden/invalid_unicode_sqlite.tsv
@@ -0,0 +1,2 @@
+contents
+test test   �(
diff --git a/tests/invalid_unicode.sqlite b/tests/invalid_unicode.sqlite
new file mode 100644
Binary files /dev/null and b/tests/invalid_unicode.sqlite differ
diff --git a/tests/invalid_unicode_sqlite.vd b/tests/invalid_unicode_sqlite.vd
new file mode 100644
--- /dev/null
+++ b/tests/invalid_unicode_sqlite.vd
@@ -0,0 +1,5 @@
+sheet	col	row	longname	input	keystrokes	comment
+global		encoding	set-option	latin-1		
+invalid_unicode		encoding	set-option	latin-1		
+			open-file	tests/invalid_unicode.sqlite	o	
+invalid_unicode		キTest	open-row		Enter	open sheet with copies of rows referenced in current row
Repository: saulpw/visidata

Issue:
options.quitguard = True in my rc file doesn't prevent vd from silently quitting
**Small description**

`options.quitguard = True` in my ~/.visidatarc file doesn't prevent `vd` from quitting via `q` _without` any confirmation when I have modified the loaded CSV.

**Expected result**

With `options.quitguard = True` in my `~/.visidatarc` file I expect after  I have modified the loaded CSV that `Q` asks me to confirm whether I want to quit despite the modifications.

**Actual result with screenshot**

`vd` quits directly despite the modifications.

**Steps to reproduce with sample data and a .vd**

1. Unzip the attached zip. 
2. Put the included `.visidatarc` in your rc file location (`~`) . 
3. Start `vd` with the included file `quitguard-sample.csv`. 
4. Then do the actions listed in the command log `quitguard-sample.vd`.
5. Then quit with `Q`

**Additional context**

Version of VisiData: v2.8

Zip file with the sample data: [quitguard_sample.zip](https://github.com/saulpw/visidata/files/8075676/quitguard_sample.zip)




Discussion:
The important part is "in rc file". `--quitguard=True` on the commandline appears to block quitting. 

**Update**
An additional important part is that the `.vd` contains an `expr-col` command. If you do an `edit-cell` command, and have `options.quitguard` in your visidatarc, then VisiData asks for confirmation.

The very specific combination of "options.quitguard=True" in rc, and `expr-col` fail to quitguard. Very curious, indeed!

**Update**

Other commands that add a column, are similarly not being guarded against when quitguard is set to True in the rc.

**Update**

Commands that add a column seem to have `vs.hasBeenModified = False`. `--quitguard=False` has been working because it sets `quitguard` on a specific sheet. When a specific sheet has been set to quitguard=True, then quitguard asks for confirmation, regardless if the sheet was modified.

**We need to check if adding a column can have hasBeenModified set to True. This might also be philosophical: if we want adding a column to be constituted as a modification.**

Resolving patch:
diff --git a/visidata/sheets.py b/visidata/sheets.py
--- a/visidata/sheets.py
+++ b/visidata/sheets.py
@@ -499,6 +499,7 @@ def addColumn(self, *cols, index=None):
             col.recalc(self)
             self.columns.insert(index+i, col)
             Sheet.visibleCols.fget.cache_clear()
+        self.setModified()
 
         return cols[0]
 


Test patch:
Repository: saulpw/visidata

Issue:
[2.9dev] using "d" to delete a selected row doesn't remove from sheet.selectedRows
**Small description**
When a row is deleted with `d`, it is not removed from `sheet.selectedRows`.

**Expected result**
For the row to be removed like when `gd` is used.

**Steps to reproduce with sample data and a .vd**
1. open with `vd --config/=/dev/null file.csv`
2. select a row with "`t`" 
3. delete that row with "`d`"
4. `=vd.sheet.selectedRows` < should be 0


Discussion:

Resolving patch:
diff --git a/visidata/clipboard.py b/visidata/clipboard.py
--- a/visidata/clipboard.py
+++ b/visidata/clipboard.py
@@ -106,6 +106,10 @@ def delete_row(sheet, rowidx):
     if not sheet.defer:
         oldrow = sheet.rows.pop(rowidx)
         vd.addUndo(sheet.rows.insert, rowidx, oldrow)
+        # clear the deleted row from selected rows
+        if sheet.isSelected(oldrow):
+            sheet.addUndoSelection()
+            sheet.unselectRow(oldrow)
     else:
         oldrow = sheet.rows[rowidx]
         sheet.rowDeleted(oldrow)
diff --git a/visidata/modify.py b/visidata/modify.py
--- a/visidata/modify.py
+++ b/visidata/modify.py
@@ -72,6 +72,8 @@ def _undoCellChanged(col, row, oldval):
 def rowDeleted(self, row):
     'Mark row as a deferred delete-row'
     self._deferredDels[self.rowid(row)] = row
+    self.addUndoSelection()
+    self.unselectRow(row)
     def _undoRowDeleted(sheet, row):
         if sheet.rowid(row) not in sheet._deferredDels:
             vd.warning('cannot undo to before commit')


Test patch:
Repository: saulpw/visidata

Issue:
[undo develop] undoing a reload blanks the entire sheet
Since v2.5 undo for reload has been removed, and replaced with quitguard+confirm! However, in that case an undo should not be set.

Current behaviour is that it blanks the sheet.


Discussion:
We can block undos for reload, using this: https://github.com/saulpw/visidata/commit/135aad6e1e20d5e485d9f4950ac7c71784f27330#diff-b99dd34ef8d9894525621b5b3013867b22a9d257cee647261c252d4c57112ddfR10

This will need to be tested. Does it go to an undo for the most recent modification command before a reload?

Resolving patch:
diff --git a/visidata/undo.py b/visidata/undo.py
--- a/visidata/undo.py
+++ b/visidata/undo.py
@@ -7,7 +7,7 @@
 
 vd.option('undo', True, 'enable undo/redo')
 
-nonUndo = '''commit open-file'''.split()
+nonUndo = '''commit open-file reload-sheet'''.split()
 
 def isUndoableCommand(longname):
     for n in nonUndo:


Test patch:
Repository: saulpw/visidata

Issue:
[v2.9dev] Disable adding new row in DirSheet
**Small description**
Unless used, `add-row` should probably be disabled on DirSheet as it creates an error

**Expected result**
A warning to be shown to the user that a new row/file cannot be created.

**Actual result with screenshot**
![image](https://user-images.githubusercontent.com/11225502/155373843-aeef6d8e-cc96-4559-b3e6-dc9690aab25f.png)

**Steps to reproduce with sample data and a .vd**
Open vd directory with vd (`vd .`) and press `a`


Discussion:

Resolving patch:
diff --git a/visidata/shell.py b/visidata/shell.py
--- a/visidata/shell.py
+++ b/visidata/shell.py
@@ -151,6 +151,9 @@ def removeFile(self, path):
     def deleteSourceRow(self, r):
         self.removeFile(r)
 
+    def newRow(self):
+        vd.fail('new file not supported')
+
     def iterload(self):
         hidden_files = self.options.dir_hidden
 


Test patch:
Repository: saulpw/visidata

Issue:
Fix documentation on website
Not sure if this belongs here, but I believe to have found a small issue on the website.

Paragraph # 7 in [10 Ways to Use VisiData](https://www.visidata.org/blog/2020/ten/) says you should use `visidata.view_pandas(df)` to view a dataframe in pandas.

I believe that should be `visidata.vd.view_pandas(df)`

![image](https://user-images.githubusercontent.com/14904570/158566552-df4f22c0-cb08-476c-a2d9-076577ebad5c.png)



Discussion:
This might actually be a bug! 

I need to check in with @saulpw, but `def view_pandas` has a `VisiData.global_api` decorator, which should support `visidata.view_pandas`. But, you are right that currently `visidata.vd.view_pandas` is what works, and possibly the documentation should be changed in the meanwhile.
VisiData is moving towards a model of `visidata.vd.func`, so I went ahead and updated the documentation! The change should go live soon. 

I will keep this issue open until it is understood why `visidata.view_pandas` stopped working. It appears to have broken in this commit: 44429926151f99cfc45665bfe46b99f57f85c9d6.

Thanks for drawing our attention to this!

Resolving patch:
diff --git a/visidata/vdobj.py b/visidata/vdobj.py
--- a/visidata/vdobj.py
+++ b/visidata/vdobj.py
@@ -32,6 +32,7 @@ def global_api(cls, func):
         'Make global func() and identical vd.func()'
         def _vdfunc(*args, **kwargs):
             return func(visidata.vd, *args, **kwargs)
+        visidata.vd.addGlobals({func.__name__: func})
         setattr(cls, func.__name__, func)
         return wraps(func)(_vdfunc)
 


Test patch:
Repository: saulpw/visidata

Issue:
vd --help doesn't play well with pipes and non-ttys
**Small description**

    vd --help | col -b > ~/tmp/vd-help.txt

has garbled codes in the resulting file.

**Expected result**

A nice plain text file containing the help text to vd.

**Additional context**

This happens in version 2.6.1 and version 2.8

See also [issue 1089](https://github.com/saulpw/visidata/issues/1089).

_Side note:_ I personally think `vd --help` should not use _any_ control characters  and be rather brief, while a full man page could be produced with `--man` - but that's obviously subjective. 


Discussion:
## Debugging Notes

The output of ` vd --help | col -b` changed in 7ab2f1249c2099dc506e92c8603df005f5fc980e which was between v2.4 and v2.5.
We do package a `.txt` version of the manpage with VisiData, and the simplest change may be that `vd --help` outputs that. I will give that a whirl!

Resolving patch:
diff --git a/visidata/main.py b/visidata/main.py
--- a/visidata/main.py
+++ b/visidata/main.py
@@ -13,6 +13,7 @@
 import datetime
 import signal
 import warnings
+from pkg_resources import resource_filename
 
 from visidata import vd, options, run, BaseSheet, AttrDict
 from visidata import Path
@@ -81,6 +82,14 @@ def optalias(abbr, name, val=None):
 
 def main_vd():
     'Open the given sources using the VisiData interface.'
+    if '-v' in sys.argv or '--version' in sys.argv:
+        print(vd.version_info)
+        return 0
+    if '-h' in sys.argv or '--help' in sys.argv:
+        with open(resource_filename(__name__, 'man/vd.txt'), 'r') as fp:
+            print(fp.read())
+        return 0
+
     try:
         locale.setlocale(locale.LC_ALL, '')
     except locale.Error as e:
@@ -121,15 +130,8 @@ def main_vd():
             fmtargs.append(arg)
         elif arg in ['--']:
             optsdone = True
-        elif arg in ['-v', '--version']:
-            print(vd.version_info)
-            return 0
         elif arg == '-':
             inputs.append((vd.stdinSource, copy(current_args)))
-        elif arg in ['-h', '--help']:
-            import curses
-            curses.wrapper(lambda scr: vd.openManPage())
-            return 0
         elif arg in ['-g', '--global']:
             flGlobal = True
         elif arg in ['-n', '--nonglobal']:


Test patch:
Repository: saulpw/visidata

Issue:
vdj variable name issues
Hello,

I'm using `visidata` version 4f9a1d5e74f6801e3f17bd8c53c734cef4a24150 and I've created a very simple vdj file with a variable in place, but I'm getting an error on playback.

```
$ cat test.vdj
#!vd -p
{"longname": "open-file", "input": "myfile_{date}.xlsx", "keystrokes": "o"}
```

And here's the error:

```
$ vd -b -p test.vdj date=2022-05-02 myfile_{date}.xlsx
myfile_{date}.xlsx does not exist, creating new sheet
And yesterday things went on just as usual.
Traceback (most recent call last):
  File "/home/zeke/.local/bin/vd", line 6, in <module>
    visidata.main.vd_cli()
  File "/home/zeke/.local/lib/python3.10/site-packages/visidata/main.py", line 332, in vd_cli
    rc = main_vd()
  File "/home/zeke/.local/lib/python3.10/site-packages/visidata/main.py", line 305, in main_vd
    vs = eval_vd(vdfile, *fmtargs, **fmtkwargs)
  File "/home/zeke/.local/lib/python3.10/site-packages/visidata/main.py", line 36, in eval_vd
    log = log.format(*args, **kwargs)
KeyError: '"longname"'
```

Saul says `{varname}` is acceptable with `vd` or `vdj` files:
https://github.com/saulpw/visidata/discussions/1350#discussioncomment-2536775

What am I doing wrong?



Discussion:
Results with a `vd` file:

```
$ cat test.vd
sheet   col     row     longname        input   keystrokes      comment
                        open-file       myfile_{date}.xlsx      o
```

and the replay:
```
$ vd -b -p test.vd date=2022-05-02 myfile_{date}.xlsx
myfile_{date}.xlsx does not exist, creating new sheet
You're enough to try the patience of an oyster!
opening test.vd as vd
"myfile_2022-05-02.xlsx"
opening myfile_2022-05-02.xlsx as xlsx
replay complete
```
Thank you for opening an issue for this! This is on my todo list. Variable names are not supported yet in `.vdj`. 

The fix is being prioritised by me in the near future. =)
That’s great. Thank you.


Resolving patch:
diff --git a/visidata/main.py b/visidata/main.py
--- a/visidata/main.py
+++ b/visidata/main.py
@@ -33,7 +33,11 @@ def eval_vd(logpath, *args, **kwargs):
     'Instantiate logpath with args/kwargs replaced and replay all commands.'
     log = logpath.read_text()
     if args or kwargs:
-        log = log.format(*args, **kwargs)
+        if logpath.ext in ['vdj', 'json', 'jsonl']:
+            from string import Template
+            log = Template(log).safe_substitute(**kwargs)
+        else:
+            log = log.format(*args, **kwargs)
 
     src = Path(logpath.given, fp=io.StringIO(log), filesize=len(log))
     vs = vd.openSource(src, filetype=src.ext)


Test patch:
Repository: saulpw/visidata

Issue:
v2.9: Switch from .vd to .vdj for cmdlogs appears to be incomplete
**Small description**

As of https://github.com/saulpw/visidata/commit/b6e71931139325b7a9d5af4bd05273277a04124a, `Control-d` now defaults to saving cmdlogs as `.vdj` files, instead of `.vd` files. But executing `Control-s` from a cmdlog still defaults to `.vd`, I believe due to this line:

https://github.com/saulpw/visidata/blob/8a768b785ad833e908ba00b1ccdbd1259239a51a/visidata/cmdlog.py#L171

**Expected result**

That saving a cmdlog via `Control-d` and executing `Control-s` from the cmdlog suggest the same default file extension (and perhaps also the same filename?).

**Actual result with screenshot**

Using `Control-d`:

<img width="310" alt="Screen Shot 2022-07-26 at 10 15 50 AM" src="https://user-images.githubusercontent.com/534702/181028339-eece8913-3a90-4c80-a000-6919030fdcab.png">

Using `Control-s` from cmdlog:

<img width="299" alt="Screen Shot 2022-07-26 at 10 16 03 AM" src="https://user-images.githubusercontent.com/534702/181028345-ead7dcc8-a64f-41d1-8a93-638ecf4ee96b.png">


**Steps to reproduce with sample data and a .vd**

- `vd sample_data/benchmark.csv`
- `Control-d` to see one default
- `Shift-D` followed by `Control-s` to see the other

**Additional context**

VisiData v2.9.1



Discussion:

Resolving patch:
diff --git a/visidata/cmdlog.py b/visidata/cmdlog.py
--- a/visidata/cmdlog.py
+++ b/visidata/cmdlog.py
@@ -238,8 +238,10 @@ class CommandLog(_CommandLog, VisiDataMetaSheet):
 
 class CommandLogJsonl(_CommandLog, JsonLinesSheet):
 
-    def newRow(self):
-        return JsonLinesSheet.newRow(self)
+    filetype = 'vdj'
+
+    def newRow(self, **fields):
+        return AttrDict(JsonLinesSheet.newRow(self, **fields))
 
     def iterload(self):
         for r in JsonLinesSheet.iterload(self):
@@ -420,12 +422,12 @@ def cmdlog(sheet):
     rows = sheet.cmdlog_sheet.rows
     if isinstance(sheet.source, BaseSheet):
         rows = sheet.source.cmdlog.rows + rows
-    return CommandLog(sheet.name+'_cmdlog', source=sheet, rows=rows)
+    return CommandLogJsonl(sheet.name+'_cmdlog', source=sheet, rows=rows)
 
 
 @BaseSheet.lazy_property
 def cmdlog_sheet(sheet):
-    return CommandLog(sheet.name+'_cmdlog', source=sheet, rows=[])
+    return CommandLogJsonl(sheet.name+'_cmdlog', source=sheet, rows=[])
 
 
 @BaseSheet.property
@@ -448,7 +450,7 @@ def shortcut(self):
 @VisiData.property
 def cmdlog(vd):
     if not vd._cmdlog:
-        vd._cmdlog = CommandLog('cmdlog', rows=[])
+        vd._cmdlog = CommandLogJsonl('cmdlog', rows=[])
         vd.beforeExecHooks.append(vd._cmdlog.beforeExecHook)
     return vd._cmdlog
 
diff --git a/visidata/loaders/json.py b/visidata/loaders/json.py
--- a/visidata/loaders/json.py
+++ b/visidata/loaders/json.py
@@ -55,8 +55,8 @@ def addRow(self, row, index=None):
 
         return super().addRow(row, index=index)
 
-    def newRow(self):
-        return {}
+    def newRow(self, **fields):
+        return fields
 
 
 ## saving json and jsonl


Test patch:
Repository: saulpw/visidata

Issue:
Confusing model and keystroke consumption in menu bar
From [a discussion](https://github.com/saulpw/visidata/discussions/1464#discussioncomment-3368730):

I would think that once the menubar is active (ctrl+h) I can press those letters to go to their sub-menus.

Additionally, if I hit alt+c for the column, and then change my mind and want to go to the row menu:

1. `r` does nothing;
2. `alt+r` calls a `row key by regex` command; I suspect the menu ate the `alt` key and escaped the menu and then executed `r`.

This is confusing because is the menu system eating characters or not?


Discussion:

Resolving patch:
diff --git a/visidata/menu.py b/visidata/menu.py
--- a/visidata/menu.py
+++ b/visidata/menu.py
@@ -776,6 +776,10 @@ def runMenu(vd):
             else:
                 break
 
+        elif k in main_menu.keys():
+            sheet.pressMenu(main_menu[k])
+
+
         sheet.checkMenu()
 
     finally:
@@ -786,6 +790,7 @@ def runMenu(vd):
     vd.draw_all()
     sheet.execCommand(currentItem.longname)
 
+main_menu = {'f': 'File', 'e': 'Edit', 'v': 'View', 'c': 'Column', 'r': 'Row', 'd': 'Data', 'p': 'Plot', 's': 'System', 'h': 'Help'}
 
 BaseSheet.addCommand('^[f', 'menu-file', 'pressMenu("File")', '')
 BaseSheet.addCommand('^[e', 'menu-edit', 'pressMenu("Edit")', '')


Test patch:
Repository: saulpw/visidata

Issue:
[alt-shift- ]  The open-memos keyboard shortcut doesn't work
**Small description**
The open-memos keyboard shortcut doesn't work

**Expected result**
The open-memos keyboard shortcut would open the memo sheet.

**Actual result with screenshot**
https://asciinema.org/a/iFDKQSKcR6Sn9XTPsRCb3hb2f

**Steps to reproduce with sample data and a .vd**

`vd` then press `Alt+Shift+M`  VisiData is calling it `Alt+Shift+M`, while the shortcut is called `Alt+M`

**Additional context**
Please include the version of VisiData.  Latest develop version.



Discussion:
Nice find! `Alt+Shift+<keystroke>` not working as expected is the bug. `open-memos` is our only one in this category for now.
The culprit is `vd.prettykeys`. Essentially, this line https://github.com/saulpw/visidata/blob/03a2325902e9c905ee2873b692028930462550f5/visidata/keys.py#L77 results in the ignoring of `Shift+` in a `Shift+<keystroke` for `Alt+` and `Ctrl+`. What is left to decide is whether to support `Alt+Shift+`. If we do, then that is where I change the code. 

(@saulpw) 

Resolving patch:
diff --git a/visidata/keys.py b/visidata/keys.py
--- a/visidata/keys.py
+++ b/visidata/keys.py
@@ -74,7 +74,8 @@ def prettykeys(vd, key):
 
     # replace ^ with Ctrl but not if ^ is last char
     key = key[:-1].replace('^', 'Ctrl+')+key[-1]
-    if key[-1] in string.ascii_uppercase and '+' not in key and '_' not in key:
+    # allow Shift+ for Alt keys
+    if key[-1] in string.ascii_uppercase and ('+' not in key and 'Alt+' not in key) and '_' not in key:
         key = key[:-1] + 'Shift+' + key[-1]
 
     return key.strip()
diff --git a/visidata/main.py b/visidata/main.py
--- a/visidata/main.py
+++ b/visidata/main.py
@@ -306,7 +306,11 @@ def main_vd():
             if startcol:
                 for vs in sheets:
                     if vs:
-                        vs.moveToCol(startcol) or vd.warning(f'{vs} has no column "{startcol}"')
+                        if not vs.moveToCol(startcol):
+                            if startcol.isdigit():
+                                vs.moveToCol(int(startcol)) # handle indexing by column number
+                            else:
+                                vd.warning(f'{vs} has no column "{startcol}"')
 
         if not args.batch:
             run(vd.sheets[0])


Test patch:
Repository: saulpw/visidata

Issue:
[sqlite] Selecting table from the CLI not working
**Small description**
Selecting a sqlite table from the CLI is not working

**Expected result**
Go directly to a sqlite table from the CLI args.

**Actual result with screenshot**

https://asciinema.org/a/oizQ0C2Wmz8D9XOrUesiU69Sq


**Steps to reproduce with sample data and a .vd**

```
vd employees.sqlite +:emp_view::
```

**Additional context**
Please include the version of VisiData. latest develop version


Discussion:

Resolving patch:
diff --git a/visidata/main.py b/visidata/main.py
--- a/visidata/main.py
+++ b/visidata/main.py
@@ -286,7 +286,8 @@ def main_vd():
                     vd.warning(f'no sheet "{startsheet}"')
                     continue
 
-                vd.sync(vs.ensureLoaded())
+                vs.ensureLoaded()
+                vd.sync()
                 vd.clearCaches()
                 for startsheet in startsheets[1:]:
                     rowidx = vs.getRowIndexFromStr(options.rowkey_prefix + startsheet)


Test patch: