diff --git a/src/duckdb_py/typing/pytype.cpp b/src/duckdb_py/typing/pytype.cpp index 449c4c7d..f04c14ba 100644 --- a/src/duckdb_py/typing/pytype.cpp +++ b/src/duckdb_py/typing/pytype.cpp @@ -330,6 +330,9 @@ void DuckDBPyType::Initialize(py::handle &m) { py::is_operator()); type_module.def("__eq__", &DuckDBPyType::EqualsString, "Compare two types for equality", py::arg("other"), py::is_operator()); + type_module.def("__hash__", [](const DuckDBPyType &type) { + return py::hash(py::str(type.ToString())); + }); type_module.def_property_readonly("id", &DuckDBPyType::GetId); type_module.def_property_readonly("children", &DuckDBPyType::Children); type_module.def(py::init<>([](const string &type_str, shared_ptr connection = nullptr) { diff --git a/tests/fast/test_type.py b/tests/fast/test_type.py index 6f648179..c5a62694 100644 --- a/tests/fast/test_type.py +++ b/tests/fast/test_type.py @@ -214,6 +214,20 @@ def test_struct_from_dict(self): res = duckdb.list_type({'a': VARCHAR, 'b': VARCHAR}) assert res == 'STRUCT(a VARCHAR, b VARCHAR)[]' + def test_hash_method(self): + type1 = duckdb.list_type({'a': VARCHAR, 'b': VARCHAR}) + type2 = duckdb.list_type({'b': VARCHAR, 'a': VARCHAR}) + type3 = VARCHAR + + type_set = set() + type_set.add(type1) + type_set.add(type2) + type_set.add(type3) + + type_set.add(type1) + expected = ['STRUCT(a VARCHAR, b VARCHAR)[]', 'STRUCT(b VARCHAR, a VARCHAR)[]', 'VARCHAR'] + assert sorted([str(x) for x in list(type_set)]) == expected + # NOTE: we can support this, but I don't think going through hoops for an outdated version of python is worth it @pytest.mark.skipif(sys.version_info < (3, 9), reason="python3.7 does not store Optional[..] in a recognized way") def test_optional(self):