diff --git a/.travis.yml b/.travis.yml index cbf7ece6..39df03b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,13 @@ -dist: xenial +dist: bionic services: - redis-server language: python python: - - "2.7" - "3.5" - "3.6" - "3.7" - "3.8" - "3.9" - - "pypy" - "pypy3" install: - make develop diff --git a/Pipfile b/Pipfile index a991f949..deeedbff 100644 --- a/Pipfile +++ b/Pipfile @@ -5,7 +5,6 @@ name = "pypi" [packages] python-magic = ">=0.4.5" -six = ">=1.5.0" decorator = ">=4.0.0" urllib3 = ">=1.25.3" http-parser = ">=0.9.0" diff --git a/README.rst b/README.rst index a1ac1f8a..706d7087 100644 --- a/README.rst +++ b/README.rst @@ -27,6 +27,8 @@ Versioning ========== Starting from *3.7.0*, Mocket major version will follow the same numbering pattern as Python's and therefore indicate the most recent Python version that is supported. +FYI: the last version compatible with Python 2.7 is *3.9.4*, bugfixing or backporting of features introduced after that release will only be available as commercial support. + Support it ========== *Star* the project on GitHub, *Buy Me a Coffee* clicking the button below or, even better, contribute with patches or documentation. diff --git a/mocket/__init__.py b/mocket/__init__.py index e9fde168..02fc0eaa 100644 --- a/mocket/__init__.py +++ b/mocket/__init__.py @@ -7,4 +7,4 @@ __all__ = ("mocketize", "Mocket", "MocketEntry", "Mocketizer") -__version__ = "3.9.4" +__version__ = "3.9.35" diff --git a/mocket/async_mocket.py b/mocket/async_mocket.py index ff63efa1..ea3d5330 100644 --- a/mocket/async_mocket.py +++ b/mocket/async_mocket.py @@ -1,50 +1,19 @@ -from sys import version_info - -import decorator - -from mocket import Mocket, Mocketizer +from mocket import Mocketizer def get_async_mocketize(): - major, minor = version_info[:2] - if major == 3 and minor >= 5: - - class AsyncMocketizer(Mocketizer): - async def __aenter__(self): - Mocket.enable( - namespace=self.namespace, - truesocket_recording_dir=self.truesocket_recording_dir, - ) - if self.instance: - self.check_and_call("mocketize_setup") - - async def __aexit__(self, type, value, tb): - if self.instance: - self.check_and_call("mocketize_teardown") - Mocket.disable() + class AsyncMocketizer(Mocketizer): + async def __aenter__(*args, **kwargs): + return Mocketizer.__enter__(*args, **kwargs) - @staticmethod - def async_wrap(test=None, truesocket_recording_dir=None): - async def wrapper(t, *args, **kw): - instance = args[0] if args else None - namespace = ".".join( - ( - instance.__class__.__module__, - instance.__class__.__name__, - t.__name__, - ) - ) - async with AsyncMocketizer( - instance, - namespace=namespace, - truesocket_recording_dir=truesocket_recording_dir, - ): - await t(*args, **kw) - return wrapper + async def __aexit__(*args, **kwargs): + return Mocketizer.__exit__(*args, **kwargs) - return decorator.decorator(wrapper, test) + @staticmethod + def async_wrap(*args, **kwargs): + return Mocketizer.wrap(*args, **kwargs) - return AsyncMocketizer.async_wrap + return AsyncMocketizer.async_wrap async_mocketize = get_async_mocketize() diff --git a/mocket/compat.py b/mocket/compat.py index 74616894..5b5f017e 100644 --- a/mocket/compat.py +++ b/mocket/compat.py @@ -1,41 +1,15 @@ import codecs import os import shlex -import sys -from socket import error as sock_error - -import six encoding = os.getenv("MOCKET_ENCODING", "utf-8") -text_type = six.text_type -byte_type = six.binary_type -basestring = six.string_types - -PY2 = sys.version_info[0] == 2 -if PY2: - import collections as collections_abc - from BaseHTTPServer import BaseHTTPRequestHandler - from urlparse import urlsplit, parse_qs, unquote - - def unquote_utf8(qs): - if isinstance(qs, text_type): - qs = qs.encode(encoding) - s = unquote(qs) - if isinstance(s, byte_type): - return s.decode(encoding) - else: - return s +text_type = str +byte_type = bytes +basestring = (str,) - FileNotFoundError = IOError - BlockingIOError = sock_error -else: - import collections.abc as collections_abc - from http.server import BaseHTTPRequestHandler - from urllib.parse import urlsplit, parse_qs, unquote as unquote_utf8 - - FileNotFoundError = FileNotFoundError - BlockingIOError = BlockingIOError +FileNotFoundError = FileNotFoundError +BlockingIOError = BlockingIOError try: from json.decoder import JSONDecodeError @@ -56,10 +30,7 @@ def decode_from_bytes(s, encoding=encoding): def shsplit(s): - if PY2: - s = encode_to_bytes(s) - else: - s = decode_from_bytes(s) + s = decode_from_bytes(s) return shlex.split(s) diff --git a/mocket/mocket.py b/mocket/mocket.py index 64cc6dfe..c4e3cafe 100644 --- a/mocket/mocket.py +++ b/mocket/mocket.py @@ -1,4 +1,5 @@ import collections +import collections.abc as collections_abc import errno import hashlib import io @@ -20,7 +21,6 @@ JSONDecodeError, basestring, byte_type, - collections_abc, decode_from_bytes, encode_to_bytes, text_type, @@ -77,14 +77,11 @@ def __init__(self, sock=None, server_hostname=None, _context=None, *args, **kwar if isinstance(sock, MocketSocket): self.sock = sock self.sock._host = server_hostname - if true_ssl_context: - self.sock.true_socket = true_ssl_socket( - sock=self.sock.true_socket, - server_hostname=server_hostname, - _context=true_ssl_context(protocol=SSL_PROTOCOL), - ) - else: # Python 2. - self.sock.true_socket = true_ssl_socket(sock=self.sock.true_socket) + self.sock.true_socket = true_ssl_socket( + sock=self.sock.true_socket, + server_hostname=server_hostname, + _context=true_ssl_context(protocol=SSL_PROTOCOL), + ) elif isinstance(sock, int) and true_ssl_context: self.context = true_ssl_context(sock) @@ -586,6 +583,7 @@ def __enter__(self): ) if self.instance: self.check_and_call("mocketize_setup") + return self def __exit__(self, type, value, tb): if self.instance: diff --git a/mocket/mockhttp.py b/mocket/mockhttp.py index b07ddab8..961f36eb 100644 --- a/mocket/mockhttp.py +++ b/mocket/mockhttp.py @@ -1,17 +1,9 @@ -from __future__ import unicode_literals - import re import time +from http.server import BaseHTTPRequestHandler +from urllib.parse import parse_qs, unquote, urlsplit -from .compat import ( - BaseHTTPRequestHandler, - decode_from_bytes, - do_the_magic, - encode_to_bytes, - parse_qs, - unquote_utf8, - urlsplit, -) +from .compat import decode_from_bytes, do_the_magic, encode_to_bytes from .mocket import Mocket, MocketEntry try: @@ -41,7 +33,7 @@ def __init__(self, data): self.path = self.parser.get_path() self.headers = self.parser.get_headers() self.querystring = parse_qs( - unquote_utf8(self.parser.get_query_string()), keep_blank_values=True + unquote(self.parser.get_query_string()), keep_blank_values=True ) if self.querystring: self.path += "?{}".format(self.parser.get_query_string()) diff --git a/mocket/mockredis.py b/mocket/mockredis.py index 2599dfad..23ca5179 100644 --- a/mocket/mockredis.py +++ b/mocket/mockredis.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - from itertools import chain from .compat import byte_type, decode_from_bytes, encode_to_bytes, shsplit, text_type diff --git a/runtests.py b/run_tests.py similarity index 93% rename from runtests.py rename to run_tests.py index d8a4cb0b..8cfcfd64 100644 --- a/runtests.py +++ b/run_tests.py @@ -3,7 +3,7 @@ import sys -def runtests(args=None): +def main(args=None): import pytest if not args: @@ -37,4 +37,4 @@ def runtests(args=None): if __name__ == "__main__": - runtests(sys.argv) + main(sys.argv) diff --git a/setup.py b/setup.py index b794e1b5..bcf0bbac 100644 --- a/setup.py +++ b/setup.py @@ -49,13 +49,12 @@ def read_version(package): "dev": [], "pook": pook_requires, # plugins version supporting mocket.plugins.pook.MocketEngine }, - test_suite="runtests.runtests", + test_suite="run_tests.main", license="BSD", classifiers=[ "Development Status :: 6 - Mature", "Intended Audience :: Developers", "Operating System :: OS Independent", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7",