responses: RecursionError with passthru and _real_send override

Describe the bug

When using the responses._real_send = self.r_mock.unbound_on_send() solution described here, I am getting a recursion error.

Additional context

This issue replaces this one

Version of responses

0.23.3

Steps to Reproduce

You can run unittest on this file and get the error 😃

import os
import re
import unittest
import requests

os.environ["ENVIRONMENT"] = "tests"

import responses


def my_function():
    # Send an email
    requests.post("https://example.org")

    # Do something else with the passthru
    requests.post("http://localhost:7700/indexes/test/documents")

    return "OK"


class _TestCase(unittest.TestCase):
    def setUp(self):
        self.r_mock = responses.RequestsMock(assert_all_requests_are_fired=True)
        self.r_mock.start()
        self.r_mock.add_passthru(re.compile(rf"http://localhost:7700.*"))
        responses._real_send = self.r_mock.unbound_on_send()

    def tearDown(self):
        self.r_mock.stop()
        self.r_mock.reset()


class MyTest(_TestCase):

    def test_indexing(self):
        self.r_mock.add(responses.POST, "https://example.org", status=200)
        self.assertEqual("OK", my_function())

Expected Result

The test should run fine

Actual Result

============================= test session starts ==============================
collecting ... collected 1 item

reproduce.py::MyTest::test_indexing 

============================== 1 failed in 0.19s ===============================
FAILED                               [100%]
reproduce.py:34 (MyTest.test_indexing)
self = <reproduce.MyTest testMethod=test_indexing>

    def test_indexing(self):
        self.r_mock.add(responses.POST, "https://example.org", status=200)
>       self.assertEqual("OK", my_function())

reproduce.py:37: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
reproduce.py:16: in my_function
    requests.post("http://localhost:7700/indexes/test/documents")
.venv/lib/python3.11/site-packages/requests/api.py:115: in post
    return request("post", url, data=data, json=json, **kwargs)
.venv/lib/python3.11/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
.venv/lib/python3.11/site-packages/requests/sessions.py:587: in request
    resp = self.send(prep, **send_kwargs)
.venv/lib/python3.11/site-packages/requests/sessions.py:701: in send
    r = adapter.send(request, **kwargs)
.venv/lib/python3.11/site-packages/responses/__init__.py:1127: in send
    return self._on_request(adapter, request, **kwargs)
.venv/lib/python3.11/site-packages/responses/__init__.py:1033: in _on_request
    return _real_send(adapter, request, **kwargs)
.venv/lib/python3.11/site-packages/responses/__init__.py:1127: in send
    return self._on_request(adapter, request, **kwargs)
E   RecursionError: maximum recursion depth exceeded while calling a Python object
!!! Recursion detected (same locals & position)

About this issue

  • Original URL
  • State: closed
  • Created 9 months ago
  • Comments: 33 (7 by maintainers)

Most upvoted comments

Screenshot 2023-10-19 at 14 16 12

It’s working 😃

@beliaev-maksim Yes, it does work! @Seluj78 's test case works when overwriting _real_send - sorry if that wasn’t clear.

Thanks @Seluj78, that makes sense.

I’ve managed to get this to work without any modifications to Moto, by installing the PR from @beliaev-maksim .

pip install https://github.com/beliaev-maksim/responses/archive/refs/heads/mbeliaev/real_send.zip

The only change I made was in _TestCase.setup:

from moto.core.models import responses_mock

def setUp(self):
    self.r_mock = responses.RequestsMock(assert_all_requests_are_fired=True)
    self.r_mock.start()
    self.r_mock.add_passthru(re.compile(rf"http://localhost:7700.*"))
    responses_mock._real_send = self.r_mock.unbound_on_send()

@beliaev-maksim The RequestsMock that Moto uses is initialized on import, so changing that to pass the real_adapter_send-argument is not trivial. (Do-able, I guess, just not easy.)

Is it an option to make the attribute part of the public API instead? I.e. RequestsMock.real_send = ..? Being able to set this on demand, instead of needing to know the value on instantiation, would be much easier (for me at least… 🙂 )