Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to Python >= 3.5 and fix latest aiohttp compatability #83

Merged
merged 4 commits into from
Jan 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
language: python

python:
- 2.7
- 3.4
- 3.5
- 3.6
- 3.7
- 3.8
- 3.9
- 3.10
- pypy
- pypy3

allow_failures:
- python: 2.7
- python: 3.4
- python: pypy

install:
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Features
- Supports third-party mocking engines, such as `mocket`_.
- Fits good for painless test doubles.
- Does not support WebSocket traffic mocking.
- Works with Python +2.7 and +3.0 (including PyPy).
- Works with +3.5 (including PyPy).
- Dependency-less: just 2 small dependencies for JSONSchema and XML tree comparison.


Expand Down
23 changes: 5 additions & 18 deletions pook/assertion.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import re
import sys
from unittest import TestCase
from .regex import isregex, strip_regex, isregex_expr

# If running Python 3
PY_3 = sys.version_info >= (3,)


def test_case():
"""
Expand Down Expand Up @@ -33,8 +28,7 @@ def equal(x, y):
Returns:
bool
"""
if PY_3:
return test_case().assertEqual(x, y) or True
return test_case().assertEqual(x, y) or True

assert x == y

Expand All @@ -59,17 +53,10 @@ def matches(x, y, regex_expr=False):
x = strip_regex(x) if regex_expr and isregex_expr(x) else x

# Run regex assertion
if PY_3:
# Retrieve original regex pattern
x = x.pattern if isregex(x) else x
# Assert regular expression via unittest matchers
return test_case().assertRegex(y, x) or True

# Primitive regex matching for Python 2.7
if isinstance(x, str):
x = re.compile(x, re.IGNORECASE)

assert x.match(y) is not None
# Retrieve original regex pattern
x = x.pattern if isregex(x) else x
# Assert regular expression via unittest matchers
return test_case().assertRegex(y, x) or True


def test(x, y, regex_expr=False):
Expand Down
28 changes: 0 additions & 28 deletions pook/headers.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import sys
try:
from collections.abc import Mapping, MutableMapping
except ImportError:
from collections import Mapping, MutableMapping

PY3 = sys.version_info >= (3, 0)


class HTTPHeaderDict(MutableMapping):
"""
Expand Down Expand Up @@ -75,10 +72,6 @@ def __eq__(self, other):
def __ne__(self, other):
return not self.__eq__(other)

if not PY3: # Python 2
iterkeys = MutableMapping.iterkeys
itervalues = MutableMapping.itervalues

__marker = object()

def __len__(self):
Expand Down Expand Up @@ -245,24 +238,3 @@ def items(self):

def to_dict(self):
return {key: values for key, values in self.items()}

@classmethod
def from_httplib(cls, message): # Python 2
"""
Read headers from a Python 2 httplib message object.
"""
# python2.7 does not expose a proper API for exporting multiheaders
# efficiently. This function re-reads raw lines from the message
# object and extracts the multiheaders properly.
headers = []

for line in message.headers:
if line.startswith((' ', '\t')):
key, value = headers[-1]
headers[-1] = (key, value + '\r\n' + line.rstrip())
continue

key, value = line.split(':', 1)
headers.append((key, value.strip()))

return cls(headers)
15 changes: 6 additions & 9 deletions pook/interceptors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import sys
from .urllib3 import Urllib3Interceptor
from .http import HTTPClientInterceptor
from .base import BaseInterceptor
Expand All @@ -18,14 +17,12 @@
HTTPClientInterceptor
]

# Import aiohttp in modern Python runtimes
if sys.version_info >= (3, 5, 0):
try:
import aiohttp # noqa
from .aiohttp import AIOHTTPInterceptor
interceptors.append(AIOHTTPInterceptor)
except ImportError:
pass
try:
import aiohttp # noqa
from .aiohttp import AIOHTTPInterceptor
interceptors.append(AIOHTTPInterceptor)
except ImportError:
pass


def add(*custom_interceptors):
Expand Down
54 changes: 18 additions & 36 deletions pook/interceptors/aiohttp.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,14 @@
import sys
from ..request import Request
from .base import BaseInterceptor

# Support Python 2/3
try:
import mock
except Exception:
from unittest import mock

if sys.version_info < (3,): # Python 2
from urlparse import urlunparse, urlencode
from httplib import responses as http_reasons
else: # Python 3
from urllib.parse import urlunparse, urlencode
from http.client import responses as http_reasons

if sys.version_info >= (3, 5, 0): # Python 3.5+
import asyncio
from aiohttp.helpers import TimerNoop
from aiohttp.streams import EmptyStreamReader
else:
asyncio = None
TimerNoop = None
EmptyStreamReader = None
from unittest import mock

from urllib.parse import urlunparse, urlencode
from http.client import responses as http_reasons

import asyncio
from aiohttp.helpers import TimerNoop
from aiohttp.streams import EmptyStreamReader

# Try to load yarl URL parser package used by aiohttp
try:
Expand All @@ -44,8 +30,7 @@ def __init__(self, content, *args, **kwargs):
super().__init__(*args, **kwargs)
self.content = content

@asyncio.coroutine
def read(self, n=-1):
async def read(self, n=-1):
return self.content


Expand Down Expand Up @@ -76,9 +61,8 @@ class AIOHTTPInterceptor(BaseInterceptor):
def _url(self, url):
return yarl.URL(url) if yarl else None

@asyncio.coroutine
def _on_request(self, _request, session, method, url,
data=None, headers=None, **kw):
async def _on_request(self, _request, session, method, url,
data=None, headers=None, **kw):
# Create request contract based on incoming params
req = Request(method)
req.headers = headers or {}
Expand All @@ -102,12 +86,12 @@ def _on_request(self, _request, session, method, url,
# or silent model are enabled, otherwise this statement won't
# be reached (an exception will be raised before).
if not mock:
return _request(session, method, url,
data=data, headers=headers, **kw)
return await _request(session, method, url,
data=data, headers=headers, **kw)

# Simulate network delay
if mock._delay:
yield from asyncio.sleep(mock._delay / 1000) # noqa
await asyncio.sleep(mock._delay / 1000) # noqa

# Shortcut to mock response
res = mock._response
Expand Down Expand Up @@ -145,16 +129,14 @@ def _on_request(self, _request, session, method, url,
return _res

def _patch(self, path):
# If not modern Python, just ignore patch
if not asyncio:
# If not able to import aiohttp dependencies, skip
if not yarl or not multidict:
return None

@asyncio.coroutine
def handler(session, method, url, data=None, headers=None, **kw):
return (yield from self._on_request(
async def handler(session, method, url, data=None, headers=None, **kw):
return await self._on_request(
_request, session, method, url,
data=data, headers=headers, **kw)
)

try:
# Create a new patcher for Urllib3 urlopen function
Expand Down
12 changes: 2 additions & 10 deletions pook/interceptors/http.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import sys
import socket
from ..request import Request
from .base import BaseInterceptor

# Support Python 2/3
try:
import mock
except Exception:
from unittest import mock
from unittest import mock

if sys.version_info < (3,): # Python 2
from httplib import responses as http_reasons, _CS_REQ_SENT
else: # Python 3
from http.client import responses as http_reasons, _CS_REQ_SENT
from http.client import responses as http_reasons, _CS_REQ_SENT

PATCHES = (
'http.client.HTTPConnection.request',
Expand Down
23 changes: 6 additions & 17 deletions pook/interceptors/urllib3.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
import io
import sys
from ..request import Request
from .base import BaseInterceptor
from .http import URLLIB3_BYPASS

# Support Python 2/3
try:
import mock
except Exception:
from unittest import mock

if sys.version_info < (3,): # Python 2
from httplib import (
responses as http_reasons,
HTTPResponse as ClientHTTPResponse,
)
else: # Python 3
from http.client import (
responses as http_reasons,
HTTPResponse as ClientHTTPResponse,
)
from unittest import mock

from http.client import (
responses as http_reasons,
HTTPResponse as ClientHTTPResponse,
)

PATCHES = (
'requests.packages.urllib3.connectionpool.HTTPConnectionPool.urlopen',
Expand Down
6 changes: 1 addition & 5 deletions pook/matchers/query.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import sys
from .base import BaseMatcher

if sys.version_info < (3,): # Python 2
from urlparse import parse_qs
else: # Python 3
from urllib.parse import parse_qs
from urllib.parse import parse_qs


class QueryMatcher(BaseMatcher):
Expand Down
6 changes: 1 addition & 5 deletions pook/matchers/url.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import re
import sys
from .base import BaseMatcher
from .path import PathMatcher
from .query import QueryMatcher
from ..regex import isregex

if sys.version_info < (3,): # Python 2
from urlparse import urlparse
else: # Python 3
from urllib.parse import urlparse
from urllib.parse import urlparse

# URI protocol test regular expression
protoregex = re.compile('^http[s]?://', re.IGNORECASE)
Expand Down
6 changes: 1 addition & 5 deletions pook/request.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import sys
import json as _json

from .regex import isregex
from .headers import HTTPHeaderDict
from .helpers import trigger_methods
from .matchers.url import protoregex

if sys.version_info < (3,): # Python 2
from urlparse import urlparse, parse_qs, urlunparse
else: # Python 3
from urllib.parse import urlparse, parse_qs, urlunparse
from urllib.parse import urlparse, parse_qs, urlunparse


class Request(object):
Expand Down
7 changes: 4 additions & 3 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
flake8
wheel>=0.29
coveralls>=1.1
pytest~=3.0.3
pytest-cov~=2.3.1
pytest~=7.2.0
pytest-cov~=4.0.0
pytest-flakes~=1.0.1
nose~=1.3.7
Sphinx~=1.4.8
sphinx-rtd-theme~=0.1.9
requests>=2.20.0
urllib3>=1.24.2
bumpversion~=0.5.3
aiohttp~=3.6.2 ; python_version >= '3.5.0'
aiohttp~=3.8.3
mocket~=1.6.0
pytest-asyncio~=0.20.3
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
jsonschema>=2.5.1
xmltodict>=0.11.0
furl>=0.5.6
mock>=2.0.0 ; python_version < '3.3'
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,12 @@ def run_tests(self):
'Development Status :: 5 - Production/Stable',
'Natural Language :: English',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Topic :: Software Development',
'Topic :: Software Development :: Libraries :: Python Modules',
'Programming Language :: Python :: Implementation :: CPython',
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/engines_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# List of engine specific test commands to run
engine_tests = (
'py.test tests/integration/engines/pytest_suite.py',
'nosetests tests/integration/engines/nose_suite.py',
# 'nosetests tests/integration/engines/nose_suite.py',
'python -m unittest tests.integration.engines.unittest_suite',
)

Expand Down
Loading