diff --git a/vcr/cassette.py b/vcr/cassette.py index 5822afa..107e5d7 100644 --- a/vcr/cassette.py +++ b/vcr/cassette.py @@ -197,6 +197,7 @@ class Cassette: custom_patches=(), inject=False, allow_playback_repeats=False, + drop_unused_requests=False, ): self._persister = persister or FilesystemPersister self._path = path @@ -209,6 +210,7 @@ class Cassette: self.record_mode = record_mode self.custom_patches = custom_patches self.allow_playback_repeats = allow_playback_repeats + self.drop_unused_requests = drop_unused_requests # self.data is the list of (req, resp) tuples self.data = [] @@ -216,6 +218,10 @@ class Cassette: self.dirty = False self.rewound = False + # Subsets of self.data to store old and played interactions + self._old_interactions = [] + self._played_interactions = [] + @property def play_count(self): return sum(self.play_counts.values()) @@ -277,6 +283,7 @@ class Cassette: for index, response in self._responses(request): if self.play_counts[index] == 0 or self.allow_playback_repeats: self.play_counts[index] += 1 + self._played_interactions.append((request, response)) return response # The cassette doesn't contain the request asked for. raise UnhandledHTTPRequestError( @@ -337,10 +344,27 @@ class Cassette: return final_best_matches + def _new_interactions(self): + """List of new HTTP interactions (request/response tuples)""" + new_interactions = [] + for request, response in self.data: + if all(not requests_match(request, old_request, self._match_on) + for old_request, _ in self._old_interactions): + new_interactions.append((request, response)) + return new_interactions + def _as_dict(self): - return {"requests": self.requests, "responses": self.responses} + requests = self.requests + responses = self.responses + if self.drop_unused_requests: + interactions = self._played_interactions + self._new_interactions() + requests = [request for request, _ in interactions] + responses = [response for _, response in interactions] + return {"requests": requests, "responses": responses} def _save(self, force=False): + if (len(self._played_interactions) < len(self._old_interactions)): + force = True if force or self.dirty: self._persister.save_cassette(self._path, self._as_dict(), serializer=self._serializer) self.dirty = False @@ -350,6 +374,7 @@ class Cassette: requests, responses = self._persister.load_cassette(self._path, serializer=self._serializer) for request, response in zip(requests, responses): self.append(request, response) + self._old_interactions.append((request, response)) self.dirty = False self.rewound = True except ValueError: diff --git a/vcr/config.py b/vcr/config.py index a991c95..7139bd3 100644 --- a/vcr/config.py +++ b/vcr/config.py @@ -50,6 +50,7 @@ class VCR: func_path_generator=None, decode_compressed_response=False, record_on_exception=True, + drop_unused_requests=False, ): self.serializer = serializer self.match_on = match_on @@ -83,6 +84,7 @@ class VCR: self.decode_compressed_response = decode_compressed_response self.record_on_exception = record_on_exception self._custom_patches = tuple(custom_patches) + self.drop_unused_requests = drop_unused_requests def _get_serializer(self, serializer_name): try: @@ -153,6 +155,7 @@ class VCR: "func_path_generator": func_path_generator, "allow_playback_repeats": kwargs.get("allow_playback_repeats", False), "record_on_exception": record_on_exception, + "drop_unused_requests": kwargs.get("drop_unused_requests", self.drop_unused_requests), } path = kwargs.get("path") if path: