Skip to content

Commit

Permalink
pytest-asyncio 0.24 event loop scope
Browse files Browse the repository at this point in the history
  • Loading branch information
commonism committed Oct 3, 2024
1 parent a2eaba6 commit 44451e0
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 104 deletions.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ filterwarnings = [
"ignore:unclosed <ssl.SSLSocket:ResourceWarning",
"ignore:unclosed <socket.socket fd=:ResourceWarning",
"ignore:Ignoring Schema with additionalProperties and named properties:UserWarning",
"ignore:'flask.Markup' is deprecated and will be removed in Flask 2.4. Import 'markupsafe.Markup' instead.:DeprecationWarning"
"ignore:'flask.Markup' is deprecated and will be removed in Flask 2.4. Import 'markupsafe.Markup' instead.:DeprecationWarning",
"ignore:unclosed resource <TCPTransport:ResourceWarning"
]
asyncio_mode = "strict"

Expand Down
33 changes: 18 additions & 15 deletions tests/apiv1_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,25 @@ def config(unused_tcp_port_factory):
return c


@pytest_asyncio.fixture(scope="session")
async def server(event_loop, config):
policy = asyncio.get_event_loop_policy()
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
@pytest_asyncio.fixture(loop_scope="session")
async def server(config):
event_loop = asyncio.get_running_loop()
try:
sd = asyncio.Event()
task = event_loop.create_task(serve(app, config, shutdown_trigger=sd.wait))
yield config
finally:
sd.set()
await task
asyncio.set_event_loop_policy(policy)


@pytest_asyncio.fixture(scope="session")
async def client(event_loop, server):
@pytest.fixture(scope="session")
def event_loop_policy():
return uvloop.EventLoopPolicy()


@pytest_asyncio.fixture(loop_scope="session")
async def client(server):
api = await asyncio.to_thread(aiopenapi3.OpenAPI.load_sync, f"http://{server.bind[0]}/v1/openapi.json")
return api

Expand All @@ -47,9 +50,9 @@ def randomPet(name=None):
return {"data": {"pet": {"name": str(name or uuid.uuid4()), "pet_type": "dog"}}, "return_headers": True}


@pytest.mark.asyncio
@pytest.mark.asyncio(loop_scope="session")
@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires asyncio.to_thread")
async def test_createPet(event_loop, server, client):
async def test_createPet(server, client):
h, r = await asyncio.to_thread(client._.createPet, **randomPet())
assert type(r).model_json_schema() == client.components.schemas["Pet"].get_type().model_json_schema()
assert h["X-Limit-Remain"] == 5
Expand All @@ -58,17 +61,17 @@ async def test_createPet(event_loop, server, client):
assert type(r).model_json_schema() == client.components.schemas["Error"].get_type().model_json_schema()


@pytest.mark.asyncio
@pytest.mark.asyncio(loop_scope="session")
@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires asyncio.to_thread")
async def test_listPet(event_loop, server, client):
async def test_listPet(server, client):
h, r = await asyncio.to_thread(client._.createPet, **randomPet(uuid.uuid4()))
l = await asyncio.to_thread(client._.listPet)
assert len(l) > 0


@pytest.mark.asyncio
@pytest.mark.asyncio(loop_scope="session")
@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires asyncio.to_thread")
async def test_getPet(event_loop, server, client):
async def test_getPet(server, client):
h, pet = await asyncio.to_thread(client._.createPet, **randomPet(uuid.uuid4()))
r = await asyncio.to_thread(client._.getPet, parameters={"petId": pet.id})
# FastAPI 0.101 Serialization changes
Expand All @@ -79,9 +82,9 @@ async def test_getPet(event_loop, server, client):
assert type(r).model_json_schema() == client.components.schemas["Error"].get_type().model_json_schema()


@pytest.mark.asyncio
@pytest.mark.asyncio(loop_scope="session")
@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires asyncio.to_thread")
async def test_deletePet(event_loop, server, client):
async def test_deletePet(server, client):
r = await asyncio.to_thread(client._.deletePet, parameters={"petId": -1})
print(r)
assert type(r).model_json_schema() == client.components.schemas["Error"].get_type().model_json_schema()
Expand Down
54 changes: 29 additions & 25 deletions tests/apiv2_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,21 @@ def config(unused_tcp_port_factory):
return c


@pytest_asyncio.fixture(scope="session")
async def server(event_loop, config):
policy = asyncio.get_event_loop_policy()
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
@pytest.fixture(scope="session")
def event_loop_policy():
return uvloop.EventLoopPolicy()


@pytest_asyncio.fixture(loop_scope="session")
async def server(config):
event_loop = asyncio.get_running_loop()
try:
sd = asyncio.Event()
task = event_loop.create_task(serve(app, config, shutdown_trigger=sd.wait))
yield config
finally:
sd.set()
await task
asyncio.set_event_loop_policy(policy)


@pytest.fixture(scope="session", params=[2])
Expand All @@ -63,14 +66,15 @@ def version(request):
from aiopenapi3.debug import DescriptionDocumentDumper


@pytest_asyncio.fixture(scope="session")
async def client(event_loop, server, version):
@pytest_asyncio.fixture(loop_scope="session")
async def client(server, version):
url = f"http://{server.bind[0]}/{version}/openapi.json"

api = await aiopenapi3.OpenAPI.load_async(url, plugins=[DescriptionDocumentDumper("/tmp/schema.yaml")])
return api


@pytest.mark.asyncio(loop_scope="session")
@pytest.mark.xfail()
def test_Pet():
import json
Expand All @@ -84,24 +88,24 @@ def test_Pet():
assert t.model_json_schema() == data


@pytest.mark.asyncio
@pytest.mark.asyncio(loop_scope="session")
@pytest.mark.skipif(sys.version_info < (3, 9), reason="requires asyncio.to_thread")
async def test_sync(event_loop, server, version):
async def test_sync(server, version):
url = f"http://{server.bind[0]}/{version}/openapi.json"
api = await asyncio.to_thread(aiopenapi3.OpenAPI.load_sync, url)
return api


@pytest.mark.asyncio
async def test_description_document(event_loop, server, version):
@pytest.mark.asyncio(loop_scope="session")
async def test_description_document(server, version):
url = f"http://{server.bind[0]}/{version}/openapi.json"
api = await aiopenapi3.OpenAPI.load_async(url)
return api


@pytest.mark.xfail()
@pytest.mark.asyncio
async def test_model(event_loop, server, client):
@pytest.mark.asyncio(loop_scope="session")
async def test_model(server, client):
orig = client.components.schemas["WhiteCat"].model_dump(exclude_unset=True)
crea = client.components.schemas["WhiteCat"].get_type().model_json_schema()
assert orig == crea
Expand Down Expand Up @@ -150,16 +154,16 @@ def randomPet(client, name=None, cat=False):
}


@pytest.mark.asyncio
async def test_Request(event_loop, server, client):
@pytest.mark.asyncio(loop_scope="session")
async def test_Request(server, client):
client._.createPet.data
client._.createPet.parameters
client._.createPet.args()
client._.createPet.return_value()


@pytest.mark.asyncio
async def test_createPet(event_loop, server, client):
@pytest.mark.asyncio(loop_scope="session")
async def test_createPet(server, client):
data = {
"pet": client.components.schemas["WhiteCat"]
.model(
Expand Down Expand Up @@ -188,8 +192,8 @@ async def test_createPet(event_loop, server, client):
cls()


@pytest.mark.asyncio
async def test_listPet(event_loop, server, client):
@pytest.mark.asyncio(loop_scope="session")
async def test_listPet(server, client):
r = await client._.createPet(data=randomPet(client, str(uuid.uuid4())))
l = await client._.listPet(parameters={"limit": 1})
assert len(l) > 0
Expand All @@ -198,8 +202,8 @@ async def test_listPet(event_loop, server, client):
assert isinstance(l, client.components.schemas["HTTPValidationError"].get_type())


@pytest.mark.asyncio
async def test_getPet(event_loop, server, client):
@pytest.mark.asyncio(loop_scope="session")
async def test_getPet(server, client):
pet = await client._.createPet(data=randomPet(client, str(uuid.uuid4())))
r = await client._.getPet(parameters={"petId": pet.identifier})

Expand All @@ -211,8 +215,8 @@ async def test_getPet(event_loop, server, client):
assert type(r).model_json_schema() == client.components.schemas["Error"].get_type().model_json_schema()


@pytest.mark.asyncio
async def test_deletePet(event_loop, server, client):
@pytest.mark.asyncio(loop_scope="session")
async def test_deletePet(server, client):
r = await client._.deletePet(parameters={"petId": uuid.uuid4(), "x-raise-nonexist": False})
assert type(r).model_json_schema() == client.components.schemas["Error"].get_type().model_json_schema()

Expand All @@ -224,8 +228,8 @@ async def test_deletePet(event_loop, server, client):
await client._.deletePet(parameters={"petId": pet.identifier, "x-raise-nonexist": None})


@pytest.mark.asyncio
async def test_patchPet(event_loop, server, client):
@pytest.mark.asyncio(loop_scope="session")
async def test_patchPet(server, client):
Pet = client.components.schemas["Pet-Input"].get_type()
Dog = typing.get_args(typing.get_args(Pet.model_fields["root"].annotation)[0])[1]
pets = [
Expand Down
8 changes: 0 additions & 8 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import asyncio
import os
import dataclasses

Expand All @@ -13,13 +12,6 @@
URLBASE = "/"


@pytest.fixture(scope="session")
def event_loop(request):
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
loop.close()


@pytest.fixture(autouse=True)
def skip_env(request):
if request.node.get_closest_marker("skip_env"):
Expand Down
47 changes: 23 additions & 24 deletions tests/forms_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,9 @@ def config(unused_tcp_port_factory):
return c


@pytest_asyncio.fixture(scope="session")
async def server(event_loop, config, app):
policy = asyncio.get_event_loop_policy()
@pytest_asyncio.fixture(loop_scope="session")
async def server(config, app):
event_loop = asyncio.get_event_loop()
try:
sd = asyncio.Event()
asgi = WsgiToAsgi(app)
Expand All @@ -281,15 +281,14 @@ async def server(event_loop, config, app):
sd.set()
del asgi
await task
asyncio.set_event_loop_policy(policy)


@pytest.fixture(scope="session", params=["application/x-www-form-urlencoded", "multipart/form-data"])
def form_type(request):
return f"{request.param}"


@pytest_asyncio.fixture(scope="session")
@pytest_asyncio.fixture(loop_scope="session")
async def client(server, form_type, with_paths_requestbody_formdata_wtforms):
data = copy.deepcopy(with_paths_requestbody_formdata_wtforms)
if form_type != "multipart/form-data":
Expand All @@ -303,22 +302,22 @@ async def client(server, form_type, with_paths_requestbody_formdata_wtforms):


@pytest.mark.asyncio
async def _test_service(event_loop, server, client):
async def _test_service(server, client):
while True:
await asyncio.sleep(1)


@pytest.mark.asyncio
async def test_Test(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_Test(server, client, form_type):
cls = client._.test.operation.requestBody.content[form_type].schema_.get_type()
data = cls(string="yes", number="5", file="test")

r = await client._.test(data=data, parameters={"Accept": form_type})
assert r == "ok"


@pytest.mark.asyncio
async def test_String(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_String(server, client, form_type):
cls = client._.string.operation.requestBody.content[form_type].schema_.get_type()
data = cls(
string="yes",
Expand All @@ -334,8 +333,8 @@ async def test_String(event_loop, server, client, form_type):
assert r == "ok"


@pytest.mark.asyncio
async def test_DateTime(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_DateTime(server, client, form_type):
cls = client._.datetime.operation.requestBody.content[form_type].schema_.get_type()
now = datetime.datetime.now()

Expand All @@ -347,8 +346,8 @@ async def test_DateTime(event_loop, server, client, form_type):
assert r == "ok"


@pytest.mark.asyncio
async def test_Numbers(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_Numbers(server, client, form_type):
cls = client._.numbers.operation.requestBody.content[form_type].schema_.get_type()

data = cls(
Expand All @@ -364,8 +363,8 @@ async def test_Numbers(event_loop, server, client, form_type):
assert r == "ok"


@pytest.mark.asyncio
async def test_File(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_File(server, client, form_type):
cls = client._.file.operation.requestBody.content[form_type].schema_.get_type()

data = cls(file=b"4711", files=[b"a", b"b"], xml=b"yes")
Expand All @@ -374,8 +373,8 @@ async def test_File(event_loop, server, client, form_type):
assert r == "ok"


@pytest.mark.asyncio
async def test_Select(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_Select(server, client, form_type):
cls = client._.select.operation.requestBody.content[form_type].schema_.get_type()

data = cls(radio="py", select="rb", selectmultiple=["c", "cpp"])
Expand All @@ -384,8 +383,8 @@ async def test_Select(event_loop, server, client, form_type):
assert r == "ok"


@pytest.mark.asyncio
async def test_Control(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_Control(server, client, form_type):
cls = client._.control.operation.requestBody.content[form_type].schema_.get_type()

data = cls(submit="yes", search="no")
Expand All @@ -394,8 +393,8 @@ async def test_Control(event_loop, server, client, form_type):
assert r == "ok"


@pytest.mark.asyncio
async def test_Header(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_Header(server, client, form_type):
if form_type != "multipart/form-data":
pytest.skip()

Expand All @@ -409,8 +408,8 @@ async def test_Header(event_loop, server, client, form_type):
assert r == "ok"


@pytest.mark.asyncio
async def test_Graph(event_loop, server, client, form_type):
@pytest.mark.asyncio(loop_scope="session")
async def test_Graph(server, client, form_type):
if form_type != "multipart/form-data":
pytest.skip()

Expand Down
Loading

0 comments on commit 44451e0

Please sign in to comment.