Skip to content

Commit adfb650

Browse files
committed
drop support for py3.5 and aiohttp2.x
Currently supported versions of Python: 3.6, 3.7, 3.8
1 parent d201b4d commit adfb650

File tree

8 files changed

+110
-79
lines changed

8 files changed

+110
-79
lines changed

.travis.yml

-31
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,6 @@ language: python
55

66
matrix:
77
include:
8-
- python: 3.5
9-
env: TOXENV=py35-aiohttp20
10-
- python: 3.5
11-
env: TOXENV=py35-aiohttp21
12-
- python: 3.5
13-
env: TOXENV=py35-aiohttp22
14-
- python: 3.5
15-
env: TOXENV=py35-aiohttp23
16-
- python: 3.5
17-
env: TOXENV=py35-aiohttp30
18-
- python: 3.5
19-
env: TOXENV=py35-aiohttp31
20-
- python: 3.5
21-
env: TOXENV=py35-aiohttp32
22-
- python: 3.5
23-
env: TOXENV=py35-aiohttp33
24-
- python: 3.5
25-
env: TOXENV=py35-aiohttp34
26-
- python: 3.5
27-
env: TOXENV=py35-aiohttp35
28-
- python: 3.5
29-
env: TOXENV=py35-aiohttp36
30-
31-
- python: 3.6
32-
env: TOXENV=py36-aiohttp20
33-
- python: 3.6
34-
env: TOXENV=py36-aiohttp21
35-
- python: 3.6
36-
env: TOXENV=py36-aiohttp22
37-
- python: 3.6
38-
env: TOXENV=py36-aiohttp23
398
- python: 3.6
409
env: TOXENV=py36-aiohttp30
4110
- python: 3.6

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ clean-pyc: ## remove Python file artifacts
4444

4545
clean-test: ## remove test and coverage artifacts
4646
rm -fr .tox/
47+
rm -fr .pytest_cache/
4748
rm -f .coverage
4849
rm -fr htmlcov/
4950

aioresponses/compat.py

+60-2
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,40 @@
99
from multidict import MultiDict
1010
from yarl import URL
1111

12+
try:
13+
# as from Py3.8 unittest supports coroutines as test functions
14+
from unittest import IsolatedAsyncioTestCase, skipIf
15+
16+
17+
def fail_on(**kw): # noqa
18+
def outer(fn):
19+
def inner(*args, **kwargs):
20+
return fn(*args, **kwargs)
21+
22+
return inner
23+
24+
return outer
25+
26+
27+
except ImportError:
28+
# fallback to asynctest
29+
from asynctest import fail_on, skipIf
30+
from asynctest.case import TestCase as IsolatedAsyncioTestCase
31+
1232
if sys.version_info < (3, 7):
1333
from re import _pattern_type as Pattern
1434
else:
1535
from re import Pattern
1636

1737
AIOHTTP_VERSION = StrictVersion(aiohttp_version)
38+
IS_GTE_PY38 = sys.version_info >= (3, 8)
1839

1940
if AIOHTTP_VERSION >= StrictVersion('3.0.0'):
2041
from aiohttp.client_proto import ResponseHandler
2142

22-
def stream_reader_factory(
23-
loop: 'Optional[asyncio.AbstractEventLoop]' = None
43+
44+
def stream_reader_factory( # noqa
45+
loop: 'Optional[asyncio.AbstractEventLoop]' = None
2446
):
2547
protocol = ResponseHandler(loop=loop)
2648
return StreamReader(protocol, loop=loop)
@@ -46,11 +68,47 @@ def normalize_url(url: 'Union[URL, str]') -> 'URL':
4668
return url.with_query(urlencode(sorted(parse_qsl(url.query_string))))
4769

4870

71+
class AsyncTestCase(IsolatedAsyncioTestCase):
72+
"""Asynchronous test case class that covers up differences in usage
73+
between unittest (starting from Python 3.8) and asynctest.
74+
75+
`setup` and `teardown` is used to be called before each test case
76+
(note: that they are in lowercase)
77+
"""
78+
79+
async def setup(self):
80+
pass
81+
82+
async def teardown(self):
83+
pass
84+
85+
if IS_GTE_PY38:
86+
# from Python3.8
87+
async def asyncSetUp(self):
88+
self.loop = asyncio.get_event_loop()
89+
await self.setup()
90+
91+
async def asyncTearDown(self):
92+
await self.teardown()
93+
else:
94+
# asynctest
95+
use_default_loop = False
96+
97+
async def setUp(self) -> None:
98+
await self.setup()
99+
100+
async def tearDown(self) -> None:
101+
await self.teardown()
102+
103+
49104
__all__ = [
50105
'URL',
51106
'Pattern',
107+
'skipIf',
52108
'AIOHTTP_VERSION',
109+
'AsyncTestCase',
53110
'merge_params',
54111
'stream_reader_factory',
55112
'normalize_url',
113+
'fail_on',
56114
]

aioresponses/core.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# -*- coding: utf-8 -*-
22
import asyncio
3-
import json
43
import copy
4+
import inspect
5+
import json
56
from collections import namedtuple
67
from distutils.version import StrictVersion
78
from functools import wraps
89
from typing import Callable, Dict, Tuple, Union, Optional, List # noqa
910
from unittest.mock import Mock, patch
10-
import inspect
11+
1112
from aiohttp import (
1213
ClientConnectionError,
1314
ClientResponse,
@@ -174,7 +175,7 @@ def _build_response(self, url: 'Union[URL, str]',
174175
return resp
175176

176177
async def build_response(
177-
self, url: URL, **kwargs
178+
self, url: URL, **kwargs
178179
) -> 'Union[ClientResponse, Exception]':
179180
if self.exception is not None:
180181
return self.exception
@@ -324,8 +325,8 @@ def is_exception(resp_or_exc: Union[ClientResponse, Exception]) -> bool:
324325
return False
325326

326327
async def match(
327-
self, method: str, url: URL,
328-
allow_redirects: bool = True, **kwargs: Dict
328+
self, method: str, url: URL,
329+
allow_redirects: bool = True, **kwargs: Dict
329330
) -> Optional['ClientResponse']:
330331
history = []
331332
while True:
@@ -343,9 +344,8 @@ async def match(
343344

344345
if self.is_exception(response_or_exc):
345346
raise response_or_exc
346-
347-
if response_or_exc.status in (
348-
301, 302, 303, 307, 308) and allow_redirects:
347+
is_redirect = response_or_exc.status in (301, 302, 303, 307, 308)
348+
if is_redirect and allow_redirects:
349349
if hdrs.LOCATION not in response_or_exc.headers:
350350
break
351351
history.append(response_or_exc)

requirements-dev.txt

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
pip
22
wheel
3-
flake8==3.5.0
4-
tox==3.4.0
5-
coverage==4.5.1
3+
flake8==3.8.3
4+
tox==3.19.0
5+
coverage==5.2.1
66
Sphinx==1.5.6
7-
pytest==3.8.1
8-
pytest-cov==2.6.0
9-
pytest-html==1.19.0
10-
ddt==1.2.0
7+
pytest==6.0.1
8+
pytest-cov==2.10.1
9+
pytest-html==2.1.1
10+
ddt==1.4.1
1111
typing
12+
asynctest==0.13.0

setup.cfg

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@ summary = Mock out requests made by ClientSession from aiohttp package
66
description-file = README.rst
77
home-page = https://github.com/pnuckowski/aioresponses
88
classifier =
9-
Development Status :: 3 - Alpha
9+
Development Status :: 4 - Beta
1010
Intended Audience :: Developers
11+
Operating System :: OS Independent
1112
Topic :: Internet :: WWW/HTTP
1213
Topic :: Software Development :: Testing
14+
Topic :: Software Development :: Testing :: Mocking
1315
License :: OSI Approved :: MIT License
1416
Natural Language :: English
1517
Programming Language :: Python :: 3
16-
Programming Language :: Python :: 3.5
1718
Programming Language :: Python :: 3.6
1819
Programming Language :: Python :: 3.7
20+
Programming Language :: Python :: 3.8
1921

2022
[files]
2123
packages =

tests/test_aioresponses.py

+28-24
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# -*- coding: utf-8 -*-
22
import asyncio
33
import re
4+
from asyncio import CancelledError, TimeoutError
45
from typing import Coroutine, Generator, Union
5-
from unittest import IsolatedAsyncioTestCase, skipIf
66
from unittest.mock import patch
77

88
from aiohttp import hdrs
99
from aiohttp import http
1010
from aiohttp.client import ClientSession
1111
from aiohttp.client_reqrep import ClientResponse
1212
from ddt import ddt, data
13-
from asyncio import CancelledError, TimeoutError
13+
1414
try:
1515
from aiohttp.errors import (
1616
ClientConnectionError,
@@ -24,30 +24,33 @@
2424
)
2525
from aiohttp.http_exceptions import HttpProcessingError
2626

27-
from aioresponses.compat import AIOHTTP_VERSION, URL
27+
from aioresponses.compat import (
28+
AIOHTTP_VERSION, URL,
29+
fail_on,
30+
skipIf,
31+
AsyncTestCase
32+
)
33+
2834
from aioresponses import CallbackResult, aioresponses
2935

3036

3137
@ddt
32-
class AIOResponsesTestCase(IsolatedAsyncioTestCase):
38+
class AIOResponsesTestCase(AsyncTestCase):
3339

34-
async def asyncSetUp(self):
40+
async def setup(self):
3541
self.url = 'http://example.com/api?foo=bar#fragment'
3642
self.session = ClientSession()
37-
self.loop = asyncio.get_event_loop()
38-
super().setUp()
3943

40-
async def asyncTearDown(self):
44+
async def teardown(self):
4145
close_result = self.session.close()
4246
if close_result is not None:
4347
await close_result
44-
super().tearDown()
4548

4649
def run_async(self, coroutine: Union[Coroutine, Generator]):
4750
return self.loop.run_until_complete(coroutine)
4851

4952
async def request(self, url: str):
50-
return (await self.session.get(url))
53+
return await self.session.get(url)
5154

5255
@data(
5356
hdrs.METH_HEAD,
@@ -59,6 +62,7 @@ async def request(self, url: str):
5962
hdrs.METH_OPTIONS,
6063
)
6164
@patch('aioresponses.aioresponses.add')
65+
@fail_on(unused_loop=False)
6266
def test_shortcut_method(self, http_method, mocked):
6367
with aioresponses() as m:
6468
getattr(m, http_method.lower())(self.url)
@@ -194,6 +198,7 @@ async def foo(mocked):
194198

195199
await foo()
196200

201+
@fail_on(unused_loop=False)
197202
def test_mocking_as_decorator_wrong_mocked_arg_name(self):
198203
@aioresponses(param='foo')
199204
def foo(bar):
@@ -310,7 +315,8 @@ def non_deep_copyable():
310315
request = m.requests[key][0]
311316
self.assertEqual(request.args, tuple())
312317
self.assertEqual(request.kwargs,
313-
{'allow_redirects': True, "data": generator_value})
318+
{'allow_redirects': True,
319+
"data": generator_value})
314320

315321
async def test_request_retrieval_in_case_no_response(self):
316322
with aioresponses() as m:
@@ -359,7 +365,9 @@ async def test_pass_through_with_origin_params(self):
359365
async def doit(params):
360366
# we have to hit actual url,
361367
# otherwise we do not test pass through option properly
362-
ext_rep = (await self.session.get(URL(external_api), params=params))
368+
ext_rep = await self.session.get(
369+
URL(external_api), params=params
370+
)
363371
return ext_rep
364372

365373
with aioresponses(passthrough=[external_api]) as m:
@@ -475,7 +483,7 @@ async def test_exception_requests_are_tracked(self, mocked):
475483
self.assertEqual(request.kwargs, kwargs)
476484

477485

478-
class AIOResponsesRaiseForStatusSessionTestCase(IsolatedAsyncioTestCase):
486+
class AIOResponsesRaiseForStatusSessionTestCase(AsyncTestCase):
479487
"""Test case for sessions with raise_for_status=True.
480488
481489
This flag, introduced in aiohttp v2.0.0, automatically calls
@@ -485,17 +493,14 @@ class AIOResponsesRaiseForStatusSessionTestCase(IsolatedAsyncioTestCase):
485493
486494
"""
487495

488-
489-
async def asyncSetUp(self):
496+
async def setup(self):
490497
self.url = 'http://example.com/api?foo=bar#fragment'
491498
self.session = ClientSession(raise_for_status=True)
492-
super().setUp()
493499

494-
async def asyncTearDown(self):
500+
async def teardown(self):
495501
close_result = self.session.close()
496502
if close_result is not None:
497503
await close_result
498-
super().tearDown()
499504

500505
@aioresponses()
501506
async def test_raise_for_status(self, m):
@@ -511,22 +516,21 @@ async def test_raise_for_status(self, m):
511516
async def test_do_not_raise_for_status(self, m):
512517
m.get(self.url, status=400)
513518
response = await self.session.get(self.url,
514-
raise_for_status=False)
519+
raise_for_status=False)
515520

516521
self.assertEqual(response.status, 400)
517522

518523

519-
class AIOResponseRedirectTest(IsolatedAsyncioTestCase):
520-
async def asyncSetUp(self):
524+
class AIOResponseRedirectTest(AsyncTestCase):
525+
526+
async def setup(self):
521527
self.url = "http://10.1.1.1:8080/redirect"
522528
self.session = ClientSession()
523-
super().setUp()
524529

525-
async def asyncTearDown(self):
530+
async def teardown(self):
526531
close_result = self.session.close()
527532
if close_result is not None:
528533
await close_result
529-
super().tearDown()
530534

531535
@aioresponses()
532536
async def test_redirect_followed(self, rsps):

tox.ini

+1-5
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@
22
envlist =
33
flake8,
44
coverage,
5-
py35-aiohttp{20,21,22,23,30,31,32,33,34,35,36}
6-
py36-aiohttp-master
7-
py36-aiohttp{20,21,22,23,30,31,32,33,34,35,36}
8-
py37-aiohttp-master
5+
py36-aiohttp{30,31,32,33,34,35,36}
96
py37-aiohttp{30,31,32,33,34,35,36}
10-
py38-aiohttp-master
117
py38-aiohttp{30,31,32,33,34,35,36}
128
skipsdist = True
139

0 commit comments

Comments
 (0)