github kevin1024/vcrpy v9.0.0

latest releases: v9.2.0, v9.1.0
3 hours ago

Upgrading from 8.x

9.0.0 has five changes that can affect existing test suites:

  1. Python 3.11+ is required. Python 3.10 reached its end of life on 2026-10-01 (#1061). On 3.10, pip keeps installing 8.x.
  2. New CannotOverwriteExistingCassetteException message. If your code or tests match on the message text (e.g. "Can't overwrite existing cassette"), update them. The exception class and its cassette and failed_request attributes are unchanged, and a new reason attribute ("cassette_not_found", "already_played", "no_match" or "nothing_similar") is a sturdier thing to check (#1076).
  3. filter_post_data_parameters now filters request bodies for every HTTP method, not just POST (#328, #1004). Requests are filtered before they're matched, so if you match on body, re-record cassettes that have unfiltered PUT/PATCH/DELETE bodies. vcr.filters.replace_post_data_parameters itself still only filters POST; use the new replace_body_parameters for any method.
  4. aiohttp error responses are recorded when raise_for_status is used (on the session or the request), and replaying them raises like aiohttp does (#635, #925). Before, they weren't recorded, and a replayed error response didn't raise.
  5. urllib3 (and requests) responses have HTTPHeaderDict headers, as they do without vcrpy, instead of an HTTPMessage (#841, #1015).

What's Changed

Much better errors when a request isn't in the cassette

The CannotOverwriteExistingCassetteException message now says what actually went wrong, shows how the closest recorded requests differ, and suggests how to fix it (#1076). It fixes:

  • "Can't overwrite existing cassette" when the cassette doesn't exist (#838)
  • no explanation or fix when a request is made more times than it was recorded (#516, #673, #929)
  • empty output for body mismatches, which now show a short diff (#840)
  • messages tens of MB long for cassettes with many similar requests, which are now summarized (#837)

For example:

Can't play back this request: it matches 1 recorded interaction, but that has already been played back.
record_mode 'none' doesn't record new requests.

  GET https://example.com/foo

Cassette: tests/cassettes/ex.yaml
  record_mode: none
  match_on: method, scheme, host, port, path, query
  interactions: 1 recorded, 1 played

How to fix:
  * If it's fine for this request to get the same response each time, set
    allow_playback_repeats=True [1].
  * Otherwise record the extra request: run once with record_mode='new_episodes'
    [2].

[1] https://vcrpy.readthedocs.io/en/latest/advanced.html#playback-repeats
[2] https://vcrpy.readthedocs.io/en/latest/usage.html#record-modes

Thanks @philsong4-ai (#1027) and @ChrisJr404 (#1037) for the PRs that started this.

Fixes

  • aiohttp error responses are recorded and replayed when raise_for_status is used (#635, #925). Thanks @andrescollares
  • filter_post_data_parameters filters request bodies for every HTTP method (#328, #1004). Thanks @andrescollares
  • Headers sent more than once (e.g. two Link headers) keep every value in urllib3 and requests responses (#947, #1015). Thanks @Sanjays2402
  • The body matcher no longer crashes when a body doesn't parse as its headers say, e.g. invalid JSON sent as application/json (#1075)

Python support

Full Changelog: v8.5.0...v9.0.0

Don't miss a new vcrpy release

NewReleases is sending notifications on new releases.