Skip to content

Commit 531a146

Browse files
committed
feat: apply changes related to tests from Top-gg-Community#87
1 parent aa5907b commit 531a146

File tree

9 files changed

+279
-350
lines changed

9 files changed

+279
-350
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
- uses: actions/checkout@v5
1010
- uses: actions/setup-python@v6
1111
with:
12-
python-version: 3.13
12+
python-version: 3.14
1313
- name: Install dependencies
1414
run: python3 -m pip install build twine
1515
- name: Build and publish

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
python-version: [ 3.9, '3.10', 3.11, 3.12, 3.13 ]
12+
python-version: [ '3.10', 3.11, 3.12, 3.13, 3.14 ]
1313
steps:
1414
- uses: actions/checkout@v5
1515
- name: Set up Python ${{ matrix.python-version }}
1616
uses: actions/setup-python@v6
1717
with:
1818
python-version: ${{ matrix.python-version }}
1919
- name: Install
20-
run: python -m pip install .[dev]
20+
run: python -m pip install . pytest mock pytest-mock pytest-asyncio
2121
- name: Test with pytest
2222
run: pytest

MANIFEST.in

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
prune .github
2-
prune .pytest_cache
32
prune .ruff_cache
4-
prune build
53
prune docs
64
prune examples
7-
prune scripts
85
prune tests
9-
10-
exclude .coverage
116
exclude .gitignore
127
exclude .readthedocs.yml
13-
exclude ISSUE_TEMPLATE.md
14-
exclude mypy.ini
15-
exclude PULL_REQUEST_TEMPLATE.md
16-
exclude pytest.ini
178
exclude ruff.toml
18-
exclude LICENSE
9+
exclude LICENSE
10+
exclude ISSUE_TEMPLATE.md
11+
exclude PULL_REQUEST_TEMPLATE.md

tests/test_autopost.py

Lines changed: 92 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,92 @@
1-
import datetime
2-
3-
import mock
4-
import pytest
5-
from aiohttp import ClientSession
6-
from pytest_mock import MockerFixture
7-
8-
from topgg import DBLClient
9-
from topgg.autopost import AutoPoster
10-
from topgg.errors import HTTPException, TopGGException
11-
12-
13-
MOCK_TOKEN = ".eyJfdCI6IiIsImlkIjoiMzY0ODA2MDI5ODc2NTU1Nzc2In0=."
14-
15-
16-
@pytest.fixture
17-
def session() -> ClientSession:
18-
return mock.Mock(ClientSession)
19-
20-
21-
@pytest.fixture
22-
def autopost(session: ClientSession) -> AutoPoster:
23-
return AutoPoster(DBLClient(MOCK_TOKEN, session=session))
24-
25-
26-
@pytest.mark.asyncio
27-
async def test_AutoPoster_breaks_autopost_loop_on_401(
28-
mocker: MockerFixture, session: ClientSession
29-
) -> None:
30-
response = mock.Mock("reason, status")
31-
response.reason = "Unauthorized"
32-
response.status = 401
33-
34-
mocker.patch(
35-
"topgg.DBLClient.post_guild_count", side_effect=HTTPException(response, {})
36-
)
37-
38-
callback = mock.Mock()
39-
autopost = DBLClient(MOCK_TOKEN, session=session).autopost().stats(callback)
40-
assert isinstance(autopost, AutoPoster)
41-
assert not isinstance(autopost.stats()(callback), AutoPoster)
42-
43-
with pytest.raises(HTTPException):
44-
await autopost.start()
45-
46-
callback.assert_called_once()
47-
assert not autopost.is_running
48-
49-
50-
@pytest.mark.asyncio
51-
async def test_AutoPoster_raises_missing_stats(autopost: AutoPoster) -> None:
52-
with pytest.raises(
53-
TopGGException, match="you must provide a callback that returns the stats."
54-
):
55-
await autopost.start()
56-
57-
58-
@pytest.mark.asyncio
59-
async def test_AutoPoster_raises_already_running(autopost: AutoPoster) -> None:
60-
autopost.stats(mock.Mock()).start()
61-
with pytest.raises(TopGGException, match="the autopost is already running."):
62-
await autopost.start()
63-
64-
65-
@pytest.mark.asyncio
66-
async def test_AutoPoster_interval_too_short(autopost: AutoPoster) -> None:
67-
with pytest.raises(ValueError, match="interval must be greated than 900 seconds."):
68-
autopost.set_interval(50)
69-
70-
71-
@pytest.mark.asyncio
72-
async def test_AutoPoster_error_callback(
73-
mocker: MockerFixture, autopost: AutoPoster
74-
) -> None:
75-
error_callback = mock.Mock()
76-
response = mock.Mock("reason, status")
77-
response.reason = "Internal Server Error"
78-
response.status = 500
79-
side_effect = HTTPException(response, {})
80-
81-
mocker.patch("topgg.DBLClient.post_guild_count", side_effect=side_effect)
82-
task = autopost.on_error(error_callback).stats(mock.Mock()).start()
83-
autopost.stop()
84-
await task
85-
error_callback.assert_called_once_with(side_effect)
86-
87-
88-
def test_AutoPoster_interval(autopost: AutoPoster):
89-
assert autopost.interval == 900
90-
autopost.set_interval(datetime.timedelta(hours=1))
91-
assert autopost.interval == 3600
92-
autopost.interval = datetime.timedelta(hours=2)
93-
assert autopost.interval == 7200
94-
autopost.interval = 3600
95-
assert autopost.interval == 3600
1+
import datetime
2+
3+
import mock
4+
import pytest
5+
from aiohttp import ClientSession
6+
from pytest_mock import MockerFixture
7+
8+
from topgg import DBLClient
9+
from topgg.autopost import AutoPoster
10+
from topgg.errors import HTTPException, TopGGException
11+
12+
13+
MOCK_TOKEN = ".eyJfdCI6IiIsImlkIjoiMzY0ODA2MDI5ODc2NTU1Nzc2In0=."
14+
15+
16+
@pytest.fixture
17+
def session() -> ClientSession:
18+
return mock.Mock(ClientSession)
19+
20+
21+
@pytest.fixture
22+
def autopost(session: ClientSession) -> AutoPoster:
23+
return AutoPoster(DBLClient(MOCK_TOKEN, session=session))
24+
25+
26+
@pytest.mark.asyncio
27+
async def test_AutoPoster_breaks_autopost_loop_on_401(
28+
mocker: MockerFixture, session: ClientSession
29+
) -> None:
30+
mocker.patch(
31+
"topgg.DBLClient.post_guild_count",
32+
side_effect=HTTPException("Unauthorized", 401),
33+
)
34+
35+
callback = mock.Mock()
36+
autopost = DBLClient(MOCK_TOKEN, session=session).autopost().stats(callback)
37+
38+
assert isinstance(autopost, AutoPoster)
39+
assert not isinstance(autopost.stats()(callback), AutoPoster)
40+
41+
autopost._interval = 1
42+
43+
with pytest.raises(HTTPException):
44+
await autopost.start()
45+
46+
callback.assert_called_once()
47+
assert not autopost.is_running
48+
49+
50+
@pytest.mark.asyncio
51+
async def test_AutoPoster_raises_missing_stats(autopost: AutoPoster) -> None:
52+
with pytest.raises(
53+
TopGGException, match="You must provide a callback that returns the stats."
54+
):
55+
await autopost.start()
56+
57+
58+
@pytest.mark.asyncio
59+
async def test_AutoPoster_raises_already_running(autopost: AutoPoster) -> None:
60+
autopost.stats(mock.Mock()).start()
61+
with pytest.raises(TopGGException, match="The autoposter is already running."):
62+
await autopost.start()
63+
64+
65+
@pytest.mark.asyncio
66+
async def test_AutoPoster_interval_too_short(autopost: AutoPoster) -> None:
67+
with pytest.raises(ValueError, match="interval must be greater than 900 seconds."):
68+
autopost.set_interval(50)
69+
70+
71+
@pytest.mark.asyncio
72+
async def test_AutoPoster_error_callback(
73+
mocker: MockerFixture, autopost: AutoPoster
74+
) -> None:
75+
error_callback = mock.Mock()
76+
side_effect = HTTPException("Internal Server Error", 500)
77+
78+
mocker.patch("topgg.DBLClient.post_guild_count", side_effect=side_effect)
79+
task = autopost.on_error(error_callback).stats(mock.Mock()).start()
80+
autopost.stop()
81+
await task
82+
error_callback.assert_called_once_with(side_effect)
83+
84+
85+
def test_AutoPoster_interval(autopost: AutoPoster):
86+
assert autopost.interval == 900
87+
autopost.set_interval(datetime.timedelta(hours=1))
88+
assert autopost.interval == 3600
89+
autopost.interval = datetime.timedelta(hours=2)
90+
assert autopost.interval == 7200
91+
autopost.interval = 3600
92+
assert autopost.interval == 3600

tests/test_client.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,65 @@
11
import mock
22
import pytest
3+
from aiohttp import ClientSession
34

45
import topgg
56

67

78
MOCK_TOKEN = ".eyJfdCI6IiIsImlkIjoiMzY0ODA2MDI5ODc2NTU1Nzc2In0=."
89

910

11+
@pytest.fixture
12+
def session() -> ClientSession:
13+
return mock.Mock(ClientSession)
14+
15+
16+
@pytest.fixture
17+
def client(session: ClientSession) -> topgg.DBLClient:
18+
return topgg.DBLClient(MOCK_TOKEN, session=session)
19+
20+
1021
@pytest.mark.asyncio
11-
async def test_DBLClient_post_guild_count_with_no_args():
12-
client = topgg.DBLClient(MOCK_TOKEN)
13-
with pytest.raises(TypeError, match="stats or guild_count must be provided."):
22+
async def test_DBLClient_post_guild_count_with_no_args(client: topgg.DBLClient):
23+
with pytest.raises(ValueError, match="Got an invalid server count. Got None."):
1424
await client.post_guild_count()
1525

1626

1727
@pytest.mark.asyncio
18-
async def test_DBLClient_get_weekend_status(monkeypatch):
19-
client = topgg.DBLClient(MOCK_TOKEN)
28+
async def test_DBLClient_get_weekend_status(monkeypatch, client: topgg.DBLClient):
2029
monkeypatch.setattr("topgg.DBLClient._DBLClient__request", mock.AsyncMock())
2130
await client.get_weekend_status()
2231
client._DBLClient__request.assert_called_once()
2332

2433

2534
@pytest.mark.asyncio
26-
async def test_DBLClient_post_guild_count(monkeypatch):
27-
client = topgg.DBLClient(MOCK_TOKEN)
35+
async def test_DBLClient_post_guild_count(monkeypatch, client: topgg.DBLClient):
2836
monkeypatch.setattr("topgg.DBLClient._DBLClient__request", mock.AsyncMock())
2937
await client.post_guild_count(guild_count=123)
3038
client._DBLClient__request.assert_called_once()
3139

3240

3341
@pytest.mark.asyncio
34-
async def test_DBLClient_get_guild_count(monkeypatch):
35-
client = topgg.DBLClient(MOCK_TOKEN)
36-
monkeypatch.setattr("topgg.DBLClient._DBLClient__request", mock.AsyncMock(return_value={}))
42+
async def test_DBLClient_get_guild_count(monkeypatch, client: topgg.DBLClient):
43+
monkeypatch.setattr(
44+
"topgg.DBLClient._DBLClient__request", mock.AsyncMock(return_value={})
45+
)
3746
await client.get_guild_count()
3847
client._DBLClient__request.assert_called_once()
3948

4049

4150
@pytest.mark.asyncio
42-
async def test_DBLClient_get_bot_votes(monkeypatch):
43-
client = topgg.DBLClient(MOCK_TOKEN)
44-
monkeypatch.setattr("topgg.DBLClient._DBLClient__request", mock.AsyncMock(return_value=[]))
51+
async def test_DBLClient_get_bot_votes(monkeypatch, client: topgg.DBLClient):
52+
monkeypatch.setattr(
53+
"topgg.DBLClient._DBLClient__request", mock.AsyncMock(return_value=[])
54+
)
4555
await client.get_bot_votes()
4656
client._DBLClient__request.assert_called_once()
4757

4858

4959
@pytest.mark.asyncio
50-
async def test_DBLClient_get_user_vote(monkeypatch):
51-
client = topgg.DBLClient(MOCK_TOKEN)
52-
monkeypatch.setattr("topgg.DBLClient._DBLClient__request", mock.AsyncMock(return_value={"voted": 1}))
60+
async def test_DBLClient_get_user_vote(monkeypatch, client: topgg.DBLClient):
61+
monkeypatch.setattr(
62+
"topgg.DBLClient._DBLClient__request", mock.AsyncMock(return_value={"voted": 1})
63+
)
5364
await client.get_user_vote(1234)
5465
client._DBLClient__request.assert_called_once()

tests/test_data_container.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,15 @@ def data_container() -> DataContainerMixin:
1515

1616
async def _async_callback(
1717
text: str = data(str), number: int = data(int), mapping: dict = data(dict)
18-
):
19-
...
18+
): ...
2019

2120

2221
def _sync_callback(
2322
text: str = data(str), number: int = data(int), mapping: dict = data(dict)
24-
):
25-
...
23+
): ...
2624

2725

28-
def _invalid_callback(number: float = data(float)):
29-
...
26+
def _invalid_callback(number: float = data(float)): ...
3027

3128

3229
@pytest.mark.asyncio

tests/test_ratelimiter.py

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
import pytest
2-
3-
from topgg.ratelimiter import Ratelimiter
4-
5-
n = period = 10
6-
7-
8-
@pytest.fixture
9-
def limiter() -> Ratelimiter:
10-
return Ratelimiter(max_calls=n, period=period)
11-
12-
13-
@pytest.mark.asyncio
14-
async def test_AsyncRateLimiter_calls(limiter: Ratelimiter) -> None:
15-
for _ in range(n):
16-
async with limiter:
17-
pass
18-
19-
assert len(limiter._Ratelimiter__calls) == limiter._Ratelimiter__max_calls == n
20-
21-
22-
@pytest.mark.asyncio
23-
async def test_AsyncRateLimiter_timespan_property(limiter: Ratelimiter) -> None:
24-
for _ in range(n):
25-
async with limiter:
26-
pass
27-
28-
assert limiter._timespan < period
1+
import pytest
2+
3+
from topgg.ratelimiter import Ratelimiter
4+
5+
n = period = 10
6+
7+
8+
@pytest.fixture
9+
def limiter() -> Ratelimiter:
10+
return Ratelimiter(max_calls=n, period=period)
11+
12+
13+
@pytest.mark.asyncio
14+
async def test_AsyncRateLimiter_calls(limiter: Ratelimiter) -> None:
15+
for _ in range(n):
16+
async with limiter:
17+
pass
18+
19+
assert len(limiter._Ratelimiter__calls) == limiter._Ratelimiter__max_calls == n
20+
21+
22+
@pytest.mark.asyncio
23+
async def test_AsyncRateLimiter_timespan_property(limiter: Ratelimiter) -> None:
24+
for _ in range(n):
25+
async with limiter:
26+
pass
27+
28+
assert limiter._timespan < period

0 commit comments

Comments
 (0)