Repository: pact-foundation/pact-python

Issue:
Interactions not cleared when error in test
### Have you read the Contributing Guidelines on issues?

- [ ] I have read the [Contributing Guidelines on issues](https://github.com/pact-foundation/pact-python/main/CONTRIBUTING.md#issues).

### Prerequisites

- [X] I'm using the latest version of `pact-python`.
- [ ] I have read the console error message carefully (if applicable).

### Description

I have two tests with the same pact. When the first one raise an exception "verify" is not called and interactions are not cleared. When next test runs it sees other tests interactions and fails. When tests run in different order then there is no dependency issue.

### Reproducible demo

https://gist.github.com/dryobates/2a5b3028fc7f92dca23830b3ec0be225

### Steps to reproduce

pytest test_failing_pact_dependency.py

### Expected behavior

There should be no dependency between two tests.

### Actual behavior

Currently when one test raise an exception, the other test also fails but should not.

### Your environment

- Pact Python version used: master branch and 1.7.0
- OS: ArchLinux


### Self-service

- [X] I'd be willing to fix this bug myself.

Discussion:

Patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1eb9ad5..8ec20af 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -45,7 +45,7 @@ jobs:
           hatch build --target sdist
 
       - name: Upload sdist
-        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4
+        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4
         with:
           name: wheels-sdist
           path: ./dist/*.tar.*
@@ -80,7 +80,7 @@ jobs:
           CIBW_ARCHS: ${{ matrix.archs }}
 
       - name: Upload wheels
-        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4
+        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4
         with:
           name: wheels-${{ matrix.os }}-${{ matrix.archs }}
           path: ./wheelhouse/*.whl
@@ -122,7 +122,7 @@ jobs:
           CIBW_ARCHS: ${{ matrix.archs }}
 
       - name: Upload wheels
-        uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4
+        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4
         with:
           name: wheels-${{ matrix.os }}-${{ matrix.archs }}
           path: ./wheelhouse/*.whl
@@ -145,7 +145,7 @@ jobs:
         with:
           python-version: ${{ env.STABLE_PYTHON_VERSION }}
 
-      - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4
+      - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4
         with:
           path: wheelhouse
 
@@ -166,7 +166,7 @@ jobs:
       id-token: write
 
     steps:
-      - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4
+      - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4
         with:
           path: wheels
 
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 1ce73ba..42f703f 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -49,7 +49,7 @@ repos:
         exclude: ^(pact|tests)/(?!v3/).*\.py$
 
   - repo: https://github.com/commitizen-tools/commitizen
-    rev: v3.13.0
+    rev: v3.14.1
     hooks:
       - id: commitizen
         stages: [commit-msg]
diff --git a/Dockerfile.ubuntu b/Dockerfile.ubuntu
index 7c31ccd..5d77228 100644
--- a/Dockerfile.ubuntu
+++ b/Dockerfile.ubuntu
@@ -1,4 +1,4 @@
-FROM ubuntu:22.04@sha256:e6173d4dc55e76b87c4af8db8821b1feae4146dd47341e4d431118c7dd060a74
+FROM ubuntu:22.04@sha256:e9569c25505f33ff72e88b2990887c9dcf230f23259da296eb814fc2b41af999
 ENV DEBIAN_FRONTEND=noninteractive
 ARG PYTHON_VERSION 3.9
 
diff --git a/pact/pact.py b/pact/pact.py
index c03e02a..5906a83 100644
--- a/pact/pact.py
+++ b/pact/pact.py
@@ -383,6 +383,7 @@ class Pact(Broker):
         Calls the mock service to verify that all interactions occurred as
         expected, and has it write out the contracts to disk.
         """
+        self._interactions = []
         if (exc_type, exc_val, exc_tb) != (None, None, None):
             return
 


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5286638..15d2bcc 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -56,7 +56,7 @@ jobs:
       - name: Upload coverage
         # TODO: Configure code coverage monitoring
         if: false && matrix.python-version == env.STABLE_PYTHON_VERSION && matrix.os == 'ubuntu-latest'
-        uses: codecov/codecov-action@f30e4959ba63075080d4f7f90cacc18d9f3fafd7 # v4
+        uses: codecov/codecov-action@e0b68c6749509c5f83f984dd99a76a1c1a231044 # v4
         with:
           token: ${{ secrets.CODECOV_TOKEN }}
 
@@ -78,7 +78,7 @@ jobs:
 
     services:
       broker:
-        image: pactfoundation/pact-broker:latest@sha256:9cdd475459ee608b8ab4c32ad72e7aa9236bc5072c123fe689bdc3f44e1ea8dc
+        image: pactfoundation/pact-broker:latest@sha256:a341c6af670704b3d0a20a15fcefba62850d915eb9c9dde5e3334879a4541a54
         ports:
           - "9292:9292"
         env:
diff --git a/tests/test_pact.py b/tests/test_pact.py
index 76e1e70..7316f1c 100644
--- a/tests/test_pact.py
+++ b/tests/test_pact.py
@@ -562,6 +562,22 @@ class PactContextManagerTestCase(PactTestCase):
         self.mock_setup.assert_called_once_with(pact)
         self.assertFalse(self.mock_verify.called)
 
+    def test_does_not_leave_interactions_after_exception(self):
+        pact = Pact(self.consumer, self.provider)
+        (pact
+         .given('I am creating a new pact using the Pact class')
+         .upon_receiving('a specific request to the server')
+         .with_request('GET', '/path')
+         .will_respond_with(200, body='success'))
+        with self.assertRaises(RuntimeError):
+            with pact:
+                raise RuntimeError
+
+        assert pact._interactions == []
+
+
+
+
 
 class PactContextManagerSetupTestCase(PactTestCase):
     def test_definition_without_description(self):