Skip to content

Commit 0931683

Browse files
committed
Implemented --tsv option, closes #41
1 parent ef112ff commit 0931683

File tree

3 files changed

+69
-9
lines changed

3 files changed

+69
-9
lines changed

docs/cli.rst

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ The ``--nl``, ``--csv`` and ``--table`` options are all available.
187187

188188
.. _cli_inserting_data:
189189

190-
Inserting data
191-
==============
190+
Inserting JSON data
191+
===================
192192

193193
If you have data as JSON, you can use ``sqlite-utils insert tablename`` to insert it into a database. The table will be created with the correct (automatically detected) columns if it does not already exist.
194194

@@ -249,6 +249,17 @@ This also means you pipe ``sqlite-utils`` together to easily create a new SQLite
249249
207368,920 Kirkham St,37.760210314285,-122.47073935813
250250
188702,1501 Evans Ave,37.7422086702947,-122.387293152263
251251

252+
Inserting CSV or TSV data
253+
=========================
254+
255+
If your data is in CSV format, you can insert it using the ``--csv`` option::
256+
257+
$ sqlite-utils insert dogs.db dogs docs.csv --csv
258+
259+
For tab-delimited data, use ``--tsv``::
260+
261+
$ sqlite-utils insert dogs.db dogs docs.tsv --tsv
262+
252263
Upserting data
253264
==============
254265

sqlite_utils/cli.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ def insert_upsert_options(fn):
307307
),
308308
click.option("--nl", is_flag=True, help="Expect newline-delimited JSON"),
309309
click.option("-c", "--csv", is_flag=True, help="Expect CSV"),
310+
click.option("--tsv", is_flag=True, help="Expect TSV"),
310311
click.option(
311312
"--batch-size", type=int, default=100, help="Commit every X records"
312313
),
@@ -339,6 +340,7 @@ def insert_upsert_implementation(
339340
pk,
340341
nl,
341342
csv,
343+
tsv,
342344
batch_size,
343345
alter,
344346
upsert,
@@ -347,13 +349,13 @@ def insert_upsert_implementation(
347349
default=None,
348350
):
349351
db = sqlite_utils.Database(path)
350-
if nl and csv:
351-
click.echo("Use just one of --nl and --csv", err=True)
352-
return
352+
if (nl + csv + tsv) >= 2:
353+
raise click.ClickException("Use just one of --nl, --csv or --tsv")
353354
if pk and len(pk) == 1:
354355
pk = pk[0]
355-
if csv:
356-
reader = csv_std.reader(json_file)
356+
if csv or tsv:
357+
dialect = "excel-tab" if tsv else "excel"
358+
reader = csv_std.reader(json_file, dialect=dialect)
357359
headers = next(reader)
358360
docs = (dict(zip(headers, row)) for row in reader)
359361
elif nl:
@@ -381,7 +383,18 @@ def insert_upsert_implementation(
381383
"--ignore", is_flag=True, default=False, help="Ignore records if pk already exists"
382384
)
383385
def insert(
384-
path, table, json_file, pk, nl, csv, batch_size, alter, ignore, not_null, default
386+
path,
387+
table,
388+
json_file,
389+
pk,
390+
nl,
391+
csv,
392+
tsv,
393+
batch_size,
394+
alter,
395+
ignore,
396+
not_null,
397+
default,
385398
):
386399
"""
387400
Insert records from JSON file into a table, creating the table if it
@@ -396,6 +409,7 @@ def insert(
396409
pk,
397410
nl,
398411
csv,
412+
tsv,
399413
batch_size,
400414
alter=alter,
401415
upsert=False,
@@ -407,7 +421,9 @@ def insert(
407421

408422
@cli.command()
409423
@insert_upsert_options
410-
def upsert(path, table, json_file, pk, nl, csv, batch_size, alter, not_null, default):
424+
def upsert(
425+
path, table, json_file, pk, nl, csv, tsv, batch_size, alter, not_null, default
426+
):
411427
"""
412428
Upsert records based on their primary key. Works like 'insert' but if
413429
an incoming record has a primary key that matches an existing record
@@ -420,6 +436,7 @@ def upsert(path, table, json_file, pk, nl, csv, batch_size, alter, not_null, def
420436
pk,
421437
nl,
422438
csv,
439+
tsv,
423440
batch_size,
424441
alter=alter,
425442
upsert=True,

tests/test_cli.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,38 @@ def test_insert_ignore(db_path, tmpdir):
511511
)
512512

513513

514+
@pytest.mark.parametrize(
515+
"content,option",
516+
(("foo\tbar\tbaz\n1\t2\t3", "--tsv"), ("foo,bar,baz\n1,2,3", "--csv")),
517+
)
518+
def test_insert_csv_tsv(content, option, db_path, tmpdir):
519+
db = Database(db_path)
520+
file_path = str(tmpdir / "insert.csv-tsv")
521+
open(file_path, "w").write(content)
522+
result = CliRunner().invoke(cli.cli, ["insert", db_path, "data", file_path, option])
523+
assert 0 == result.exit_code
524+
assert [{"foo": "1", "bar": "2", "baz": "3"}] == list(db["data"].rows)
525+
526+
527+
@pytest.mark.parametrize(
528+
"options",
529+
(
530+
["--tsv", "--nl"],
531+
["--tsv", "--csv"],
532+
["--csv", "--nl"],
533+
["--csv", "--nl", "--tsv"],
534+
),
535+
)
536+
def test_only_allow_one_of_nl_tsv_csv(options, db_path, tmpdir):
537+
file_path = str(tmpdir / "insert.csv-tsv")
538+
open(file_path, "w").write("foo")
539+
result = CliRunner().invoke(
540+
cli.cli, ["insert", db_path, "data", file_path] + options
541+
)
542+
assert 0 != result.exit_code
543+
assert "Error: Use just one of --nl, --csv or --tsv" == result.output.strip()
544+
545+
514546
def test_upsert(db_path, tmpdir):
515547
test_insert_multiple_with_primary_key(db_path, tmpdir)
516548
json_path = str(tmpdir / "upsert.json")

0 commit comments

Comments
 (0)