Skip to content

Commit e925c9b

Browse files
committed
Merge branch 'main' into feat/ci_again
2 parents 922d5c7 + 21a3978 commit e925c9b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+134
-157
lines changed

.github/DISCUSSION_TEMPLATE/questions.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,14 @@ body:
6464
If I (or someone) can copy it, run it, and see it right away, there's a much higher chance I (or someone) will be able to help you.
6565
6666
placeholder: |
67-
from typing import Optional
68-
6967
from sqlmodel import Field, Session, SQLModel, create_engine
7068
7169
7270
class Hero(SQLModel, table=True):
73-
id: Optional[int] = Field(default=None, primary_key=True)
71+
id: int | None = Field(default=None, primary_key=True)
7472
name: str
7573
secret_name: str
76-
age: Optional[int] = None
74+
age: int | None = None
7775
7876
7977
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")

.github/workflows/build-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
with:
6060
python-version: "3.11"
6161
- name: Setup uv
62-
uses: astral-sh/setup-uv@v5
62+
uses: astral-sh/setup-uv@v6
6363
with:
6464
version: "0.4.15"
6565
enable-cache: true

.github/workflows/deploy-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
with:
3030
python-version: "3.11"
3131
- name: Setup uv
32-
uses: astral-sh/setup-uv@v5
32+
uses: astral-sh/setup-uv@v6
3333
with:
3434
version: "0.4.15"
3535
enable-cache: true

.github/workflows/smokeshow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
with:
2222
python-version: '3.9'
2323
- name: Setup uv
24-
uses: astral-sh/setup-uv@v5
24+
uses: astral-sh/setup-uv@v6
2525
with:
2626
version: "0.4.15"
2727
enable-cache: true

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
with:
4646
python-version: ${{ matrix.python-version }}
4747
- name: Setup uv
48-
uses: astral-sh/setup-uv@v5
48+
uses: astral-sh/setup-uv@v6
4949
with:
5050
version: "0.4.15"
5151
enable-cache: true
@@ -67,7 +67,7 @@ jobs:
6767
if: matrix.pydantic-version == 'pydantic-v2'
6868
run: uv pip install --upgrade "pydantic>=2.0.2,<3.0.0"
6969
- name: Lint
70-
if: matrix.pydantic-version == 'pydantic-v2'
70+
if: matrix.pydantic-version == 'pydantic-v2' && matrix.python-version != '3.8'
7171
run: bash scripts/lint.sh
7272
- run: mkdir coverage
7373
- name: Test
@@ -92,7 +92,7 @@ jobs:
9292
with:
9393
python-version: '3.13'
9494
- name: Setup uv
95-
uses: astral-sh/setup-uv@v5
95+
uses: astral-sh/setup-uv@v6
9696
with:
9797
version: "0.4.15"
9898
enable-cache: true

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ repos:
1414
- id: end-of-file-fixer
1515
- id: trailing-whitespace
1616
- repo: https://github.com/astral-sh/ruff-pre-commit
17-
rev: v0.11.0
17+
rev: v0.11.2
1818
hooks:
1919
- id: ruff
2020
args:

README.md

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,14 @@ And you want it to have this data:
105105
Then you could create a **SQLModel** model like this:
106106

107107
```Python
108-
from typing import Optional
109-
110108
from sqlmodel import Field, SQLModel
111109

112110

113111
class Hero(SQLModel, table=True):
114-
id: Optional[int] = Field(default=None, primary_key=True)
112+
id: int | None = Field(default=None, primary_key=True)
115113
name: str
116114
secret_name: str
117-
age: Optional[int] = None
115+
age: int | None = None
118116
```
119117

120118
That class `Hero` is a **SQLModel** model, the equivalent of a SQL table in Python code.
@@ -149,17 +147,15 @@ And **inline errors**:
149147

150148
You can learn a lot more about **SQLModel** by quickly following the **tutorial**, but if you need a taste right now of how to put all that together and save to the database, you can do this:
151149

152-
```Python hl_lines="18 21 23-27"
153-
from typing import Optional
154-
150+
```Python hl_lines="16 19 21-25"
155151
from sqlmodel import Field, Session, SQLModel, create_engine
156152

157153

158154
class Hero(SQLModel, table=True):
159-
id: Optional[int] = Field(default=None, primary_key=True)
155+
id: int | None = Field(default=None, primary_key=True)
160156
name: str
161157
secret_name: str
162-
age: Optional[int] = None
158+
age: int | None = None
163159

164160

165161
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
@@ -185,17 +181,15 @@ That will save a **SQLite** database with the 3 heroes.
185181

186182
Then you could write queries to select from that same database, for example with:
187183

188-
```Python hl_lines="15-18"
189-
from typing import Optional
190-
184+
```Python hl_lines="13-17"
191185
from sqlmodel import Field, Session, SQLModel, create_engine, select
192186

193187

194188
class Hero(SQLModel, table=True):
195-
id: Optional[int] = Field(default=None, primary_key=True)
189+
id: int | None = Field(default=None, primary_key=True)
196190
name: str
197191
secret_name: str
198-
age: Optional[int] = None
192+
age: int | None = None
199193

200194

201195
engine = create_engine("sqlite:///database.db")

docs/contributing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ There is a script that you can run locally to test all the code and generate cov
6363
<div class="termy">
6464

6565
```console
66-
$ bash scripts/test-cov-html.sh
66+
$ bash scripts/test.sh
6767
```
6868

6969
</div>

docs/db-to-code.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,10 @@ For example this class is part of that **Object** Oriented Programming:
252252

253253
```Python
254254
class Hero(SQLModel):
255-
id: Optional[int] = Field(default=None, primary_key=True)
255+
id: int | None = Field(default=None, primary_key=True)
256256
name: str
257257
secret_name: str
258-
age: Optional[int] = None
258+
age: int | None = None
259259
```
260260

261261
* **Relational**: refers to the **SQL Databases**. Remember that they are also called **Relational Databases**, because each of those tables is also called a "**relation**"? That's where the "**Relational**" comes from.

docs/img/index/autocompletion01.png

48.1 KB
Loading

docs/img/index/autocompletion02.png

104 KB
Loading

docs/img/index/inline-errors01.png

59.7 KB
Loading

docs/index.md

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,14 @@ And you want it to have this data:
118118
Then you could create a **SQLModel** model like this:
119119

120120
```Python
121-
from typing import Optional
122-
123121
from sqlmodel import Field, SQLModel
124122

125123

126124
class Hero(SQLModel, table=True):
127-
id: Optional[int] = Field(default=None, primary_key=True)
125+
id: int | None = Field(default=None, primary_key=True)
128126
name: str
129127
secret_name: str
130-
age: Optional[int] = None
128+
age: int | None = None
131129
```
132130

133131
That class `Hero` is a **SQLModel** model, the equivalent of a SQL table in Python code.
@@ -162,17 +160,15 @@ And **inline errors**:
162160

163161
You can learn a lot more about **SQLModel** by quickly following the **tutorial**, but if you need a taste right now of how to put all that together and save to the database, you can do this:
164162

165-
```Python hl_lines="18 21 23-27"
166-
from typing import Optional
167-
163+
```Python hl_lines="16 19 21-25"
168164
from sqlmodel import Field, Session, SQLModel, create_engine
169165

170166

171167
class Hero(SQLModel, table=True):
172-
id: Optional[int] = Field(default=None, primary_key=True)
168+
id: int | None = Field(default=None, primary_key=True)
173169
name: str
174170
secret_name: str
175-
age: Optional[int] = None
171+
age: int | None = None
176172

177173

178174
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
@@ -198,17 +194,15 @@ That will save a **SQLite** database with the 3 heroes.
198194

199195
Then you could write queries to select from that same database, for example with:
200196

201-
```Python hl_lines="15-18"
202-
from typing import Optional
203-
197+
```Python hl_lines="13-17"
204198
from sqlmodel import Field, Session, SQLModel, create_engine, select
205199

206200

207201
class Hero(SQLModel, table=True):
208-
id: Optional[int] = Field(default=None, primary_key=True)
202+
id: int | None = Field(default=None, primary_key=True)
209203
name: str
210204
secret_name: str
211-
age: Optional[int] = None
205+
age: int | None = None
212206

213207

214208
engine = create_engine("sqlite:///database.db")

docs/release-notes.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,22 @@
66

77
* ⬆️ Drop support for Python 3.7, require Python 3.8 or above. PR [#1316](https://github.com/fastapi/sqlmodel/pull/1316) by [@svlandeg](https://github.com/svlandeg).
88

9+
### Docs
10+
11+
* 📝 Update all docs references to `Optional` to use the new syntax in Python 3.10, e.g. `int | None`. PR [#1351](https://github.com/fastapi/sqlmodel/pull/1351) by [@tiangolo](https://github.com/tiangolo).
12+
* 📝 Update install and usage with FastAPI CLI in FastAPI tutorial. PR [#1350](https://github.com/fastapi/sqlmodel/pull/1350) by [@tiangolo](https://github.com/tiangolo).
13+
* 📝 Update FastAPI tutorial docs to use the new `model.sqlmodel_update()` instead of old `setattr()`. PR [#1117](https://github.com/fastapi/sqlmodel/pull/1117) by [@jpizquierdo](https://github.com/jpizquierdo).
14+
* ✏️ Update `docs/virtual-environments.md`. PR [#1321](https://github.com/fastapi/sqlmodel/pull/1321) by [@sylvainHellin](https://github.com/sylvainHellin).
15+
916
### Internal
1017

18+
* ⬆ Bump typer from 0.12.3 to 0.15.2. PR [#1325](https://github.com/fastapi/sqlmodel/pull/1325) by [@dependabot[bot]](https://github.com/apps/dependabot).
19+
* ⬆ Bump httpx from 0.24.1 to 0.28.1. PR [#1238](https://github.com/fastapi/sqlmodel/pull/1238) by [@dependabot[bot]](https://github.com/apps/dependabot).
20+
* ⬆ Bump astral-sh/setup-uv from 5 to 6. PR [#1348](https://github.com/fastapi/sqlmodel/pull/1348) by [@dependabot[bot]](https://github.com/apps/dependabot).
21+
* ⬆ Update pytest requirement from <8.0.0,>=7.0.1 to >=7.0.1,<9.0.0. PR [#1022](https://github.com/fastapi/sqlmodel/pull/1022) by [@dependabot[bot]](https://github.com/apps/dependabot).
22+
* ♻️ Update `tests/test_select_gen.py`, pass environment variables, needed for NixOS nixpkgs. PR [#969](https://github.com/fastapi/sqlmodel/pull/969) by [@pbsds](https://github.com/pbsds).
23+
* 💚 Fix linting in CI. PR [#1340](https://github.com/fastapi/sqlmodel/pull/1340) by [@svlandeg](https://github.com/svlandeg).
24+
*[pre-commit.ci] pre-commit autoupdate. PR [#1327](https://github.com/fastapi/sqlmodel/pull/1327) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
1125
* ⬆ Bump jinja2 from 3.1.4 to 3.1.6. PR [#1317](https://github.com/fastapi/sqlmodel/pull/1317) by [@dependabot[bot]](https://github.com/apps/dependabot).
1226
*[pre-commit.ci] pre-commit autoupdate. PR [#1319](https://github.com/fastapi/sqlmodel/pull/1319) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
1327

docs/tutorial/automatic-id-none-refresh.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ In the previous chapter, we saw how to add rows to the database using **SQLModel
44

55
Now let's talk a bit about why the `id` field **can't be `NULL`** on the database because it's a **primary key**, and we declare it using `Field(primary_key=True)`.
66

7-
But the same `id` field actually **can be `None`** in the Python code, so we declare the type with `int | None (or Optional[int])`, and set the default value to `Field(default=None)`:
7+
But the same `id` field actually **can be `None`** in the Python code, so we declare the type with `int | None`, and set the default value to `Field(default=None)`:
88

99
{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[4:8] hl[5] *}
1010

@@ -18,15 +18,15 @@ When we create a new `Hero` instance, we don't set the `id`:
1818

1919
{* ./docs_src/tutorial/automatic_id_none_refresh/tutorial001_py310.py ln[21:24] hl[21:24] *}
2020

21-
### How `Optional` Helps
21+
### How `int | None` Helps
2222

2323
Because we don't set the `id`, it takes the Python's default value of `None` that we set in `Field(default=None)`.
2424

25-
This is the only reason why we define it with `Optional` and with a default value of `None`.
25+
This is the only reason why we define it with `int | None` and with a default value of `None`.
2626

2727
Because at this point in the code, **before interacting with the database**, the Python value could actually be `None`.
2828

29-
If we assumed that the `id` was *always* an `int` and added the type annotation without `Optional`, we could end up writing broken code, like:
29+
If we assumed that the `id` was *always* an `int` and added the type annotation without `int | None`, we could end up writing broken code, like:
3030

3131
```Python
3232
next_hero_id = hero_1.id + 1
@@ -38,7 +38,7 @@ If we ran this code before saving the hero to the database and the `hero_1.id` w
3838
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
3939
```
4040

41-
But by declaring it with `Optional[int]`, the editor will help us to avoid writing broken code by showing us a warning telling us that the code could be invalid if `hero_1.id` is `None`. 🔍
41+
But by declaring it with `int | None`, the editor will help us to avoid writing broken code by showing us a warning telling us that the code could be invalid if `hero_1.id` is `None`. 🔍
4242

4343
## Print the Default `id` Values
4444

docs/tutorial/connect/create-connected-rows.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ WHERE team.id = ?
141141
INFO Engine [cached since 0.001795s ago] (1,)
142142
```
143143

144-
There's something else to note. We marked `team_id` as `Optional[int]`, meaning that this could be `NULL` on the database (and `None` in Python).
144+
There's something else to note. We marked `team_id` as `int | None`, meaning that this could be `NULL` on the database (and `None` in Python).
145145

146146
That means that a hero doesn't have to have a team. And in this case, **Spider-Boy** doesn't have one.
147147

docs/tutorial/create-db-and-table.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,9 @@ And the type of each of them will also be the type of table column:
6767

6868
Let's now see with more detail these field/column declarations.
6969

70-
### Optional Fields, Nullable Columns
70+
### `None` Fields, Nullable Columns
7171

72-
Let's start with `age`, notice that it has a type of `int | None (or Optional[int])`.
73-
74-
And we import that `Optional` from the `typing` standard module.
72+
Let's start with `age`, notice that it has a type of `int | None`.
7573

7674
That is the standard way to declare that something "could be an `int` or `None`" in Python.
7775

@@ -81,21 +79,23 @@ And we also set the default value of `age` to `None`.
8179

8280
/// tip
8381

84-
We also define `id` with `Optional`. But we will talk about `id` below.
82+
We also define `id` with `int | None`. But we will talk about `id` below.
8583

8684
///
8785

88-
This way, we tell **SQLModel** that `age` is not required when validating data and that it has a default value of `None`.
86+
Because the type is `int | None`:
8987

90-
And we also tell it that, in the SQL database, the default value of `age` is `NULL` (the SQL equivalent to Python's `None`).
88+
* When validating data, `None` will be an allowed value for `age`.
89+
* In the database, the column for `age` will be allowed to have `NULL` (the SQL equivalent to Python's `None`).
9190

92-
So, this column is "nullable" (can be set to `NULL`).
91+
And because there's a default value `= None`:
9392

94-
/// info
93+
* When validating data, this `age` field won't be required, it will be `None` by default.
94+
* When saving to the database, the `age` column will have a `NULL` value by default.
9595

96-
In terms of **Pydantic**, `age` is an **optional field**.
96+
/// tip
9797

98-
In terms of **SQLAlchemy**, `age` is a **nullable column**.
98+
The default value could have been something else, like `= 42`.
9999

100100
///
101101

@@ -111,7 +111,7 @@ To do that, we use the special `Field` function from `sqlmodel` and set the argu
111111

112112
That way, we tell **SQLModel** that this `id` field/column is the primary key of the table.
113113

114-
But inside the SQL database, it is **always required** and can't be `NULL`. Why should we declare it with `Optional`?
114+
But inside the SQL database, it is **always required** and can't be `NULL`. Why should we declare it with `int | None`?
115115

116116
The `id` will be required in the database, but it will be *generated by the database*, not by our code.
117117

@@ -128,7 +128,7 @@ somehow_save_in_db(my_hero)
128128
do_something(my_hero.id) # Now my_hero.id has a value generated in DB 🎉
129129
```
130130

131-
So, because in *our code* (not in the database) the value of `id` *could be* `None`, we use `Optional`. This way **the editor will be able to help us**, for example, if we try to access the `id` of an object that we haven't saved in the database yet and would still be `None`.
131+
So, because in *our code* (not in the database) the value of `id` *could be* `None`, we use `int | None`. This way **the editor will be able to help us**, for example, if we try to access the `id` of an object that we haven't saved in the database yet and would still be `None`.
132132

133133
<img class="shadow" src="/img/create-db-and-table/inline-errors01.png">
134134

0 commit comments

Comments
 (0)