```console
- // Remember that you might need to use python3.9 or similar 💡
+ // Remember that you might need to use python3.9 or similar 💡
// Create the virtual environment using the module "venv"
$ python3 -m venv env
- // ...here it creates the virtual enviroment in the directory "env"
+ // ...here it creates the virtual environment in the directory "env"
// Activate the virtual environment
$ source ./env/bin/activate
// Verify that the virtual environment is active
@@ -157,7 +157,7 @@ Here are the commands you could use:
```console
// Create the virtual environment using the module "venv"
# >$ python3 -m venv env
- // ...here it creates the virtual enviroment in the directory "env"
+ // ...here it creates the virtual environment in the directory "env"
// Activate the virtual environment
# >$ .\env\Scripts\Activate.ps1
// Verify that the virtual environment is active
diff --git a/docs/tutorial/indexes.md b/docs/tutorial/indexes.md
index 6513d7d462..fef0081dc8 100644
--- a/docs/tutorial/indexes.md
+++ b/docs/tutorial/indexes.md
@@ -342,10 +342,10 @@ $ python app.py
// Create the table
CREATE TABLE hero (
- id INTEGER,
- name VARCHAR NOT NULL,
- secret_name VARCHAR NOT NULL,
- age INTEGER,
+ id INTEGER,
+ name VARCHAR NOT NULL,
+ secret_name VARCHAR NOT NULL,
+ age INTEGER,
PRIMARY KEY (id)
)
@@ -353,8 +353,8 @@ CREATE TABLE hero (
CREATE INDEX ix_hero_name ON hero (name)
// The SELECT with WHERE looks the same
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00014s] ('Deadpond',)
diff --git a/docs/tutorial/insert.md b/docs/tutorial/insert.md
index 5947e1e5dc..ecf87adbad 100644
--- a/docs/tutorial/insert.md
+++ b/docs/tutorial/insert.md
@@ -171,7 +171,7 @@ The first step is to import the `Session` class:
```Python hl_lines="3"
{!./docs_src/tutorial/insert/tutorial001.py[ln:1-3]!}
-# Code below ommitted 👇
+# Code below omitted 👇
```
diff --git a/docs/tutorial/limit-and-offset.md b/docs/tutorial/limit-and-offset.md
index 3fb001cf97..c8b0ddf72f 100644
--- a/docs/tutorial/limit-and-offset.md
+++ b/docs/tutorial/limit-and-offset.md
@@ -93,7 +93,7 @@ $ python app.py
// Previous output omitted 🙈
// Select with LIMIT
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
LIMIT ? OFFSET ?
INFO Engine [no key 0.00014s] (3, 0)
@@ -165,7 +165,7 @@ $python app.py
// Previous output omitted 🙈
// Select with LIMIT and OFFSET
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
LIMIT ? OFFSET ?
INFO Engine [no key 0.00020s] (3, 3)
@@ -221,7 +221,7 @@ $ python app.py
// Previous output omitted 🙈
// Select last batch with LIMIT and OFFSET
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
LIMIT ? OFFSET ?
INFO Engine [no key 0.00038s] (3, 6)
@@ -241,7 +241,7 @@ You probably noticed the new SQL keywords `LIMIT` and `OFFSET`.
You can use them in SQL, at the end of the other parts:
```SQL
-SELECT id, name, secret_name, age
+SELECT id, name, secret_name, age
FROM hero
LIMIT 3 OFFSET 6
```
@@ -271,11 +271,11 @@ Of course, you can also combine `.limit()` and `.offset()` with `.where()` and o
-## Run the Program with Limit and Where on the Command Line
+## Run the Program with Limit, Offset, and Where on the Command Line
If we run it on the command line, it will find all the heroes in the database with an age above 32. That would normally be 4 heroes.
-But we are limiting the results to only get the first 3:
+But we are starting to include after an offset of 1 (so we don't count the first one), and we are limiting the results to only get the first 2 after that:
@@ -284,18 +284,17 @@ $ python app.py
// Previous output omitted 🙈
-// Select with WHERE and LIMIT
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+// Select with WHERE and LIMIT and OFFSET
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.age > ?
LIMIT ? OFFSET ?
-INFO Engine [no key 0.00022s] (32, 3, 0)
+INFO Engine [no key 0.00022s] (32, 2, 1)
-// Print the heroes received, only 3
+// Print the heroes received, only 2
[
- Hero(age=35, secret_name='Trevor Challa', id=5, name='Black Lion'),
- Hero(age=36, secret_name='Steve Weird', id=6, name='Dr. Weird'),
- Hero(age=48, secret_name='Tommy Sharp', id=3, name='Rusty-Man')
+ Hero(age=36, id=6, name='Dr. Weird', secret_name='Steve Weird'),
+ Hero(age=48, id=3, name='Rusty-Man', secret_name='Tommy Sharp')
]
```
diff --git a/docs/tutorial/many-to-many/create-data.md b/docs/tutorial/many-to-many/create-data.md
index 22afb7ce7e..971659b9a6 100644
--- a/docs/tutorial/many-to-many/create-data.md
+++ b/docs/tutorial/many-to-many/create-data.md
@@ -122,16 +122,16 @@ INFO Engine COMMIT
// Automatically start a new transaction
INFO Engine BEGIN (implicit)
// Refresh the data
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00019s] (1,)
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.001959s ago] (2,)
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.003215s ago] (3,)
@@ -139,8 +139,8 @@ INFO Engine [cached since 0.003215s ago] (3,)
Deadpond: name='Deadpond' age=None id=1 secret_name='Dive Wilson'
// Accessing the .team attribute triggers a refresh
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team, heroteamlink
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team, heroteamlink
WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id
INFO Engine [generated in 0.00025s] (1,)
@@ -151,8 +151,8 @@ Deadpond teams: [Team(id=1, name='Z-Force', headquarters='Sister Margaret’s Ba
Rusty-Man: name='Rusty-Man' age=48 id=2 secret_name='Tommy Sharp'
// Accessing the .team attribute triggers a refresh
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team, heroteamlink
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team, heroteamlink
WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id
INFO Engine [cached since 0.001716s ago] (2,)
@@ -163,8 +163,8 @@ Rusty-Man Teams: [Team(id=2, name='Preventers', headquarters='Sharp Tower')]
Spider-Boy: name='Spider-Boy' age=None id=3 secret_name='Pedro Parqueador'
// Accessing the .team attribute triggers a refresh
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team, heroteamlink
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team, heroteamlink
WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id
INFO Engine [cached since 0.002739s ago] (3,)
@@ -179,4 +179,4 @@ INFO Engine ROLLBACK
## Recap
-After setting up the model link, using it with **relationship attributes** is fairly straighforward, just Python objects. ✨
+After setting up the model link, using it with **relationship attributes** is fairly straightforward, just Python objects. ✨
diff --git a/docs/tutorial/many-to-many/create-models-with-link.md b/docs/tutorial/many-to-many/create-models-with-link.md
index bc4481f73d..63cbf3eb82 100644
--- a/docs/tutorial/many-to-many/create-models-with-link.md
+++ b/docs/tutorial/many-to-many/create-models-with-link.md
@@ -151,35 +151,35 @@ $ python app.py
// Boilerplate omitted 😉
-INFO Engine
+INFO Engine
CREATE TABLE team (
- id INTEGER,
- name VARCHAR NOT NULL,
- headquarters VARCHAR NOT NULL,
+ id INTEGER,
+ name VARCHAR NOT NULL,
+ headquarters VARCHAR NOT NULL,
PRIMARY KEY (id)
)
INFO Engine [no key 0.00033s] ()
-INFO Engine
+INFO Engine
CREATE TABLE hero (
- id INTEGER,
- name VARCHAR NOT NULL,
- secret_name VARCHAR NOT NULL,
- age INTEGER,
+ id INTEGER,
+ name VARCHAR NOT NULL,
+ secret_name VARCHAR NOT NULL,
+ age INTEGER,
PRIMARY KEY (id)
)
INFO Engine [no key 0.00016s] ()
-INFO Engine
+INFO Engine
// Our shinny new link table ✨
CREATE TABLE heroteamlink (
- team_id INTEGER,
- hero_id INTEGER,
- PRIMARY KEY (team_id, hero_id),
- FOREIGN KEY(team_id) REFERENCES team (id),
+ team_id INTEGER,
+ hero_id INTEGER,
+ PRIMARY KEY (team_id, hero_id),
+ FOREIGN KEY(team_id) REFERENCES team (id),
FOREIGN KEY(hero_id) REFERENCES hero (id)
)
diff --git a/docs/tutorial/many-to-many/link-with-extra-fields.md b/docs/tutorial/many-to-many/link-with-extra-fields.md
index 9c3309da91..c998175a72 100644
--- a/docs/tutorial/many-to-many/link-with-extra-fields.md
+++ b/docs/tutorial/many-to-many/link-with-extra-fields.md
@@ -165,16 +165,16 @@ INFO Engine COMMIT
INFO Engine BEGIN (implicit)
// Automatically fetch the data on attribute access
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team
WHERE team.id = ?
INFO Engine [generated in 0.00028s] (1,)
-INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
-FROM heroteamlink
+INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
+FROM heroteamlink
WHERE ? = heroteamlink.team_id
INFO Engine [generated in 0.00026s] (1,)
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00024s] (1,)
@@ -182,12 +182,12 @@ INFO Engine [generated in 0.00024s] (1,)
Z-Force hero: name='Deadpond' age=None id=1 secret_name='Dive Wilson' is training: False
// Automatically fetch the data on attribute access
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team
WHERE team.id = ?
INFO Engine [cached since 0.008822s ago] (2,)
-INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
-FROM heroteamlink
+INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
+FROM heroteamlink
WHERE ? = heroteamlink.team_id
INFO Engine [cached since 0.005778s ago] (2,)
@@ -195,8 +195,8 @@ INFO Engine [cached since 0.005778s ago] (2,)
Preventers hero: name='Deadpond' age=None id=1 secret_name='Dive Wilson' is training: True
// Automatically fetch the data on attribute access
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.004196s ago] (2,)
@@ -204,8 +204,8 @@ INFO Engine [cached since 0.004196s ago] (2,)
Preventers hero: name='Spider-Boy' age=None id=2 secret_name='Pedro Parqueador' is training: True
// Automatically fetch the data on attribute access
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.006005s ago] (3,)
@@ -253,14 +253,14 @@ $ python app.py
INFO Engine BEGIN (implicit)
// Select the hero
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00014s] ('Spider-Boy',)
// Select the team
-INFO Engine SELECT team.id, team.name, team.headquarters
-FROM team
+INFO Engine SELECT team.id, team.name, team.headquarters
+FROM team
WHERE team.name = ?
INFO Engine [no key 0.00012s] ('Z-Force',)
@@ -269,18 +269,18 @@ INFO Engine INSERT INTO heroteamlink (team_id, hero_id, is_training) VALUES (?,
INFO Engine [generated in 0.00023s] (1, 2, 1)
// Automatically refresh the data on attribute access
-INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
-FROM heroteamlink
+INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
+FROM heroteamlink
WHERE ? = heroteamlink.team_id
INFO Engine [cached since 0.01514s ago] (1,)
INFO Engine COMMIT
INFO Engine BEGIN (implicit)
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.08953s ago] (2,)
-INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
-FROM heroteamlink
+INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
+FROM heroteamlink
WHERE ? = heroteamlink.hero_id
INFO Engine [generated in 0.00018s] (2,)
@@ -291,18 +291,18 @@ Updated Spider-Boy's Teams: [
]
// Automatically refresh team data on attribute access
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team
WHERE team.id = ?
INFO Engine [cached since 0.1084s ago] (1,)
-INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
-FROM heroteamlink
+INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
+FROM heroteamlink
WHERE ? = heroteamlink.team_id
INFO Engine [cached since 0.1054s ago] (1,)
// Print team hero links
Z-Force heroes: [
- HeroTeamLink(team_id=1, is_training=False, hero_id=1),
+ HeroTeamLink(team_id=1, is_training=False, hero_id=1),
HeroTeamLink(team_id=1, is_training=True, hero_id=2)
]
```
@@ -350,8 +350,8 @@ $ python app.py
// Previous output omitted 🙈
// Automatically fetch team data on attribute access
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team
WHERE team.id = ?
INFO Engine [generated in 0.00015s] (2,)
@@ -366,16 +366,16 @@ INFO Engine COMMIT
INFO Engine BEGIN (implicit)
// Automatically fetch data on attribute access
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.2004s ago] (2,)
-INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
-FROM heroteamlink
+INFO Engine SELECT heroteamlink.team_id AS heroteamlink_team_id, heroteamlink.hero_id AS heroteamlink_hero_id, heroteamlink.is_training AS heroteamlink_is_training
+FROM heroteamlink
WHERE ? = heroteamlink.hero_id
INFO Engine [cached since 0.1005s ago] (2,)
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team
WHERE team.id = ?
INFO Engine [cached since 0.09707s ago] (2,)
@@ -383,8 +383,8 @@ INFO Engine [cached since 0.09707s ago] (2,)
Spider-Boy team: headquarters='Sharp Tower' id=2 name='Preventers' is training: False
// Automatically fetch data on attribute access
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team
WHERE team.id = ?
INFO Engine [cached since 0.2097s ago] (1,)
diff --git a/docs/tutorial/many-to-many/update-remove-relationships.md b/docs/tutorial/many-to-many/update-remove-relationships.md
index 5cc55e1f41..91f2f2c0e2 100644
--- a/docs/tutorial/many-to-many/update-remove-relationships.md
+++ b/docs/tutorial/many-to-many/update-remove-relationships.md
@@ -115,12 +115,12 @@ INFO Engine COMMIT
INFO Engine BEGIN (implicit)
// Automatically refresh the data while accessing the attribute .teams
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00044s] (3,)
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team, heroteamlink
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team, heroteamlink
WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id
INFO Engine [cached since 0.1648s ago] (3,)
@@ -131,8 +131,8 @@ Updated Spider-Boy's Teams: [
]
// Automatically refresh the data while accessing the attribute .heores
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero, heroteamlink
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero, heroteamlink
WHERE ? = heroteamlink.team_id AND hero.id = heroteamlink.hero_id
INFO Engine [cached since 0.1499s ago] (1,)
@@ -208,12 +208,12 @@ INFO Engine COMMIT
INFO Engine BEGIN (implicit)
// Automatically refresh the data while accessing the attribute .heroes
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team
WHERE team.id = ?
INFO Engine [generated in 0.00029s] (1,)
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero, heroteamlink
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero, heroteamlink
WHERE ? = heroteamlink.team_id AND hero.id = heroteamlink.hero_id
INFO Engine [cached since 0.5625s ago] (1,)
@@ -223,12 +223,12 @@ Reverted Z-Force's heroes: [
]
// Automatically refresh the data while accessing the attribute .teams
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.4209s ago] (3,)
-INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
-FROM team, heroteamlink
+INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
+FROM team, heroteamlink
WHERE ? = heroteamlink.hero_id AND team.id = heroteamlink.team_id
INFO Engine [cached since 0.5842s ago] (3,)
diff --git a/docs/tutorial/one.md b/docs/tutorial/one.md
index 3b60653ed9..eadfc62a37 100644
--- a/docs/tutorial/one.md
+++ b/docs/tutorial/one.md
@@ -12,7 +12,7 @@ Let's see the utilities to read a single row.
## Continue From Previous Code
-We'll continue with the same examples we have been using in the previous chapters to create and select data and we'll keep udpating them.
+We'll continue with the same examples we have been using in the previous chapters to create and select data and we'll keep updating them.
👀 Full file preview
@@ -86,8 +86,8 @@ $ python app.py
// Some boilerplate output omitted 😉
// The SELECT with WHERE
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.age <= ?
INFO Engine [no key 0.00021s] (35,)
@@ -132,8 +132,8 @@ $ python app.py
// Some boilerplate output omitted 😉
// The SELECT with WHERE
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.age <= ?
INFO Engine [no key 0.00021s] (35,)
@@ -180,8 +180,8 @@ $ python app.py
// Some boilerplate output omitted 😉
// The SELECT with WHERE
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00015s] ('Deadpond',)
@@ -203,8 +203,8 @@ $ python app.py
// Some boilerplate output omitted 😉
// The SELECT with WHERE
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00015s] ('Deadpond',)
@@ -274,8 +274,8 @@ $ python app.py
// Some boilerplate output omitted 😉
// SELECT with WHERE
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.age < ?
INFO Engine [no key 0.00014s] (25,)
@@ -370,8 +370,8 @@ $ python app.py
// Some boilerplate output omitted 😉
// SELECT with WHERE
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00021s] (1,)
@@ -413,8 +413,8 @@ $ python app.py
// SELECT with WHERE
INFO Engine BEGIN (implicit)
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00024s] (9001,)
diff --git a/docs/tutorial/relationship-attributes/back-populates.md b/docs/tutorial/relationship-attributes/back-populates.md
index 86a4c2a70a..dbd3e8c1a3 100644
--- a/docs/tutorial/relationship-attributes/back-populates.md
+++ b/docs/tutorial/relationship-attributes/back-populates.md
@@ -123,7 +123,7 @@ Now let's update **Spider-Boy**, removing him from the team by setting `hero_spi
-The first important thing is, we *haven't commited* the hero yet, so accessing the list of heroes would not trigger an automatic refresh.
+The first important thing is, we *haven't committed* the hero yet, so accessing the list of heroes would not trigger an automatic refresh.
But in our code, in this exact point in time, we already said that **Spider-Boy** is no longer part of the **Preventers**. 🔥
@@ -144,10 +144,10 @@ But now, what happens when we print the `preventers_team.heroes`?
``` hl_lines="3"
Preventers Team Heroes again: [
- Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),
- Hero(name='Spider-Boy', age=None, id=3, secret_name='Pedro Parqueador', team_id=2, team=None),
- Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),
- Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),
+ Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),
+ Hero(name='Spider-Boy', age=None, id=3, secret_name='Pedro Parqueador', team_id=2, team=None),
+ Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),
+ Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),
Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2)
]
```
@@ -182,15 +182,15 @@ Now, if we commit it and print again:
When we access `preventers_team.heroes` after the `commit`, that triggers a refresh, so we get the latest list, without **Spider-Boy**, so that's fine again:
```
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id
+FROM hero
WHERE ? = hero.team_id
2021-08-13 11:15:24,658 INFO sqlalchemy.engine.Engine [cached since 0.1924s ago] (2,)
Preventers Team Heroes after commit: [
- Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),
- Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),
- Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),
+ Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),
+ Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),
+ Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),
Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2)
]
```
@@ -260,9 +260,9 @@ That second print would output:
```
Preventers Team Heroes again: [
- Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),
- Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),
- Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),
+ Hero(name='Rusty-Man', age=48, id=2, secret_name='Tommy Sharp', team_id=2),
+ Hero(name='Tarantula', age=32, id=6, secret_name='Natalia Roman-on', team_id=2),
+ Hero(name='Dr. Weird', age=36, id=7, secret_name='Steve Weird', team_id=2),
Hero(name='Captain North America', age=93, id=8, secret_name='Esteban Rogelios', team_id=2)
]
```
diff --git a/docs/tutorial/relationship-attributes/define-relationships-attributes.md b/docs/tutorial/relationship-attributes/define-relationships-attributes.md
index 0531ec53e5..b6e77d9b45 100644
--- a/docs/tutorial/relationship-attributes/define-relationships-attributes.md
+++ b/docs/tutorial/relationship-attributes/define-relationships-attributes.md
@@ -115,9 +115,7 @@ This means that this attribute could be `None`, or it could be a full `Team` obj
This is because the related **`team_id` could also be `None`** (or `NULL` in the database).
-If it was required for a `Hero` instance to belong to a `Team`, then the `team_id` would be `int` instead of `Optional[int]`.
-
-And the `team` attribute would be a `Team` instead of `Optional[Team]`.
+If it was required for a `Hero` instance to belong to a `Team`, then the `team_id` would be `int` instead of `Optional[int]`, its `Field` would be `Field(foreign_key="team.id")` instead of `Field(default=None, foreign_key="team.id")` and the `team` attribute would be a `Team` instead of `Optional[Team]`.
## Relationship Attributes With Lists
diff --git a/docs/tutorial/relationship-attributes/read-relationships.md b/docs/tutorial/relationship-attributes/read-relationships.md
index 181b229589..78e4207ae5 100644
--- a/docs/tutorial/relationship-attributes/read-relationships.md
+++ b/docs/tutorial/relationship-attributes/read-relationships.md
@@ -52,7 +52,7 @@ With what we have learned **up to now**, we could use a `select()` statement, th
## Get Relationship Team - New Way
-But now that we have the **relationship attributes**, we can just access them, and **SQLModel** (actually SQLAlchemy) will go and fetch the correspoinding data from the database, and make it available in the attribute. ✨
+But now that we have the **relationship attributes**, we can just access them, and **SQLModel** (actually SQLAlchemy) will go and fetch the corresponding data from the database, and make it available in the attribute. ✨
So, the highlighted block above, has the same results as the block below:
@@ -111,8 +111,8 @@ That would print a list with all the heroes in the Preventers team:
$ python app.py
// Automatically fetch the heroes
-INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id
-FROM hero
+INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age, hero.team_id AS hero_team_id
+FROM hero
WHERE ? = hero.team_id
INFO Engine [cached since 0.8774s ago] (2,)
diff --git a/docs/tutorial/select.md b/docs/tutorial/select.md
index fb638c1212..e2f9af447c 100644
--- a/docs/tutorial/select.md
+++ b/docs/tutorial/select.md
@@ -190,7 +190,7 @@ First we have to import `select` from `sqlmodel` at the top of the file:
```Python hl_lines="3"
{!./docs_src/tutorial/select/tutorial001.py[ln:1-3]!}
-# More code below ommitted 👇
+# More code below omitted 👇
```
@@ -274,7 +274,7 @@ This `session.exec(statement)` will generate this output:
```
INFO Engine BEGIN (implicit)
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
INFO Engine [no key 0.00032s] ()
```
@@ -455,7 +455,7 @@ In this chapter we are touching some of them.
### SQLModel's `select`
-When importing from `sqlmodel` the `select()` function, you are using **SQLModel**'s version of `select`.
+When importing from `sqlmodel` the `select()` function, you are using **SQLModel**'s version of `select`.
SQLAchemy also has it's own `select`, and SQLModel's `select` uses SQLAlchemy's `select` internally.
@@ -472,7 +472,7 @@ SQLAlchemy's own `Session` has a method `session.execute()`. It doesn't have a `
If you see SQLAlchemy tutorials, they will always use `session.execute()`.
-**SQLModel**'s own `Session` inherits directly from SQLAlchemy's `Session`, and adds this additonal method `session.exec()`. Underneath, it uses the same `session.execute()`.
+**SQLModel**'s own `Session` inherits directly from SQLAlchemy's `Session`, and adds this additional method `session.exec()`. Underneath, it uses the same `session.execute()`.
But `session.exec()` does several **tricks** combined with the tricks in `session()` to give you the **best editor support**, with **autocompletion** and **inline errors** everywhere, even after getting data from a select. ✨
diff --git a/docs/tutorial/update.md b/docs/tutorial/update.md
index b3099f5a16..56cc7ac1a5 100644
--- a/docs/tutorial/update.md
+++ b/docs/tutorial/update.md
@@ -132,8 +132,8 @@ $ python app.py
// Some boilerplate and previous output omitted 😉
// The SELECT with WHERE
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00017s] ('Spider-Boy',)
@@ -275,8 +275,8 @@ $ python app.py
// Previous output omitted 🙈
// The SQL to SELECT the fresh hero data
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00018s] (2,)
```
diff --git a/docs/tutorial/where.md b/docs/tutorial/where.md
index ca85a4dd00..a3bf6b0529 100644
--- a/docs/tutorial/where.md
+++ b/docs/tutorial/where.md
@@ -206,7 +206,7 @@ We care specially about the **select** statement:
## Filter Rows Using `WHERE` with **SQLModel**
-Now, the same way that we add `WHERE` to a SQL statement to filter rows, we can add a `.where()` to a **SQLModel** `select()` statment to filter rows, which will filter the objects returned:
+Now, the same way that we add `WHERE` to a SQL statement to filter rows, we can add a `.where()` to a **SQLModel** `select()` statement to filter rows, which will filter the objects returned:
```Python hl_lines="5"
# Code above omitted 👆
@@ -490,8 +490,8 @@ $ python app.py
// Now the important part, the SELECT with WHERE 💡
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00014s] ('Deadpond',)
@@ -726,8 +726,8 @@ This will select the rows `WHERE` the `age` is **greater than or equal** to `35`
The equivalent SQL would be:
```SQL hl_lines="3"
-SELECT id, name, secret_name, age
-FROM hero
+SELECT id, name, secret_name, age
+FROM hero
WHERE age >= 35 AND age < 40
```
@@ -743,12 +743,12 @@ $ python app.py
// Some boilerplate output omitted 😉
// The SELECT statement with WHERE, also using AND
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.age >= ? AND hero.age < ?
INFO Engine [no key 0.00014s] (35, 40)
-// The two heros printed
+// The two heroes printed
age=35 id=5 name='Black Lion' secret_name='Trevor Challa'
age=36 id=6 name='Dr. Weird' secret_name='Steve Weird'
@@ -838,8 +838,8 @@ $ python app.py
// Some boilerplate output omitted 😉
// The SELECT statement with WHERE, also using OR 🔍
-INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
-FROM hero
+INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+FROM hero
WHERE hero.age <= ? OR hero.age > ?
INFO Engine [no key 0.00021s] (35, 90)
diff --git a/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md b/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md
index fd33fec778..725fcb6601 100644
--- a/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md
+++ b/docs_src/tutorial/automatic_id_none_refresh/annotations/en/tutorial002.md
@@ -157,7 +157,7 @@
Hero 3:
```
-21. Print the line `"After commiting the session, show IDs"`.
+21. Print the line `"After committing the session, show IDs"`.
Generates the output:
@@ -181,8 +181,8 @@
```
INFO Engine BEGIN (implicit)
- INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
- FROM hero
+ INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+ FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00017s] (1,)
@@ -196,8 +196,8 @@
Generates the output:
```
- INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
- FROM hero
+ INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+ FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.001245s ago] (2,)
@@ -211,8 +211,8 @@
Generates the output:
```
- INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
- FROM hero
+ INFO Engine SELECT hero.id AS hero_id, hero.name AS hero_name, hero.secret_name AS hero_secret_name, hero.age AS hero_age
+ FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.002215s ago] (3,)
@@ -265,8 +265,8 @@
Generates the output:
```
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00024s] (1,)
```
@@ -278,8 +278,8 @@
Generates the output:
```
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.001487s ago] (2,)
```
@@ -291,8 +291,8 @@
Generates the output:
```
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.002377s ago] (3,)
```
diff --git a/docs_src/tutorial/delete/annotations/en/tutorial002.md b/docs_src/tutorial/delete/annotations/en/tutorial002.md
index 130016daec..28dcc50fb3 100644
--- a/docs_src/tutorial/delete/annotations/en/tutorial002.md
+++ b/docs_src/tutorial/delete/annotations/en/tutorial002.md
@@ -6,8 +6,8 @@
```
INFO Engine BEGIN (implicit)
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00011s] ('Spider-Youngster',)
```
@@ -65,8 +65,8 @@
```
INFO Engine BEGIN (implicit)
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00013s] ('Spider-Youngster',)
```
diff --git a/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py b/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py
index 88b8fbbcea..3f0602e4b4 100644
--- a/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py
+++ b/docs_src/tutorial/fastapi/app_testing/tutorial001/main.py
@@ -66,7 +66,7 @@ def read_heroes(
*,
session: Session = Depends(get_session),
offset: int = 0,
- limit: int = Query(default=100, lte=100),
+ limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes
@@ -98,7 +98,6 @@ def update_hero(
@app.delete("/heroes/{hero_id}")
def delete_hero(*, session: Session = Depends(get_session), hero_id: int):
-
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
diff --git a/docs_src/tutorial/fastapi/delete/tutorial001.py b/docs_src/tutorial/fastapi/delete/tutorial001.py
index 3c15efbb2d..3069fc5e87 100644
--- a/docs_src/tutorial/fastapi/delete/tutorial001.py
+++ b/docs_src/tutorial/fastapi/delete/tutorial001.py
@@ -58,7 +58,7 @@ def create_hero(hero: HeroCreate):
@app.get("/heroes/", response_model=List[HeroRead])
-def read_heroes(offset: int = 0, limit: int = Query(default=100, lte=100)):
+def read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)):
with Session(engine) as session:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes
diff --git a/docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py b/docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py
index aef21332a7..2b8739ca70 100644
--- a/docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py
+++ b/docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py
@@ -52,7 +52,7 @@ def create_hero(hero: HeroCreate):
@app.get("/heroes/", response_model=List[HeroRead])
-def read_heroes(offset: int = 0, limit: int = Query(default=100, lte=100)):
+def read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)):
with Session(engine) as session:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes
diff --git a/docs_src/tutorial/fastapi/relationships/tutorial001.py b/docs_src/tutorial/fastapi/relationships/tutorial001.py
index 97220b95e5..8477e4a2a0 100644
--- a/docs_src/tutorial/fastapi/relationships/tutorial001.py
+++ b/docs_src/tutorial/fastapi/relationships/tutorial001.py
@@ -104,7 +104,7 @@ def read_heroes(
*,
session: Session = Depends(get_session),
offset: int = 0,
- limit: int = Query(default=100, lte=100),
+ limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes
@@ -136,7 +136,6 @@ def update_hero(
@app.delete("/heroes/{hero_id}")
def delete_hero(*, session: Session = Depends(get_session), hero_id: int):
-
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
@@ -159,7 +158,7 @@ def read_teams(
*,
session: Session = Depends(get_session),
offset: int = 0,
- limit: int = Query(default=100, lte=100),
+ limit: int = Query(default=100, le=100),
):
teams = session.exec(select(Team).offset(offset).limit(limit)).all()
return teams
diff --git a/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py b/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py
index 88b8fbbcea..3f0602e4b4 100644
--- a/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py
+++ b/docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py
@@ -66,7 +66,7 @@ def read_heroes(
*,
session: Session = Depends(get_session),
offset: int = 0,
- limit: int = Query(default=100, lte=100),
+ limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes
@@ -98,7 +98,6 @@ def update_hero(
@app.delete("/heroes/{hero_id}")
def delete_hero(*, session: Session = Depends(get_session), hero_id: int):
-
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
diff --git a/docs_src/tutorial/fastapi/teams/tutorial001.py b/docs_src/tutorial/fastapi/teams/tutorial001.py
index 2a0bd600fc..1da0dad8a2 100644
--- a/docs_src/tutorial/fastapi/teams/tutorial001.py
+++ b/docs_src/tutorial/fastapi/teams/tutorial001.py
@@ -95,7 +95,7 @@ def read_heroes(
*,
session: Session = Depends(get_session),
offset: int = 0,
- limit: int = Query(default=100, lte=100),
+ limit: int = Query(default=100, le=100),
):
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes
@@ -127,7 +127,6 @@ def update_hero(
@app.delete("/heroes/{hero_id}")
def delete_hero(*, session: Session = Depends(get_session), hero_id: int):
-
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
@@ -150,7 +149,7 @@ def read_teams(
*,
session: Session = Depends(get_session),
offset: int = 0,
- limit: int = Query(default=100, lte=100),
+ limit: int = Query(default=100, le=100),
):
teams = session.exec(select(Team).offset(offset).limit(limit)).all()
return teams
diff --git a/docs_src/tutorial/fastapi/update/tutorial001.py b/docs_src/tutorial/fastapi/update/tutorial001.py
index 35554878db..bb98efd581 100644
--- a/docs_src/tutorial/fastapi/update/tutorial001.py
+++ b/docs_src/tutorial/fastapi/update/tutorial001.py
@@ -58,7 +58,7 @@ def create_hero(hero: HeroCreate):
@app.get("/heroes/", response_model=List[HeroRead])
-def read_heroes(offset: int = 0, limit: int = Query(default=100, lte=100)):
+def read_heroes(offset: int = 0, limit: int = Query(default=100, le=100)):
with Session(engine) as session:
heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()
return heroes
diff --git a/docs_src/tutorial/offset_and_limit/tutorial004.py b/docs_src/tutorial/offset_and_limit/tutorial004.py
index a95715cd98..43828b853f 100644
--- a/docs_src/tutorial/offset_and_limit/tutorial004.py
+++ b/docs_src/tutorial/offset_and_limit/tutorial004.py
@@ -43,7 +43,7 @@ def create_heroes():
def select_heroes():
with Session(engine) as session:
- statement = select(Hero).where(Hero.age > 32).limit(3)
+ statement = select(Hero).where(Hero.age > 32).offset(1).limit(2)
results = session.exec(statement)
heroes = results.all()
print(heroes)
diff --git a/docs_src/tutorial/select/annotations/en/tutorial002.md b/docs_src/tutorial/select/annotations/en/tutorial002.md
index 2570b542c4..312bd81a94 100644
--- a/docs_src/tutorial/select/annotations/en/tutorial002.md
+++ b/docs_src/tutorial/select/annotations/en/tutorial002.md
@@ -35,7 +35,7 @@
```
INFO Engine BEGIN (implicit)
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
FROM hero
INFO Engine [no key 0.00032s] ()
```
diff --git a/docs_src/tutorial/update/annotations/en/tutorial002.md b/docs_src/tutorial/update/annotations/en/tutorial002.md
index 3a52bd9bdf..eb1a820c0b 100644
--- a/docs_src/tutorial/update/annotations/en/tutorial002.md
+++ b/docs_src/tutorial/update/annotations/en/tutorial002.md
@@ -5,8 +5,8 @@
This generates the output:
```
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00017s] ('Spider-Boy',)
```
@@ -53,8 +53,8 @@
This generates the output:
```
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00018s] (2,)
```
diff --git a/docs_src/tutorial/update/annotations/en/tutorial004.md b/docs_src/tutorial/update/annotations/en/tutorial004.md
index 55755cd88d..8378d1b3a7 100644
--- a/docs_src/tutorial/update/annotations/en/tutorial004.md
+++ b/docs_src/tutorial/update/annotations/en/tutorial004.md
@@ -5,8 +5,8 @@
This generates the output:
```
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00018s] ('Spider-Boy',)
```
@@ -29,8 +29,8 @@
```
INFO Engine BEGIN (implicit)
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.name = ?
INFO Engine [no key 0.00020s] ('Captain North America',)
```
@@ -109,8 +109,8 @@
```
INFO Engine BEGIN (implicit)
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00023s] (2,)
```
@@ -123,8 +123,8 @@
This generates the output:
```
- INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
- FROM hero
+ INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age
+ FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.001709s ago] (7,)
```
@@ -132,7 +132,7 @@
!!! tip
SQLAlchemy is still using the previous transaction, so it doesn't have to create a new one.
-18. Print the first hero, now udpated.
+18. Print the first hero, now updated.
This generates the output:
diff --git a/pyproject.toml b/pyproject.toml
index 9561cd2761..aa78144892 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -31,25 +31,22 @@ classifiers = [
[tool.poetry.dependencies]
python = "^3.7"
-SQLAlchemy = ">=1.4.17,<=1.4.41"
+SQLAlchemy = ">=1.4.36,<2.0.0"
pydantic = "^1.8.2"
sqlalchemy2-stubs = {version = "*", allow-prereleases = true}
-[tool.poetry.dev-dependencies]
+[tool.poetry.group.dev.dependencies]
pytest = "^7.0.1"
mypy = "0.971"
-flake8 = "^5.0.4"
black = "^22.10.0"
-mkdocs = "^1.2.1"
-mkdocs-material = "^8.1.4"
+mkdocs-material = "9.1.21"
pillow = "^9.3.0"
cairosvg = "^2.5.2"
mdx-include = "^1.4.1"
coverage = {extras = ["toml"], version = "^6.2"}
fastapi = "^0.68.1"
requests = "^2.26.0"
-autoflake = "^1.4"
-isort = "^5.9.3"
+ruff = "^0.1.1"
testcontainers = "^3.7.1"
psycopg2-binary = "^2.9.7"
asyncpg = "^0.28.0"
@@ -78,33 +75,30 @@ exclude_lines = [
"if TYPE_CHECKING:",
]
-[tool.isort]
-profile = "black"
-known_third_party = ["sqlmodel"]
-skip_glob = [
- "sqlmodel/__init__.py",
- ]
-
-
[tool.mypy]
-# --strict
-disallow_any_generics = true
-disallow_subclassing_any = true
-disallow_untyped_calls = true
-disallow_untyped_defs = true
-disallow_incomplete_defs = true
-check_untyped_defs = true
-disallow_untyped_decorators = true
-no_implicit_optional = true
-warn_redundant_casts = true
-warn_unused_ignores = true
-warn_return_any = true
-implicit_reexport = false
-strict_equality = true
-# --strict end
+strict = true
[[tool.mypy.overrides]]
module = "sqlmodel.sql.expression"
warn_unused_ignores = false
-# invalidate CI cache: 1
+[tool.ruff]
+select = [
+ "E", # pycodestyle errors
+ "W", # pycodestyle warnings
+ "F", # pyflakes
+ "I", # isort
+ "C", # flake8-comprehensions
+ "B", # flake8-bugbear
+]
+ignore = [
+ "E501", # line too long, handled by black
+ "B008", # do not perform function calls in argument defaults
+ "C901", # too complex
+]
+
+[tool.ruff.per-file-ignores]
+# "__init__.py" = ["F401"]
+
+[tool.ruff.isort]
+known-third-party = ["sqlmodel", "sqlalchemy", "pydantic", "fastapi"]
diff --git a/scripts/docs-live.sh b/scripts/docs-live.sh
index 5342a9e59f..f9d31ba361 100755
--- a/scripts/docs-live.sh
+++ b/scripts/docs-live.sh
@@ -2,4 +2,6 @@
set -e
+export DYLD_FALLBACK_LIBRARY_PATH="/opt/homebrew/lib"
+
mkdocs serve --dev-addr 127.0.0.1:8008
diff --git a/scripts/format.sh b/scripts/format.sh
index 0d456398fb..b6aebd10d4 100755
--- a/scripts/format.sh
+++ b/scripts/format.sh
@@ -1,6 +1,5 @@
#!/bin/sh -e
set -x
-autoflake --remove-all-unused-imports --recursive --remove-unused-variables --in-place sqlmodel docs_src tests --exclude=__init__.py
-black sqlmodel tests docs_src
-isort sqlmodel tests docs_src
+ruff sqlmodel tests docs_src scripts --fix
+black sqlmodel tests docs_src scripts
diff --git a/scripts/lint.sh b/scripts/lint.sh
index 4191d90f1f..b328e3d9ac 100755
--- a/scripts/lint.sh
+++ b/scripts/lint.sh
@@ -4,6 +4,5 @@ set -e
set -x
mypy sqlmodel
-flake8 sqlmodel tests docs_src
+ruff sqlmodel tests docs_src scripts
black sqlmodel tests docs_src --check
-isort sqlmodel tests docs_src scripts --check-only
diff --git a/sqlmodel/__init__.py b/sqlmodel/__init__.py
index 720aa8c929..b51084b3fc 100644
--- a/sqlmodel/__init__.py
+++ b/sqlmodel/__init__.py
@@ -1,16 +1,16 @@
-__version__ = "0.0.8"
+__version__ = "0.0.9"
# Re-export from SQLAlchemy
from sqlalchemy.engine import create_mock_engine as create_mock_engine
from sqlalchemy.engine import engine_from_config as engine_from_config
from sqlalchemy.inspection import inspect as inspect
from sqlalchemy.schema import BLANK_SCHEMA as BLANK_SCHEMA
+from sqlalchemy.schema import DDL as DDL
from sqlalchemy.schema import CheckConstraint as CheckConstraint
from sqlalchemy.schema import Column as Column
from sqlalchemy.schema import ColumnDefault as ColumnDefault
from sqlalchemy.schema import Computed as Computed
from sqlalchemy.schema import Constraint as Constraint
-from sqlalchemy.schema import DDL as DDL
from sqlalchemy.schema import DefaultClause as DefaultClause
from sqlalchemy.schema import FetchedValue as FetchedValue
from sqlalchemy.schema import ForeignKey as ForeignKey
@@ -23,6 +23,14 @@
from sqlalchemy.schema import Table as Table
from sqlalchemy.schema import ThreadLocalMetaData as ThreadLocalMetaData
from sqlalchemy.schema import UniqueConstraint as UniqueConstraint
+from sqlalchemy.sql import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT
+from sqlalchemy.sql import (
+ LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY,
+)
+from sqlalchemy.sql import LABEL_STYLE_NONE as LABEL_STYLE_NONE
+from sqlalchemy.sql import (
+ LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL,
+)
from sqlalchemy.sql import alias as alias
from sqlalchemy.sql import all_ as all_
from sqlalchemy.sql import and_ as and_
@@ -48,14 +56,6 @@
from sqlalchemy.sql import intersect as intersect
from sqlalchemy.sql import intersect_all as intersect_all
from sqlalchemy.sql import join as join
-from sqlalchemy.sql import LABEL_STYLE_DEFAULT as LABEL_STYLE_DEFAULT
-from sqlalchemy.sql import (
- LABEL_STYLE_DISAMBIGUATE_ONLY as LABEL_STYLE_DISAMBIGUATE_ONLY,
-)
-from sqlalchemy.sql import LABEL_STYLE_NONE as LABEL_STYLE_NONE
-from sqlalchemy.sql import (
- LABEL_STYLE_TABLENAME_PLUS_COL as LABEL_STYLE_TABLENAME_PLUS_COL,
-)
from sqlalchemy.sql import lambda_stmt as lambda_stmt
from sqlalchemy.sql import lateral as lateral
from sqlalchemy.sql import literal as literal
@@ -85,55 +85,53 @@
from sqlalchemy.sql import within_group as within_group
from sqlalchemy.types import ARRAY as ARRAY
from sqlalchemy.types import BIGINT as BIGINT
-from sqlalchemy.types import BigInteger as BigInteger
from sqlalchemy.types import BINARY as BINARY
from sqlalchemy.types import BLOB as BLOB
from sqlalchemy.types import BOOLEAN as BOOLEAN
-from sqlalchemy.types import Boolean as Boolean
from sqlalchemy.types import CHAR as CHAR
from sqlalchemy.types import CLOB as CLOB
from sqlalchemy.types import DATE as DATE
-from sqlalchemy.types import Date as Date
from sqlalchemy.types import DATETIME as DATETIME
-from sqlalchemy.types import DateTime as DateTime
from sqlalchemy.types import DECIMAL as DECIMAL
-from sqlalchemy.types import Enum as Enum
from sqlalchemy.types import FLOAT as FLOAT
-from sqlalchemy.types import Float as Float
from sqlalchemy.types import INT as INT
from sqlalchemy.types import INTEGER as INTEGER
-from sqlalchemy.types import Integer as Integer
-from sqlalchemy.types import Interval as Interval
from sqlalchemy.types import JSON as JSON
-from sqlalchemy.types import LargeBinary as LargeBinary
from sqlalchemy.types import NCHAR as NCHAR
from sqlalchemy.types import NUMERIC as NUMERIC
-from sqlalchemy.types import Numeric as Numeric
from sqlalchemy.types import NVARCHAR as NVARCHAR
-from sqlalchemy.types import PickleType as PickleType
from sqlalchemy.types import REAL as REAL
from sqlalchemy.types import SMALLINT as SMALLINT
+from sqlalchemy.types import TEXT as TEXT
+from sqlalchemy.types import TIME as TIME
+from sqlalchemy.types import TIMESTAMP as TIMESTAMP
+from sqlalchemy.types import VARBINARY as VARBINARY
+from sqlalchemy.types import VARCHAR as VARCHAR
+from sqlalchemy.types import BigInteger as BigInteger
+from sqlalchemy.types import Boolean as Boolean
+from sqlalchemy.types import Date as Date
+from sqlalchemy.types import DateTime as DateTime
+from sqlalchemy.types import Enum as Enum
+from sqlalchemy.types import Float as Float
+from sqlalchemy.types import Integer as Integer
+from sqlalchemy.types import Interval as Interval
+from sqlalchemy.types import LargeBinary as LargeBinary
+from sqlalchemy.types import Numeric as Numeric
+from sqlalchemy.types import PickleType as PickleType
from sqlalchemy.types import SmallInteger as SmallInteger
from sqlalchemy.types import String as String
-from sqlalchemy.types import TEXT as TEXT
from sqlalchemy.types import Text as Text
-from sqlalchemy.types import TIME as TIME
from sqlalchemy.types import Time as Time
-from sqlalchemy.types import TIMESTAMP as TIMESTAMP
from sqlalchemy.types import TypeDecorator as TypeDecorator
from sqlalchemy.types import Unicode as Unicode
from sqlalchemy.types import UnicodeText as UnicodeText
-from sqlalchemy.types import VARBINARY as VARBINARY
-from sqlalchemy.types import VARCHAR as VARCHAR
-# Extensions and modifications of SQLAlchemy in SQLModel
+# From SQLModel, modifications of SQLAlchemy or equivalents of Pydantic
from .engine.create import create_engine as create_engine
+from .main import Field as Field
+from .main import Relationship as Relationship
+from .main import SQLModel as SQLModel
from .orm.session import Session as Session
-from .sql.expression import select as select
from .sql.expression import col as col
+from .sql.expression import select as select
from .sql.sqltypes import AutoString as AutoString
-
-# Export SQLModel specifics (equivalent to Pydantic)
-from .main import SQLModel as SQLModel
-from .main import Field as Field
-from .main import Relationship as Relationship
diff --git a/sqlmodel/default.py b/sqlmodel/default.py
index bb44972e24..e8e37a5566 100644
--- a/sqlmodel/default.py
+++ b/sqlmodel/default.py
@@ -6,7 +6,7 @@ class _DefaultPlaceholder:
You shouldn't use this class directly.
It's used internally to recognize when a default value has been overwritten, even
- if the overriden default value was truthy.
+ if the overridden default value was truthy.
"""
def __init__(self, value: Any):
@@ -27,6 +27,6 @@ def Default(value: _TDefaultType) -> _TDefaultType:
You shouldn't use this function directly.
It's used internally to recognize when a default value has been overwritten, even
- if the overriden default value was truthy.
+ if the overridden default value was truthy.
"""
return _DefaultPlaceholder(value) # type: ignore
diff --git a/sqlmodel/ext/asyncio/session.py b/sqlmodel/ext/asyncio/session.py
index 79dae568a6..f500c44dc2 100644
--- a/sqlmodel/ext/asyncio/session.py
+++ b/sqlmodel/ext/asyncio/session.py
@@ -1,17 +1,17 @@
-from typing import Any, Mapping, Optional, Sequence, TypeVar, Union
+from typing import Any, Mapping, Optional, Sequence, TypeVar, Union, overload
from sqlalchemy import util
from sqlalchemy.ext.asyncio import AsyncSession as _AsyncSession
from sqlalchemy.ext.asyncio import engine
from sqlalchemy.ext.asyncio.engine import AsyncConnection, AsyncEngine
from sqlalchemy.util.concurrency import greenlet_spawn
-from sqlmodel.sql.base import Executable
-from ...engine.result import ScalarResult
+from ...engine.result import Result, ScalarResult
from ...orm.session import Session
+from ...sql.base import Executable
from ...sql.expression import Select, SelectOfScalar
-_T = TypeVar("_T")
+_TSelectParam = TypeVar("_TSelectParam")
class AsyncSession(_AsyncSession):
@@ -40,14 +40,46 @@ def __init__(
Session(bind=bind, binds=binds, **kw) # type: ignore
)
+ @overload
async def exec(
self,
- statement: Union[Select[_T], SelectOfScalar[_T], Executable[_T]],
+ statement: Select[_TSelectParam],
+ *,
+ params: Optional[Union[Mapping[str, Any], Sequence[Mapping[str, Any]]]] = None,
+ execution_options: Mapping[str, Any] = util.EMPTY_DICT,
+ bind_arguments: Optional[Mapping[str, Any]] = None,
+ _parent_execute_state: Optional[Any] = None,
+ _add_event: Optional[Any] = None,
+ **kw: Any,
+ ) -> Result[_TSelectParam]:
+ ...
+
+ @overload
+ async def exec(
+ self,
+ statement: SelectOfScalar[_TSelectParam],
+ *,
+ params: Optional[Union[Mapping[str, Any], Sequence[Mapping[str, Any]]]] = None,
+ execution_options: Mapping[str, Any] = util.EMPTY_DICT,
+ bind_arguments: Optional[Mapping[str, Any]] = None,
+ _parent_execute_state: Optional[Any] = None,
+ _add_event: Optional[Any] = None,
+ **kw: Any,
+ ) -> ScalarResult[_TSelectParam]:
+ ...
+
+ async def exec(
+ self,
+ statement: Union[
+ Select[_TSelectParam],
+ SelectOfScalar[_TSelectParam],
+ Executable[_TSelectParam],
+ ],
params: Optional[Union[Mapping[str, Any], Sequence[Mapping[str, Any]]]] = None,
execution_options: Mapping[Any, Any] = util.EMPTY_DICT,
bind_arguments: Optional[Mapping[str, Any]] = None,
**kw: Any,
- ) -> ScalarResult[_T]:
+ ) -> Union[Result[_TSelectParam], ScalarResult[_TSelectParam]]:
# TODO: the documentation says execution_options accepts a dict, but only
# util.immutabledict has the union() method. Is this a bug in SQLAlchemy?
execution_options = execution_options.union({"prebuffer_rows": True}) # type: ignore
diff --git a/sqlmodel/main.py b/sqlmodel/main.py
index 5b5950a811..07e600e4d4 100644
--- a/sqlmodel/main.py
+++ b/sqlmodel/main.py
@@ -26,15 +26,24 @@
from pydantic import BaseConfig, BaseModel
from pydantic.errors import ConfigError, DictError
-from pydantic.fields import SHAPE_SINGLETON
+from pydantic.fields import SHAPE_SINGLETON, ModelField, Undefined, UndefinedType
from pydantic.fields import FieldInfo as PydanticFieldInfo
-from pydantic.fields import ModelField, Undefined, UndefinedType
from pydantic.main import ModelMetaclass, validate_model
from pydantic.typing import NoArgAnyCallable, resolve_annotations
from pydantic.utils import ROOT_KEY, Representation
-from sqlalchemy import Boolean, Column, Date, DateTime
+from sqlalchemy import (
+ Boolean,
+ Column,
+ Date,
+ DateTime,
+ Float,
+ ForeignKey,
+ Integer,
+ Interval,
+ Numeric,
+ inspect,
+)
from sqlalchemy import Enum as sa_Enum
-from sqlalchemy import Float, ForeignKey, Integer, Interval, Numeric, inspect
from sqlalchemy.orm import RelationshipProperty, declared_attr, registry, relationship
from sqlalchemy.orm.attributes import set_attribute
from sqlalchemy.orm.decl_api import DeclarativeMeta
@@ -305,9 +314,9 @@ def get_config(name: str) -> Any:
config_registry = cast(registry, config_registry)
# If it was passed by kwargs, ensure it's also set in config
new_cls.__config__.registry = config_table
- setattr(new_cls, "_sa_registry", config_registry)
- setattr(new_cls, "metadata", config_registry.metadata)
- setattr(new_cls, "__abstract__", True)
+ setattr(new_cls, "_sa_registry", config_registry) # noqa: B010
+ setattr(new_cls, "metadata", config_registry.metadata) # noqa: B010
+ setattr(new_cls, "__abstract__", True) # noqa: B010
return new_cls
# Override SQLAlchemy, allow both SQLAlchemy and plain Pydantic models
@@ -320,19 +329,16 @@ def __init__(
# triggers an error
base_is_table = False
for base in bases:
- config = getattr(base, "__config__")
+ config = getattr(base, "__config__") # noqa: B009
if config and getattr(config, "table", False):
base_is_table = True
break
if getattr(cls.__config__, "table", False) and not base_is_table:
- dict_used = dict_.copy()
- for field_name, field_value in cls.__fields__.items():
- dict_used[field_name] = get_column_from_field(field_value)
for rel_name, rel_info in cls.__sqlmodel_relationships__.items():
if rel_info.sa_relationship:
# There's a SQLAlchemy relationship declared, that takes precedence
# over anything else, use that and continue with the next attribute
- dict_used[rel_name] = rel_info.sa_relationship
+ setattr(cls, rel_name, rel_info.sa_relationship) # Fix #315
continue
ann = cls.__annotations__[rel_name]
temp_field = ModelField.infer(
@@ -350,7 +356,7 @@ def __init__(
rel_kwargs["back_populates"] = rel_info.back_populates
if rel_info.link_model:
ins = inspect(rel_info.link_model)
- local_table = getattr(ins, "local_table")
+ local_table = getattr(ins, "local_table") # noqa: B009
if local_table is None:
raise RuntimeError(
"Couldn't find the secondary table for "
@@ -365,53 +371,57 @@ def __init__(
rel_value: RelationshipProperty = relationship( # type: ignore
relationship_to, *rel_args, **rel_kwargs
)
- dict_used[rel_name] = rel_value
setattr(cls, rel_name, rel_value) # Fix #315
- DeclarativeMeta.__init__(cls, classname, bases, dict_used, **kw)
+ # SQLAlchemy no longer uses dict_
+ # Ref: https://github.com/sqlalchemy/sqlalchemy/commit/428ea01f00a9cc7f85e435018565eb6da7af1b77
+ # Tag: 1.4.36
+ DeclarativeMeta.__init__(cls, classname, bases, dict_, **kw)
else:
ModelMetaclass.__init__(cls, classname, bases, dict_, **kw)
def get_sqlalchemy_type(field: ModelField) -> Any:
- if issubclass(field.type_, str):
- if field.field_info.max_length:
- return AutoString(length=field.field_info.max_length)
- return AutoString
- if issubclass(field.type_, float):
- return Float
- if issubclass(field.type_, bool):
- return Boolean
- if issubclass(field.type_, int):
- return Integer
- if issubclass(field.type_, datetime):
- return DateTime
- if issubclass(field.type_, date):
- return Date
- if issubclass(field.type_, timedelta):
- return Interval
- if issubclass(field.type_, time):
- return Time
- if issubclass(field.type_, Enum):
- return sa_Enum(field.type_)
- if issubclass(field.type_, bytes):
- return LargeBinary
- if issubclass(field.type_, Decimal):
- return Numeric(
- precision=getattr(field.type_, "max_digits", None),
- scale=getattr(field.type_, "decimal_places", None),
- )
- if issubclass(field.type_, ipaddress.IPv4Address):
- return AutoString
- if issubclass(field.type_, ipaddress.IPv4Network):
- return AutoString
- if issubclass(field.type_, ipaddress.IPv6Address):
- return AutoString
- if issubclass(field.type_, ipaddress.IPv6Network):
- return AutoString
- if issubclass(field.type_, Path):
- return AutoString
- if issubclass(field.type_, uuid.UUID):
- return GUID
+ if isinstance(field.type_, type) and field.shape == SHAPE_SINGLETON:
+ # Check enums first as an enum can also be a str, needed by Pydantic/FastAPI
+ if issubclass(field.type_, Enum):
+ return sa_Enum(field.type_)
+ if issubclass(field.type_, str):
+ if field.field_info.max_length:
+ return AutoString(length=field.field_info.max_length)
+ return AutoString
+ if issubclass(field.type_, float):
+ return Float
+ if issubclass(field.type_, bool):
+ return Boolean
+ if issubclass(field.type_, int):
+ return Integer
+ if issubclass(field.type_, datetime):
+ return DateTime
+ if issubclass(field.type_, date):
+ return Date
+ if issubclass(field.type_, timedelta):
+ return Interval
+ if issubclass(field.type_, time):
+ return Time
+ if issubclass(field.type_, bytes):
+ return LargeBinary
+ if issubclass(field.type_, Decimal):
+ return Numeric(
+ precision=getattr(field.type_, "max_digits", None),
+ scale=getattr(field.type_, "decimal_places", None),
+ )
+ if issubclass(field.type_, ipaddress.IPv4Address):
+ return AutoString
+ if issubclass(field.type_, ipaddress.IPv4Network):
+ return AutoString
+ if issubclass(field.type_, ipaddress.IPv6Address):
+ return AutoString
+ if issubclass(field.type_, ipaddress.IPv6Network):
+ return AutoString
+ if issubclass(field.type_, Path):
+ return AutoString
+ if issubclass(field.type_, uuid.UUID):
+ return GUID
raise ValueError(f"The field {field.name} has no matching SQLAlchemy type")
@@ -428,7 +438,7 @@ def get_column_from_field(field: ModelField) -> Column: # type: ignore
# Override derived nullability if the nullable property is set explicitly
# on the field
if hasattr(field.field_info, "nullable"):
- field_nullable = getattr(field.field_info, "nullable")
+ field_nullable = getattr(field.field_info, "nullable") # noqa: B009
if field_nullable != Undefined:
nullable = field_nullable
args = []
diff --git a/sqlmodel/orm/session.py b/sqlmodel/orm/session.py
index 1692fdcbcb..0c70c290ae 100644
--- a/sqlmodel/orm/session.py
+++ b/sqlmodel/orm/session.py
@@ -4,11 +4,11 @@
from sqlalchemy.orm import Query as _Query
from sqlalchemy.orm import Session as _Session
from sqlalchemy.sql.base import Executable as _Executable
-from sqlmodel.sql.expression import Select, SelectOfScalar
from typing_extensions import Literal
from ..engine.result import Result, ScalarResult
from ..sql.base import Executable
+from ..sql.expression import Select, SelectOfScalar
_TSelectParam = TypeVar("_TSelectParam")
diff --git a/sqlmodel/sql/sqltypes.py b/sqlmodel/sql/sqltypes.py
index 09b8239476..17d9b06126 100644
--- a/sqlmodel/sql/sqltypes.py
+++ b/sqlmodel/sql/sqltypes.py
@@ -8,7 +8,6 @@
class AutoString(types.TypeDecorator): # type: ignore
-
impl = types.String
cache_ok = True
mysql_default_length = 255
diff --git a/tests/test_enums.py b/tests/test_enums.py
index aeec6456da..194bdefea1 100644
--- a/tests/test_enums.py
+++ b/tests/test_enums.py
@@ -14,12 +14,12 @@
"""
-class MyEnum1(enum.Enum):
+class MyEnum1(str, enum.Enum):
A = "A"
B = "B"
-class MyEnum2(enum.Enum):
+class MyEnum2(str, enum.Enum):
C = "C"
D = "D"
@@ -70,3 +70,43 @@ def test_sqlite_ddl_sql(capsys):
captured = capsys.readouterr()
assert "enum_field VARCHAR(1) NOT NULL" in captured.out
assert "CREATE TYPE" not in captured.out
+
+
+def test_json_schema_flat_model():
+ assert FlatModel.schema() == {
+ "title": "FlatModel",
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "string", "format": "uuid"},
+ "enum_field": {"$ref": "#/definitions/MyEnum1"},
+ },
+ "required": ["id", "enum_field"],
+ "definitions": {
+ "MyEnum1": {
+ "title": "MyEnum1",
+ "description": "An enumeration.",
+ "enum": ["A", "B"],
+ "type": "string",
+ }
+ },
+ }
+
+
+def test_json_schema_inherit_model():
+ assert InheritModel.schema() == {
+ "title": "InheritModel",
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "string", "format": "uuid"},
+ "enum_field": {"$ref": "#/definitions/MyEnum2"},
+ },
+ "required": ["id", "enum_field"],
+ "definitions": {
+ "MyEnum2": {
+ "title": "MyEnum2",
+ "description": "An enumeration.",
+ "enum": ["C", "D"],
+ "type": "string",
+ }
+ },
+ }
diff --git a/tests/test_main.py b/tests/test_main.py
index 22c62327da..72465cda33 100644
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -1,8 +1,9 @@
-from typing import Optional
+from typing import List, Optional
import pytest
from sqlalchemy.exc import IntegrityError
-from sqlmodel import Field, Session, SQLModel, create_engine
+from sqlalchemy.orm import RelationshipProperty
+from sqlmodel import Field, Relationship, Session, SQLModel, create_engine
def test_should_allow_duplicate_row_if_unique_constraint_is_not_passed(clear_sqlmodel):
@@ -91,3 +92,37 @@ class Hero(SQLModel, table=True):
session.add(hero_2)
session.commit()
session.refresh(hero_2)
+
+
+def test_sa_relationship_property(clear_sqlmodel):
+ """Test https://github.com/tiangolo/sqlmodel/issues/315#issuecomment-1272122306"""
+
+ class Team(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ name: str = Field(unique=True)
+ heroes: List["Hero"] = Relationship( # noqa: F821
+ sa_relationship=RelationshipProperty("Hero", back_populates="team")
+ )
+
+ class Hero(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ name: str = Field(unique=True)
+ team_id: Optional[int] = Field(default=None, foreign_key="team.id")
+ team: Optional[Team] = Relationship(
+ sa_relationship=RelationshipProperty("Team", back_populates="heroes")
+ )
+
+ team_preventers = Team(name="Preventers")
+ hero_rusty_man = Hero(name="Rusty-Man", team=team_preventers)
+
+ engine = create_engine("sqlite://", echo=True)
+
+ SQLModel.metadata.create_all(engine)
+
+ with Session(engine) as session:
+ session.add(hero_rusty_man)
+ session.commit()
+ session.refresh(hero_rusty_man)
+ # The next statement should not raise an AttributeError
+ assert hero_rusty_man.team
+ assert hero_rusty_man.team.name == "Preventers"
diff --git a/tests/test_sqlalchemy_type_errors.py b/tests/test_sqlalchemy_type_errors.py
new file mode 100644
index 0000000000..e211c46a34
--- /dev/null
+++ b/tests/test_sqlalchemy_type_errors.py
@@ -0,0 +1,28 @@
+from typing import Any, Dict, List, Optional, Union
+
+import pytest
+from sqlmodel import Field, SQLModel
+
+
+def test_type_list_breaks() -> None:
+ with pytest.raises(ValueError):
+
+ class Hero(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ tags: List[str]
+
+
+def test_type_dict_breaks() -> None:
+ with pytest.raises(ValueError):
+
+ class Hero(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ tags: Dict[str, Any]
+
+
+def test_type_union_breaks() -> None:
+ with pytest.raises(ValueError):
+
+ class Hero(SQLModel, table=True):
+ id: Optional[int] = Field(default=None, primary_key=True)
+ tags: Union[int, str]
diff --git a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py
index e560d04c0e..b08affb920 100644
--- a/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_delete/test_tutorial001.py
@@ -2,255 +2,6 @@
from sqlmodel import create_engine
from sqlmodel.pool import StaticPool
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/heroes/": {
- "get": {
- "summary": "Read Heroes",
- "operationId": "read_heroes_heroes__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Offset", "type": "integer", "default": 0},
- "name": "offset",
- "in": "query",
- },
- {
- "required": False,
- "schema": {
- "title": "Limit",
- "type": "integer",
- "default": 100,
- "lte": 100,
- },
- "name": "limit",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Heroes Heroes Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/HeroRead"},
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "post": {
- "summary": "Create Hero",
- "operationId": "create_hero_heroes__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroCreate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/heroes/{hero_id}": {
- "get": {
- "summary": "Read Hero",
- "operationId": "read_hero_heroes__hero_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "delete": {
- "summary": "Delete Hero",
- "operationId": "delete_hero_heroes__hero_id__delete",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "patch": {
- "summary": "Update Hero",
- "operationId": "update_hero_heroes__hero_id__patch",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroUpdate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "HeroCreate": {
- "title": "HeroCreate",
- "required": ["name", "secret_name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- },
- },
- "HeroRead": {
- "title": "HeroRead",
- "required": ["name", "secret_name", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "id": {"title": "Id", "type": "integer"},
- },
- },
- "HeroUpdate": {
- "title": "HeroUpdate",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"type": "string"},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
def test_tutorial(clear_sqlmodel):
from docs_src.tutorial.fastapi.delete import tutorial001 as mod
@@ -261,7 +12,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
@@ -285,10 +35,6 @@ def test_tutorial(clear_sqlmodel):
assert response.status_code == 200, response.text
response = client.get("/heroes/9000")
assert response.status_code == 404, response.text
- response = client.get("/openapi.json")
- data = response.json()
- assert response.status_code == 200, response.text
- assert data == openapi_schema
response = client.get("/heroes/")
assert response.status_code == 200, response.text
data = response.json()
@@ -309,3 +55,272 @@ def test_tutorial(clear_sqlmodel):
response = client.delete("/heroes/9000")
assert response.status_code == 404, response.text
+
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/heroes/": {
+ "get": {
+ "summary": "Read Heroes",
+ "operationId": "read_heroes_heroes__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Offset",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "offset",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "maximum": 100.0,
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Heroes Heroes Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/HeroRead"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "post": {
+ "summary": "Create Hero",
+ "operationId": "create_hero_heroes__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroCreate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/heroes/{hero_id}": {
+ "get": {
+ "summary": "Read Hero",
+ "operationId": "read_hero_heroes__hero_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "delete": {
+ "summary": "Delete Hero",
+ "operationId": "delete_hero_heroes__hero_id__delete",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "patch": {
+ "summary": "Update Hero",
+ "operationId": "update_hero_heroes__hero_id__patch",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroUpdate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ "HeroCreate": {
+ "title": "HeroCreate",
+ "required": ["name", "secret_name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ },
+ },
+ "HeroRead": {
+ "title": "HeroRead",
+ "required": ["name", "secret_name", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "id": {"title": "Id", "type": "integer"},
+ },
+ },
+ "HeroUpdate": {
+ "title": "HeroUpdate",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py
index b58afdf683..0aee3ca004 100644
--- a/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_limit_and_offset/test_tutorial001.py
@@ -2,178 +2,6 @@
from sqlmodel import create_engine
from sqlmodel.pool import StaticPool
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/heroes/": {
- "get": {
- "summary": "Read Heroes",
- "operationId": "read_heroes_heroes__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Offset", "type": "integer", "default": 0},
- "name": "offset",
- "in": "query",
- },
- {
- "required": False,
- "schema": {
- "title": "Limit",
- "type": "integer",
- "default": 100,
- "lte": 100,
- },
- "name": "limit",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Heroes Heroes Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/HeroRead"},
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "post": {
- "summary": "Create Hero",
- "operationId": "create_hero_heroes__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroCreate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/heroes/{hero_id}": {
- "get": {
- "summary": "Read Hero",
- "operationId": "read_hero_heroes__hero_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- }
- },
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "HeroCreate": {
- "title": "HeroCreate",
- "required": ["name", "secret_name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- },
- },
- "HeroRead": {
- "title": "HeroRead",
- "required": ["name", "secret_name", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "id": {"title": "Id", "type": "integer"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"type": "string"},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
def test_tutorial(clear_sqlmodel):
from docs_src.tutorial.fastapi.limit_and_offset import tutorial001 as mod
@@ -184,7 +12,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
@@ -208,10 +35,6 @@ def test_tutorial(clear_sqlmodel):
assert response.status_code == 200, response.text
response = client.get("/heroes/9000")
assert response.status_code == 404, response.text
- response = client.get("/openapi.json")
- data = response.json()
- assert response.status_code == 200, response.text
- assert data == openapi_schema
response = client.get("/heroes/")
assert response.status_code == 200, response.text
@@ -237,3 +60,191 @@ def test_tutorial(clear_sqlmodel):
data = response.json()
assert len(data) == 1
assert data[0]["name"] == hero2_data["name"]
+
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/heroes/": {
+ "get": {
+ "summary": "Read Heroes",
+ "operationId": "read_heroes_heroes__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Offset",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "offset",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "maximum": 100.0,
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Heroes Heroes Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/HeroRead"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "post": {
+ "summary": "Create Hero",
+ "operationId": "create_hero_heroes__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroCreate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/heroes/{hero_id}": {
+ "get": {
+ "summary": "Read Hero",
+ "operationId": "read_hero_heroes__hero_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ }
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ "HeroCreate": {
+ "title": "HeroCreate",
+ "required": ["name", "secret_name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ },
+ },
+ "HeroRead": {
+ "title": "HeroRead",
+ "required": ["name", "secret_name", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "id": {"title": "Id", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py
index cf008563f4..8d99cf9f5b 100644
--- a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial001.py
@@ -123,7 +123,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
@@ -173,8 +172,18 @@ def test_tutorial(clear_sqlmodel):
insp: Inspector = inspect(mod.engine)
indexes = insp.get_indexes(str(mod.Hero.__tablename__))
expected_indexes = [
- {"name": "ix_hero_name", "column_names": ["name"], "unique": 0},
- {"name": "ix_hero_age", "column_names": ["age"], "unique": 0},
+ {
+ "name": "ix_hero_name",
+ "dialect_options": {},
+ "column_names": ["name"],
+ "unique": 0,
+ },
+ {
+ "name": "ix_hero_age",
+ "dialect_options": {},
+ "column_names": ["age"],
+ "unique": 0,
+ },
]
for index in expected_indexes:
assert index in indexes, "This expected index should be in the indexes in DB"
diff --git a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py
index 57393a7ddc..94a41b3076 100644
--- a/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py
+++ b/tests/test_tutorial/test_fastapi/test_multiple_models/test_tutorial002.py
@@ -123,7 +123,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
@@ -173,8 +172,18 @@ def test_tutorial(clear_sqlmodel):
insp: Inspector = inspect(mod.engine)
indexes = insp.get_indexes(str(mod.Hero.__tablename__))
expected_indexes = [
- {"name": "ix_hero_age", "column_names": ["age"], "unique": 0},
- {"name": "ix_hero_name", "column_names": ["name"], "unique": 0},
+ {
+ "name": "ix_hero_age",
+ "dialect_options": {},
+ "column_names": ["age"],
+ "unique": 0,
+ },
+ {
+ "name": "ix_hero_name",
+ "dialect_options": {},
+ "column_names": ["name"],
+ "unique": 0,
+ },
]
for index in expected_indexes:
assert index in indexes, "This expected index should be in the indexes in DB"
diff --git a/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py
index 5b3c771bb9..0609ae41ff 100644
--- a/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_read_one/test_tutorial001.py
@@ -155,7 +155,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
diff --git a/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py
index 125e00179c..8869862e95 100644
--- a/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_relationships/test_tutorial001.py
@@ -2,502 +2,6 @@
from sqlmodel import create_engine
from sqlmodel.pool import StaticPool
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/heroes/": {
- "get": {
- "summary": "Read Heroes",
- "operationId": "read_heroes_heroes__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Offset", "type": "integer", "default": 0},
- "name": "offset",
- "in": "query",
- },
- {
- "required": False,
- "schema": {
- "title": "Limit",
- "type": "integer",
- "default": 100,
- "lte": 100,
- },
- "name": "limit",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Heroes Heroes Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/HeroRead"},
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "post": {
- "summary": "Create Hero",
- "operationId": "create_hero_heroes__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroCreate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/heroes/{hero_id}": {
- "get": {
- "summary": "Read Hero",
- "operationId": "read_hero_heroes__hero_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HeroReadWithTeam"
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "delete": {
- "summary": "Delete Hero",
- "operationId": "delete_hero_heroes__hero_id__delete",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "patch": {
- "summary": "Update Hero",
- "operationId": "update_hero_heroes__hero_id__patch",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroUpdate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/teams/": {
- "get": {
- "summary": "Read Teams",
- "operationId": "read_teams_teams__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Offset", "type": "integer", "default": 0},
- "name": "offset",
- "in": "query",
- },
- {
- "required": False,
- "schema": {
- "title": "Limit",
- "type": "integer",
- "default": 100,
- "lte": 100,
- },
- "name": "limit",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Teams Teams Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/TeamRead"},
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "post": {
- "summary": "Create Team",
- "operationId": "create_team_teams__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamCreate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/teams/{team_id}": {
- "get": {
- "summary": "Read Team",
- "operationId": "read_team_teams__team_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Team Id", "type": "integer"},
- "name": "team_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/TeamReadWithHeroes"
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "delete": {
- "summary": "Delete Team",
- "operationId": "delete_team_teams__team_id__delete",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Team Id", "type": "integer"},
- "name": "team_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "patch": {
- "summary": "Update Team",
- "operationId": "update_team_teams__team_id__patch",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Team Id", "type": "integer"},
- "name": "team_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamUpdate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "HeroCreate": {
- "title": "HeroCreate",
- "required": ["name", "secret_name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "team_id": {"title": "Team Id", "type": "integer"},
- },
- },
- "HeroRead": {
- "title": "HeroRead",
- "required": ["name", "secret_name", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "team_id": {"title": "Team Id", "type": "integer"},
- "id": {"title": "Id", "type": "integer"},
- },
- },
- "HeroReadWithTeam": {
- "title": "HeroReadWithTeam",
- "required": ["name", "secret_name", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "team_id": {"title": "Team Id", "type": "integer"},
- "id": {"title": "Id", "type": "integer"},
- "team": {"$ref": "#/components/schemas/TeamRead"},
- },
- },
- "HeroUpdate": {
- "title": "HeroUpdate",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "team_id": {"title": "Team Id", "type": "integer"},
- },
- },
- "TeamCreate": {
- "title": "TeamCreate",
- "required": ["name", "headquarters"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "headquarters": {"title": "Headquarters", "type": "string"},
- },
- },
- "TeamRead": {
- "title": "TeamRead",
- "required": ["name", "headquarters", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "headquarters": {"title": "Headquarters", "type": "string"},
- "id": {"title": "Id", "type": "integer"},
- },
- },
- "TeamReadWithHeroes": {
- "title": "TeamReadWithHeroes",
- "required": ["name", "headquarters", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "headquarters": {"title": "Headquarters", "type": "string"},
- "id": {"title": "Id", "type": "integer"},
- "heroes": {
- "title": "Heroes",
- "type": "array",
- "items": {"$ref": "#/components/schemas/HeroRead"},
- "default": [],
- },
- },
- },
- "TeamUpdate": {
- "title": "TeamUpdate",
- "type": "object",
- "properties": {
- "id": {"title": "Id", "type": "integer"},
- "name": {"title": "Name", "type": "string"},
- "headquarters": {"title": "Headquarters", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"type": "string"},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
def test_tutorial(clear_sqlmodel):
from docs_src.tutorial.fastapi.relationships import tutorial001 as mod
@@ -508,11 +12,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
- response = client.get("/openapi.json")
- data = response.json()
- assert response.status_code == 200, response.text
- assert data == openapi_schema
-
team_preventers = {"name": "Preventers", "headquarters": "Sharp Tower"}
team_z_force = {"name": "Z-Force", "headquarters": "Sister Margaret’s Bar"}
response = client.post("/teams/", json=team_preventers)
@@ -604,3 +103,531 @@ def test_tutorial(clear_sqlmodel):
assert response.status_code == 200, response.text
data = response.json()
assert len(data) == 1
+
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/heroes/": {
+ "get": {
+ "summary": "Read Heroes",
+ "operationId": "read_heroes_heroes__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Offset",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "offset",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "maximum": 100.0,
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Heroes Heroes Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/HeroRead"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "post": {
+ "summary": "Create Hero",
+ "operationId": "create_hero_heroes__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroCreate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/heroes/{hero_id}": {
+ "get": {
+ "summary": "Read Hero",
+ "operationId": "read_hero_heroes__hero_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroReadWithTeam"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "delete": {
+ "summary": "Delete Hero",
+ "operationId": "delete_hero_heroes__hero_id__delete",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "patch": {
+ "summary": "Update Hero",
+ "operationId": "update_hero_heroes__hero_id__patch",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroUpdate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/teams/": {
+ "get": {
+ "summary": "Read Teams",
+ "operationId": "read_teams_teams__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Offset",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "offset",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "maximum": 100.0,
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Teams Teams Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/TeamRead"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "post": {
+ "summary": "Create Team",
+ "operationId": "create_team_teams__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamCreate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/teams/{team_id}": {
+ "get": {
+ "summary": "Read Team",
+ "operationId": "read_team_teams__team_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Team Id", "type": "integer"},
+ "name": "team_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamReadWithHeroes"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "delete": {
+ "summary": "Delete Team",
+ "operationId": "delete_team_teams__team_id__delete",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Team Id", "type": "integer"},
+ "name": "team_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "patch": {
+ "summary": "Update Team",
+ "operationId": "update_team_teams__team_id__patch",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Team Id", "type": "integer"},
+ "name": "team_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamUpdate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ "HeroCreate": {
+ "title": "HeroCreate",
+ "required": ["name", "secret_name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "team_id": {"title": "Team Id", "type": "integer"},
+ },
+ },
+ "HeroRead": {
+ "title": "HeroRead",
+ "required": ["name", "secret_name", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "team_id": {"title": "Team Id", "type": "integer"},
+ "id": {"title": "Id", "type": "integer"},
+ },
+ },
+ "HeroReadWithTeam": {
+ "title": "HeroReadWithTeam",
+ "required": ["name", "secret_name", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "team_id": {"title": "Team Id", "type": "integer"},
+ "id": {"title": "Id", "type": "integer"},
+ "team": {"$ref": "#/components/schemas/TeamRead"},
+ },
+ },
+ "HeroUpdate": {
+ "title": "HeroUpdate",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "team_id": {"title": "Team Id", "type": "integer"},
+ },
+ },
+ "TeamCreate": {
+ "title": "TeamCreate",
+ "required": ["name", "headquarters"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "headquarters": {"title": "Headquarters", "type": "string"},
+ },
+ },
+ "TeamRead": {
+ "title": "TeamRead",
+ "required": ["name", "headquarters", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "headquarters": {"title": "Headquarters", "type": "string"},
+ "id": {"title": "Id", "type": "integer"},
+ },
+ },
+ "TeamReadWithHeroes": {
+ "title": "TeamReadWithHeroes",
+ "required": ["name", "headquarters", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "headquarters": {"title": "Headquarters", "type": "string"},
+ "id": {"title": "Id", "type": "integer"},
+ "heroes": {
+ "title": "Heroes",
+ "type": "array",
+ "items": {"$ref": "#/components/schemas/HeroRead"},
+ "default": [],
+ },
+ },
+ },
+ "TeamUpdate": {
+ "title": "TeamUpdate",
+ "type": "object",
+ "properties": {
+ "id": {"title": "Id", "type": "integer"},
+ "name": {"title": "Name", "type": "string"},
+ "headquarters": {"title": "Headquarters", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py
index 54fbbdccad..ebb3046ef3 100644
--- a/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_response_model/test_tutorial001.py
@@ -111,7 +111,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
response = client.post("/heroes/", json=hero_data)
data = response.json()
diff --git a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py
index d8dbe3f7fb..cb0a6f9282 100644
--- a/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_session_with_dependency/test_tutorial001.py
@@ -2,255 +2,6 @@
from sqlmodel import create_engine
from sqlmodel.pool import StaticPool
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/heroes/": {
- "get": {
- "summary": "Read Heroes",
- "operationId": "read_heroes_heroes__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Offset", "type": "integer", "default": 0},
- "name": "offset",
- "in": "query",
- },
- {
- "required": False,
- "schema": {
- "title": "Limit",
- "type": "integer",
- "default": 100,
- "lte": 100,
- },
- "name": "limit",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Heroes Heroes Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/HeroRead"},
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "post": {
- "summary": "Create Hero",
- "operationId": "create_hero_heroes__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroCreate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/heroes/{hero_id}": {
- "get": {
- "summary": "Read Hero",
- "operationId": "read_hero_heroes__hero_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "delete": {
- "summary": "Delete Hero",
- "operationId": "delete_hero_heroes__hero_id__delete",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "patch": {
- "summary": "Update Hero",
- "operationId": "update_hero_heroes__hero_id__patch",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroUpdate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "HeroCreate": {
- "title": "HeroCreate",
- "required": ["name", "secret_name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- },
- },
- "HeroRead": {
- "title": "HeroRead",
- "required": ["name", "secret_name", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "id": {"title": "Id", "type": "integer"},
- },
- },
- "HeroUpdate": {
- "title": "HeroUpdate",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"type": "string"},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
def test_tutorial(clear_sqlmodel):
from docs_src.tutorial.fastapi.session_with_dependency import tutorial001 as mod
@@ -261,7 +12,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
@@ -285,10 +35,6 @@ def test_tutorial(clear_sqlmodel):
assert response.status_code == 200, response.text
response = client.get("/heroes/9000")
assert response.status_code == 404, response.text
- response = client.get("/openapi.json")
- data = response.json()
- assert response.status_code == 200, response.text
- assert data == openapi_schema
response = client.get("/heroes/")
assert response.status_code == 200, response.text
data = response.json()
@@ -309,3 +55,272 @@ def test_tutorial(clear_sqlmodel):
response = client.delete("/heroes/9000")
assert response.status_code == 404, response.text
+
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/heroes/": {
+ "get": {
+ "summary": "Read Heroes",
+ "operationId": "read_heroes_heroes__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Offset",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "offset",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "maximum": 100.0,
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Heroes Heroes Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/HeroRead"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "post": {
+ "summary": "Create Hero",
+ "operationId": "create_hero_heroes__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroCreate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/heroes/{hero_id}": {
+ "get": {
+ "summary": "Read Hero",
+ "operationId": "read_hero_heroes__hero_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "delete": {
+ "summary": "Delete Hero",
+ "operationId": "delete_hero_heroes__hero_id__delete",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "patch": {
+ "summary": "Update Hero",
+ "operationId": "update_hero_heroes__hero_id__patch",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroUpdate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ "HeroCreate": {
+ "title": "HeroCreate",
+ "required": ["name", "secret_name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ },
+ },
+ "HeroRead": {
+ "title": "HeroRead",
+ "required": ["name", "secret_name", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "id": {"title": "Id", "type": "integer"},
+ },
+ },
+ "HeroUpdate": {
+ "title": "HeroUpdate",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py
index 2f87fafeff..eb834ec2a4 100644
--- a/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_simple_hero_api/test_tutorial001.py
@@ -99,7 +99,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
diff --git a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py
index 6ac1cffc5e..e66c975142 100644
--- a/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_teams/test_tutorial001.py
@@ -2,468 +2,6 @@
from sqlmodel import create_engine
from sqlmodel.pool import StaticPool
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/heroes/": {
- "get": {
- "summary": "Read Heroes",
- "operationId": "read_heroes_heroes__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Offset", "type": "integer", "default": 0},
- "name": "offset",
- "in": "query",
- },
- {
- "required": False,
- "schema": {
- "title": "Limit",
- "type": "integer",
- "default": 100,
- "lte": 100,
- },
- "name": "limit",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Heroes Heroes Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/HeroRead"},
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "post": {
- "summary": "Create Hero",
- "operationId": "create_hero_heroes__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroCreate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/heroes/{hero_id}": {
- "get": {
- "summary": "Read Hero",
- "operationId": "read_hero_heroes__hero_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "delete": {
- "summary": "Delete Hero",
- "operationId": "delete_hero_heroes__hero_id__delete",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "patch": {
- "summary": "Update Hero",
- "operationId": "update_hero_heroes__hero_id__patch",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroUpdate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/teams/": {
- "get": {
- "summary": "Read Teams",
- "operationId": "read_teams_teams__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Offset", "type": "integer", "default": 0},
- "name": "offset",
- "in": "query",
- },
- {
- "required": False,
- "schema": {
- "title": "Limit",
- "type": "integer",
- "default": 100,
- "lte": 100,
- },
- "name": "limit",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Teams Teams Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/TeamRead"},
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "post": {
- "summary": "Create Team",
- "operationId": "create_team_teams__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamCreate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/teams/{team_id}": {
- "get": {
- "summary": "Read Team",
- "operationId": "read_team_teams__team_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Team Id", "type": "integer"},
- "name": "team_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "delete": {
- "summary": "Delete Team",
- "operationId": "delete_team_teams__team_id__delete",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Team Id", "type": "integer"},
- "name": "team_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {"application/json": {"schema": {}}},
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "patch": {
- "summary": "Update Team",
- "operationId": "update_team_teams__team_id__patch",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Team Id", "type": "integer"},
- "name": "team_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamUpdate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/TeamRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "HeroCreate": {
- "title": "HeroCreate",
- "required": ["name", "secret_name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "team_id": {"title": "Team Id", "type": "integer"},
- },
- },
- "HeroRead": {
- "title": "HeroRead",
- "required": ["name", "secret_name", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "team_id": {"title": "Team Id", "type": "integer"},
- "id": {"title": "Id", "type": "integer"},
- },
- },
- "HeroUpdate": {
- "title": "HeroUpdate",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "team_id": {"title": "Team Id", "type": "integer"},
- },
- },
- "TeamCreate": {
- "title": "TeamCreate",
- "required": ["name", "headquarters"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "headquarters": {"title": "Headquarters", "type": "string"},
- },
- },
- "TeamRead": {
- "title": "TeamRead",
- "required": ["name", "headquarters", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "headquarters": {"title": "Headquarters", "type": "string"},
- "id": {"title": "Id", "type": "integer"},
- },
- },
- "TeamUpdate": {
- "title": "TeamUpdate",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "headquarters": {"title": "Headquarters", "type": "string"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"type": "string"},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
def test_tutorial(clear_sqlmodel):
from docs_src.tutorial.fastapi.teams import tutorial001 as mod
@@ -474,7 +12,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
@@ -486,10 +23,6 @@ def test_tutorial(clear_sqlmodel):
"secret_name": "Tommy Sharp",
"age": 48,
}
- response = client.get("/openapi.json")
- data = response.json()
- assert response.status_code == 200, response.text
- assert data == openapi_schema
response = client.post("/heroes/", json=hero1_data)
assert response.status_code == 200, response.text
response = client.post("/heroes/", json=hero2_data)
@@ -557,3 +90,501 @@ def test_tutorial(clear_sqlmodel):
assert response.status_code == 200, response.text
data = response.json()
assert len(data) == 1
+
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/heroes/": {
+ "get": {
+ "summary": "Read Heroes",
+ "operationId": "read_heroes_heroes__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Offset",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "offset",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "maximum": 100.0,
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Heroes Heroes Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/HeroRead"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "post": {
+ "summary": "Create Hero",
+ "operationId": "create_hero_heroes__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroCreate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/heroes/{hero_id}": {
+ "get": {
+ "summary": "Read Hero",
+ "operationId": "read_hero_heroes__hero_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "delete": {
+ "summary": "Delete Hero",
+ "operationId": "delete_hero_heroes__hero_id__delete",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "patch": {
+ "summary": "Update Hero",
+ "operationId": "update_hero_heroes__hero_id__patch",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroUpdate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/teams/": {
+ "get": {
+ "summary": "Read Teams",
+ "operationId": "read_teams_teams__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Offset",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "offset",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "maximum": 100.0,
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Teams Teams Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/TeamRead"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "post": {
+ "summary": "Create Team",
+ "operationId": "create_team_teams__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamCreate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/teams/{team_id}": {
+ "get": {
+ "summary": "Read Team",
+ "operationId": "read_team_teams__team_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Team Id", "type": "integer"},
+ "name": "team_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "delete": {
+ "summary": "Delete Team",
+ "operationId": "delete_team_teams__team_id__delete",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Team Id", "type": "integer"},
+ "name": "team_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {"application/json": {"schema": {}}},
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "patch": {
+ "summary": "Update Team",
+ "operationId": "update_team_teams__team_id__patch",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Team Id", "type": "integer"},
+ "name": "team_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamUpdate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/TeamRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ "HeroCreate": {
+ "title": "HeroCreate",
+ "required": ["name", "secret_name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "team_id": {"title": "Team Id", "type": "integer"},
+ },
+ },
+ "HeroRead": {
+ "title": "HeroRead",
+ "required": ["name", "secret_name", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "team_id": {"title": "Team Id", "type": "integer"},
+ "id": {"title": "Id", "type": "integer"},
+ },
+ },
+ "HeroUpdate": {
+ "title": "HeroUpdate",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "team_id": {"title": "Team Id", "type": "integer"},
+ },
+ },
+ "TeamCreate": {
+ "title": "TeamCreate",
+ "required": ["name", "headquarters"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "headquarters": {"title": "Headquarters", "type": "string"},
+ },
+ },
+ "TeamRead": {
+ "title": "TeamRead",
+ "required": ["name", "headquarters", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "headquarters": {"title": "Headquarters", "type": "string"},
+ "id": {"title": "Id", "type": "integer"},
+ },
+ },
+ "TeamUpdate": {
+ "title": "TeamUpdate",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "headquarters": {"title": "Headquarters", "type": "string"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py
index e622fd37fb..49906256c9 100644
--- a/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py
+++ b/tests/test_tutorial/test_fastapi/test_update/test_tutorial001.py
@@ -2,227 +2,6 @@
from sqlmodel import create_engine
from sqlmodel.pool import StaticPool
-openapi_schema = {
- "openapi": "3.0.2",
- "info": {"title": "FastAPI", "version": "0.1.0"},
- "paths": {
- "/heroes/": {
- "get": {
- "summary": "Read Heroes",
- "operationId": "read_heroes_heroes__get",
- "parameters": [
- {
- "required": False,
- "schema": {"title": "Offset", "type": "integer", "default": 0},
- "name": "offset",
- "in": "query",
- },
- {
- "required": False,
- "schema": {
- "title": "Limit",
- "type": "integer",
- "default": 100,
- "lte": 100,
- },
- "name": "limit",
- "in": "query",
- },
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {
- "title": "Response Read Heroes Heroes Get",
- "type": "array",
- "items": {"$ref": "#/components/schemas/HeroRead"},
- }
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "post": {
- "summary": "Create Hero",
- "operationId": "create_hero_heroes__post",
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroCreate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- "/heroes/{hero_id}": {
- "get": {
- "summary": "Read Hero",
- "operationId": "read_hero_heroes__hero_id__get",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- "patch": {
- "summary": "Update Hero",
- "operationId": "update_hero_heroes__hero_id__patch",
- "parameters": [
- {
- "required": True,
- "schema": {"title": "Hero Id", "type": "integer"},
- "name": "hero_id",
- "in": "path",
- }
- ],
- "requestBody": {
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroUpdate"}
- }
- },
- "required": True,
- },
- "responses": {
- "200": {
- "description": "Successful Response",
- "content": {
- "application/json": {
- "schema": {"$ref": "#/components/schemas/HeroRead"}
- }
- },
- },
- "422": {
- "description": "Validation Error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/HTTPValidationError"
- }
- }
- },
- },
- },
- },
- },
- },
- "components": {
- "schemas": {
- "HTTPValidationError": {
- "title": "HTTPValidationError",
- "type": "object",
- "properties": {
- "detail": {
- "title": "Detail",
- "type": "array",
- "items": {"$ref": "#/components/schemas/ValidationError"},
- }
- },
- },
- "HeroCreate": {
- "title": "HeroCreate",
- "required": ["name", "secret_name"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- },
- },
- "HeroRead": {
- "title": "HeroRead",
- "required": ["name", "secret_name", "id"],
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- "id": {"title": "Id", "type": "integer"},
- },
- },
- "HeroUpdate": {
- "title": "HeroUpdate",
- "type": "object",
- "properties": {
- "name": {"title": "Name", "type": "string"},
- "secret_name": {"title": "Secret Name", "type": "string"},
- "age": {"title": "Age", "type": "integer"},
- },
- },
- "ValidationError": {
- "title": "ValidationError",
- "required": ["loc", "msg", "type"],
- "type": "object",
- "properties": {
- "loc": {
- "title": "Location",
- "type": "array",
- "items": {"type": "string"},
- },
- "msg": {"title": "Message", "type": "string"},
- "type": {"title": "Error Type", "type": "string"},
- },
- },
- }
- },
-}
-
def test_tutorial(clear_sqlmodel):
from docs_src.tutorial.fastapi.update import tutorial001 as mod
@@ -233,7 +12,6 @@ def test_tutorial(clear_sqlmodel):
)
with TestClient(mod.app) as client:
-
hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"}
hero2_data = {
"name": "Spider-Boy",
@@ -259,10 +37,6 @@ def test_tutorial(clear_sqlmodel):
assert response.status_code == 200, response.text
response = client.get("/heroes/9000")
assert response.status_code == 404, response.text
- response = client.get("/openapi.json")
- data = response.json()
- assert response.status_code == 200, response.text
- assert data == openapi_schema
response = client.get("/heroes/")
assert response.status_code == 200, response.text
data = response.json()
@@ -288,3 +62,244 @@ def test_tutorial(clear_sqlmodel):
response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"})
assert response.status_code == 404, response.text
+
+ response = client.get("/openapi.json")
+ assert response.status_code == 200, response.text
+ assert response.json() == {
+ "openapi": "3.0.2",
+ "info": {"title": "FastAPI", "version": "0.1.0"},
+ "paths": {
+ "/heroes/": {
+ "get": {
+ "summary": "Read Heroes",
+ "operationId": "read_heroes_heroes__get",
+ "parameters": [
+ {
+ "required": False,
+ "schema": {
+ "title": "Offset",
+ "type": "integer",
+ "default": 0,
+ },
+ "name": "offset",
+ "in": "query",
+ },
+ {
+ "required": False,
+ "schema": {
+ "title": "Limit",
+ "maximum": 100.0,
+ "type": "integer",
+ "default": 100,
+ },
+ "name": "limit",
+ "in": "query",
+ },
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "title": "Response Read Heroes Heroes Get",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/HeroRead"
+ },
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "post": {
+ "summary": "Create Hero",
+ "operationId": "create_hero_heroes__post",
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroCreate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ "/heroes/{hero_id}": {
+ "get": {
+ "summary": "Read Hero",
+ "operationId": "read_hero_heroes__hero_id__get",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ "patch": {
+ "summary": "Update Hero",
+ "operationId": "update_hero_heroes__hero_id__patch",
+ "parameters": [
+ {
+ "required": True,
+ "schema": {"title": "Hero Id", "type": "integer"},
+ "name": "hero_id",
+ "in": "path",
+ }
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroUpdate"
+ }
+ }
+ },
+ "required": True,
+ },
+ "responses": {
+ "200": {
+ "description": "Successful Response",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HeroRead"
+ }
+ }
+ },
+ },
+ "422": {
+ "description": "Validation Error",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/HTTPValidationError"
+ }
+ }
+ },
+ },
+ },
+ },
+ },
+ },
+ "components": {
+ "schemas": {
+ "HTTPValidationError": {
+ "title": "HTTPValidationError",
+ "type": "object",
+ "properties": {
+ "detail": {
+ "title": "Detail",
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/ValidationError"
+ },
+ }
+ },
+ },
+ "HeroCreate": {
+ "title": "HeroCreate",
+ "required": ["name", "secret_name"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ },
+ },
+ "HeroRead": {
+ "title": "HeroRead",
+ "required": ["name", "secret_name", "id"],
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ "id": {"title": "Id", "type": "integer"},
+ },
+ },
+ "HeroUpdate": {
+ "title": "HeroUpdate",
+ "type": "object",
+ "properties": {
+ "name": {"title": "Name", "type": "string"},
+ "secret_name": {"title": "Secret Name", "type": "string"},
+ "age": {"title": "Age", "type": "integer"},
+ },
+ },
+ "ValidationError": {
+ "title": "ValidationError",
+ "required": ["loc", "msg", "type"],
+ "type": "object",
+ "properties": {
+ "loc": {
+ "title": "Location",
+ "type": "array",
+ "items": {"type": "string"},
+ },
+ "msg": {"title": "Message", "type": "string"},
+ "type": {"title": "Error Type", "type": "string"},
+ },
+ },
+ }
+ },
+ }
diff --git a/tests/test_tutorial/test_indexes/test_tutorial001.py b/tests/test_tutorial/test_indexes/test_tutorial001.py
index 596207737d..f33db5bcc7 100644
--- a/tests/test_tutorial/test_indexes/test_tutorial001.py
+++ b/tests/test_tutorial/test_indexes/test_tutorial001.py
@@ -25,8 +25,18 @@ def test_tutorial(clear_sqlmodel):
insp: Inspector = inspect(mod.engine)
indexes = insp.get_indexes(str(mod.Hero.__tablename__))
expected_indexes = [
- {"name": "ix_hero_name", "column_names": ["name"], "unique": 0},
- {"name": "ix_hero_age", "column_names": ["age"], "unique": 0},
+ {
+ "name": "ix_hero_name",
+ "dialect_options": {},
+ "column_names": ["name"],
+ "unique": 0,
+ },
+ {
+ "name": "ix_hero_age",
+ "dialect_options": {},
+ "column_names": ["age"],
+ "unique": 0,
+ },
]
for index in expected_indexes:
assert index in indexes, "This expected index should be in the indexes in DB"
diff --git a/tests/test_tutorial/test_indexes/test_tutorial006.py b/tests/test_tutorial/test_indexes/test_tutorial006.py
index e26f8b2ed8..893043dad1 100644
--- a/tests/test_tutorial/test_indexes/test_tutorial006.py
+++ b/tests/test_tutorial/test_indexes/test_tutorial006.py
@@ -26,8 +26,18 @@ def test_tutorial(clear_sqlmodel):
insp: Inspector = inspect(mod.engine)
indexes = insp.get_indexes(str(mod.Hero.__tablename__))
expected_indexes = [
- {"name": "ix_hero_name", "column_names": ["name"], "unique": 0},
- {"name": "ix_hero_age", "column_names": ["age"], "unique": 0},
+ {
+ "name": "ix_hero_name",
+ "dialect_options": {},
+ "column_names": ["name"],
+ "unique": 0,
+ },
+ {
+ "name": "ix_hero_age",
+ "dialect_options": {},
+ "column_names": ["age"],
+ "unique": 0,
+ },
]
for index in expected_indexes:
assert index in indexes, "This expected index should be in the indexes in DB"
diff --git a/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py b/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py
index 448b191249..eb15a1560e 100644
--- a/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py
+++ b/tests/test_tutorial/test_limit_and_offset/test_tutorial004.py
@@ -4,16 +4,6 @@
from ...conftest import get_testing_print_function
-expected_calls = [
- [
- [
- {"id": 5, "name": "Black Lion", "secret_name": "Trevor Challa", "age": 35},
- {"id": 6, "name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36},
- {"id": 3, "name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48},
- ]
- ]
-]
-
def test_tutorial(clear_sqlmodel):
from docs_src.tutorial.offset_and_limit import tutorial004 as mod
@@ -26,4 +16,11 @@ def test_tutorial(clear_sqlmodel):
with patch("builtins.print", new=new_print):
mod.main()
- assert calls == expected_calls
+ assert calls == [
+ [
+ [
+ {"name": "Dr. Weird", "secret_name": "Steve Weird", "age": 36, "id": 6},
+ {"name": "Rusty-Man", "secret_name": "Tommy Sharp", "age": 48, "id": 3},
+ ]
+ ]
+ ]
diff --git a/tests/test_validation.py b/tests/test_validation.py
index a3ff6e39ba..ad60fcb945 100644
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -7,7 +7,7 @@
def test_validation(clear_sqlmodel):
- """Test validation of implicit and explict None values.
+ """Test validation of implicit and explicit None values.
# For consistency with pydantic, validators are not to be called on
# arguments that are not explicitly provided.