]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
⬆ Add support for Python 3.9 (#2298)
authorMarcelo Trylesinski <marcelotryle@gmail.com>
Mon, 2 Aug 2021 14:02:34 +0000 (16:02 +0200)
committerGitHub <noreply@github.com>
Mon, 2 Aug 2021 14:02:34 +0000 (16:02 +0200)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
.github/workflows/test.yml
pyproject.toml
tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py
tests/test_typing_python39.py [new file with mode: 0644]
tests/test_union_inherited_body.py
tests/utils.py

index f346cab6be363a1e43ce7dfeb5434ad72d8212c2..1867cbb00bcbb5365cd674731690b5992cb0e02c 100644 (file)
@@ -10,9 +10,9 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: [3.6, 3.7, 3.8]
+        python-version: [3.6, 3.7, 3.8, 3.9]
       fail-fast: false
-    
+
     steps:
       - uses: actions/checkout@v2
       - name: Set up Python
index 45880cc313785d4c486f11571d3b2aa521be7a9d..d7014e8beadae62f799d1351fd634957f62cc5d2 100644 (file)
@@ -28,6 +28,7 @@ classifiers = [
     "Programming Language :: Python :: 3.6",
     "Programming Language :: Python :: 3.7",
     "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
     "Topic :: Internet :: WWW/HTTP :: HTTP Servers",
     "Topic :: Internet :: WWW/HTTP",
 ]
index 08cfa5ca9278cbed57256ad401ce28f5e1a79eeb..2ebc31b95319723941910bdbeadcf40d9184f3d9 100644 (file)
@@ -5,7 +5,7 @@ from unittest.mock import MagicMock
 import pytest
 from fastapi.testclient import TestClient
 
-from ...utils import skip_py36
+from ...utils import needs_py37
 
 openapi_schema = {
     "openapi": "3.0.2",
@@ -340,14 +340,14 @@ def client():
     test_db.unlink()
 
 
-@skip_py36
+@needs_py37
 def test_openapi_schema(client):
     response = client.get("/openapi.json")
     assert response.status_code == 200, response.text
     assert response.json() == openapi_schema
 
 
-@skip_py36
+@needs_py37
 def test_create_user(client):
     test_user = {"email": "johndoe@example.com", "password": "secret"}
     response = client.post("/users/", json=test_user)
@@ -359,7 +359,7 @@ def test_create_user(client):
     assert response.status_code == 400, response.text
 
 
-@skip_py36
+@needs_py37
 def test_get_user(client):
     response = client.get("/users/1")
     assert response.status_code == 200, response.text
@@ -368,13 +368,13 @@ def test_get_user(client):
     assert "id" in data
 
 
-@skip_py36
+@needs_py37
 def test_inexistent_user(client):
     response = client.get("/users/999")
     assert response.status_code == 404, response.text
 
 
-@skip_py36
+@needs_py37
 def test_get_users(client):
     response = client.get("/users/")
     assert response.status_code == 200, response.text
@@ -386,7 +386,7 @@ def test_get_users(client):
 time.sleep = MagicMock()
 
 
-@skip_py36
+@needs_py37
 def test_get_slowusers(client):
     response = client.get("/slowusers/")
     assert response.status_code == 200, response.text
@@ -395,7 +395,7 @@ def test_get_slowusers(client):
     assert "id" in data[0]
 
 
-@skip_py36
+@needs_py37
 def test_create_item(client):
     item = {"title": "Foo", "description": "Something that fights"}
     response = client.post("/users/1/items/", json=item)
@@ -419,7 +419,7 @@ def test_create_item(client):
     assert item_to_check["description"] == item["description"]
 
 
-@skip_py36
+@needs_py37
 def test_read_items(client):
     response = client.get("/items/")
     assert response.status_code == 200, response.text
diff --git a/tests/test_typing_python39.py b/tests/test_typing_python39.py
new file mode 100644 (file)
index 0000000..b1ea635
--- /dev/null
@@ -0,0 +1,24 @@
+from fastapi import FastAPI
+from fastapi.testclient import TestClient
+
+from .utils import needs_py39
+
+
+@needs_py39
+def test_typing():
+    types = {
+        list[int]: [1, 2, 3],
+        dict[str, list[int]]: {"a": [1, 2, 3], "b": [4, 5, 6]},
+        set[int]: [1, 2, 3],  # `set` is converted to `list`
+        tuple[int, ...]: [1, 2, 3],  # `tuple` is converted to `list`
+    }
+    for test_type, expect in types.items():
+        app = FastAPI()
+
+        @app.post("/", response_model=test_type)
+        def post_endpoint(input: test_type):
+            return input
+
+        res = TestClient(app).post("/", json=expect)
+        assert res.status_code == 200, res.json()
+        assert res.json() == expect
index a1a3f0ed5b5b749a518d323d221aa5cc21a25591..e3d0acc99d49c86a50c972007623e9fec72f3385 100644 (file)
@@ -4,7 +4,7 @@ from fastapi import FastAPI
 from fastapi.testclient import TestClient
 from pydantic import BaseModel
 
-from .utils import skip_py36
+from .utils import needs_py37
 
 # In Python 3.6:
 # u = Union[ExtendedItem, Item] == __main__.Item
@@ -118,21 +118,21 @@ inherited_item_openapi_schema = {
 }
 
 
-@skip_py36
+@needs_py37
 def test_inherited_item_openapi_schema():
     response = client.get("/openapi.json")
     assert response.status_code == 200, response.text
     assert response.json() == inherited_item_openapi_schema
 
 
-@skip_py36
+@needs_py37
 def test_post_extended_item():
     response = client.post("/items/", json={"name": "Foo", "age": 5})
     assert response.status_code == 200, response.text
     assert response.json() == {"item": {"name": "Foo", "age": 5}}
 
 
-@skip_py36
+@needs_py37
 def test_post_item():
     response = client.post("/items/", json={"name": "Foo"})
     assert response.status_code == 200, response.text
index 2c6c2067d8152e358b744873c5027994f193967c..92d1c48e873e24d848ee98c1a5de70ed3d097d8c 100644 (file)
@@ -2,4 +2,5 @@ import sys
 
 import pytest
 
-skip_py36 = pytest.mark.skipif(sys.version_info < (3, 7), reason="skip python3.6")
+needs_py37 = pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7+")
+needs_py39 = pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python3.9+")