Skip to content

Commit 50d2096

Browse files
committed
--no-headers option for sqlite-utils insert --csv, closes #228
1 parent 427dace commit 50d2096

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

docs/cli.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,17 @@ You can import that using::
518518

519519
Passing ``--delimiter``, ``--quotechar`` or ``--sniff`` implies ``--csv``, so you can omit the ``--csv`` option.
520520

521+
.. _cli_insert_csv_tsv_no_header:
522+
523+
CSV files without a header row
524+
------------------------------
525+
526+
The first row of any CSV or TSV file is expected to contain the names of the columns in that file.
527+
528+
If your file does not include this row, you can use the ``--no-headers`` option to specify that the tool should not use that fist row as headers.
529+
530+
If you do this, the table will be created with column names called ``untitled_1`` and ``untitled_2`` and so on. You can then rename them using the ``sqlite-utils transform ... --rename`` command, see :ref:`cli_transform_table`.
531+
521532
.. _cli_insert_replace:
522533

523534
Insert-replacing data

sqlite_utils/cli.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,9 @@ def insert_upsert_options(fn):
618618
click.option(
619619
"--sniff", is_flag=True, help="Detect delimiter and quote character"
620620
),
621+
click.option(
622+
"--no-headers", is_flag=True, help="CSV file has no header row"
623+
),
621624
click.option(
622625
"--batch-size", type=int, default=100, help="Commit every X records"
623626
),
@@ -660,6 +663,7 @@ def insert_upsert_implementation(
660663
delimiter,
661664
quotechar,
662665
sniff,
666+
no_headers,
663667
batch_size,
664668
alter,
665669
upsert,
@@ -674,7 +678,7 @@ def insert_upsert_implementation(
674678
):
675679
db = sqlite_utils.Database(path)
676680
_load_extensions(db, load_extension)
677-
if delimiter or quotechar or sniff:
681+
if delimiter or quotechar or sniff or no_headers:
678682
csv = True
679683
if (nl + csv + tsv) >= 2:
680684
raise click.ClickException("Use just one of --nl, --csv or --tsv")
@@ -699,7 +703,12 @@ def insert_upsert_implementation(
699703
if quotechar:
700704
csv_reader_args["quotechar"] = quotechar
701705
reader = csv_std.reader(decoded, **csv_reader_args)
702-
headers = next(reader)
706+
first_row = next(reader)
707+
if no_headers:
708+
headers = ["untitled_{}".format(i + 1) for i in range(len(first_row))]
709+
reader = itertools.chain([first_row], reader)
710+
else:
711+
headers = first_row
703712
docs = (dict(zip(headers, row)) for row in reader)
704713
else:
705714
try:
@@ -756,6 +765,7 @@ def insert(
756765
delimiter,
757766
quotechar,
758767
sniff,
768+
no_headers,
759769
batch_size,
760770
alter,
761771
encoding,
@@ -785,6 +795,7 @@ def insert(
785795
delimiter,
786796
quotechar,
787797
sniff,
798+
no_headers,
788799
batch_size,
789800
alter=alter,
790801
upsert=False,
@@ -815,6 +826,7 @@ def upsert(
815826
delimiter,
816827
quotechar,
817828
sniff,
829+
no_headers,
818830
alter,
819831
not_null,
820832
default,
@@ -839,6 +851,7 @@ def upsert(
839851
delimiter,
840852
quotechar,
841853
sniff,
854+
no_headers,
842855
batch_size,
843856
alter=alter,
844857
upsert=True,

tests/test_cli.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1819,3 +1819,39 @@ def test_long_csv_column_value(tmpdir):
18191819
rows = list(db["bigtable"].rows)
18201820
assert len(rows) == 1
18211821
assert rows[0]["text"] == long_string
1822+
1823+
1824+
@pytest.mark.parametrize(
1825+
"args",
1826+
(
1827+
["--csv", "--no-headers"],
1828+
["--no-headers"],
1829+
),
1830+
)
1831+
def test_csv_import_no_headers(tmpdir, args):
1832+
db_path = str(tmpdir / "test.db")
1833+
csv_path = str(tmpdir / "test.csv")
1834+
csv_file = open(csv_path, "w")
1835+
csv_file.write("Cleo,Dog,5\n")
1836+
csv_file.write("Tracy,Spider,7\n")
1837+
csv_file.close()
1838+
result = CliRunner().invoke(
1839+
cli.cli,
1840+
["insert", db_path, "creatures", csv_path] + args,
1841+
catch_exceptions=False,
1842+
)
1843+
assert result.exit_code == 0
1844+
db = Database(db_path)
1845+
schema = db["creatures"].schema
1846+
assert schema == (
1847+
"CREATE TABLE [creatures] (\n"
1848+
" [untitled_1] TEXT,\n"
1849+
" [untitled_2] TEXT,\n"
1850+
" [untitled_3] TEXT\n"
1851+
")"
1852+
)
1853+
rows = list(db["creatures"].rows)
1854+
assert rows == [
1855+
{"untitled_1": "Cleo", "untitled_2": "Dog", "untitled_3": "5"},
1856+
{"untitled_1": "Tracy", "untitled_2": "Spider", "untitled_3": "7"},
1857+
]

0 commit comments

Comments
 (0)