1
0
mirror of https://github.com/kevin1024/vcrpy.git synced 2025-12-08 16:53:23 +00:00

Drop support to python 3.7

This commit is contained in:
Jair Henrique
2023-05-10 18:21:29 -03:00
parent 92ca5a102c
commit b827cbe2da
30 changed files with 68 additions and 103 deletions

View File

@@ -13,7 +13,7 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "pypy-3.8"] python-version: ["3.8", "3.9", "3.10", "3.11", "pypy-3.8"]
steps: steps:
- uses: actions/checkout@v3.5.2 - uses: actions/checkout@v3.5.2

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# #
# vcrpy documentation build configuration file, created by # vcrpy documentation build configuration file, created by
# sphinx-quickstart on Sun Sep 13 11:18:00 2015. # sphinx-quickstart on Sun Sep 13 11:18:00 2015.

View File

@@ -96,11 +96,11 @@ The test suite is pretty big and slow, but you can tell tox to only run specific
tox -e {pyNN}-{HTTP_LIBRARY} -- <pytest flags passed through> tox -e {pyNN}-{HTTP_LIBRARY} -- <pytest flags passed through>
tox -e py37-requests -- -v -k "'test_status_code or test_gzip'" tox -e py38-requests -- -v -k "'test_status_code or test_gzip'"
tox -e py37-requests -- -v --last-failed tox -e py38-requests -- -v --last-failed
This will run only tests that look like ``test_status_code`` or This will run only tests that look like ``test_status_code`` or
``test_gzip`` in the test suite, and only in the python 3.7 environment ``test_gzip`` in the test suite, and only in the python 3.8 environment
that has ``requests`` installed. that has ``requests`` installed.
Also, in order for the boto tests to run, you will need an AWS key. Also, in order for the boto tests to run, you will need an AWS key.
@@ -130,17 +130,17 @@ in this example::
pip3 install tox tox-pyenv pip3 install tox tox-pyenv
# Install supported versions (at time of writing), this does not activate them # Install supported versions (at time of writing), this does not activate them
pyenv install 3.7.5 3.8.0 pypy3.8 pyenv install 3.8.0 pypy3.8
# This activates them # This activates them
pyenv local 3.7.5 3.8.0 pypy3.8 pyenv local 3.8.0 pypy3.8
# Run the whole test suite # Run the whole test suite
tox tox
# Run the whole test suite or just part of it # Run the whole test suite or just part of it
tox -e lint tox -e lint
tox -e py37-requests tox -e py38-requests
Troubleshooting on MacOSX Troubleshooting on MacOSX

View File

@@ -9,7 +9,7 @@ with pip::
Compatibility Compatibility
------------- -------------
VCR.py supports Python 3.7+, and `pypy <http://pypy.org>`__. VCR.py supports Python 3.8+, and `pypy <http://pypy.org>`__.
The following HTTP libraries are supported: The following HTTP libraries are supported:

View File

@@ -8,7 +8,7 @@ import sys
from setuptools import find_packages, setup from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand from setuptools.command.test import test as TestCommand
long_description = open("README.rst", "r").read() long_description = open("README.rst").read()
here = os.path.abspath(os.path.dirname(__file__)) here = os.path.abspath(os.path.dirname(__file__))
@@ -85,7 +85,7 @@ setup(
author_email="me@kevinmccarthy.org", author_email="me@kevinmccarthy.org",
url="https://github.com/kevin1024/vcrpy", url="https://github.com/kevin1024/vcrpy",
packages=find_packages(exclude=["tests*"]), packages=find_packages(exclude=["tests*"]),
python_requires=">=3.7", python_requires=">=3.8",
install_requires=install_requires, install_requires=install_requires,
license="MIT", license="MIT",
tests_require=tests_require, tests_require=tests_require,
@@ -95,7 +95,6 @@ setup(
"Intended Audience :: Developers", "Intended Audience :: Developers",
"Programming Language :: Python", "Programming Language :: Python",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.10",

View File

@@ -151,7 +151,7 @@ def test_post(tmpdir, body, caplog, mockbin_request_url):
( (
log log
for log in caplog.records for log in caplog.records
if log.getMessage() == "<Request (POST) {}> not in cassette, sending to real server".format(url) if log.getMessage() == f"<Request (POST) {url}> not in cassette, sending to real server"
), ),
None, None,
), "Log message not found." ), "Log message not found."

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Basic tests for cassettes""" """Basic tests for cassettes"""
# External imports # External imports

View File

@@ -20,12 +20,12 @@ except ImportError:
# https://github.com/boto/botocore/pull/1495 # https://github.com/boto/botocore/pull/1495
boto3_skip_vendored_requests = pytest.mark.skipif( boto3_skip_vendored_requests = pytest.mark.skipif(
botocore_awsrequest, botocore_awsrequest,
reason="botocore version {ver} does not use vendored requests anymore.".format(ver=botocore.__version__), reason=f"botocore version {botocore.__version__} does not use vendored requests anymore.",
) )
boto3_skip_awsrequest = pytest.mark.skipif( boto3_skip_awsrequest = pytest.mark.skipif(
not botocore_awsrequest, not botocore_awsrequest,
reason="botocore version {ver} still uses vendored requests.".format(ver=botocore.__version__), reason=f"botocore version {botocore.__version__} still uses vendored requests.",
) )
IAM_USER_NAME = "vcrpy" IAM_USER_NAME = "vcrpy"

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Basic tests about save behavior""" """Basic tests about save behavior"""
# External imports # External imports

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Integration tests with httplib2""" """Integration tests with httplib2"""
from urllib.parse import urlencode from urllib.parse import urlencode

View File

@@ -28,9 +28,9 @@ def test_ignore_localhost(tmpdir, httpbin):
with overridden_dns({"httpbin.org": "127.0.0.1"}): with overridden_dns({"httpbin.org": "127.0.0.1"}):
cass_file = str(tmpdir.join("filter_qs.yaml")) cass_file = str(tmpdir.join("filter_qs.yaml"))
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass: with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
urlopen("http://localhost:{}/".format(httpbin.port)) urlopen(f"http://localhost:{httpbin.port}/")
assert len(cass) == 0 assert len(cass) == 0
urlopen("http://httpbin.org:{}/".format(httpbin.port)) urlopen(f"http://httpbin.org:{httpbin.port}/")
assert len(cass) == 1 assert len(cass) == 1
@@ -38,9 +38,9 @@ def test_ignore_httpbin(tmpdir, httpbin):
with overridden_dns({"httpbin.org": "127.0.0.1"}): with overridden_dns({"httpbin.org": "127.0.0.1"}):
cass_file = str(tmpdir.join("filter_qs.yaml")) cass_file = str(tmpdir.join("filter_qs.yaml"))
with vcr.use_cassette(cass_file, ignore_hosts=["httpbin.org"]) as cass: with vcr.use_cassette(cass_file, ignore_hosts=["httpbin.org"]) as cass:
urlopen("http://httpbin.org:{}/".format(httpbin.port)) urlopen(f"http://httpbin.org:{httpbin.port}/")
assert len(cass) == 0 assert len(cass) == 0
urlopen("http://localhost:{}/".format(httpbin.port)) urlopen(f"http://localhost:{httpbin.port}/")
assert len(cass) == 1 assert len(cass) == 1
@@ -48,8 +48,8 @@ def test_ignore_localhost_and_httpbin(tmpdir, httpbin):
with overridden_dns({"httpbin.org": "127.0.0.1"}): with overridden_dns({"httpbin.org": "127.0.0.1"}):
cass_file = str(tmpdir.join("filter_qs.yaml")) cass_file = str(tmpdir.join("filter_qs.yaml"))
with vcr.use_cassette(cass_file, ignore_hosts=["httpbin.org"], ignore_localhost=True) as cass: with vcr.use_cassette(cass_file, ignore_hosts=["httpbin.org"], ignore_localhost=True) as cass:
urlopen("http://httpbin.org:{}".format(httpbin.port)) urlopen(f"http://httpbin.org:{httpbin.port}")
urlopen("http://localhost:{}".format(httpbin.port)) urlopen(f"http://localhost:{httpbin.port}")
assert len(cass) == 0 assert len(cass) == 0
@@ -57,12 +57,12 @@ def test_ignore_localhost_twice(tmpdir, httpbin):
with overridden_dns({"httpbin.org": "127.0.0.1"}): with overridden_dns({"httpbin.org": "127.0.0.1"}):
cass_file = str(tmpdir.join("filter_qs.yaml")) cass_file = str(tmpdir.join("filter_qs.yaml"))
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass: with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
urlopen("http://localhost:{}".format(httpbin.port)) urlopen(f"http://localhost:{httpbin.port}")
assert len(cass) == 0 assert len(cass) == 0
urlopen("http://httpbin.org:{}".format(httpbin.port)) urlopen(f"http://httpbin.org:{httpbin.port}")
assert len(cass) == 1 assert len(cass) == 1
with vcr.use_cassette(cass_file, ignore_localhost=True) as cass: with vcr.use_cassette(cass_file, ignore_localhost=True) as cass:
assert len(cass) == 1 assert len(cass) == 1
urlopen("http://localhost:{}".format(httpbin.port)) urlopen(f"http://localhost:{httpbin.port}")
urlopen("http://httpbin.org:{}".format(httpbin.port)) urlopen(f"http://httpbin.org:{httpbin.port}")
assert len(cass) == 1 assert len(cass) == 1

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Test using a proxy.""" """Test using a proxy."""
import http.server import http.server

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Tests for cassettes with custom persistence""" """Tests for cassettes with custom persistence"""
# External imports # External imports

View File

@@ -114,22 +114,6 @@ def test_post_chunked_binary(tmpdir, httpbin):
assert req1 == req2 assert req1 == req2
@pytest.mark.skipif("sys.version_info >= (3, 6)", strict=True, raises=ConnectionError)
def test_post_chunked_binary_secure(tmpdir, httpbin_secure):
"""Ensure that we can send chunked binary without breaking while trying to concatenate bytes with str."""
data1 = iter([b"data", b"to", b"send"])
data2 = iter([b"data", b"to", b"send"])
url = httpbin_secure.url + "/post"
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
req1 = requests.post(url, data1).content
print(req1)
with vcr.use_cassette(str(tmpdir.join("requests.yaml"))):
req2 = requests.post(url, data2).content
assert req1 == req2
def test_redirects(tmpdir, httpbin_both): def test_redirects(tmpdir, httpbin_both):
"""Ensure that we can handle redirects""" """Ensure that we can handle redirects"""
url = httpbin_both + "/redirect-to?url=bytes/1024" url = httpbin_both + "/redirect-to?url=bytes/1024"

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Test requests' interaction with vcr""" """Test requests' interaction with vcr"""
import json import json

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Integration tests with urllib2""" """Integration tests with urllib2"""
import ssl import ssl

View File

@@ -17,9 +17,9 @@ def test_try_migrate_with_json(tmpdir):
cassette = tmpdir.join("cassette.json").strpath cassette = tmpdir.join("cassette.json").strpath
shutil.copy("tests/fixtures/migration/old_cassette.json", cassette) shutil.copy("tests/fixtures/migration/old_cassette.json", cassette)
assert vcr.migration.try_migrate(cassette) assert vcr.migration.try_migrate(cassette)
with open("tests/fixtures/migration/new_cassette.json", "r") as f: with open("tests/fixtures/migration/new_cassette.json") as f:
expected_json = json.load(f) expected_json = json.load(f)
with open(cassette, "r") as f: with open(cassette) as f:
actual_json = json.load(f) actual_json = json.load(f)
assert actual_json == expected_json assert actual_json == expected_json
@@ -28,9 +28,9 @@ def test_try_migrate_with_yaml(tmpdir):
cassette = tmpdir.join("cassette.yaml").strpath cassette = tmpdir.join("cassette.yaml").strpath
shutil.copy("tests/fixtures/migration/old_cassette.yaml", cassette) shutil.copy("tests/fixtures/migration/old_cassette.yaml", cassette)
assert vcr.migration.try_migrate(cassette) assert vcr.migration.try_migrate(cassette)
with open("tests/fixtures/migration/new_cassette.yaml", "r") as f: with open("tests/fixtures/migration/new_cassette.yaml") as f:
expected_yaml = yaml.load(f, Loader=Loader) expected_yaml = yaml.load(f, Loader=Loader)
with open(cassette, "r") as f: with open(cassette) as f:
actual_yaml = yaml.load(f, Loader=Loader) actual_yaml = yaml.load(f, Loader=Loader)
assert actual_yaml == expected_yaml assert actual_yaml == expected_yaml

View File

@@ -1,4 +1,3 @@
# coding: UTF-8
import io import io
from vcr.stubs import VCRHTTPResponse from vcr.stubs import VCRHTTPResponse

View File

@@ -1,4 +1,3 @@
# -*- encoding: utf-8 -*-
from unittest import mock from unittest import mock
import pytest import pytest
@@ -9,24 +8,24 @@ from vcr.serializers import compat, jsonserializer, yamlserializer
def test_deserialize_old_yaml_cassette(): def test_deserialize_old_yaml_cassette():
with open("tests/fixtures/migration/old_cassette.yaml", "r") as f: with open("tests/fixtures/migration/old_cassette.yaml") as f:
with pytest.raises(ValueError): with pytest.raises(ValueError):
deserialize(f.read(), yamlserializer) deserialize(f.read(), yamlserializer)
def test_deserialize_old_json_cassette(): def test_deserialize_old_json_cassette():
with open("tests/fixtures/migration/old_cassette.json", "r") as f: with open("tests/fixtures/migration/old_cassette.json") as f:
with pytest.raises(ValueError): with pytest.raises(ValueError):
deserialize(f.read(), jsonserializer) deserialize(f.read(), jsonserializer)
def test_deserialize_new_yaml_cassette(): def test_deserialize_new_yaml_cassette():
with open("tests/fixtures/migration/new_cassette.yaml", "r") as f: with open("tests/fixtures/migration/new_cassette.yaml") as f:
deserialize(f.read(), yamlserializer) deserialize(f.read(), yamlserializer)
def test_deserialize_new_json_cassette(): def test_deserialize_new_json_cassette():
with open("tests/fixtures/migration/new_cassette.json", "r") as f: with open("tests/fixtures/migration/new_cassette.json") as f:
deserialize(f.read(), jsonserializer) deserialize(f.read(), jsonserializer)

18
tox.ini
View File

@@ -3,7 +3,7 @@ skip_missing_interpreters=true
envlist = envlist =
cov-clean, cov-clean,
lint, lint,
{py37,py38,py39,py310,py311}-{requests-urllib3-1,httplib2,urllib3-1,tornado4,boto3,aiohttp,httpx}, {py38,py39,py310,py311}-{requests-urllib3-1,httplib2,urllib3-1,tornado4,boto3,aiohttp,httpx},
{py310,py311}-{requests-urllib3-2,urllib3-2}, {py310,py311}-{requests-urllib3-2,urllib3-2},
{pypy3}-{requests-urllib3-1,httplib2,urllib3-1,tornado4,boto3}, {pypy3}-{requests-urllib3-1,httplib2,urllib3-1,tornado4,boto3},
{py310}-httpx019, {py310}-httpx019,
@@ -12,7 +12,6 @@ envlist =
[gh-actions] [gh-actions]
python = python =
3.7: py37
3.8: py38 3.8: py38
3.9: py39 3.9: py39
3.10: py310, lint 3.10: py310, lint
@@ -66,9 +65,9 @@ deps =
# In other circumstances, we might want to generate a PDF or an ebook # In other circumstances, we might want to generate a PDF or an ebook
commands = commands =
sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html 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 # We use Python 3.8. 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. # the testenv, but "docs" does not give useful clues so we have to be explicit.
basepython = python3.7 basepython = python3.8
[testenv] [testenv]
# Need to use develop install so that paths # Need to use develop install so that paths
@@ -94,15 +93,14 @@ deps =
aiohttp: pytest-asyncio aiohttp: pytest-asyncio
aiohttp: pytest-aiohttp aiohttp: pytest-aiohttp
httpx: httpx httpx: httpx
{py37,py38,py39,py310}-{httpx}: httpx {py38,py39,py310}-{httpx}: httpx
{py37,py38,py39,py310}-{httpx}: pytest-asyncio {py38,py39,py310}-{httpx}: pytest-asyncio
httpx: httpx>0.19 httpx: httpx>0.19
# httpx==0.19 is the latest version that supports allow_redirects, newer versions use follow_redirects
httpx019: httpx==0.19 httpx019: httpx==0.19
{py37,py38,py39,py310}-{httpx}: pytest-asyncio {py38,py39,py310}-{httpx}: pytest-asyncio
depends = depends =
lint,{py37,py38,py39,py310,py311,pypy3}-{requests-urllib3-1,httplib2,urllib3-1,tornado4,boto3},{py310,py311}-{requests-urllib3-2,urllib3-2},{py37,py38,py39,py310,py311}-{aiohttp},{py37,py38,py39,py310,py311}-{httpx}: cov-clean lint,{py38,py39,py310,py311,pypy3}-{requests-urllib3-1,httplib2,urllib3-1,tornado4,boto3},{py310,py311}-{requests-urllib3-2,urllib3-2},{py38,py39,py310,py311}-{aiohttp},{py38,py39,py310,py311}-{httpx}: cov-clean
cov-report: lint,{py37,py38,py39,py310,py311,pypy3}-{requests-urllib3-1,httplib2,urllib3-1,tornado4,boto3},{py310,py311}-{requests-urllib3-2,urllib3-2},{py37,py38,py39,py310,py311}-{aiohttp} cov-report: lint,{py38,py39,py310,py311,pypy3}-{requests-urllib3-1,httplib2,urllib3-1,tornado4,boto3},{py310,py311}-{requests-urllib3-2,urllib3-2},{py38,py39,py310,py311}-{aiohttp}
passenv = passenv =
AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID
AWS_DEFAULT_REGION AWS_DEFAULT_REGION

View File

@@ -280,7 +280,7 @@ class Cassette:
return response return response
# The cassette doesn't contain the request asked for. # The cassette doesn't contain the request asked for.
raise UnhandledHTTPRequestError( raise UnhandledHTTPRequestError(
"The cassette (%r) doesn't contain the request (%r) asked for" % (self._path, request) f"The cassette ({self._path!r}) doesn't contain the request ({request!r}) asked for"
) )
def responses_of(self, request): def responses_of(self, request):
@@ -295,7 +295,7 @@ class Cassette:
return responses return responses
# The cassette doesn't contain the request asked for. # The cassette doesn't contain the request asked for.
raise UnhandledHTTPRequestError( raise UnhandledHTTPRequestError(
"The cassette (%r) doesn't contain the request (%r) asked for" % (self._path, request) f"The cassette ({self._path!r}) doesn't contain the request ({request!r}) asked for"
) )
def rewind(self): def rewind(self):
@@ -356,7 +356,7 @@ class Cassette:
pass pass
def __str__(self): def __str__(self):
return "<Cassette containing {} recorded response(s)>".format(len(self)) return f"<Cassette containing {len(self)} recorded response(s)>"
def __len__(self): def __len__(self):
"""Return the number of request,response pairs stored in here""" """Return the number of request,response pairs stored in here"""

View File

@@ -88,7 +88,7 @@ class VCR:
try: try:
serializer = self.serializers[serializer_name] serializer = self.serializers[serializer_name]
except KeyError: except KeyError:
raise KeyError("Serializer {} doesn't exist or isn't registered".format(serializer_name)) raise KeyError(f"Serializer {serializer_name} doesn't exist or isn't registered")
return serializer return serializer
def _get_matchers(self, matcher_names): def _get_matchers(self, matcher_names):
@@ -97,7 +97,7 @@ class VCR:
for m in matcher_names: for m in matcher_names:
matchers.append(self.matchers[m]) matchers.append(self.matchers[m])
except KeyError: except KeyError:
raise KeyError("Matcher {} doesn't exist or isn't registered".format(m)) raise KeyError(f"Matcher {m} doesn't exist or isn't registered")
return matchers return matchers
def use_cassette(self, path=None, **kwargs): def use_cassette(self, path=None, **kwargs):

View File

@@ -10,37 +10,37 @@ log = logging.getLogger(__name__)
def method(r1, r2): def method(r1, r2):
if r1.method != r2.method: if r1.method != r2.method:
raise AssertionError("{} != {}".format(r1.method, r2.method)) raise AssertionError(f"{r1.method} != {r2.method}")
def uri(r1, r2): def uri(r1, r2):
if r1.uri != r2.uri: if r1.uri != r2.uri:
raise AssertionError("{} != {}".format(r1.uri, r2.uri)) raise AssertionError(f"{r1.uri} != {r2.uri}")
def host(r1, r2): def host(r1, r2):
if r1.host != r2.host: if r1.host != r2.host:
raise AssertionError("{} != {}".format(r1.host, r2.host)) raise AssertionError(f"{r1.host} != {r2.host}")
def scheme(r1, r2): def scheme(r1, r2):
if r1.scheme != r2.scheme: if r1.scheme != r2.scheme:
raise AssertionError("{} != {}".format(r1.scheme, r2.scheme)) raise AssertionError(f"{r1.scheme} != {r2.scheme}")
def port(r1, r2): def port(r1, r2):
if r1.port != r2.port: if r1.port != r2.port:
raise AssertionError("{} != {}".format(r1.port, r2.port)) raise AssertionError(f"{r1.port} != {r2.port}")
def path(r1, r2): def path(r1, r2):
if r1.path != r2.path: if r1.path != r2.path:
raise AssertionError("{} != {}".format(r1.path, r2.path)) raise AssertionError(f"{r1.path} != {r2.path}")
def query(r1, r2): def query(r1, r2):
if r1.query != r2.query: if r1.query != r2.query:
raise AssertionError("{} != {}".format(r1.query, r2.query)) raise AssertionError(f"{r1.query} != {r2.query}")
def raw_body(r1, r2): def raw_body(r1, r2):
@@ -59,7 +59,7 @@ def body(r1, r2):
def headers(r1, r2): def headers(r1, r2):
if r1.headers != r2.headers: if r1.headers != r2.headers:
raise AssertionError("{} != {}".format(r1.headers, r2.headers)) raise AssertionError(f"{r1.headers} != {r2.headers}")
def _header_checker(value, header="Content-Type"): def _header_checker(value, header="Content-Type"):
@@ -107,7 +107,7 @@ def _get_transformer(request):
def requests_match(r1, r2, matchers): def requests_match(r1, r2, matchers):
successes, failures = get_matchers_results(r1, r2, matchers) successes, failures = get_matchers_results(r1, r2, matchers)
if failures: if failures:
log.debug("Requests {} and {} differ.\n" "Failure details:\n" "{}".format(r1, r2, failures)) log.debug(f"Requests {r1} and {r2} differ.\nFailure details:\n{failures}")
return len(failures) == 0 return len(failures) == 0

View File

@@ -55,7 +55,7 @@ def build_uri(**parts):
port = parts["port"] port = parts["port"]
scheme = parts["protocol"] scheme = parts["protocol"]
default_port = {"https": 443, "http": 80}[scheme] default_port = {"https": 443, "http": 80}[scheme]
parts["port"] = ":{}".format(port) if port != default_port else "" parts["port"] = f":{port}" if port != default_port else ""
return "{protocol}://{host}{port}{path}".format(**parts) return "{protocol}://{host}{port}{path}".format(**parts)
@@ -118,7 +118,7 @@ def migrate(file_path, migration_fn):
# because we assume that original files can be reverted # because we assume that original files can be reverted
# we will try to copy the content. (os.rename not needed) # we will try to copy the content. (os.rename not needed)
with tempfile.TemporaryFile(mode="w+") as out_fp: with tempfile.TemporaryFile(mode="w+") as out_fp:
with open(file_path, "r") as in_fp: with open(file_path) as in_fp:
if not migration_fn(in_fp, out_fp): if not migration_fn(in_fp, out_fp):
return False return False
with open(file_path, "w") as in_fp: with open(file_path, "w") as in_fp:
@@ -150,7 +150,7 @@ def main():
for file_path in files: for file_path in files:
migrated = try_migrate(file_path) migrated = try_migrate(file_path)
status = "OK" if migrated else "FAIL" status = "OK" if migrated else "FAIL"
sys.stderr.write("[{}] {}\n".format(status, file_path)) sys.stderr.write(f"[{status}] {file_path}\n")
sys.stderr.write("Done.\n") sys.stderr.write("Done.\n")

View File

@@ -186,9 +186,7 @@ class CassettePatcherBuilder:
bases = (base_class,) bases = (base_class,)
if not issubclass(base_class, object): # Check for old style class if not issubclass(base_class, object): # Check for old style class
bases += (object,) bases += (object,)
return type( return type(f"{base_class.__name__}{self._cassette._path}", bases, dict(cassette=self._cassette))
"{}{}".format(base_class.__name__, self._cassette._path), bases, dict(cassette=self._cassette)
)
@_build_patchers_from_mock_triples_decorator @_build_patchers_from_mock_triples_decorator
def _httplib(self): def _httplib(self):

View File

@@ -90,7 +90,7 @@ class Request:
return self.scheme return self.scheme
def __str__(self): def __str__(self):
return "<Request ({}) {}>".format(self.method, self.uri) return f"<Request ({self.method}) {self.uri}>"
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()

View File

@@ -188,26 +188,26 @@ class VCRConnection:
""" """
port = self.real_connection.port port = self.real_connection.port
default_port = {"https": 443, "http": 80}[self._protocol] default_port = {"https": 443, "http": 80}[self._protocol]
return ":{}".format(port) if port != default_port else "" return f":{port}" if port != default_port else ""
def _uri(self, url): def _uri(self, url):
"""Returns request absolute URI""" """Returns request absolute URI"""
if url and not url.startswith("/"): if url and not url.startswith("/"):
# Then this must be a proxy request. # Then this must be a proxy request.
return url return url
uri = "{}://{}{}{}".format(self._protocol, self.real_connection.host, self._port_postfix(), url) uri = f"{self._protocol}://{self.real_connection.host}{self._port_postfix()}{url}"
log.debug("Absolute URI: %s", uri) log.debug("Absolute URI: %s", uri)
return uri return uri
def _url(self, uri): def _url(self, uri):
"""Returns request selector url from absolute URI""" """Returns request selector url from absolute URI"""
prefix = "{}://{}{}".format(self._protocol, self.real_connection.host, self._port_postfix()) prefix = f"{self._protocol}://{self.real_connection.host}{self._port_postfix()}"
return uri.replace(prefix, "", 1) return uri.replace(prefix, "", 1)
def request(self, method, url, body=None, headers=None, *args, **kwargs): def request(self, method, url, body=None, headers=None, *args, **kwargs):
"""Persist the request metadata in self._vcr_request""" """Persist the request metadata in self._vcr_request"""
self._vcr_request = Request(method=method, uri=self._uri(url), body=body, headers=headers or {}) self._vcr_request = Request(method=method, uri=self._uri(url), body=body, headers=headers or {})
log.debug("Got {}".format(self._vcr_request)) log.debug(f"Got {self._vcr_request}")
# Note: The request may not actually be finished at this point, so # Note: The request may not actually be finished at this point, so
# I'm not sending the actual request until getresponse(). This # I'm not sending the actual request until getresponse(). This
@@ -223,7 +223,7 @@ class VCRConnection:
of putheader() calls. of putheader() calls.
""" """
self._vcr_request = Request(method=method, uri=self._uri(url), body="", headers={}) self._vcr_request = Request(method=method, uri=self._uri(url), body="", headers={})
log.debug("Got {}".format(self._vcr_request)) log.debug(f"Got {self._vcr_request}")
def putheader(self, header, *values): def putheader(self, header, *values):
self._vcr_request.headers[header] = values self._vcr_request.headers[header] = values
@@ -255,7 +255,7 @@ class VCRConnection:
# Check to see if the cassette has a response for this request. If so, # Check to see if the cassette has a response for this request. If so,
# then return it # then return it
if self.cassette.can_play_response_for(self._vcr_request): if self.cassette.can_play_response_for(self._vcr_request):
log.info("Playing response for {} from cassette".format(self._vcr_request)) log.info(f"Playing response for {self._vcr_request} from cassette")
response = self.cassette.play_response(self._vcr_request) response = self.cassette.play_response(self._vcr_request)
return VCRHTTPResponse(response) return VCRHTTPResponse(response)
else: else:
@@ -267,7 +267,7 @@ class VCRConnection:
# Otherwise, we should send the request, then get the response # Otherwise, we should send the request, then get the response
# and return it. # and return it.
log.info("{} not in cassette, sending to real server".format(self._vcr_request)) log.info(f"{self._vcr_request} not in cassette, sending to real server")
# This is imported here to avoid circular import. # This is imported here to avoid circular import.
# TODO(@IvanMalison): Refactor to allow normal import. # TODO(@IvanMalison): Refactor to allow normal import.
from vcr.patch import force_reset from vcr.patch import force_reset

View File

@@ -261,7 +261,7 @@ def vcr_request(cassette, real_request):
vcr_request = Request(method, str(request_url), data, _serialize_headers(headers)) vcr_request = Request(method, str(request_url), data, _serialize_headers(headers))
if cassette.can_play_response_for(vcr_request): if cassette.can_play_response_for(vcr_request):
log.info("Playing response for {} from cassette".format(vcr_request)) log.info(f"Playing response for {vcr_request} from cassette")
response = play_responses(cassette, vcr_request, kwargs) response = play_responses(cassette, vcr_request, kwargs)
for redirect in response.history: for redirect in response.history:
self._cookie_jar.update_cookies(redirect.cookies, redirect.url) self._cookie_jar.update_cookies(redirect.cookies, redirect.url)

View File

@@ -32,7 +32,7 @@ class VCRMixin:
return os.path.join(testdir, "cassettes") return os.path.join(testdir, "cassettes")
def _get_cassette_name(self): def _get_cassette_name(self):
return "{0}.{1}.yaml".format(self.__class__.__name__, self._testMethodName) return f"{self.__class__.__name__}.{self._testMethodName}.yaml"
class VCRTestCase(VCRMixin, unittest.TestCase): class VCRTestCase(VCRMixin, unittest.TestCase):

View File

@@ -1,9 +1,5 @@
import types import types
from collections.abc import Mapping, MutableMapping
try:
from collections.abc import Mapping, MutableMapping
except ImportError:
from collections import Mapping, MutableMapping
# Shamelessly stolen from https://github.com/kennethreitz/requests/blob/master/requests/structures.py # Shamelessly stolen from https://github.com/kennethreitz/requests/blob/master/requests/structures.py