Repository: duckdb/duckdb
File: tools/pythonpkg/tests/fast/test_type.py (Python)

Code before:
        for builtin in builtins:
            print(builtin)
            type = duckdb_cursor.list_type(builtin)
            dtype_str = str(builtin().dtype)
            duckdb_type_str = str(type.child)
            assert type_mapping[dtype_str] == duckdb_type_str

    def test_attribute_accessor(self):
        type = duckdb.row_type([BIGINT, duckdb.list_type(duckdb.map_type(BLOB, BIT))])
        assert hasattr(type, 'a') == False
        assert hasattr(type, 'v1') == True

        field_one = type['v1']
        assert str(field_one) == 'BIGINT'
        field_one = type.v1
        assert str(field_one) == 'BIGINT'

        field_two = type['v2']
        assert str(field_two) == 'MAP(BLOB, BIT)[]'

        child_type = type.v2.child
        assert str(child_type) == 'MAP(BLOB, BIT)'

    def test_optional(self):
        type = duckdb.typing.DuckDBPyType(Optional[str])
        assert type == 'VARCHAR'
        type = duckdb.typing.DuckDBPyType(Optional[Union[int, bool]])
        assert type == 'UNION(u1 BIGINT, u2 BOOLEAN)'
        type = duckdb.typing.DuckDBPyType(Optional[list[int]])
        assert type == 'BIGINT[]'
        type = duckdb.typing.DuckDBPyType(Optional[dict[int, str]])
        assert type == 'MAP(BIGINT, VARCHAR)'
        type = duckdb.typing.DuckDBPyType(Optional[dict[Optional[int], Optional[str]]])
        assert type == 'MAP(BIGINT, VARCHAR)'
        type = duckdb.typing.DuckDBPyType(Optional[dict[Optional[int], Optional[str]]])
        assert type == 'MAP(BIGINT, VARCHAR)'
        type = duckdb.typing.DuckDBPyType(Optional[Union[Optional[str], Optional[bool]]])
        assert type == 'UNION(u1 VARCHAR, u2 BOOLEAN)'


Review comment (suggestion):
Can you add a test with `Union[str, None]` or similar? Newer Python versions encourage `str | None` which is syntax sugar for that

Code after:
        builtins += [np.double]

        for builtin in builtins:
            print(builtin)
            type = duckdb_cursor.list_type(builtin)
            dtype_str = str(builtin().dtype)
            duckdb_type_str = str(type.child)
            assert type_mapping[dtype_str] == duckdb_type_str

    def test_attribute_accessor(self):
        type = duckdb.row_type([BIGINT, duckdb.list_type(duckdb.map_type(BLOB, BIT))])
        assert hasattr(type, 'a') == False
        assert hasattr(type, 'v1') == True

        field_one = type['v1']
        assert str(field_one) == 'BIGINT'
        field_one = type.v1
        assert str(field_one) == 'BIGINT'

        field_two = type['v2']
        assert str(field_two) == 'MAP(BLOB, BIT)[]'

        child_type = type.v2.child
        assert str(child_type) == 'MAP(BLOB, BIT)'

    def test_optional(self):
        type = duckdb.typing.DuckDBPyType(Optional[str])
        assert type == 'VARCHAR'
        type = duckdb.typing.DuckDBPyType(Optional[Union[int, bool]])
        assert type == 'UNION(u1 BIGINT, u2 BOOLEAN)'
        type = duckdb.typing.DuckDBPyType(Optional[list[int]])
        assert type == 'BIGINT[]'
        type = duckdb.typing.DuckDBPyType(Optional[dict[int, str]])
        assert type == 'MAP(BIGINT, VARCHAR)'
        type = duckdb.typing.DuckDBPyType(Optional[dict[Optional[int], Optional[str]]])
        assert type == 'MAP(BIGINT, VARCHAR)'
        type = duckdb.typing.DuckDBPyType(Optional[dict[Optional[int], Optional[str]]])
        assert type == 'MAP(BIGINT, VARCHAR)'
        type = duckdb.typing.DuckDBPyType(Optional[Union[Optional[str], Optional[bool]]])
        assert type == 'UNION(u1 VARCHAR, u2 BOOLEAN)'
        type = duckdb.typing.DuckDBPyType(Union[str, None])
        assert type == 'VARCHAR'

    @pytest.mark.skipif(sys.version_info < (3, 10), reason="'str | None' syntax requires Python 3.10 or higher")
    def test_optional_310(self):
        type = duckdb.typing.DuckDBPyType(str | None)
        assert type == 'VARCHAR'