Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
968e4e6
Update `docs_src/tutorial/automatic_id_none_refresh`
YuriiMotov Dec 24, 2025
3d43821
Update `docs_src/tutorial/code_structure`
YuriiMotov Dec 24, 2025
c3fb2ed
Update `docs_src/tutorial/connect`
YuriiMotov Dec 24, 2025
a0da1be
Update `docs_src/tutorial/create_db_and_table`
YuriiMotov Dec 24, 2025
d34d9ec
Update `docs_src/tutorial/delete`
YuriiMotov Dec 24, 2025
d603cc1
Update `docs_src/tutorial/fastapi`
YuriiMotov Dec 24, 2025
fdb770d
Update `docs_src/tutorial/where`
YuriiMotov Dec 24, 2025
4604612
Update `docs_src/tutorial/indexes`
YuriiMotov Dec 24, 2025
9abc261
Update `docs_src/tutorial/insert`
YuriiMotov Dec 24, 2025
45a627b
Update `docs_src/tutorial/many_to_many`
YuriiMotov Dec 24, 2025
496fda3
Update `docs_src/tutorial/offset_and_limit`
YuriiMotov Dec 24, 2025
e9d0655
Update `docs_src/tutorial/one`
YuriiMotov Dec 24, 2025
2955480
Update `docs_src/tutorial/relationship_attributes`
YuriiMotov Dec 24, 2025
e903a19
Update `docs_src/tutorial/select`
YuriiMotov Dec 24, 2025
b25e3a3
Update `docs_src/tutorial/update`
YuriiMotov Dec 24, 2025
fb49224
Update `docs_src/advanced/decimal`
YuriiMotov Dec 25, 2025
2c9dc52
Update `docs_src/advanced/uuid`
YuriiMotov Dec 25, 2025
4de5664
Update `management-tasks.md`
YuriiMotov Dec 25, 2025
05af4de
Fix copying coverage file in `cov_tmp_path` fixture
YuriiMotov Dec 25, 2025
695d448
Merge branch 'drop-python3.8-support' into update-code-examples-to-py…
YuriiMotov Dec 25, 2025
03e7be2
Update `tutorial003.md` annotations for Python 3.10+
YuriiMotov Dec 25, 2025
eec65c6
Remove `needs_py39` marker
YuriiMotov Dec 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/management-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ A PR should have a specific use case that it is solving.
* If the PR is for a feature, it should have docs.
* Unless it's a feature we want to discourage, like support for a corner case that we don't want users to use.
* The docs should include a source example file, not write Python directly in Markdown.
* If the source example(s) file can have different syntax for Python 3.8, 3.9, 3.10, there should be different versions of the file, and they should be shown in tabs in the docs.
* If the source example(s) file can have different syntax for different Python versions, there should be different versions of the file, and they should be shown in tabs in the docs.
* There should be tests testing the source example.
* Before the PR is applied, the new tests should fail.
* After applying the PR, the new tests should pass.
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial/automatic-id-none-refresh.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,10 @@ And as we created the **engine** with `echo=True`, we can see the SQL statements

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```Python
{!./docs_src/tutorial/automatic_id_none_refresh/tutorial002.py!}
{!./docs_src/tutorial/automatic_id_none_refresh/tutorial002_py39.py!}
```

{!./docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md!}
Expand Down
24 changes: 6 additions & 18 deletions docs/tutorial/code-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,7 @@ We can use these relative imports because, for example, in the file `app.py` (th

You could put all the database Models in a single Python module (a single Python file), for example `models.py`:

```Python
{!./docs_src/tutorial/code_structure/tutorial001/models.py!}
```
{* ./docs_src/tutorial/code_structure/tutorial001_py310/models.py *}

This way, you wouldn't have to deal with circular imports for other models.

Expand All @@ -79,19 +77,15 @@ And then you could import the models from this file/module in any other file/mod

Then you could put the code creating the **engine** and the function to create all the tables (if you are not using migrations) in another file `database.py`:

```Python
{!./docs_src/tutorial/code_structure/tutorial001/database.py!}
```
{* ./docs_src/tutorial/code_structure/tutorial001_py310/database.py *}

This file would also be imported by your application code, to use the shared **engine** and to get and call the function `create_db_and_tables()`.

### Application File

Finally, you could put the code to create the **app** in another file `app.py`:

```Python hl_lines="3-4"
{!./docs_src/tutorial/code_structure/tutorial001/app.py!}
```
{* ./docs_src/tutorial/code_structure/tutorial001_py310/app.py hl[3:4] *}

Here we import the models, the engine, and the function to create all the tables and then we can use them all internally.

Expand Down Expand Up @@ -207,29 +201,23 @@ So, we can use it in an `if` block and import things inside the `if` block. And

Using that trick of `TYPE_CHECKING` we can "import" the `Team` in `hero_model.py`:

```Python hl_lines="1 5-6 16"
{!./docs_src/tutorial/code_structure/tutorial002/hero_model.py!}
```
{* ./docs_src/tutorial/code_structure/tutorial002_py310/hero_model.py hl[1,5:6,16] *}

Have in mind that now we *have* to put the annotation of `Team` as a string: `"Team"`, so that Python doesn't have errors at runtime.

### Team Model File

We use the same trick in the `team_model.py` file:

```Python hl_lines="1 5-6 14"
{!./docs_src/tutorial/code_structure/tutorial002/team_model.py!}
```
{* ./docs_src/tutorial/code_structure/tutorial002_py310/team_model.py hl[1,5:6,14] *}

Now we get editor support, autocompletion, inline errors, and **SQLModel** keeps working. 🎉

### App File

Now, just for completeness, the `app.py` file would import the models from both modules:

```Python hl_lines="4-5 10 12-14"
{!./docs_src/tutorial/code_structure/tutorial002/app.py!}
```
{* ./docs_src/tutorial/code_structure/tutorial002_py310/app.py hl[4:5,10,12:14] *}

And of course, all the tricks with `TYPE_CHECKING` and type annotations in strings are **only needed in the files with circular imports**.

Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial/create-db-and-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -562,10 +562,10 @@ Now, let's give the code a final look:

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```{.python .annotate}
{!./docs_src/tutorial/create_db_and_table/tutorial003.py!}
{!./docs_src/tutorial/create_db_and_table/tutorial003_py39.py!}
```

{!./docs_src/tutorial/create_db_and_table/annotations/en/tutorial003.md!}
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial/delete.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,10 @@ Now let's review all that code:

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```{ .python .annotate hl_lines="72-90" }
{!./docs_src/tutorial/delete/tutorial002.py!}
{!./docs_src/tutorial/delete/tutorial002_py39.py!}
```

{!./docs_src/tutorial/delete/annotations/en/tutorial002.md!}
Expand Down
38 changes: 19 additions & 19 deletions docs/tutorial/fastapi/tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ We will use the application with the hero models, but without team models, and w

Now we will see how useful it is to have this session dependency. ✨

{* ./docs_src/tutorial/fastapi/app_testing/tutorial001/main.py ln[0] *}
{* ./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/main.py ln[0] *}

## File Structure

Expand Down Expand Up @@ -53,16 +53,16 @@ $ pip install requests pytest
Let's start with a simple test, with just the basic test code we need the check that the **FastAPI** application is creating a new hero correctly.

```{ .python .annotate }
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_001.py[ln:1-7]!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_001.py[ln:1-7]!}
# Some code here omitted, we will see it later 👈
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_001.py[ln:20-24]!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_001.py[ln:20-24]!}
# Some code here omitted, we will see it later 👈
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_001.py[ln:26-32]!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_001.py[ln:26-32]!}
# Code below omitted 👇
```

{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_001.md!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_001.md!}

/// tip

Expand Down Expand Up @@ -103,14 +103,14 @@ We will override it to use a different **session** object just for the tests.
That way we protect the production database and we have better control of the data we are testing.

```{ .python .annotate hl_lines="4 9-10 12 19" }
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_002.py[ln:1-7]!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_002.py[ln:1-7]!}
# Some code here omitted, we will see it later 👈
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_002.py[ln:15-32]!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_002.py[ln:15-32]!}
# Code below omitted 👇
```

{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_002.md!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_002.md!}

/// tip

Expand All @@ -131,10 +131,10 @@ sqlite:///testing.db
So, the testing database will be in the file `testing.db`.

``` { .python .annotate hl_lines="4 8-11 13 16 33"}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_003.py!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_003.py!}
```

{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_003.md!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_003.md!}

### Import Table Models

Expand Down Expand Up @@ -187,12 +187,12 @@ Let's update our code to use the in-memory database.
We just have to change a couple of parameters in the **engine**.

```{ .python .annotate hl_lines="3 9-13"}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_004.py[ln:1-13]!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_004.py[ln:1-13]!}
# Code below omitted 👇
```

{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_004.md!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_004.md!}

/// tip

Expand Down Expand Up @@ -235,10 +235,10 @@ You can read more about them in the <a href="https://docs.pytest.org/en/6.2.x/fi
Let's see the first code example with a fixture:

``` { .python .annotate }
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_005.py!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_005.py!}
```

{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_005.md!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_005.md!}

/// tip

Expand Down Expand Up @@ -275,10 +275,10 @@ Each **pytest** fixture (the same way as **FastAPI** dependencies), can require
So, we can create a **client fixture** that will be used in all the tests, and it will itself require the **session fixture**.

``` { .python .annotate hl_lines="19-28 31" }
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main_006.py!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main_006.py!}
```

{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_006.md!}
{!./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/annotations/en/test_main_006.md!}

/// tip

Expand All @@ -298,7 +298,7 @@ But normally we will create **lots of other test functions**. And now all the bo

Let's add some more tests:

{* ./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main.py ln[30:58] hl[30,49] *}
{* ./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main.py ln[30:58] hl[30,49] *}

/// tip

Expand All @@ -318,7 +318,7 @@ For these examples, **that would have been simpler**, there's no need to separat

But for the next test function, we will require **both fixtures**, the **client** and the **session**.

{* ./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main.py ln[1:6,61:81] hl[6,61] *}
{* ./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main.py ln[1:6,61:81] hl[6,61] *}

In this test function, we want to check that the *path operation* to **read a list of heroes** actually sends us heroes.

Expand All @@ -344,7 +344,7 @@ The function for the **client fixture** and the actual testing function will **b

Using the same ideas, requiring the fixtures, creating data that we need for the tests, etc., we can now add the rest of the tests. They look quite similar to what we have done up to now.

{* ./docs_src/tutorial/fastapi/app_testing/tutorial001/test_main.py ln[84:125] hl[84,99,114] *}
{* ./docs_src/tutorial/fastapi/app_testing/tutorial001_py310/test_main.py ln[84:125] hl[84,99,114] *}

## Run the Tests

Expand Down
10 changes: 5 additions & 5 deletions docs/tutorial/insert.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ This is the code we had to create the database and table, nothing new here:

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```{.python .annotate hl_lines="22" }
{!./docs_src/tutorial/create_db_and_table/tutorial003.py[ln:1-20]!}
{!./docs_src/tutorial/create_db_and_table/tutorial003_py39.py[ln:1-20]!}
# More code here later 👈
{!./docs_src/tutorial/create_db_and_table/tutorial003.py[ln:23-24]!}
{!./docs_src/tutorial/create_db_and_table/tutorial003_py39.py[ln:23-24]!}
```

{!./docs_src/tutorial/create_db_and_table/annotations/en/tutorial003.md!}
Expand Down Expand Up @@ -343,10 +343,10 @@ Let's focus on the new code:

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```{.python .annotate }
{!./docs_src/tutorial/insert/tutorial003.py!}
{!./docs_src/tutorial/insert/tutorial003_py39.py!}
```

{!./docs_src/tutorial/insert/annotations/en/tutorial003.md!}
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial/select.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,10 @@ Let's review the code up to this point:

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```{ .python .annotate }
{!./docs_src/tutorial/select/tutorial002.py!}
{!./docs_src/tutorial/select/tutorial002_py39.py!}
```

{!./docs_src/tutorial/select/annotations/en/tutorial002.md!}
Expand Down
12 changes: 6 additions & 6 deletions docs/tutorial/update.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,10 +236,10 @@ Now let's review all that code:

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```{ .python .annotate hl_lines="44-55" }
{!./docs_src/tutorial/update/tutorial002.py!}
{!./docs_src/tutorial/update/tutorial002_py39.py!}
```

{!./docs_src/tutorial/update/annotations/en/tutorial002.md!}
Expand Down Expand Up @@ -272,12 +272,12 @@ This also means that you can update several fields (attributes, columns) at once

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```{ .python .annotate hl_lines="15-17 19-21 23" }
# Code above omitted 👆
{!./docs_src/tutorial/update/tutorial004.py[ln:44-70]!}
{!./docs_src/tutorial/update/tutorial004_py39.py[ln:44-70]!}
# Code below omitted 👇
```
Expand All @@ -296,10 +296,10 @@ This also means that you can update several fields (attributes, columns) at once

////

//// tab | Python 3.8+
//// tab | Python 3.9+

```Python
{!./docs_src/tutorial/update/tutorial004.py!}
{!./docs_src/tutorial/update/tutorial004_py39.py!}
```

////
Expand Down
Empty file.
29 changes: 0 additions & 29 deletions docs_src/tutorial/code_structure/tutorial001/app.py

This file was deleted.

10 changes: 0 additions & 10 deletions docs_src/tutorial/code_structure/tutorial001/database.py

This file was deleted.

21 changes: 0 additions & 21 deletions docs_src/tutorial/code_structure/tutorial001/models.py

This file was deleted.

Empty file.
Loading