Coverage for tests/test_nullable.py: 100%
68 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-27 00:03 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-27 00:03 +0000
1from typing import Optional 1uvwxyzABCD
3import pytest 1uvwxyzABCD
4from sqlalchemy.exc import IntegrityError 1uvwxyzABCD
5from sqlmodel import Field, Session, SQLModel, create_engine 1uvwxyzABCD
8def test_nullable_fields(clear_sqlmodel, caplog): 1uvwxyzABCD
9 class Hero(SQLModel, table=True): 1abcdefghij
10 primary_key: Optional[int] = Field( 1abcdefghij
11 default=None,
12 primary_key=True,
13 )
14 required_value: str 1abcdefghij
15 optional_default_ellipsis: Optional[str] = Field(default=...) 1abcdefghij
16 optional_default_none: Optional[str] = Field(default=None) 1abcdefghij
17 optional_non_nullable: Optional[str] = Field( 1abcdefghij
18 nullable=False,
19 )
20 optional_nullable: Optional[str] = Field( 1abcdefghij
21 nullable=True,
22 )
23 optional_default_ellipses_non_nullable: Optional[str] = Field( 1abcdefghij
24 default=...,
25 nullable=False,
26 )
27 optional_default_ellipses_nullable: Optional[str] = Field( 1abcdefghij
28 default=...,
29 nullable=True,
30 )
31 optional_default_none_non_nullable: Optional[str] = Field( 1abcdefghij
32 default=None,
33 nullable=False,
34 )
35 optional_default_none_nullable: Optional[str] = Field( 1abcdefghij
36 default=None,
37 nullable=True,
38 )
39 default_ellipses_non_nullable: str = Field(default=..., nullable=False) 1abcdefghij
40 optional_default_str: Optional[str] = "default" 1abcdefghij
41 optional_default_str_non_nullable: Optional[str] = Field( 1abcdefghij
42 default="default", nullable=False
43 )
44 optional_default_str_nullable: Optional[str] = Field( 1abcdefghij
45 default="default", nullable=True
46 )
47 str_default_str: str = "default" 1abcdefghij
48 str_default_str_non_nullable: str = Field(default="default", nullable=False) 1abcdefghij
49 str_default_str_nullable: str = Field(default="default", nullable=True) 1abcdefghij
50 str_default_ellipsis_non_nullable: str = Field(default=..., nullable=False) 1abcdefghij
51 str_default_ellipsis_nullable: str = Field(default=..., nullable=True) 1abcdefghij
53 engine = create_engine("sqlite://", echo=True) 1abcdefghij
54 SQLModel.metadata.create_all(engine) 1abcdefghij
56 create_table_log = [ 1abcdefghij
57 message for message in caplog.messages if "CREATE TABLE hero" in message
58 ][0]
59 assert "primary_key INTEGER NOT NULL," in create_table_log 1abcdefghij
60 assert "required_value VARCHAR NOT NULL," in create_table_log 1abcdefghij
61 assert "optional_default_ellipsis VARCHAR," in create_table_log 1abcdefghij
62 assert "optional_default_none VARCHAR," in create_table_log 1abcdefghij
63 assert "optional_non_nullable VARCHAR NOT NULL," in create_table_log 1abcdefghij
64 assert "optional_nullable VARCHAR," in create_table_log 1abcdefghij
65 assert ( 1abcdefghij
66 "optional_default_ellipses_non_nullable VARCHAR NOT NULL," in create_table_log
67 )
68 assert "optional_default_ellipses_nullable VARCHAR," in create_table_log 1abcdefghij
69 assert "optional_default_none_non_nullable VARCHAR NOT NULL," in create_table_log 1abcdefghij
70 assert "optional_default_none_nullable VARCHAR," in create_table_log 1abcdefghij
71 assert "default_ellipses_non_nullable VARCHAR NOT NULL," in create_table_log 1abcdefghij
72 assert "optional_default_str VARCHAR," in create_table_log 1abcdefghij
73 assert "optional_default_str_non_nullable VARCHAR NOT NULL," in create_table_log 1abcdefghij
74 assert "optional_default_str_nullable VARCHAR," in create_table_log 1abcdefghij
75 assert "str_default_str VARCHAR NOT NULL," in create_table_log 1abcdefghij
76 assert "str_default_str_non_nullable VARCHAR NOT NULL," in create_table_log 1abcdefghij
77 assert "str_default_str_nullable VARCHAR," in create_table_log 1abcdefghij
78 assert "str_default_ellipsis_non_nullable VARCHAR NOT NULL," in create_table_log 1abcdefghij
79 assert "str_default_ellipsis_nullable VARCHAR," in create_table_log 1abcdefghij
82# Test for regression in https://github.com/tiangolo/sqlmodel/issues/420
83def test_non_nullable_optional_field_with_no_default_set(clear_sqlmodel, caplog): 1uvwxyzABCD
84 class Hero(SQLModel, table=True): 1klmnopqrst
85 primary_key: Optional[int] = Field( 1klmnopqrst
86 default=None,
87 primary_key=True,
88 )
90 optional_non_nullable_no_default: Optional[str] = Field(nullable=False) 1klmnopqrst
92 engine = create_engine("sqlite://", echo=True) 1klmnopqrst
93 SQLModel.metadata.create_all(engine) 1klmnopqrst
95 create_table_log = [ 1klmnopqrst
96 message for message in caplog.messages if "CREATE TABLE hero" in message
97 ][0]
98 assert "primary_key INTEGER NOT NULL," in create_table_log 1klmnopqrst
99 assert "optional_non_nullable_no_default VARCHAR NOT NULL," in create_table_log 1klmnopqrst
101 # We can create a hero with `None` set for the optional non-nullable field
102 hero = Hero(primary_key=123, optional_non_nullable_no_default=None) 1klmnopqrst
103 # But we cannot commit it.
104 with Session(engine) as session: 1klmnopqrst
105 session.add(hero) 1klmnopqrst
106 with pytest.raises(IntegrityError): 1klmnopqrst
107 session.commit() 1klmnopqrst
110def test_nullable_primary_key(clear_sqlmodel, caplog): 1uvwxyzABCD
111 # Probably the weirdest corner case, it shouldn't happen anywhere, but let's test it
112 class Hero(SQLModel, table=True): 1EFGHIJKLMN
113 nullable_integer_primary_key: Optional[int] = Field( 1EFGHIJKLMN
114 default=None,
115 primary_key=True,
116 nullable=True,
117 )
119 engine = create_engine("sqlite://", echo=True) 1EFGHIJKLMN
120 SQLModel.metadata.create_all(engine) 1EFGHIJKLMN
122 create_table_log = [ 1EFGHIJKLMN
123 message for message in caplog.messages if "CREATE TABLE hero" in message
124 ][0]
125 assert "nullable_integer_primary_key INTEGER," in create_table_log 1EFGHIJKLMN