Skip to content

Commit

Permalink
test(fix): Fix all async tests warnings
Browse files Browse the repository at this point in the history
Also, `get_resume` did not need the `session`, so remove that argument
  • Loading branch information
alexpovel committed Oct 27, 2024
1 parent 99d6a18 commit cb5b24e
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 25 deletions.
5 changes: 1 addition & 4 deletions ancv/web/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from http import HTTPStatus
from types import SimpleNamespace

import aiohttp
import gidgethub
from gidgethub.aiohttp import GitHubAPI
from humanize import naturalsize
Expand All @@ -20,7 +19,6 @@

async def get_resume(
user: str,
session: aiohttp.ClientSession,
github: GitHubAPI,
stopwatch: Stopwatch,
filename: str = "resume.json",
Expand All @@ -46,7 +44,6 @@ async def get_resume(
Args:
user: The GitHub username to fetch the resume from.
session: The `aiohttp.ClientSession` to use for the request.
github: The API object to use for the request.
stopwatch: The `Stopwatch` to use for timing.
filename: The name of the file to look for in the user's gists.
Expand All @@ -56,7 +53,7 @@ async def get_resume(
The parsed resume.
"""

log = LOGGER.bind(user=user, session=session)
log = LOGGER.bind(user=user)

stopwatch("Fetching Gists")
gists = github.getiter(f"/users/{user}/gists")
Expand Down
5 changes: 1 addition & 4 deletions ancv/web/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,16 +185,13 @@ async def username(self, request: web.Request) -> web.Response:
# Implicit 'downcasting' from `Any` doesn't require an explicit `cast` call, just
# regular type hints:
# https://adamj.eu/tech/2021/07/06/python-type-hints-how-to-use-typing-cast/
session: ClientSession = request.app["client_session"]
github: GitHubAPI = request.app["github"]

log = log.bind(user=user)

stopwatch.stop()
try:
resume = await get_resume(
user=user, session=session, github=github, stopwatch=stopwatch
)
resume = await get_resume(user=user, github=github, stopwatch=stopwatch)
except ResumeLookupError as e:
stopwatch.stop()
log.warning(str(e))
Expand Down
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ dev-dependencies = [
"pydeps>=2.0.1",
"pytest-aiohttp>=1.0.5",
"pytest-cov>=5.0.0",
"pytest-asyncio>=0.24.0",
"pytest-rerunfailures>=14.0",
"pytest>=8.3.3",
"requests>=2.32.3",
Expand All @@ -82,6 +83,10 @@ fail_under = 80.0
[tool.datamodel-codegen]
target-python-version = "3.12"

[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"

[tool.mypy]
mypy_path = "stubs/"
show_error_codes = true
Expand Down
28 changes: 18 additions & 10 deletions tests/web/test_client.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
from contextlib import nullcontext as does_not_raise
from typing import ContextManager

Expand All @@ -19,14 +20,22 @@ def stopwatch():


@pytest.fixture(scope="function")
async def client_session():
async def client_session() -> aiohttp.ClientSession:
assert (
asyncio.get_running_loop()
), "`aiohttp.ClientSession` constructor will need loop running."

# The constructor accesses the async event loop, and if none is running errors. So
# this pytest fixture function needs to be marked `async` for `pytest-asyncio` with
# the `asyncio_mode = "auto"` option set to pick it up automatically and *provide* a
# loop.
return aiohttp.ClientSession()


@pytest.fixture(scope="function")
async def gh_api(client_session):
def gh_api(client_session: aiohttp.ClientSession):
return GitHubAPI(
await client_session,
client_session,
requester=f"{METADATA.name}-PYTEST-REQUESTER",
oauth_token=GH_TOKEN,
)
Expand Down Expand Up @@ -67,23 +76,22 @@ async def gh_api(client_session):
),
],
)
@pytest.mark.asyncio
@gh_rate_limited
async def test_get_resume_validations(
username: str,
client_session: aiohttp.ClientSession,
gh_api: GitHubAPI,
stopwatch: Stopwatch,
size_limit: int,
filename: str,
expectation: ContextManager,
# Fixtures:
gh_api: GitHubAPI,
stopwatch: Stopwatch,
) -> None:
api = await gh_api
assert asyncio.get_running_loop()

with expectation:
await get_resume(
user=username,
session=client_session,
github=api,
github=gh_api,
stopwatch=stopwatch,
filename=filename,
size_limit=size_limit,
Expand Down
18 changes: 11 additions & 7 deletions tests/web/test_server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
from contextlib import nullcontext as does_not_raise
from datetime import timedelta
from http import HTTPStatus
Expand Down Expand Up @@ -59,7 +60,6 @@ def test_is_terminal_client(user_agent: str, expected: bool) -> None:

@pytest.mark.filterwarnings("ignore:Request.message is deprecated") # No idea...
@pytest.mark.filterwarnings("ignore:Exception ignored in") # No idea...
@pytest.mark.asyncio
class TestApiHandler:
@pytest.mark.parametrize(
["user_agent", "expected_http_code"],
Expand All @@ -80,8 +80,9 @@ async def test_root_endpoint(
expected_http_code: HTTPStatus,
aiohttp_client: Any,
api_client_app: Application,
event_loop: Any,
) -> None:
assert asyncio.get_running_loop()

client = await aiohttp_client(api_client_app)

resp: ClientResponse = await client.get(
Expand Down Expand Up @@ -139,8 +140,9 @@ async def test_username_endpoint(
expected_error_message: Optional[str],
aiohttp_client: Any,
api_client_app: Application,
event_loop: Any,
) -> None:
assert asyncio.get_running_loop()

client = await aiohttp_client(api_client_app)

resp = await client.get(f"/{username}")
Expand All @@ -153,8 +155,9 @@ async def test_showcase_endpoint(
self,
aiohttp_client: Any,
api_client_app: Application,
event_loop: Any,
) -> None:
assert asyncio.get_running_loop()

client = await aiohttp_client(api_client_app)

resp: ClientResponse = await client.get(f"/{_SHOWCASE_USERNAME}")
Expand All @@ -174,8 +177,9 @@ async def test_return_content(
expected_contained_text: str,
aiohttp_client: Any,
api_client_app: Application,
event_loop: Any,
) -> None:
assert asyncio.get_running_loop()

client = await aiohttp_client(api_client_app)

resp = await client.get(f"/{username}")
Expand All @@ -186,7 +190,6 @@ async def test_return_content(

@pytest.mark.filterwarnings("ignore:Request.message is deprecated") # No idea...
@pytest.mark.filterwarnings("ignore:Exception ignored in") # No idea...
@pytest.mark.asyncio
class TestFileHandler:
@pytest.mark.parametrize(
["expected_http_code", "expected_str_content"],
Expand All @@ -202,8 +205,9 @@ async def test_root_endpoint(
expected_str_content: str,
aiohttp_client: Any,
file_handler_app: Application,
event_loop: Any,
) -> None:
assert asyncio.get_running_loop()

client = await aiohttp_client(file_handler_app)

resp: ClientResponse = await client.get("/")
Expand Down
2 changes: 2 additions & 0 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit cb5b24e

Please sign in to comment.