Skip to content

Commit 5c2e9dd

Browse files
authored
Merge branch 'main' into fix/turn-to-lowercase
2 parents 9109e89 + 04b8b3e commit 5c2e9dd

File tree

20 files changed

+112
-23
lines changed

20 files changed

+112
-23
lines changed

.github/dependabot.yml

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
version: 2
22
updates:
3+
# GitHub Actions
4+
- package-ecosystem: "github-actions"
5+
directory: "/"
6+
schedule:
7+
interval: "daily"
8+
# Python
39
- package-ecosystem: "pip"
410
directory: "/"
511
schedule:

.github/workflows/test.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
runs-on: ubuntu-20.04
1919
strategy:
2020
matrix:
21-
python-version: [3.6, 3.7, 3.8, 3.9]
21+
python-version: ["3.6.15", "3.7", "3.8", "3.9", "3.10"]
2222
fail-fast: false
2323

2424
steps:
@@ -54,9 +54,9 @@ jobs:
5454
if: steps.cache.outputs.cache-hit != 'true'
5555
run: python -m poetry install
5656
- name: Lint
57-
if: ${{ matrix.python-version != '3.6' }}
57+
if: ${{ matrix.python-version != '3.6.15' }}
5858
run: python -m poetry run bash scripts/lint.sh
5959
- name: Test
6060
run: python -m poetry run bash scripts/test.sh
6161
- name: Upload coverage
62-
uses: codecov/codecov-action@v1
62+
uses: codecov/codecov-action@v2

docs/help.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ And there are several ways to get help too.
1212

1313
## Subscribe to the FastAPI and Friends newsletter
1414

15-
You can subscribe to the (infrequent) [**FastAPI and friends** newsletter](/newsletter/){.internal-link target=_blank} to stay updated about:
15+
You can subscribe to the (infrequent) <a href="https://fastapi.tiangolo.com/newsletter" class="external-link" target="_blank">**FastAPI and friends** newsletter</a> to stay updated about:
1616

1717
* News about FastAPI and friends, including SQLModel 🚀
1818
* Guides 📝

docs/overrides/main.html

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{% extends "base.html" %}
2+
{%- block scripts %}
3+
{{ super() }}
4+
<script src="https://cdn.jsdelivr.net/npm/qabot@0.4"></script>
5+
<script>
6+
// This prevents the global search from interfering with qa-bot's internal text input.
7+
document.addEventListener('DOMContentLoaded', () => {
8+
document.querySelectorAll('qa-bot').forEach((x) => {
9+
x.addEventListener('keydown', (event) => {
10+
event.stopPropagation();
11+
});
12+
});
13+
});
14+
</script>
15+
<qa-bot
16+
server="https://tiangolo-sqlmodel.docsqa.jina.ai"
17+
theme="infer"
18+
title="SQLModel Bot"
19+
description="SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness."
20+
style="font-size: 0.8rem"
21+
>
22+
<template>
23+
<dl>
24+
<dt>You can ask questions about SQLModel. Try:</dt>
25+
<dd>Which Python version is supported?</dd>
26+
<dd>How SQLModel interacts with the database?</dd>
27+
<dd>How can I link tables?</dd>
28+
</dl>
29+
</template>
30+
</qa-bot>
31+
{%- endblock %}

docs/release-notes.md

+24
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,30 @@
22

33
## Latest Changes
44

5+
* ✏ Fix typo in `docs/tutorial/fastapi/simple-hero-api.md`. PR [#247](https://github.com/tiangolo/sqlmodel/pull/247) by [@hao-wang](https://github.com/hao-wang).
6+
* ✏ Fix typos in `docs/tutorial/automatic-id-none-refresh.md`, `docs/tutorial/fastapi/update.md`, `docs/tutorial/select.md`. PR [#185](https://github.com/tiangolo/sqlmodel/pull/185) by [@rootux](https://github.com/rootux).
7+
* ✏ Fix typo in `docs/databases.md`. PR [#177](https://github.com/tiangolo/sqlmodel/pull/177) by [@seandlg](https://github.com/seandlg).
8+
* ✏ Fix typos in `docs/tutorial/fastapi/update.md`. PR [#162](https://github.com/tiangolo/sqlmodel/pull/162) by [@wmcgee3](https://github.com/wmcgee3).
9+
* ✏ Fix typos in `docs/tutorial/code-structure.md`, `docs/tutorial/fastapi/multiple-models.md`, `docs/tutorial/fastapi/simple-hero-api.md`, `docs/tutorial/many-to-many/index.md`. PR [#116](https://github.com/tiangolo/sqlmodel/pull/116) by [@moonso](https://github.com/moonso).
10+
* ✏ Fix typo in `docs/tutorial/fastapi/teams.md`. PR [#154](https://github.com/tiangolo/sqlmodel/pull/154) by [@chrisgoddard](https://github.com/chrisgoddard).
11+
* ✏ Fix typo variable in example about relationships and `back_populates`, always use `hero` instead of `owner`. PR [#120](https://github.com/tiangolo/sqlmodel/pull/120) by [@onionj](https://github.com/onionj).
12+
* ✏ Fix typo in `docs/tutorial/fastapi/tests.md`. PR [#113](https://github.com/tiangolo/sqlmodel/pull/113) by [@feanil](https://github.com/feanil).
13+
* ✏ Fix typo in `docs/tutorial/where.md`. PR [#72](https://github.com/tiangolo/sqlmodel/pull/72) by [@ZettZet](https://github.com/ZettZet).
14+
* ✏ Fix typo in `docs/tutorial/code-structure.md`. PR [#91](https://github.com/tiangolo/sqlmodel/pull/91) by [@dhiraj](https://github.com/dhiraj).
15+
* ✏ Fix broken link to newsletter sign-up in `docs/help.md`. PR [#84](https://github.com/tiangolo/sqlmodel/pull/84) by [@mborus](https://github.com/mborus).
16+
* ⬆ Update development requirement for FastAPI from `^0.68.0` to `^0.68.1`. PR [#48](https://github.com/tiangolo/sqlmodel/pull/48) by [@alucarddelta](https://github.com/alucarddelta).
17+
* ✏ Fix typos in `docs/tutorial/many-to-many/create-models-with-link.md`. PR [#45](https://github.com/tiangolo/sqlmodel/pull/45) by [@xginn8](https://github.com/xginn8).
18+
* ✨ Raise an exception when using a Pydantic field type with no matching SQLAlchemy type. PR [#18](https://github.com/tiangolo/sqlmodel/pull/18) by [@elben10](https://github.com/elben10).
19+
* ⏪ Revert upgrade Poetry, to make a release that supports Python 3.6 first. PR [#417](https://github.com/tiangolo/sqlmodel/pull/417) by [@tiangolo](https://github.com/tiangolo).
20+
* 👷 Add dependabot for GitHub Actions. PR [#410](https://github.com/tiangolo/sqlmodel/pull/410) by [@tiangolo](https://github.com/tiangolo).
21+
* ⬆️ Upgrade Poetry to version `==1.2.0b1`. PR [#303](https://github.com/tiangolo/sqlmodel/pull/303) by [@tiangolo](https://github.com/tiangolo).
22+
* ✏ Fix typo in `docs/tutorial/index.md`. PR [#398](https://github.com/tiangolo/sqlmodel/pull/398) by [@ryangrose](https://github.com/ryangrose).
23+
* ⬆ Upgrade constrain for SQLAlchemy = ">=1.4.17,<=1.4.41". PR [#371](https://github.com/tiangolo/sqlmodel/pull/371) by [@RobertRosca](https://github.com/RobertRosca).
24+
* 🐛 Fix SQLAlchemy version 1.4.36 breaks SQLModel relationships (#315). PR [#322](https://github.com/tiangolo/sqlmodel/pull/322) by [@byrman](https://github.com/byrman).
25+
* 👷 Add CI for Python 3.10. PR [#305](https://github.com/tiangolo/sqlmodel/pull/305) by [@tiangolo](https://github.com/tiangolo).
26+
* 📝 Add Jina's QA Bot to the docs to help people that want to ask quick questions. PR [#263](https://github.com/tiangolo/sqlmodel/pull/263) by [@tiangolo](https://github.com/tiangolo).
27+
* 👷 Upgrade Codecov GitHub Action. PR [#304](https://github.com/tiangolo/sqlmodel/pull/304) by [@tiangolo](https://github.com/tiangolo).
28+
* ✨ Add new `Session.get()` parameter `execution_options`. PR [#302](https://github.com/tiangolo/sqlmodel/pull/302) by [@tiangolo](https://github.com/tiangolo).
529
* 💚 Only run CI on push when on master, to avoid duplicate runs on PRs. PR [#244](https://github.com/tiangolo/sqlmodel/pull/244) by [@tiangolo](https://github.com/tiangolo).
630
* 🔧 Upgrade MkDocs Material and update configs. PR [#217](https://github.com/tiangolo/sqlmodel/pull/217) by [@tiangolo](https://github.com/tiangolo).
731
* ⬆ Upgrade mypy, fix type annotations. PR [#218](https://github.com/tiangolo/sqlmodel/pull/218) by [@tiangolo](https://github.com/tiangolo).

docs/tutorial/code-structure.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ The class `Hero` has a reference to the class `Team` internally.
88

99
But the class `Team` also has a reference to the class `Hero`.
1010

11-
So, if those two classes where in separate files and you tried to import the classes in each other's file directly, it would result in a **circular import**. 🔄
11+
So, if those two classes were in separate files and you tried to import the classes in each other's file directly, it would result in a **circular import**. 🔄
1212

1313
And Python will not be able to handle it and will throw an error. 🚨
1414

@@ -170,7 +170,7 @@ Let's assume that now the file structure is:
170170

171171
The problem with circular imports is that Python can't resolve them at <abbr title="While it is executing the program, as oposed to the code as just text in a file stored on disk.">*runtime*</abbr>.
172172

173-
but when using Python **type annotations** it's very common to need to declare the type of some variables with classes imported from other files.
173+
But when using Python **type annotations** it's very common to need to declare the type of some variables with classes imported from other files.
174174

175175
And the files with those classes might **also need to import** more things from the first files.
176176

docs/tutorial/fastapi/multiple-models.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ And because we can't leave the empty space when creating a new class, but we don
361361

362362
This means that there's nothing else special in this class apart from the fact that it is named `HeroCreate` and that it inherits from `HeroBase`.
363363

364-
As an alternative, we could use `HeroBase` directly in the API code instead of `HeroCreate`, but it would show up in the auomatic docs UI with that name "`HeroBase`" which could be **confusing** for clients. Instead, "`HeroCreate`" is a bit more explicit about what it is for.
364+
As an alternative, we could use `HeroBase` directly in the API code instead of `HeroCreate`, but it would show up in the automatic docs UI with that name "`HeroBase`" which could be **confusing** for clients. Instead, "`HeroCreate`" is a bit more explicit about what it is for.
365365

366366
On top of that, we could easily decide in the future that we want to receive **more data** when creating a new hero apart from the data in `HeroBase` (for example a password), and now we already have the class to put those extra fields.
367367

docs/tutorial/fastapi/simple-hero-api.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ $ python -m pip install fastapi "uvicorn[standard]"
2323
```
2424

2525
</div>
26-
s
26+
2727
## **SQLModel** Code - Models, Engine
2828

2929
Now let's start with the SQLModel code.

docs/tutorial/fastapi/tests.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ Let's add some more tests:
311311

312312
That's why we add these two extra tests here.
313313

314-
Now, any additional test functions can be as **simple** as the first one, they just have to **declate the `client` parameter** to get the `TestClient` **fixture** with all the database stuff setup. Nice! 😎
314+
Now, any additional test functions can be as **simple** as the first one, they just have to **declare the `client` parameter** to get the `TestClient` **fixture** with all the database stuff setup. Nice! 😎
315315

316316
## Why Two Fixtures
317317

docs/tutorial/fastapi/update.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Now let's see how to update data in the database with a **FastAPI** *path operat
44

55
## `HeroUpdate` Model
66

7-
We want clients to be able to udpate the `name`, the `secret_name`, and the `age` of a hero.
7+
We want clients to be able to update the `name`, the `secret_name`, and the `age` of a hero.
88

99
But we don't want them to have to include all the data again just to **update a single field**.
1010

@@ -222,7 +222,7 @@ So, we would use that value and upate the `age` to `None` in the database, **jus
222222

223223
Notice that `age` here is `None`, and **we still detected it**.
224224

225-
Also that `name` was not even sent, and we don't *accidentaly* set it to `None` or something, we just didn't touch it, because the client didn't sent it, so we are **pefectly fine**, even in these corner cases. ✨
225+
Also that `name` was not even sent, and we don't *accidentally* set it to `None` or something, we just didn't touch it, because the client didn't send it, so we are **perfectly fine**, even in these corner cases. ✨
226226

227227
These are some of the advantages of Pydantic, that we can use with SQLModel. 🎉
228228

docs/tutorial/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Type hints
44

5-
If you need a refreshed about how to use Python type hints (type annotations), check <a href="https://fastapi.tiangolo.com/python-types/" class="external-link" target="_blank">FastAPI's Python types intro</a>.
5+
If you need a refresher about how to use Python type hints (type annotations), check <a href="https://fastapi.tiangolo.com/python-types/" class="external-link" target="_blank">FastAPI's Python types intro</a>.
66

77
You can also check the <a href="https://mypy.readthedocs.io/en/latest/cheat_sheet_py3.html" class="external-link" target="_blank">mypy cheat sheet</a>.
88

docs/tutorial/many-to-many/create-models-with-link.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ And **both fields are primary keys**. We hadn't used this before. 🤓
4040
Let's see the `Team` model, it's almost identical as before, but with a little change:
4141

4242
```Python hl_lines="8"
43-
# Code above ommited 👆
43+
# Code above omitted 👆
4444

4545
{!./docs_src/tutorial/many_to_many/tutorial001.py[ln:15-20]!}
4646

@@ -56,7 +56,7 @@ Let's see the `Team` model, it's almost identical as before, but with a little c
5656

5757
</details>
5858

59-
The **relationship attribute `heroes`** is still a list of heroes, annotatted as `List["Hero"]`. Again, we use `"Hero"` in quotes because we haven't declared that class yet by this point in the code (but as you know, editors and **SQLModel** understand that).
59+
The **relationship attribute `heroes`** is still a list of heroes, annotated as `List["Hero"]`. Again, we use `"Hero"` in quotes because we haven't declared that class yet by this point in the code (but as you know, editors and **SQLModel** understand that).
6060

6161
We use the same **`Relationship()`** function.
6262

@@ -69,7 +69,7 @@ And here's the important part to allow the **many-to-many** relationship, we use
6969
Let's see the other side, here's the `Hero` model:
7070

7171
```Python hl_lines="9"
72-
# Code above ommited 👆
72+
# Code above omitted 👆
7373

7474
{!./docs_src/tutorial/many_to_many/tutorial001.py[ln:23-29]!}
7575

@@ -102,7 +102,7 @@ And now we have a **`link_model=HeroTeamLink`**. ✨
102102
The same as before, we will have the rest of the code to create the **engine**, and a function to create all the tables `create_db_and_tables()`.
103103

104104
```Python hl_lines="9"
105-
# Code above ommited 👆
105+
# Code above omitted 👆
106106

107107
{!./docs_src/tutorial/many_to_many/tutorial001.py[ln:32-39]!}
108108

@@ -122,7 +122,7 @@ The same as before, we will have the rest of the code to create the **engine**,
122122
And as in previous examples, we will add that function to a function `main()`, and we will call that `main()` function in the main block:
123123

124124
```Python hl_lines="4"
125-
# Code above ommited 👆
125+
# Code above omitted 👆
126126

127127
{!./docs_src/tutorial/many_to_many/tutorial001.py[ln:78-79]!}
128128
# We will do more stuff here later 👈
@@ -149,7 +149,7 @@ If you run the code in the command line, it would output:
149149
```console
150150
$ python app.py
151151

152-
// Boilerplate ommited 😉
152+
// Boilerplate omitted 😉
153153

154154
INFO Engine
155155
CREATE TABLE team (

docs/tutorial/many-to-many/index.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Notice that each hero can only have **one** connection. But each team can receiv
6060

6161
## Introduce Many-to-Many
6262

63-
But let's say that as **Deadpond** is a great chracter, they recruit him to the new **Preventers** team, but he's still part of the **Z-Force** team too.
63+
But let's say that as **Deadpond** is a great character, they recruit him to the new **Preventers** team, but he's still part of the **Z-Force** team too.
6464

6565
So, now, we need to be able to have a hero that is connected to **many** teams. And then, each team, should still be able to receive **many** heroes. So we need a **Many-to-Many** relationship.
6666

docs/tutorial/select.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ You can try that out in **DB Browser for SQLite**:
8888

8989
### A SQL Shortcut
9090

91-
If we want to get all the columns like in this case above, in SQL there's a shortcut, instead of specifying each of the column names wew could write a `*`:
91+
If we want to get all the columns like in this case above, in SQL there's a shortcut, instead of specifying each of the column names we could write a `*`:
9292

9393
```SQL
9494
SELECT *

docs_src/tutorial/relationship_attributes/back_populates/tutorial003.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class Hero(SQLModel, table=True):
3636
team: Optional[Team] = Relationship(back_populates="heroes")
3737

3838
weapon_id: Optional[int] = Field(default=None, foreign_key="weapon.id")
39-
weapon: Optional[Weapon] = Relationship(back_populates="owner")
39+
weapon: Optional[Weapon] = Relationship(back_populates="hero")
4040

4141
powers: List[Power] = Relationship(back_populates="hero")
4242

mkdocs.yml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ site_description: SQLModel, SQL databases in Python, designed for simplicity, co
33
site_url: https://sqlmodel.tiangolo.com/
44
theme:
55
name: material
6+
custom_dir: docs/overrides
67
palette:
78
- scheme: default
89
primary: deep purple

pyproject.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ classifiers = [
3131

3232
[tool.poetry.dependencies]
3333
python = "^3.6.1"
34-
SQLAlchemy = ">=1.4.17,<1.5.0"
34+
SQLAlchemy = ">=1.4.17,<=1.4.41"
3535
pydantic = "^1.8.2"
3636
sqlalchemy2-stubs = {version = "*", allow-prereleases = true}
3737

@@ -44,7 +44,7 @@ mkdocs = "^1.2.1"
4444
mkdocs-material = "^8.1.4"
4545
mdx-include = "^1.4.1"
4646
coverage = {extras = ["toml"], version = "^5.5"}
47-
fastapi = "^0.68.0"
47+
fastapi = "^0.68.1"
4848
requests = "^2.26.0"
4949
autoflake = "^1.4"
5050
isort = "^5.9.3"
@@ -102,3 +102,5 @@ strict_equality = true
102102
[[tool.mypy.overrides]]
103103
module = "sqlmodel.sql.expression"
104104
warn_unused_ignores = false
105+
106+
# invalidate CI cache: 1

sqlmodel/main.py

+2
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ def __init__(
369369
relationship_to, *rel_args, **rel_kwargs
370370
)
371371
dict_used[rel_name] = rel_value
372+
setattr(cls, rel_name, rel_value) # Fix #315
372373
DeclarativeMeta.__init__(cls, classname, bases, dict_used, **kw)
373374
else:
374375
ModelMetaclass.__init__(cls, classname, bases, dict_, **kw)
@@ -414,6 +415,7 @@ def get_sqlachemy_type(field: ModelField) -> Any:
414415
return AutoString
415416
if issubclass(field.type_, uuid.UUID):
416417
return GUID
418+
raise ValueError(f"The field {field.name} has no matching SQLAlchemy type")
417419

418420

419421
def get_column_from_field(field: ModelField) -> Column: # type: ignore

sqlmodel/orm/session.py

+2
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ def get(
128128
populate_existing: bool = False,
129129
with_for_update: Optional[Union[Literal[True], Mapping[str, Any]]] = None,
130130
identity_token: Optional[Any] = None,
131+
execution_options: Optional[Mapping[Any, Any]] = util.EMPTY_DICT,
131132
) -> Optional[_TSelectParam]:
132133
return super().get(
133134
entity,
@@ -136,4 +137,5 @@ def get(
136137
populate_existing=populate_existing,
137138
with_for_update=with_for_update,
138139
identity_token=identity_token,
140+
execution_options=execution_options,
139141
)

tests/test_missing_type.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from typing import Optional
2+
3+
import pytest
4+
from sqlmodel import Field, SQLModel
5+
6+
7+
def test_missing_sql_type():
8+
class CustomType:
9+
@classmethod
10+
def __get_validators__(cls):
11+
yield cls.validate
12+
13+
@classmethod
14+
def validate(cls, v):
15+
return v
16+
17+
with pytest.raises(ValueError):
18+
19+
class Item(SQLModel, table=True):
20+
id: Optional[int] = Field(default=None, primary_key=True)
21+
item: CustomType

0 commit comments

Comments
 (0)