diff --git a/0001-Revert-v4.0.x-Remove-legacy-python-and-add-python3.8.patch b/0001-Revert-v4.0.x-Remove-legacy-python-and-add-python3.8.patch new file mode 100644 index 0000000..5ec0047 --- /dev/null +++ b/0001-Revert-v4.0.x-Remove-legacy-python-and-add-python3.8.patch @@ -0,0 +1,1214 @@ +From bd3de7c8b762f7a1bdd947a0c2d817b4e70cd740 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Mark=C3=A9ta=20Cal=C3=A1bkov=C3=A1?= + +Date: Mon, 24 Feb 2020 09:53:16 +0100 +Subject: [PATCH] Revert "v4.0.x - Remove legacy python and add python3.8 + support (#499)" + +This reverts commit 4a8e80ee3e288c61a85a90d7f13c83d9e9a4db2e. +--- + setup.py | 36 +- + tests/integration/test_basic.py | 2 +- + tests/integration/test_boto.py | 7 +- + tests/integration/test_config.py | 2 +- + tests/integration/test_disksaver.py | 2 +- + tests/integration/test_filter.py | 6 +- + tests/integration/test_httplib2.py | 4 +- + tests/integration/test_ignore.py | 2 +- + tests/integration/test_matchers.py | 2 +- + tests/integration/test_multiple.py | 2 +- + tests/integration/test_proxy.py | 7 +- + tests/integration/test_record_mode.py | 2 +- + tests/integration/test_register_matcher.py | 2 +- + tests/integration/test_register_persister.py | 2 +- + tests/integration/test_register_serializer.py | 2 +- + tests/integration/test_request.py | 2 +- + tests/integration/test_stubs.py | 2 +- + tests/integration/test_urllib2.py | 6 +- + tests/integration/test_wild.py | 15 +- + tests/unit/test_cassettes.py | 6 +- + tests/unit/test_errors.py | 3 +- + tests/unit/test_filters.py | 6 +- + tests/unit/test_matchers.py | 2 +- + tests/unit/test_response.py | 4 + + tests/unit/test_serialize.py | 5 +- + tests/unit/test_stubs.py | 5 +- + tests/unit/test_vcr.py | 6 +- + tox.ini | 35 +- + vcr/__init__.py | 19 +- + vcr/cassette.py | 15 +- + vcr/compat.py | 14 + + vcr/config.py | 10 +- + vcr/errors.py | 2 +- + vcr/filters.py | 32 +- + vcr/matchers.py | 5 +- + vcr/patch.py | 9 +- + vcr/persisters/filesystem.py | 4 +- + vcr/request.py | 10 +- + vcr/serializers/compat.py | 7 +- + vcr/stubs/__init__.py | 20 +- + vcr/stubs/aiohttp_stubs/__init__.py | 2 + + vcr/stubs/boto3_stubs.py | 5 +- + vcr/stubs/compat.py | 27 +- + vcr/stubs/tornado_stubs.py | 4 +- + vcr/util.py | 4 +- + 57 files changed, 458 insertions(+), 484 deletions(-) + delete mode 100644 docs/_static/vcr.png + delete mode 100644 docs/_static/vcr.svg + create mode 100644 vcr/compat.py + +Index: vcrpy-4.0.2/setup.py +=================================================================== +--- vcrpy-4.0.2.orig/setup.py ++++ vcrpy-4.0.2/setup.py +@@ -1,31 +1,11 @@ + #!/usr/bin/env python + +-import codecs +-import os +-import re + import sys + + from setuptools import setup, find_packages + from setuptools.command.test import test as TestCommand + + long_description = open("README.rst", "r").read() +-here = os.path.abspath(os.path.dirname(__file__)) +- +- +-def read(*parts): +- # intentionally *not* adding an encoding option to open, See: +- # https://github.com/pypa/virtualenv/issues/201#issuecomment-3145690 +- with codecs.open(os.path.join(here, *parts), "r") as fp: +- return fp.read() +- +- +-def find_version(*file_paths): +- version_file = read(*file_paths) +- version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M) +- if version_match: +- return version_match.group(1) +- +- raise RuntimeError("Unable to find version string.") + + + class PyTest(TestCommand): +@@ -46,21 +26,27 @@ install_requires = [ + "PyYAML", + "wrapt", + "six>=1.5", ++ 'contextlib2; python_version=="2.7"', ++ 'mock; python_version=="2.7"', + 'yarl; python_version>="3.6"', + 'yarl<1.4; python_version=="3.5"', + ] + ++excluded_packages = ["tests*"] ++if sys.version_info[0] == 2: ++ excluded_packages.append("vcr.stubs.aiohttp_stubs") ++ + setup( + name="vcrpy", +- version=find_version("vcr", "__init__.py"), ++ version="4.0.2", + description=("Automatically mock your HTTP interactions to simplify and speed up testing"), + long_description=long_description, + long_description_content_type="text/x-rst", + author="Kevin McCarthy", + author_email="me@kevinmccarthy.org", + url="https://github.com/kevin1024/vcrpy", +- packages=find_packages(exclude=["tests*"]), +- python_requires=">=3.5", ++ packages=find_packages(exclude=excluded_packages), ++ python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*", + install_requires=install_requires, + license="MIT", + tests_require=["pytest", "mock", "pytest-httpbin"], +@@ -69,12 +55,12 @@ setup( + "Environment :: Console", + "Intended Audience :: Developers", + "Programming Language :: Python", ++ "Programming Language :: Python :: 2", ++ "Programming Language :: Python :: 2.7", + "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 :: Only", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", + "Topic :: Software Development :: Testing", +Index: vcrpy-4.0.2/tests/integration/test_basic.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_basic.py ++++ vcrpy-4.0.2/tests/integration/test_basic.py +@@ -3,7 +3,7 @@ + + # External imports + import os +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + # Internal imports + import vcr +Index: vcrpy-4.0.2/tests/integration/test_boto.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_boto.py ++++ vcrpy-4.0.2/tests/integration/test_boto.py +@@ -6,9 +6,14 @@ import boto # NOQA + import boto.iam # NOQA + from boto.s3.connection import S3Connection # NOQA + from boto.s3.key import Key # NOQA +-from configparser import DuplicateSectionError # NOQA + import vcr # NOQA + ++try: # NOQA ++ from ConfigParser import DuplicateSectionError # NOQA ++except ImportError: # NOQA ++ # python3 ++ from configparser import DuplicateSectionError # NOQA ++ + + def test_boto_stubs(tmpdir): + with vcr.use_cassette(str(tmpdir.join("boto-stubs.yml"))): +Index: vcrpy-4.0.2/tests/integration/test_config.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_config.py ++++ vcrpy-4.0.2/tests/integration/test_config.py +@@ -2,7 +2,7 @@ import os + import json + import pytest + import vcr +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + + def test_set_serializer_default_config(tmpdir, httpbin): +Index: vcrpy-4.0.2/tests/integration/test_disksaver.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_disksaver.py ++++ vcrpy-4.0.2/tests/integration/test_disksaver.py +@@ -4,7 +4,7 @@ + # External imports + import os + import time +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + # Internal imports + import vcr +Index: vcrpy-4.0.2/tests/integration/test_filter.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_filter.py ++++ vcrpy-4.0.2/tests/integration/test_filter.py +@@ -1,8 +1,8 @@ + import base64 + import pytest +-from urllib.request import urlopen, Request +-from urllib.parse import urlencode +-from urllib.error import HTTPError ++from six.moves.urllib.request import urlopen, Request ++from six.moves.urllib.parse import urlencode ++from six.moves.urllib.error import HTTPError + import vcr + import json + from assertions import assert_cassette_has_one_response, assert_is_json +Index: vcrpy-4.0.2/tests/integration/test_httplib2.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_httplib2.py ++++ vcrpy-4.0.2/tests/integration/test_httplib2.py +@@ -3,7 +3,7 @@ + + import sys + +-from urllib.parse import urlencode ++from six.moves.urllib_parse import urlencode + import pytest + import pytest_httpbin.certs + +@@ -111,7 +111,7 @@ def test_post_data(tmpdir, httpbin_both) + + def test_post_unicode_data(tmpdir, httpbin_both): + """Ensure that it works when posting unicode data""" +- data = urlencode({"snowman": "☃".encode()}) ++ data = urlencode({"snowman": u"☃".encode("utf-8")}) + url = httpbin_both.url + "/post" + with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))): + _, res1 = http().request(url, "POST", data) +Index: vcrpy-4.0.2/tests/integration/test_ignore.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_ignore.py ++++ vcrpy-4.0.2/tests/integration/test_ignore.py +@@ -1,4 +1,4 @@ +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + import socket + from contextlib import contextmanager + import vcr +Index: vcrpy-4.0.2/tests/integration/test_matchers.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_matchers.py ++++ vcrpy-4.0.2/tests/integration/test_matchers.py +@@ -1,6 +1,6 @@ + import vcr + import pytest +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + + DEFAULT_URI = "http://httpbin.org/get?p1=q1&p2=q2" # base uri for testing +Index: vcrpy-4.0.2/tests/integration/test_multiple.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_multiple.py ++++ vcrpy-4.0.2/tests/integration/test_multiple.py +@@ -1,6 +1,6 @@ + import pytest + import vcr +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + + def test_making_extra_request_raises_exception(tmpdir, httpbin): +Index: vcrpy-4.0.2/tests/integration/test_proxy.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_proxy.py ++++ vcrpy-4.0.2/tests/integration/test_proxy.py +@@ -5,9 +5,8 @@ + import multiprocessing + import pytest + +-import http.server +-import socketserver +-from urllib.request import urlopen ++from six.moves import socketserver, SimpleHTTPServer ++from six.moves.urllib.request import urlopen + + # Internal imports + import vcr +@@ -16,7 +15,7 @@ import vcr + requests = pytest.importorskip("requests") + + +-class Proxy(http.server.SimpleHTTPRequestHandler): ++class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler): + """ + Simple proxy server. + +Index: vcrpy-4.0.2/tests/integration/test_record_mode.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_record_mode.py ++++ vcrpy-4.0.2/tests/integration/test_record_mode.py +@@ -1,6 +1,6 @@ + import pytest + import vcr +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + + def test_once_record_mode(tmpdir, httpbin): +Index: vcrpy-4.0.2/tests/integration/test_register_matcher.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_register_matcher.py ++++ vcrpy-4.0.2/tests/integration/test_register_matcher.py +@@ -1,5 +1,5 @@ + import vcr +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + + def true_matcher(r1, r2): +Index: vcrpy-4.0.2/tests/integration/test_register_persister.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_register_persister.py ++++ vcrpy-4.0.2/tests/integration/test_register_persister.py +@@ -3,7 +3,7 @@ + + # External imports + import os +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + # Internal imports + import vcr +Index: vcrpy-4.0.2/tests/integration/test_register_serializer.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_register_serializer.py ++++ vcrpy-4.0.2/tests/integration/test_register_serializer.py +@@ -1,7 +1,7 @@ + import vcr + + +-class MockSerializer: ++class MockSerializer(object): + def __init__(self): + self.serialize_count = 0 + self.deserialize_count = 0 +Index: vcrpy-4.0.2/tests/integration/test_request.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_request.py ++++ vcrpy-4.0.2/tests/integration/test_request.py +@@ -1,5 +1,5 @@ + import vcr +-from urllib.request import urlopen ++from six.moves.urllib.request import urlopen + + + def test_recorded_request_uri_with_redirected_request(tmpdir, httpbin): +Index: vcrpy-4.0.2/tests/integration/test_stubs.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_stubs.py ++++ vcrpy-4.0.2/tests/integration/test_stubs.py +@@ -1,7 +1,7 @@ + import vcr + import zlib + import json +-import http.client as httplib ++import six.moves.http_client as httplib + + from assertions import assert_is_json + +Index: vcrpy-4.0.2/tests/integration/test_urllib2.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_urllib2.py ++++ vcrpy-4.0.2/tests/integration/test_urllib2.py +@@ -2,8 +2,8 @@ + """Integration tests with urllib2""" + + import ssl +-from urllib.request import urlopen +-from urllib.parse import urlencode ++from six.moves.urllib.request import urlopen ++from six.moves.urllib_parse import urlencode + import pytest_httpbin.certs + + # Internal imports +@@ -104,7 +104,7 @@ def test_post_data(httpbin_both, tmpdir) + + def test_post_unicode_data(httpbin_both, tmpdir): + """Ensure that it works when posting unicode data""" +- data = urlencode({"snowman": "☃".encode()}).encode("utf-8") ++ data = urlencode({"snowman": u"☃".encode("utf-8")}).encode("utf-8") + url = httpbin_both.url + "/post" + with vcr.use_cassette(str(tmpdir.join("post_data.yaml"))): + res1 = urlopen_with_cafile(url, data).read() +Index: vcrpy-4.0.2/tests/integration/test_wild.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/integration/test_wild.py ++++ vcrpy-4.0.2/tests/integration/test_wild.py +@@ -1,13 +1,16 @@ +-import http.client as httplib + import multiprocessing + import pytest +-from xmlrpc.client import ServerProxy +-from xmlrpc.server import SimpleXMLRPCServer ++from six.moves import xmlrpc_client, xmlrpc_server + + requests = pytest.importorskip("requests") + + import vcr # NOQA + ++try: ++ import httplib ++except ImportError: ++ import http.client as httplib ++ + + def test_domain_redirect(): + """Ensure that redirects across domains are considered unique""" +@@ -77,7 +80,7 @@ def test_amazon_doctype(tmpdir): + + + def start_rpc_server(q): +- httpd = SimpleXMLRPCServer(("127.0.0.1", 0)) ++ httpd = xmlrpc_server.SimpleXMLRPCServer(("127.0.0.1", 0)) + httpd.register_function(pow) + q.put("http://{}:{}".format(*httpd.server_address)) + httpd.serve_forever() +@@ -96,11 +99,11 @@ def rpc_server(): + + def test_xmlrpclib(tmpdir, rpc_server): + with vcr.use_cassette(str(tmpdir.join("xmlrpcvideo.yaml"))): +- roundup_server = ServerProxy(rpc_server, allow_none=True) ++ roundup_server = xmlrpc_client.ServerProxy(rpc_server, allow_none=True) + original_schema = roundup_server.pow(2, 4) + + with vcr.use_cassette(str(tmpdir.join("xmlrpcvideo.yaml"))): +- roundup_server = ServerProxy(rpc_server, allow_none=True) ++ roundup_server = xmlrpc_client.ServerProxy(rpc_server, allow_none=True) + second_schema = roundup_server.pow(2, 4) + + assert original_schema == second_schema +Index: vcrpy-4.0.2/tests/unit/test_cassettes.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/unit/test_cassettes.py ++++ vcrpy-4.0.2/tests/unit/test_cassettes.py +@@ -1,12 +1,12 @@ +-import contextlib + import copy +-import http.client as httplib + import inspect + import os +-from unittest import mock + ++from six.moves import http_client as httplib + import pytest + import yaml ++ ++from vcr.compat import mock, contextlib + from vcr.cassette import Cassette + from vcr.errors import UnhandledHTTPRequestError + from vcr.patch import force_reset +@@ -208,7 +208,7 @@ def test_nesting_context_managers_by_che + + + def test_custom_patchers(): +- class Test: ++ class Test(object): + attribute = None + + with Cassette.use(path="custom_patches", custom_patches=((Test, "attribute", VCRHTTPSConnection),)): +Index: vcrpy-4.0.2/tests/unit/test_errors.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/unit/test_errors.py ++++ vcrpy-4.0.2/tests/unit/test_errors.py +@@ -1,7 +1,6 @@ +-from unittest import mock +- + import pytest + ++from vcr.compat import mock + from vcr import errors + from vcr.cassette import Cassette + +Index: vcrpy-4.0.2/tests/unit/test_filters.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/unit/test_filters.py ++++ vcrpy-4.0.2/tests/unit/test_filters.py +@@ -1,4 +1,4 @@ +-from io import BytesIO ++from six import BytesIO + from vcr.filters import ( + remove_headers, + replace_headers, +@@ -8,10 +8,10 @@ from vcr.filters import ( + replace_post_data_parameters, + decode_response, + ) ++from vcr.compat import mock + from vcr.request import Request + import gzip + import json +-from unittest import mock + import zlib + + +Index: vcrpy-4.0.2/tests/unit/test_matchers.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/unit/test_matchers.py ++++ vcrpy-4.0.2/tests/unit/test_matchers.py +@@ -1,5 +1,5 @@ + import itertools +-from unittest import mock ++from vcr.compat import mock + + import pytest + +Index: vcrpy-4.0.2/tests/unit/test_response.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/unit/test_response.py ++++ vcrpy-4.0.2/tests/unit/test_response.py +@@ -1,5 +1,8 @@ + # coding: UTF-8 + import io ++import unittest ++ ++import six + + from vcr.stubs import VCRHTTPResponse + +@@ -55,6 +58,7 @@ def test_response_headers_should_have_co + assert response.headers.get("date") == "Fri, 24 Oct 2014 18:35:37 GMT" + + ++@unittest.skipIf(six.PY2, "Regression test for Python3 only") + def test_response_parses_correctly_and_fp_attribute_error_is_not_thrown(): + """ + Regression test for https://github.com/kevin1024/vcrpy/issues/440 +Index: vcrpy-4.0.2/tests/unit/test_serialize.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/unit/test_serialize.py ++++ vcrpy-4.0.2/tests/unit/test_serialize.py +@@ -1,8 +1,7 @@ + # -*- encoding: utf-8 -*- +-from unittest import mock +- + import pytest + ++from vcr.compat import mock + from vcr.request import Request + from vcr.serialize import deserialize, serialize + from vcr.serializers import yamlserializer, jsonserializer, compat +@@ -30,7 +29,7 @@ def test_deserialize_new_json_cassette() + deserialize(f.read(), jsonserializer) + + +-REQBODY_TEMPLATE = """\ ++REQBODY_TEMPLATE = u"""\ + interactions: + - request: + body: {req_body} +Index: vcrpy-4.0.2/tests/unit/test_stubs.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/unit/test_stubs.py ++++ vcrpy-4.0.2/tests/unit/test_stubs.py +@@ -1,10 +1,9 @@ +-from unittest import mock +- + from vcr.stubs import VCRHTTPSConnection ++from vcr.compat import mock + from vcr.cassette import Cassette + + +-class TestVCRConnection: ++class TestVCRConnection(object): + def test_setting_of_attributes_get_propogated_to_real_connection(self): + vcr_connection = VCRHTTPSConnection("www.examplehost.com") + vcr_connection.ssl_version = "example_ssl_version" +Index: vcrpy-4.0.2/tests/unit/test_vcr.py +=================================================================== +--- vcrpy-4.0.2.orig/tests/unit/test_vcr.py ++++ vcrpy-4.0.2/tests/unit/test_vcr.py +@@ -1,10 +1,10 @@ +-from unittest import mock + import os + + import pytest +-import http.client as httplib ++from six.moves import http_client as httplib + + from vcr import VCR, use_cassette ++from vcr.compat import mock + from vcr.request import Request + from vcr.stubs import VCRHTTPSConnection + from vcr.patch import _HTTPConnection, force_reset +@@ -170,7 +170,7 @@ def test_fixtures_with_use_cassette(rand + + + def test_custom_patchers(): +- class Test: ++ class Test(object): + attribute = None + attribute2 = None + +Index: vcrpy-4.0.2/tox.ini +=================================================================== +--- vcrpy-4.0.2.orig/tox.ini ++++ vcrpy-4.0.2/tox.ini +@@ -3,8 +3,8 @@ skip_missing_interpreters=true + envlist = + cov-clean, + lint, +- {py35,py36,py37,py38}-{requests,httplib2,urllib3,tornado4,boto3,aiohttp}, +- {pypy3}-{requests,httplib2,urllib3,tornado4,boto3}, ++ {py27,py35,py36,py37,py38,pypy,pypy3}-{requests,httplib2,urllib3,tornado4,boto3}, ++ {py35,py36,py37,py38}-{aiohttp}, + cov-report + + +@@ -34,27 +34,6 @@ deps = + flake8 + black + +-[testenv:docs] +-# Running sphinx from inside the "docs" directory +-# ensures it will not pick up any stray files that might +-# get into a virtual environment under the top-level directory +-# or other artifacts under build/ +-changedir = docs +-# The only dependency is sphinx +-# If we were using extensions packaged separately, +-# we would specify them here. +-# A better practice is to specify a specific version of sphinx. +-deps = +- sphinx +- sphinx_rtd_theme +-# This is the sphinx command to generate HTML. +-# In other circumstances, we might want to generate a PDF or an ebook +-commands = +- sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html +-# We use Python 3.7. Tox sometimes tries to autodetect it based on the name of +-# the testenv, but "docs" does not give useful clues so we have to be explicit. +-basepython = python3.7 +- + [testenv] + # Need to use develop install so that paths + # for aggregate code coverage combine +@@ -71,17 +50,17 @@ deps = + requests: requests>=2.22.0 + httplib2: httplib2 + urllib3: urllib3 +- {py35,py36}-tornado4: tornado>=4,<5 +- {py35,py36}-tornado4: pytest-tornado +- {py35,py36}-tornado4: pycurl ++ {py27,py35,py36,pypy}-tornado4: tornado>=4,<5 ++ {py27,py35,py36,pypy}-tornado4: pytest-tornado ++ {py27,py35,py36}-tornado4: pycurl + boto3: boto3 + boto3: urllib3 + aiohttp: aiohttp + aiohttp: pytest-asyncio + aiohttp: pytest-aiohttp + depends = +- lint,{py35,py36,py37,py38,pypy3}-{requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37,py38}-{aiohttp}: cov-clean +- cov-report: lint,{py35,py36,py37,py38,pypy3}-{requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37,py38}-{aiohttp} ++ {py27,py35,py36,py37,pypy}-{lint,requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37}-{aiohttp}: cov-clean ++ cov-report: {py27,py35,py36,py37,pypy}-{lint,requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37}-{aiohttp} + passenv = + AWS_ACCESS_KEY_ID + AWS_DEFAULT_REGION +Index: vcrpy-4.0.2/vcr/__init__.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/__init__.py ++++ vcrpy-4.0.2/vcr/__init__.py +@@ -1,8 +1,23 @@ + import logging ++import warnings ++import sys + from .config import VCR +-from logging import NullHandler + +-__version__ = "4.0.2" ++# Set default logging handler to avoid "No handler found" warnings. ++try: # Python 2.7+ ++ from logging import NullHandler ++except ImportError: ++ ++ class NullHandler(logging.Handler): ++ def emit(self, record): ++ pass ++ ++ ++if sys.version_info[0] == 2: ++ warnings.warn( ++ "Python 2.x support of vcrpy is deprecated and will be removed in an upcoming major release.", ++ DeprecationWarning, ++ ) + + logging.getLogger(__name__).addHandler(NullHandler()) + +Index: vcrpy-4.0.2/vcr/cassette.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/cassette.py ++++ vcrpy-4.0.2/vcr/cassette.py +@@ -1,5 +1,4 @@ + import collections +-import contextlib + import copy + import sys + import inspect +@@ -7,13 +6,13 @@ import logging + + import wrapt + ++from .compat import contextlib + from .errors import UnhandledHTTPRequestError + from .matchers import requests_match, uri, method, get_matchers_results + from .patch import CassettePatcherBuilder + from .serializers import yamlserializer + from .persisters.filesystem import FilesystemPersister + from .util import partition_dict +-from ._handle_coroutine import handle_coroutine + + try: + from asyncio import iscoroutinefunction +@@ -23,10 +22,18 @@ except ImportError: + return False + + ++if sys.version_info[:2] >= (3, 5): ++ from ._handle_coroutine import handle_coroutine ++else: ++ ++ def handle_coroutine(*args, **kwags): ++ raise NotImplementedError("Not implemented on Python 2") ++ ++ + log = logging.getLogger(__name__) + + +-class CassetteContextDecorator: ++class CassetteContextDecorator(object): + """Context manager/decorator that handles installing the cassette and + removing cassettes. + +@@ -152,7 +159,7 @@ class CassetteContextDecorator: + return new_args_getter + + +-class Cassette: ++class Cassette(object): + """A container for recorded requests and responses""" + + @classmethod +Index: vcrpy-4.0.2/vcr/compat.py +=================================================================== +--- /dev/null ++++ vcrpy-4.0.2/vcr/compat.py +@@ -0,0 +1,14 @@ ++try: ++ from unittest import mock ++except ImportError: ++ import mock ++ ++try: ++ import contextlib ++except ImportError: ++ import contextlib2 as contextlib ++else: ++ if not hasattr(contextlib, "ExitStack"): ++ import contextlib2 as contextlib ++ ++__all__ = ["mock", "contextlib"] +Index: vcrpy-4.0.2/vcr/config.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/config.py ++++ vcrpy-4.0.2/vcr/config.py +@@ -1,6 +1,9 @@ + import copy + +-from collections import abc as collections_abc ++try: ++ from collections import abc as collections_abc # only works on python 3.3+ ++except ImportError: ++ import collections as collections_abc + import functools + import inspect + import os +@@ -16,7 +19,7 @@ from . import matchers + from . import filters + + +-class VCR: ++class VCR(object): + @staticmethod + def is_test_method(method_name, function): + return method_name.startswith("test") and isinstance(function, types.FunctionType) +@@ -99,7 +102,7 @@ class VCR: + return matchers + + def use_cassette(self, path=None, **kwargs): +- if path is not None and not isinstance(path, str): ++ if path is not None and not isinstance(path, six.string_types): + function = path + # Assume this is an attempt to decorate a function + return self._use_cassette(**kwargs)(function) +@@ -248,5 +251,4 @@ class VCR: + + def test_case(self, predicate=None): + predicate = predicate or self.is_test_method +- # TODO: Remove this reference to `six` in favor of the Python3 equivalent + return six.with_metaclass(auto_decorate(self.use_cassette, predicate)) +Index: vcrpy-4.0.2/vcr/errors.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/errors.py ++++ vcrpy-4.0.2/vcr/errors.py +@@ -3,7 +3,7 @@ class CannotOverwriteExistingCassetteExc + self.cassette = kwargs["cassette"] + self.failed_request = kwargs["failed_request"] + message = self._get_message(kwargs["cassette"], kwargs["failed_request"]) +- super().__init__(message) ++ super(CannotOverwriteExistingCassetteException, self).__init__(message) + + @staticmethod + def _get_message(cassette, failed_request): +Index: vcrpy-4.0.2/vcr/filters.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/filters.py ++++ vcrpy-4.0.2/vcr/filters.py +@@ -1,5 +1,5 @@ +-from io import BytesIO +-from urllib.parse import urlparse, urlencode, urlunparse ++from six import BytesIO, text_type ++from six.moves.urllib.parse import urlparse, urlencode, urlunparse + import copy + import json + import zlib +@@ -8,11 +8,13 @@ from .util import CaseInsensitiveDict + + + def replace_headers(request, replacements): +- """Replace headers in request according to replacements. +- The replacements should be a list of (key, value) pairs where the value can be any of: +- 1. A simple replacement string value. +- 2. None to remove the given header. +- 3. A callable which accepts (key, value, request) and returns a string value or None. ++ """ ++ Replace headers in request according to replacements. The replacements ++ should be a list of (key, value) pairs where the value can be any of: ++ 1. A simple replacement string value. ++ 2. None to remove the given header. ++ 3. A callable which accepts (key, value, request) and returns a string ++ value or None. + """ + new_headers = request.headers.copy() + for k, rv in replacements: +@@ -35,9 +37,10 @@ def remove_headers(request, headers_to_r + + + def replace_query_parameters(request, replacements): +- """Replace query parameters in request according to replacements. +- +- The replacements should be a list of (key, value) pairs where the value can be any of: ++ """ ++ Replace query parameters in request according to replacements. The ++ replacements should be a list of (key, value) pairs where the value can be ++ any of: + 1. A simple replacement string value. + 2. None to remove the given header. + 3. A callable which accepts (key, value, request) and returns a string +@@ -70,9 +73,10 @@ def remove_query_parameters(request, que + + + def replace_post_data_parameters(request, replacements): +- """Replace post data in request--either form data or json--according to replacements. +- +- The replacements should be a list of (key, value) pairs where the value can be any of: ++ """ ++ Replace post data in request--either form data or json--according to ++ replacements. The replacements should be a list of (key, value) pairs where ++ the value can be any of: + 1. A simple replacement string value. + 2. None to remove the given header. + 3. A callable which accepts (key, value, request) and returns a string +@@ -95,7 +99,7 @@ def replace_post_data_parameters(request + json_data[k] = rv + request.body = json.dumps(json_data).encode("utf-8") + else: +- if isinstance(request.body, str): ++ if isinstance(request.body, text_type): + request.body = request.body.encode("utf-8") + splits = [p.partition(b"=") for p in request.body.split(b"&")] + new_splits = [] +Index: vcrpy-4.0.2/vcr/matchers.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/matchers.py ++++ vcrpy-4.0.2/vcr/matchers.py +@@ -1,6 +1,5 @@ + import json +-import urllib +-import xmlrpc.client ++from six.moves import urllib, xmlrpc_client + from .util import read_body + import logging + +@@ -78,7 +77,7 @@ _checker_transformer_pairs = ( + lambda body: urllib.parse.parse_qs(body.decode("ascii")), + ), + (_header_checker("application/json"), _transform_json), +- (lambda request: _xml_header_checker(request) and _xmlrpc_header_checker(request), xmlrpc.client.loads), ++ (lambda request: _xml_header_checker(request) and _xmlrpc_header_checker(request), xmlrpc_client.loads), + ) + + +Index: vcrpy-4.0.2/vcr/patch.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/patch.py ++++ vcrpy-4.0.2/vcr/patch.py +@@ -1,11 +1,10 @@ + """Utilities for patching in cassettes""" +-import contextlib + import functools + import itertools +-from unittest import mock + ++from .compat import contextlib, mock + from .stubs import VCRHTTPConnection, VCRHTTPSConnection +-import http.client as httplib ++from six.moves import http_client as httplib + + import logging + +@@ -94,7 +93,7 @@ else: + _AiohttpClientSessionRequest = aiohttp.client.ClientSession._request + + +-class CassettePatcherBuilder: ++class CassettePatcherBuilder(object): + def _build_patchers_from_mock_triples_decorator(function): + @functools.wraps(function) + def wrapped(self, *args, **kwargs): +@@ -359,7 +358,7 @@ class CassettePatcherBuilder: + ) + + +-class ConnectionRemover: ++class ConnectionRemover(object): + def __init__(self, connection_class): + self._connection_class = connection_class + self._connection_pool_to_connections = {} +Index: vcrpy-4.0.2/vcr/persisters/filesystem.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/persisters/filesystem.py ++++ vcrpy-4.0.2/vcr/persisters/filesystem.py +@@ -4,13 +4,13 @@ import os + from ..serialize import serialize, deserialize + + +-class FilesystemPersister: ++class FilesystemPersister(object): + @classmethod + def load_cassette(cls, cassette_path, serializer): + try: + with open(cassette_path) as f: + cassette_content = f.read() +- except OSError: ++ except IOError: + raise ValueError("Cassette not found.") + cassette = deserialize(cassette_content, serializer) + return cassette +Index: vcrpy-4.0.2/vcr/request.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/request.py ++++ vcrpy-4.0.2/vcr/request.py +@@ -1,13 +1,13 @@ + import warnings +-from io import BytesIO +-from urllib.parse import urlparse, parse_qsl ++from six import BytesIO, text_type ++from six.moves.urllib.parse import urlparse, parse_qsl + from .util import CaseInsensitiveDict + import logging + + log = logging.getLogger(__name__) + + +-class Request: ++class Request(object): + """ + VCR's representation of a request. + """ +@@ -39,7 +39,7 @@ class Request: + + @body.setter + def body(self, value): +- if isinstance(value, str): ++ if isinstance(value, text_type): + value = value.encode("utf-8") + self._body = value + +@@ -136,4 +136,4 @@ class HeadersDict(CaseInsensitiveDict): + if old: + key = old[0] + +- super().__setitem__(key, value) ++ super(HeadersDict, self).__setitem__(key, value) +Index: vcrpy-4.0.2/vcr/serializers/compat.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/serializers/compat.py ++++ vcrpy-4.0.2/vcr/serializers/compat.py +@@ -1,3 +1,6 @@ ++import six ++ ++ + def convert_to_bytes(resp): + resp = convert_body_to_bytes(resp) + return resp +@@ -21,7 +24,7 @@ def convert_body_to_bytes(resp): + http://pyyaml.org/wiki/PyYAMLDocumentation#Python3support + """ + try: +- if resp["body"]["string"] is not None and not isinstance(resp["body"]["string"], bytes): ++ if resp["body"]["string"] is not None and not isinstance(resp["body"]["string"], six.binary_type): + resp["body"]["string"] = resp["body"]["string"].encode("utf-8") + except (KeyError, TypeError, UnicodeEncodeError): + # The thing we were converting either wasn't a dictionary or didn't +@@ -41,7 +44,7 @@ def _convert_string_to_unicode(string): + result = string + + try: +- if string is not None and not isinstance(string, str): ++ if string is not None and not isinstance(string, six.text_type): + result = string.decode("utf-8") + except (TypeError, UnicodeDecodeError, AttributeError): + # Sometimes the string actually is binary or StringIO object, +Index: vcrpy-4.0.2/vcr/stubs/__init__.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/stubs/__init__.py ++++ vcrpy-4.0.2/vcr/stubs/__init__.py +@@ -1,12 +1,9 @@ + """Stubs for patching HTTP and HTTPS requests""" + + import logging +-from http.client import ( +- HTTPConnection, +- HTTPSConnection, +- HTTPResponse, +-) +-from io import BytesIO ++import six ++from six.moves.http_client import HTTPConnection, HTTPSConnection, HTTPResponse ++from six import BytesIO + from vcr.request import Request + from vcr.errors import CannotOverwriteExistingCassetteException + from . import compat +@@ -14,7 +11,7 @@ from . import compat + log = logging.getLogger(__name__) + + +-class VCRFakeSocket: ++class VCRFakeSocket(object): + """ + A socket that doesn't do anything! + Used when playing back cassettes, when there +@@ -146,7 +143,7 @@ class VCRHTTPResponse(HTTPResponse): + return self._content.readable() + + +-class VCRConnection: ++class VCRConnection(object): + # A reference to the cassette that's currently being patched in + cassette = None + +@@ -299,7 +296,8 @@ class VCRConnection: + self.real_connection.sock = value + + def __init__(self, *args, **kwargs): +- kwargs.pop("strict", None) # apparently this is gone in py3 ++ if six.PY3: ++ kwargs.pop("strict", None) # apparently this is gone in py3 + + # need to temporarily reset here because the real connection + # inherits from the thing that we are mocking out. Take out +@@ -330,7 +328,7 @@ class VCRConnection: + # we're setting the real_connection itself for the first time + pass + +- super().__setattr__(name, value) ++ super(VCRConnection, self).__setattr__(name, value) + + def __getattr__(self, name): + """ +@@ -342,7 +340,7 @@ class VCRConnection: + # we're setting the real_connection itself for the first time + return getattr(self.real_connection, name) + +- return super().__getattr__(name) ++ return super(VCRConnection, self).__getattr__(name) + + + for k, v in HTTPConnection.__dict__.items(): +Index: vcrpy-4.0.2/vcr/stubs/aiohttp_stubs/__init__.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/stubs/aiohttp_stubs/__init__.py ++++ vcrpy-4.0.2/vcr/stubs/aiohttp_stubs/__init__.py +@@ -1,4 +1,6 @@ + """Stubs for aiohttp HTTP clients""" ++from __future__ import absolute_import ++ + import asyncio + import functools + import logging +Index: vcrpy-4.0.2/vcr/stubs/boto3_stubs.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/stubs/boto3_stubs.py ++++ vcrpy-4.0.2/vcr/stubs/boto3_stubs.py +@@ -1,4 +1,6 @@ + """Stubs for boto3""" ++import six ++ + try: + # boto using awsrequest + from botocore.awsrequest import AWSHTTPConnection as HTTPConnection +@@ -24,7 +26,8 @@ class VCRRequestsHTTPSConnection(VCRHTTP + _baseclass = VerifiedHTTPSConnection + + def __init__(self, *args, **kwargs): +- kwargs.pop("strict", None) ++ if six.PY3: ++ kwargs.pop("strict", None) # apparently this is gone in py3 + + # need to temporarily reset here because the real connection + # inherits from the thing that we are mocking out. Take out +Index: vcrpy-4.0.2/vcr/stubs/compat.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/stubs/compat.py ++++ vcrpy-4.0.2/vcr/stubs/compat.py +@@ -1,5 +1,11 @@ +-from io import BytesIO +-import http.client ++import six ++from six import BytesIO ++from six.moves.http_client import HTTPMessage ++ ++try: ++ import http.client ++except ImportError: ++ pass + + + """ +@@ -9,7 +15,10 @@ layer that tries to cope with this move. + + + def get_header(message, name): +- return message.getallmatchingheaders(name) ++ if six.PY3: ++ return message.getallmatchingheaders(name) ++ else: ++ return message.getheader(name) + + + def get_header_items(message): +@@ -20,8 +29,16 @@ def get_header_items(message): + + def get_headers(message): + for key in set(message.keys()): +- yield key, message.get_all(key) ++ if six.PY3: ++ yield key, message.get_all(key) ++ else: ++ yield key, message.getheaders(key) + + + def get_httpmessage(headers): +- return http.client.parse_headers(BytesIO(headers)) ++ if six.PY3: ++ return http.client.parse_headers(BytesIO(headers)) ++ msg = HTTPMessage(BytesIO(headers)) ++ msg.fp.seek(0) ++ msg.readheaders() ++ return msg +Index: vcrpy-4.0.2/vcr/stubs/tornado_stubs.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/stubs/tornado_stubs.py ++++ vcrpy-4.0.2/vcr/stubs/tornado_stubs.py +@@ -1,6 +1,8 @@ + """Stubs for tornado HTTP clients""" ++from __future__ import absolute_import ++ + import functools +-from io import BytesIO ++from six import BytesIO + + from tornado import httputil + from tornado.httpclient import HTTPResponse +Index: vcrpy-4.0.2/vcr/util.py +=================================================================== +--- vcrpy-4.0.2.orig/vcr/util.py ++++ vcrpy-4.0.2/vcr/util.py +@@ -107,12 +107,12 @@ def auto_decorate(decorator, predicate=l + + class DecorateAll(type): + def __setattr__(cls, attribute, value): +- return super().__setattr__(attribute, maybe_decorate(attribute, value)) ++ return super(DecorateAll, cls).__setattr__(attribute, maybe_decorate(attribute, value)) + + def __new__(cls, name, bases, attributes_dict): + new_attributes_dict = { + attribute: maybe_decorate(attribute, value) for attribute, value in attributes_dict.items() + } +- return super().__new__(cls, name, bases, new_attributes_dict) ++ return super(DecorateAll, cls).__new__(cls, name, bases, new_attributes_dict) + + return DecorateAll diff --git a/python-vcrpy.changes b/python-vcrpy.changes index 038c6a6..51d694f 100644 --- a/python-vcrpy.changes +++ b/python-vcrpy.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Mon Feb 24 09:14:21 UTC 2020 - Marketa Calabkova + +- Added patch 0001-Revert-v4.0.x-Remove-legacy-python-and-add-python3.8.patch + * Enable python2 again since it breaks many packages. + ------------------------------------------------------------------- Fri Feb 7 14:58:03 UTC 2020 - Marketa Calabkova diff --git a/python-vcrpy.spec b/python-vcrpy.spec index 5b79786..3d90b66 100644 --- a/python-vcrpy.spec +++ b/python-vcrpy.spec @@ -18,7 +18,6 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} -%define skip_python2 1 Name: python-vcrpy Version: 4.0.2 Release: 0 @@ -27,20 +26,31 @@ License: MIT Group: Development/Languages/Python URL: https://github.com/kevin1024/vcrpy Source: https://files.pythonhosted.org/packages/source/v/vcrpy/vcrpy-%{version}.tar.gz +# Enable Python 2 again. Drop as soon as Python 2 will be dropped from Factory. +Patch0: 0001-Revert-v4.0.x-Remove-legacy-python-and-add-python3.8.patch BuildRequires: %{python_module PyYAML} BuildRequires: %{python_module pytest-httpbin} BuildRequires: %{python_module pytest} BuildRequires: %{python_module setuptools} BuildRequires: %{python_module six >= 1.5} BuildRequires: %{python_module wrapt} -BuildRequires: %{python_module yarl} BuildRequires: fdupes BuildRequires: python-rpm-macros +BuildRequires: python2-contextlib2 +BuildRequires: python2-mock +BuildRequires: python3-yarl Requires: python-PyYAML Requires: python-six >= 1.5 Requires: python-wrapt Requires: python-yarl BuildArch: noarch +%ifpython2 +Requires: python2-contextlib2 +Requires: python2-mock +%endif +%ifpython3 +Requires: python3-yarl +%endif %python_subpackages %description @@ -51,6 +61,7 @@ This is a Python version of Ruby's VCR library. %prep %setup -q -n vcrpy-%{version} +%patch0 -p1 # online integration tests rm -r tests/integration