diff --git a/docs/python-api.rst b/docs/python-api.rst index 07f2bf6..c68611c 100644 --- a/docs/python-api.rst +++ b/docs/python-api.rst @@ -1802,6 +1802,16 @@ The ``.columns_dict`` property returns a dictionary version of the columns with >>> db["PlantType"].columns_dict {'id': , 'value': } +.. _python_api_introspection_default_values: + +.default_values +--------------- + +The ``.default_values`` property returns a dictionary of default values for each column that has a default:: + + >>> db["table_with_defaults"].default_values + {'score': 5} + .. _python_api_introspection_pks: .pks diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index 25c0a70..3f9d400 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -9,6 +9,7 @@ from .utils import ( progressbar, find_spatialite, ) +import binascii from collections import namedtuple from collections.abc import Mapping import contextlib @@ -1458,6 +1459,15 @@ class Table(Queryable): "``{trigger_name: sql}`` dictionary of triggers defined on this table." return {trigger.name: trigger.sql for trigger in self.triggers} + @property + def default_values(self) -> Dict[str, Any]: + "``{column_name: default_value}`` dictionary of default values for columns in this table." + return { + column.name: _decode_default_value(column.default_value) + for column in self.columns + if column.default_value is not None + } + @property def strict(self) -> bool: "Is this a STRICT table?" @@ -3527,3 +3537,22 @@ def fix_square_braces(records: Iterable[Dict[str, Any]]): } else: yield record + + +def _decode_default_value(value): + if value.startswith("'") and value.endswith("'"): + # It's a string + return value[1:-1] + if value.isdigit(): + # It's an integer + return int(value) + if value.startswith("X'") and value.endswith("'"): + # It's a binary string, stored as hex + to_decode = value[2:-1] + return binascii.unhexlify(to_decode) + # If it is a string containing a floating point number: + try: + return float(value) + except ValueError: + pass + return value diff --git a/tests/test_introspect.py b/tests/test_introspect.py index fe9542b..c3d1b80 100644 --- a/tests/test_introspect.py +++ b/tests/test_introspect.py @@ -299,3 +299,21 @@ def test_table_strict(fresh_db, create_table, expected_strict): fresh_db.execute(create_table) table = fresh_db["t"] assert table.strict == expected_strict + + +@pytest.mark.parametrize( + "value", + ( + 1, + 1.3, + "foo", + True, + b"binary", + ), +) +def test_table_default_values(fresh_db, value): + fresh_db["default_values"].insert( + {"nodefault": 1, "value": value}, defaults={"value": value} + ) + default_values = fresh_db["default_values"].default_values + assert default_values == {"value": value}