From f7efe77ccb5f444dd4bc90a9df1ed95697823a9c Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sat, 12 Dec 2020 20:46:13 -0800 Subject: [PATCH] Tests for analyze tables --- sqlite_utils/cli.py | 15 ++++-- tests/test_analyze_tables.py | 91 ++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 tests/test_analyze_tables.py diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py index 7e653e6..fe052d2 100644 --- a/sqlite_utils/cli.py +++ b/sqlite_utils/cli.py @@ -1361,7 +1361,14 @@ def insert_files( required=True, ) @click.argument("tables", nargs=-1) -@click.option("-c", "--column", "columns", type=str, multiple=True, help="Specific columns to analyze") +@click.option( + "-c", + "--column", + "columns", + type=str, + multiple=True, + help="Specific columns to analyze", +) @click.option("--save", is_flag=True, help="Save results to _analyze_tables table") @load_extension_option def analyze_tables( @@ -1381,11 +1388,13 @@ def analyze_tables( for table in tables: table_counts[table] = db[table].count for column in db[table].columns: - if (not columns or column.name in columns): + if not columns or column.name in columns: todo.append((table, column.name)) # Now we now how many we need to do for i, (table, column) in enumerate(todo): - column_details = db[table].analyze_column(column, total_rows=table_counts[table]) + column_details = db[table].analyze_column( + column, total_rows=table_counts[table] + ) if save: db["_analyze_tables"].insert( column_details._asdict(), pk=("table", "column"), replace=True diff --git a/tests/test_analyze_tables.py b/tests/test_analyze_tables.py new file mode 100644 index 0000000..8842ee7 --- /dev/null +++ b/tests/test_analyze_tables.py @@ -0,0 +1,91 @@ +from sqlite_utils.db import ForeignKey, ColumnDetails +from sqlite_utils import cli +from sqlite_utils.utils import OperationalError +from click.testing import CliRunner +import pytest +import sqlite3 +import textwrap + + +@pytest.fixture +def db_to_analyze(fresh_db): + stuff = fresh_db["stuff"] + stuff.insert_all( + [ + {"id": 1, "owner": "Terry", "size": 5}, + {"id": 2, "owner": "Joan", "size": 4}, + {"id": 3, "owner": "Kumar", "size": 5}, + {"id": 4, "owner": "Anne", "size": 5}, + {"id": 5, "owner": "Terry", "size": 5}, + {"id": 6, "owner": "Joan", "size": 4}, + {"id": 7, "owner": "Kumar", "size": 5}, + {"id": 8, "owner": "Joan", "size": 4}, + ], + pk="id", + ) + return fresh_db + + +@pytest.mark.parametrize( + "column,expected", + [ + ( + "id", + ColumnDetails( + table="stuff", + column="id", + total_rows=8, + num_null=0, + num_blank=0, + num_distinct=8, + most_common=None, + least_common=None, + ), + ), + ( + "owner", + ColumnDetails( + table="stuff", + column="owner", + total_rows=8, + num_null=0, + num_blank=0, + num_distinct=4, + most_common=[("Joan", 3), ("Terry", 2)], + least_common=[("Anne", 1), ("Kumar", 2)], + ), + ), + ( + "size", + ColumnDetails( + table="stuff", + column="size", + total_rows=8, + num_null=0, + num_blank=0, + num_distinct=2, + most_common=[(5, 5), (4, 3)], + least_common=None, + ), + ), + ], +) +def test_analyze_column(db_to_analyze, column, expected): + assert db_to_analyze["stuff"].analyze_column(column, common_limit=2) == expected + + +def test_analyze_table(db_to_analyze, tmpdir): + path = str(tmpdir / "test.db") + db = sqlite3.connect(path) + db.executescript("\n".join(db_to_analyze.conn.iterdump())) + result = CliRunner().invoke(cli.cli, ["analyze-tables", path]) + assert ( + result.output.strip() + == textwrap.dedent( + """ + 1/3: ColumnDetails(table='stuff', column='id', total_rows=8, num_null=0, num_blank=0, num_distinct=8, most_common=None, least_common=None) + 2/3: ColumnDetails(table='stuff', column='owner', total_rows=8, num_null=0, num_blank=0, num_distinct=4, most_common=[('Joan', 3), ('Terry', 2), ('Kumar', 2), ('Anne', 1)], least_common=None) + 3/3: ColumnDetails(table='stuff', column='size', total_rows=8, num_null=0, num_blank=0, num_distinct=2, most_common=[(5, 5), (4, 3)], least_common=None) + """ + ).strip() + )