A utility for mocking out the Python Requests library.

Related tags

responses
Overview

Responses

https://travis-ci.org/getsentry/responses.svg?branch=master

A utility library for mocking out the requests Python library.

Note

Responses requires Python 2.7 or newer, and requests >= 2.0

Installing

pip install responses

Basics

The core of responses comes from registering mock responses:

import responses
import requests

@responses.activate
def test_simple():
    responses.add(responses.GET, 'http://twitter.com/api/1/foobar',
                  json={'error': 'not found'}, status=404)

    resp = requests.get('http://twitter.com/api/1/foobar')

    assert resp.json() == {"error": "not found"}

    assert len(responses.calls) == 1
    assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'
    assert responses.calls[0].response.text == '{"error": "not found"}'

If you attempt to fetch a url which doesn't hit a match, responses will raise a ConnectionError:

import responses
import requests

from requests.exceptions import ConnectionError

@responses.activate
def test_simple():
    with pytest.raises(ConnectionError):
        requests.get('http://twitter.com/api/1/foobar')

Lastly, you can pass an Exception as the body to trigger an error on the request:

import responses
import requests

@responses.activate
def test_simple():
    responses.add(responses.GET, 'http://twitter.com/api/1/foobar',
                  body=Exception('...'))
    with pytest.raises(Exception):
        requests.get('http://twitter.com/api/1/foobar')

Response Parameters

Responses are automatically registered via params on add, but can also be passed directly:

import responses

responses.add(
    responses.Response(
        method='GET',
        url='http://example.com',
    )
)

The following attributes can be passed to a Response mock:

method (str)
The HTTP method (GET, POST, etc).
url (str or compiled regular expression)
The full resource URL.
match_querystring (bool)
Include the query string when matching requests. Enabled by default if the response URL contains a query string, disabled if it doesn't or the URL is a regular expression.
body (str or BufferedReader)
The response body.
json
A Python object representing the JSON response body. Automatically configures the appropriate Content-Type.
status (int)
The HTTP status code.
content_type (content_type)
Defaults to text/plain.
headers (dict)
Response headers.
stream (bool)
Disabled by default. Indicates the response should use the streaming API.
match (list)
A list of callbacks to match requests based on request body contents.

Matching Request Parameters

When adding responses for endpoints that are sent request data you can add matchers to ensure your code is sending the right parameters and provide different responses based on the request body contents. Responses provides matchers for JSON and URLencoded request bodies and you can supply your own for other formats.

import responses
import requests

@responses.activate
def test_calc_api():
    responses.add(
        responses.POST,
        url='http://calc.com/sum',
        body="4",
        match=[
            responses.urlencoded_params_matcher({"left": "1", "right": "3"})
        ]
    )
    requests.post("http://calc.com/sum", data={"left": 1, "right": 3})

Matching JSON encoded data can be done with responses.json_params_matcher(). If your application uses other encodings you can build your own matcher that returns True or False if the request parameters match. Your matcher can expect a request_body parameter to be provided by responses.

Dynamic Responses

You can utilize callbacks to provide dynamic responses. The callback must return a tuple of (status, headers, body).

import json

import responses
import requests

@responses.activate
def test_calc_api():

    def request_callback(request):
        payload = json.loads(request.body)
        resp_body = {'value': sum(payload['numbers'])}
        headers = {'request-id': '728d329e-0e86-11e4-a748-0c84dc037c13'}
        return (200, headers, json.dumps(resp_body))

    responses.add_callback(
        responses.POST, 'http://calc.com/sum',
        callback=request_callback,
        content_type='application/json',
    )

    resp = requests.post(
        'http://calc.com/sum',
        json.dumps({'numbers': [1, 2, 3]}),
        headers={'content-type': 'application/json'},
    )

    assert resp.json() == {'value': 6}

    assert len(responses.calls) == 1
    assert responses.calls[0].request.url == 'http://calc.com/sum'
    assert responses.calls[0].response.text == '{"value": 6}'
    assert (
        responses.calls[0].response.headers['request-id'] ==
        '728d329e-0e86-11e4-a748-0c84dc037c13'
    )

You can also pass a compiled regex to add_callback to match multiple urls:

import re, json

from functools import reduce

import responses
import requests

operators = {
  'sum': lambda x, y: x+y,
  'prod': lambda x, y: x*y,
  'pow': lambda x, y: x**y
}

@responses.activate
def test_regex_url():

    def request_callback(request):
        payload = json.loads(request.body)
        operator_name = request.path_url[1:]

        operator = operators[operator_name]

        resp_body = {'value': reduce(operator, payload['numbers'])}
        headers = {'request-id': '728d329e-0e86-11e4-a748-0c84dc037c13'}
        return (200, headers, json.dumps(resp_body))

    responses.add_callback(
        responses.POST,
        re.compile('http://calc.com/(sum|prod|pow|unsupported)'),
        callback=request_callback,
        content_type='application/json',
    )

    resp = requests.post(
        'http://calc.com/prod',
        json.dumps({'numbers': [2, 3, 4]}),
        headers={'content-type': 'application/json'},
    )
    assert resp.json() == {'value': 24}

test_regex_url()

If you want to pass extra keyword arguments to the callback function, for example when reusing a callback function to give a slightly different result, you can use functools.partial:

from functools import partial

...

    def request_callback(request, id=None):
        payload = json.loads(request.body)
        resp_body = {'value': sum(payload['numbers'])}
        headers = {'request-id': id}
        return (200, headers, json.dumps(resp_body))

    responses.add_callback(
        responses.POST, 'http://calc.com/sum',
        callback=partial(request_callback, id='728d329e-0e86-11e4-a748-0c84dc037c13'),
        content_type='application/json',
    )

You can see params passed in the original request in responses.calls[].request.params:

import responses
import requests

@responses.activate
def test_request_params():
    responses.add(
        method=responses.GET,
        url="http://example.com?hello=world",
        body="test",
        match_querystring=False,
    )

    resp = requests.get('http://example.com', params={"hello": "world"})
    assert responses.calls[0].request.params == {"hello": "world"}

Responses as a context manager

import responses
import requests

def test_my_api():
    with responses.RequestsMock() as rsps:
        rsps.add(responses.GET, 'http://twitter.com/api/1/foobar',
                 body='{}', status=200,
                 content_type='application/json')
        resp = requests.get('http://twitter.com/api/1/foobar')

        assert resp.status_code == 200

    # outside the context manager requests will hit the remote server
    resp = requests.get('http://twitter.com/api/1/foobar')
    resp.status_code == 404

Responses as a pytest fixture

@pytest.fixture
def mocked_responses():
    with responses.RequestsMock() as rsps:
        yield rsps

def test_api(mocked_responses):
    mocked_responses.add(
        responses.GET, 'http://twitter.com/api/1/foobar',
        body='{}', status=200,
        content_type='application/json')
    resp = requests.get('http://twitter.com/api/1/foobar')
    assert resp.status_code == 200

Assertions on declared responses

When used as a context manager, Responses will, by default, raise an assertion error if a url was registered but not accessed. This can be disabled by passing the assert_all_requests_are_fired value:

import responses
import requests

def test_my_api():
    with responses.RequestsMock(assert_all_requests_are_fired=False) as rsps:
        rsps.add(responses.GET, 'http://twitter.com/api/1/foobar',
                 body='{}', status=200,
                 content_type='application/json')

assert_call_count

Assert that the request was called exactly n times.

import responses
import requests

@responses.activate
def test_assert_call_count():
    responses.add(responses.GET, "http://example.com")

    requests.get("http://example.com")
    assert responses.assert_call_count("http://example.com", 1) is True

    requests.get("http://example.com")
    with pytest.raises(AssertionError) as excinfo:
        responses.assert_call_count("http://example.com", 1)
    assert "Expected URL 'http://example.com' to be called 1 times. Called 2 times." in str(excinfo.value)

Multiple Responses

You can also add multiple responses for the same url:

import responses
import requests

@responses.activate
def test_my_api():
    responses.add(responses.GET, 'http://twitter.com/api/1/foobar', status=500)
    responses.add(responses.GET, 'http://twitter.com/api/1/foobar',
                  body='{}', status=200,
                  content_type='application/json')

    resp = requests.get('http://twitter.com/api/1/foobar')
    assert resp.status_code == 500
    resp = requests.get('http://twitter.com/api/1/foobar')
    assert resp.status_code == 200

Using a callback to modify the response

If you use customized processing in requests via subclassing/mixins, or if you have library tools that interact with requests at a low level, you may need to add extended processing to the mocked Response object to fully simulate the environment for your tests. A response_callback can be used, which will be wrapped by the library before being returned to the caller. The callback accepts a response as it's single argument, and is expected to return a single response object.

import responses
import requests

def response_callback(resp):
    resp.callback_processed = True
    return resp

with responses.RequestsMock(response_callback=response_callback) as m:
    m.add(responses.GET, 'http://example.com', body=b'test')
    resp = requests.get('http://example.com')
    assert resp.text == "test"
    assert hasattr(resp, 'callback_processed')
    assert resp.callback_processed is True

Passing through real requests

In some cases you may wish to allow for certain requests to pass through responses and hit a real server. This can be done with the add_passthru methods:

import responses

@responses.activate
def test_my_api():
    responses.add_passthru('https://percy.io')

This will allow any requests matching that prefix, that is otherwise not registered as a mock response, to passthru using the standard behavior.

Regex can be used like:

responses.add_passthru(re.compile('https://percy.io/\\w+'))

Viewing/Modifying registered responses

Registered responses are available as a private attribute of the RequestMock instance. It is sometimes useful for debugging purposes to view the stack of registered responses which can be accessed via responses.mock._matches.

The replace function allows a previously registered response to be changed. The method signature is identical to add. response s are identified using method and url. Only the first matched response is replaced.

import responses
import requests

@responses.activate
def test_replace():

    responses.add(responses.GET, 'http://example.org', json={'data': 1})
    responses.replace(responses.GET, 'http://example.org', json={'data': 2})

    resp = requests.get('http://example.org')

    assert resp.json() == {'data': 2}

The upsert function allows a previously registered response to be changed like replace. If the response is registered, the upsert function will registered it like add.

remove takes a method and url argument and will remove all matched responses from the registered list.

Finally, reset will reset all registered responses.

Contributing

Responses uses several linting and autoformatting utilities, so it's important that when submitting patches you use the appropriate toolchain:

Clone the repository:

git clone https://github.com/getsentry/responses.git

Create an environment (e.g. with virtualenv):

virtualenv .env && source .env/bin/activate

Configure development requirements:

make develop

Responses uses Pytest for testing. You can run all tests by:

pytest

And run a single test by:

pytest -k '<test_function_name>'
Issues
  • TypeError: cannot unpack non-iterable CallbackResponse object

    TypeError: cannot unpack non-iterable CallbackResponse object

    After upgrading from responses 0.12.0 to 0.12.1 our unit tests fail with the following error:

    ...
    
    ../../../../venv/lib/python3.8/site-packages/requests/sessions.py:590: in post
        return self.request('POST', url, data=data, json=json, **kwargs)
    ../../../../venv/lib/python3.8/site-packages/requests_oauthlib/oauth2_session.py:515: in request
        return super(OAuth2Session, self).request(
    ../../../../venv/lib/python3.8/site-packages/aws_xray_sdk/ext/requests/patch.py:27: in _xray_traced_requests
        return xray_recorder.record_subsegment(
    ../../../../venv/lib/python3.8/site-packages/aws_xray_sdk/core/recorder.py:424: in record_subsegment
        return_value = wrapped(*args, **kwargs)
    ../../../../venv/lib/python3.8/site-packages/requests/sessions.py:542: in request
        resp = self.send(prep, **send_kwargs)
    ../../../../venv/lib/python3.8/site-packages/requests/sessions.py:655: in send
        r = adapter.send(request, **kwargs)
    ../../../../venv/lib/python3.8/site-packages/responses.py:733: in unbound_on_send
        return self._on_request(adapter, request, *a, **kwargs)
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    
    self = <responses.RequestsMock object at 0x104e06880>
    adapter = <requests.adapters.HTTPAdapter object at 0x10a7a8a00>
    request = <PreparedRequest [POST]>
    kwargs = {'cert': None, 'proxies': OrderedDict(), 'stream': False, 'timeout': 10, ...}
    
        def _on_request(self, adapter, request, **kwargs):
    >       match, match_failed_reasons = self._find_match(request)
    E       TypeError: cannot unpack non-iterable CallbackResponse object
    
    ../../../../venv/lib/python3.8/site-packages/responses.py:680: TypeError
    

    This seems to have been caused by the refactoring of the Response._find_match() method.

    opened by philhoff-edeka 19
  • Update inspection to be compatible with newer Python versions

    Update inspection to be compatible with newer Python versions

    getargspec and formatargspec are deprecated since Python 3.5 and produce deprecation warnings. Since Python 3.3, a new inspection API has been available. We use it starting from Python 3.4, so we can make use of the existing six.PY34 constant.

    Fixes #134.

    I welcome any hints to make this code cleaner, I don't have a lot of experience with inspection.

    opened by Timvde 15
  • Feature Passthrough Flag

    Feature Passthrough Flag

    This PR closes #399 by adding a passthrough flag to BaseResponse, which can be used to let requests pass through instead of returning the defined mock values.

    It may be discussed, in how far it also closes other issues mentioned in #399.

    Status: In Progress 
    opened by carloshorn 14
  • Add support for removing and replacing existing mocked URLs

    Add support for removing and replacing existing mocked URLs

    This PR adds support for responses.replace(). The problem it is solving is the following: we usually have a base fixture of mocked API calls which we use like below in tests.

    @pytest.mark.usefixtures('mock_api_calls')
    def some_test():
       pass
    

    The fixture itself is defined as:

    @pytest.fixture()
    def mock_api_calls():
        responses.add(responses.GET, 'http://someurl.com/one')
        responses.add(responses.GET, 'http://someurl.com/two')
        responses.add(responses.GET, 'http://someurl.com/three')
        responses.add(responses.GET, 'http://someurl.com/four')
    

    However, in the specific test we then want to change one of the API calls to return a different response. This wasn't possible previously, as responses.add() always appends to _urls. With replace(), we can now do:

    @pytest.mark.usefixtures('mock_api_calls')
    def some_test():
      responses.replace(responses.GET, 'http://someurl.com/two', body='different')
    

    Implementation-wise I broke out the creation of the entry into _build_entry() to be able to reuse it from replace(). I also reused _find_match() by adding an extra keyword for exact_match (as I figured we don't want to replace based on regex).

    Thoughts?


    This change is Reviewable

    opened by joscarsson 12
  • Add feature to bypass responses per demand

    Add feature to bypass responses per demand

    This one is probably controversial. bypass allows to bypass responses for selected requests. Since requests is used in many libraries including elasticsearch clients for instance. I would like in my test to NOT capture those calls in the context of @responses.activate that I'm using to capture calls to the web in the mean time.

    Yep, I'm testing spaghetti code.

    opened by ticosax 12
  • Feature: cookie handling

    Feature: cookie handling

    • added cookie support
    opened by OldhamMade 11
  • Add matchers for post keys

    Add matchers for post keys

    Closes #335

    I'm not really satisfied with the external API:

    • responses.assert_call_count(url, 2, match_querystring=False) is a bit clunky
    • match_querystring should maybe be False by default to match capture behaviour? But then the change is not backwards compatible :o

    The internal change with call_url_matches is not really clean either, I don't know how to improve it :\

    opened by pmourlanne 10
  • add matcher for request headers

    add matcher for request headers

    I needed a matcher for request headers and so I built one that I felt was generic enough to warrant inclusion upstream.

    Hopefully the detail that I've added to the README.rst is enough to understand the motivation for how I built it, so I'll avoid repeating myself here.

    I'm happy to discuss any changes that you might like in order to have this merged.

    opened by eviltwin 9
  • Allow external requests

    Allow external requests

    Sometimes,you want to mock a specific service, but you still want to be able to reach other services. With this PR, if allow_external_requests is True, calls to non mocked urls don't throw ConnectionError.

    This is somewhat similar to #39.

    EDIT: If someone is interested by this behavior, note that change may never be included in responses, as per @dcramer's comment in #39. If you need a way to mock an API while being able to make external requests, request-mock seems to be a good option.

    opened by k4nar 9
  • Provide a py.test fixture in addition to the decorator

    Provide a py.test fixture in addition to the decorator

    When using py.test for tests it's usually nicer to activate features like this using a fixture. The usage with the fixture (assuming it's named responses) could be like this:

    def test_my_api(responses):
        responses.add(responses.GET, 'http://twitter.com/api/1/foobar',
                      body='{"error": "not found"}', status=404,
                      content_type='application/json')
    
        # ...
    

    I.e. instead of the decorator you'd use a responses fixture and instead of calling add as a global from the imported module (if you register it as a pytest plugin the user doesn't need to import it at all) you'd call it on the object returned by the fixture function (which could simple be the module responses, but a wrapper would be cleaner of course).

    opened by ThiefMaster 8
  • add_callback

    add_callback

    added match to add_callback replace match default to tuple since it is not a good idea to have mutable objects in the signature

    after this PR we can close PR #268 since stream now should be set via request and all other interfaces of CallbackResponse are added via current PR

    opened by beliaev-maksim 1
  • URL parse update

    URL parse update

    changed python "replace" to proper URL parser methods truncating using replace is not a clean way, it may not represent actual behavior of constructed URL

    opened by beliaev-maksim 1
  • mbeliaev/registry

    mbeliaev/registry

    I went through #411 and, sincerely, I had absolutely the same need and was thinking how would be better to implement it. thanks to @carloshorn, who inspired with the idea of Registry

    I propose fully backwards compatible implementation. Short description:

    1. User is provided with registries.BaseRegistry as abstract class that must be implemented
    2. in custom class use can define any logic of finding match (user just redefines find function that must return found_match, match_failed_reasons), eg examples mentioned in #411
    • strict: provide every response only once.
    • very strict: only provide the next response.
    • insertion: always provide responses in insertion order.
    • rotating: move found matches to the end, i.e. if they are already in order it performs a rotation (might play well with the replace method if the other responses stay the same.)
    • fall-back: the current selection order
    1. then user can replace registry for default mock by running responses.set_registry(CustomRegistry) or just set as argument in RequestsMock

    idea is the same as with matchers. Once we shift to registries, then we can populate them with some predefined, eg like in #411 or some from point 2 above. Then, users will have easy access to new types of response registries out of the box with single line of code

    Note: once we agreed to proceed with implementation, then I will polish this PR: docs, test, typing, changelog

    opened by beliaev-maksim 5
  • refactor find matches algorithm

    refactor find matches algorithm

    This PR changes the algorithm to find matches. It implements the following algorithm:

    Loop in normal order and provide responses with call_count == 0. If there is no match found, loop in reverse order and provide all responses with call_count > 0.

    This will behave like before for most use cases. There could only be cases that failed before which would now pass, e.g. imagine the following situation: registry: [r'.*', 'abc']. In previous implementation a call with requests: ['abc', 'abc', 'xyz'] would have failed, because the first abc would have popped the "match everything" response. In this implementation, it would still work.

    In my opinion this algorithm is easier to explain and comprehend and should be backward compatible with all previous use cases. Except those relying on a failure due to a popped response, which would be a very special edge case which I would not expect by any user at all.

    opened by carloshorn 4
  • Searching Responses and Manipulation of Matching Order

    Searching Responses and Manipulation of Matching Order

    Description

    Currently, the order of registered responses is only determined by the insertion order which is also the order in which a request will look for matches. #400 wants to introduce a priority attribute which provides a little more control on the matching order. However, more control over the responses within a priority group in the registry would be beneficial. It should also be possible to locate (get matching order index) a response in the registry and search for responses of some criteria.

    User Stories

    - I want to be able to specify the matching order of newly registered responses at any time, so that I do not need 
      to insert my responses in metching order.
    - I want to be able to search for registered responses, so I can more easily update or remove them.
    - I want to be able to move registered responses (without changing priority), so I can manipulate the matching
      order at any time.
    

    Interface Proposal

    Search interface

    class RequestsMock:
        ...
        def search(self, resp_filter: Callable[[response], bool]) -> list[BaseResponse]:
            ...
            return responses
        ...
    resp = RequestMock()
    for response in my_responses:
        resp.add(respons)
    index, relevant = resp.search(lambda response: response.method == responses.POST)
    

    Change Matching Order

    class RequestsMock:
        ...
        def move(self, response: Union[BaseResponse, int], pos: int, relative: bool = False) -> None:
            ...
        ...
    resp = RequestMock()
    for response in my_responses:
        resp.add(response)
    last_response = my_responses[-1]
    # move three position forward
    resp.move(last_response, -3, relative=True)
    # move in front
    resp.move(last_response, 0)
    # move last response in front (access by index) this might be useful if the response is registerd 
    # several times, because the non-index approach should only move the first occurring response.
    resp.move(-1, 0)
    

    Note that this method should try to move the response to the desired location, but it might be sorted backwards because of a lower priority. Example (only showing priority). In [HIGH, HIGH, NORMAL, LOW] using move(-1, 0) would not change the list, because the last element is the only one with priority low, but move(1, 0) would swap the first two items.

    Set Matching Position Directly

    class RequestsMock:
        ...
        def add(self, ..., pos: Optional[int] = None) -> ...:
            ...
        ...
    resp = RequestMock()
    for respons in my_responses:
        resp.add(respons)
    # add this response on third position (use python indexing starting with 0)
    resp.add(my_other_response, pos=2)
    

    Also here, the position may be sorted backwards depending on the priority.

    The methods add and move could also get a flag called force which would overwrite the priority to enforce the desired location, but I do not know if this is needed or should be the default.

    Looking forward for some feedback to the proposed feature.

    Status: In Progress 
    opened by carloshorn 4
  • fixes ChunkEnodingError when content length mismatches with the body content.

    fixes ChunkEnodingError when content length mismatches with the body content.

    Fixed Issue #394

    Status: Backlog 
    opened by ViAsmit 1
  • AttributeError when urllib3 throws an IncompleteRead

    AttributeError when urllib3 throws an IncompleteRead

    TL;DR: There is a flag in urllib3.HTTPResponse that checks if the "Content-Length" header of a HTTP request matches its body size. If this flag is set, the error raised by a mismatch between the two causes an AttributeError in responses (see further below for details). With the current version of requests, the required flag in urllib3 has to be patched in but it is also planned to be included in the requests library with their planned release of 3.0.0 (https://github.com/psf/requests/issues/4956#issue-405545488).

    Environment

    python 3.8.5 requests==2.26.0 responses==0.13.3 urllib3==1.26.6

    Steps to Reproduce

    Minimal working example:

    import unittest
    
    import requests
    import responses
    import urllib3
    from requests.exceptions import ChunkedEncodingError
    
    
    def patch_urllib3():
        """Set urllib3's enforce_content_length to True by default."""
        previous_init = urllib3.HTTPResponse.__init__
        def new_init(self, *args, **kwargs):
            previous_init(self, *args, enforce_content_length = True, **kwargs)
        urllib3.HTTPResponse.__init__ = new_init
    
    class TestResponses(unittest.TestCase):
        """Test that responses handles IncompleteRead exceptions correctly."""
    
        @responses.activate
        def test_raises_an_error(self):
            """Test that an IncorrectEncoding is thrown."""
            patch_urllib3()
            responses.add(**{
                "method"            : responses.GET,
                "url"               : "http://example.com/api/123",
                "body"              : "{'message': 'this body is too large'}",
                "adding_headers"    : {"content-length": "2"}
            })
            with self.assertRaises(ChunkedEncodingError):
                requests.get("http://example.com/api/123")
    

    Expected Result

    When building a working example with fastapi and uvicorn, a requests.exceptions.ChunkedEncodingError is thrown. I would expect this to also happen when responses is used. If a simple

    def close(self):
        return
    

    is added to responses/__init__.py:OriginalResponseShim, this is also the result that occurs with responses.

    Actual Result

    The actual result is an AttributeError:

    Traceback (most recent call last):
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/urllib3/response.py", line 438, in _error_catcher
        yield
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/urllib3/response.py", line 541, in read
        raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
    urllib3.exceptions.IncompleteRead: IncompleteRead(37 bytes read, -35 more expected)
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/urllib3/response.py", line 455, in _error_catcher
        raise ProtocolError("Connection broken: %r" % e, e)
    urllib3.exceptions.ProtocolError: ('Connection broken: IncompleteRead(37 bytes read, -35 more expected)', IncompleteRead(37 bytes read, -35 more expected))
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "<string>", line 3, in wrapper
      File "/local/home/fma/dev/pacs-interface/tests/test_minimal_exaple.py", line 32, in test_raises_an_error
        requests.get("http://example.com/api/123")
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/requests/api.py", line 75, in get
        return request('get', url, params=params, **kwargs)
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/requests/api.py", line 61, in request
        return session.request(method=method, url=url, **kwargs)
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/requests/sessions.py", line 542, in request
        resp = self.send(prep, **send_kwargs)
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/requests/sessions.py", line 655, in send
        r = adapter.send(request, **kwargs)
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/responses/__init__.py", line 768, in unbound_on_send
        return self._on_request(adapter, request, *a, **kwargs)
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/responses/__init__.py", line 759, in _on_request
        response.content  # NOQA
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/requests/models.py", line 836, in content
        self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b''
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/requests/models.py", line 758, in generate
        for chunk in self.raw.stream(chunk_size, decode_content=True):
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/urllib3/response.py", line 576, in stream
        data = self.read(amt=amt, decode_content=decode_content)
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/urllib3/response.py", line 541, in read
        raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/contextlib.py", line 131, in __exit__
        self.gen.throw(type, value, traceback)
      File "/local/home/fma/.conda/envs/endpoint/lib/python3.8/site-packages/urllib3/response.py", line 468, in _error_catcher
        self._original_response.close()
    AttributeError: 'OriginalResponseShim' object has no attribute 'close'
    
    bug Status: Backlog 
    opened by FlMart 0
  • one test .py can run successfully,but run the whole test folder,it report error

    one test .py can run successfully,but run the whole test folder,it report error

    Environment

    I mock responses in django test, when i run one test.py it run ok,but when i run whole folder by pytest folder it not ok

    the envitonment: django==1.11.20 python==3.6.13 pytest==3.8.2 responses==0.13.3

    Steps to Reproduce

    test_xx.py test_yy.py test_zz.py in tests folder pytest test_xx.py ok image

    pytest tests not ok

    image

    i don't why

    Status: Needs More Information 
    opened by bainningking 2
  • Error or better document overlapping regex matcher behaviour

    Error or better document overlapping regex matcher behaviour

    Alternate names for this issue

    Alternate name: "raise error instead of silently popping when multiple matches found (or add to readme)" Alternate name2: remove the # Multiple matches found. Remove & return the first match. in _find_match()

    <3

    First of all, I <3 responses. SOOOO extensible and amazing, Thank You!

    Issue

    I had a huge headache using multiple callbacks with different (overlapping) regexes. I assumed that the order of the regex matches mattered so i could do something like first add specific regex callback, then add general .* regex callback and the first one would match the specific case and then the general callback would be the "fallback" for the urls that didn't match the specific callback.

    Why I was confused

    This made sense to me as regex is not super great at "not" matches, so i expected the implementation would allow for that.

    But instead I ended up with this weird behavior where the first match would trigger my specific callback and then the rest would trigger the general callback. And then at the end if i checked the registered matchers, I'd end up with one missing.

    Workaround

    I was able to get this working by modifying my "general" regex to be the opposite (negative look ahead) of my specific regex so the general would not match the specific and there was no overlap.

    Issues with workaround

    • With multiple specific cases the negative case in the general regex can get complicated.
    • Regex negative lookarounds are expensive and hard to write.
    • Also when you are adding callbacks in multiple different places having them not overlap can get complicated as well.

    Proposed Solutions

    • Raise an error when we have multiple matching regexes instead of removing them. At the very least this should cause tests to fail
    • Document this behavior explicitly in the readme
    opened by markddavidoff 6
  • Allow calls to requsts between calls to responses.add

    Allow calls to requsts between calls to responses.add

    This change allows the use of multiple responses intermixed by calls to requests by removing previous matches that have already been called if multiple exist.

    opened by Jlrine2 2
Releases(0.14.0)
  • 0.14.0(Sep 10, 2021)

    • Added responses.matchers.
    • Moved responses.json_params_matcher to responses.matchers.json_param_matcher
    • Moved responses.urlencoded_params_matcher to responses.matchers.urlencoded_param_matcher
    • Added responses.query_params_matcher. This matcher allows you to match query strings with a dictionary.
    • Added auto_calculate_content_length option to responses.add(). When enabled, this option will generate a Content-Length header based on the number of bytes in the response body.
    Source code(tar.gz)
    Source code(zip)
    responses-0.14.0-py2.py3-none-any.whl(26.76 KB)
    responses-0.14.0.tar.gz(31.90 KB)
  • 0.13.4(Aug 9, 2021)

  • 0.13.2(Mar 29, 2021)

  • 0.13.1(Mar 17, 2021)

  • 0.13.0(Mar 17, 2021)

    • responses.upsert() was added. This method will add() a response if one has not already been registered for a URL, or replace() an existing response.
    • responses.registered() was added. The method allows you to get a list of the currently registered responses. This formalizes the previously private responses.mock._matches method.
    • A more useful __repr__ has been added to Response.
    • Error messages have been improved.
    Source code(tar.gz)
    Source code(zip)
  • 0.12.1(Nov 12, 2020)

    • responses.urlencoded_params_matcher and responses.json_params_matcher now accept None to match empty requests.
    • Fixed imports to work with new urllib3 versions.
    • request.params now allows parameters to have multiple values for the same key.
    • Improved ConnectionError messages.
    Source code(tar.gz)
    Source code(zip)
  • 0.12.0(Aug 30, 2020)

  • 0.11.0(Aug 24, 2020)

  • 0.10.16(Aug 11, 2020)

  • 0.10.15(Jun 12, 2020)

    • Added assert_call_count to improve ergonomics around ensuring a mock was called.
    • Fix incorrect handling of paths with query strings.
    • Add Python 3.9 support to CI matrix.
    Source code(tar.gz)
    Source code(zip)
  • 0.10.14(Apr 20, 2020)

  • 0.10.13(Apr 20, 2020)

    • Improved README examples.
    • Improved handling of unicode bodies. The inferred content-type for unicode bodies is now text/plain; charset=utf-8.
    • Streamlined querysting matching code.
    Source code(tar.gz)
    Source code(zip)
  • 0.10.12(Mar 3, 2020)

  • 0.10.11(Feb 25, 2020)

  • 0.10.10(Jan 30, 2020)

    • Added Python 3.8 support
    • Remove Python 3.4 from test suite matrix.
    • The response.request object now has a params attribute that contains the query string parameters from the request that was captured.
    • add_passthru now supports re pattern objects to match URLs.
    • ConnectionErrors raised by responses now include more details on the request that was attempted and the mocks registered.
    Source code(tar.gz)
    Source code(zip)
  • 0.10.9(Dec 20, 2019)

  • 0.10.8(Dec 12, 2019)

  • 0.10.7(Nov 25, 2019)

    Fixes

    • Improved formatting of project description in pypi.
    • Unicode cookie values are now normalized to URL quoted encoding.
    • Module exports are statically defined improving code completion and IDE navigation.
    • Improved compatibility with pytest 5
    Source code(tar.gz)
    Source code(zip)
  • 0.10.6(Mar 15, 2019)

    • Improved documentation.
    • Improved installation requirements for py3
    • ConnectionError's raised by responses now indicate which request path/method failed to match a mock.
    • test_responses.py is no longer part of the installation targets.
    Source code(tar.gz)
    Source code(zip)
  • 0.10.5(Dec 17, 2018)

  • 0.10.4(Nov 15, 2018)

  • 0.10.3(Nov 8, 2018)

  • 0.10.2(Oct 25, 2018)

    • Fixed build setup to use undeprecated pytest bin stub.
    • Updated tox configuration.
    • Added example of using responses with pytest.fixture
    • Removed dependency on biscuits in py3. Instead http.cookies is being used.
    Source code(tar.gz)
    Source code(zip)
  • 0.10.1(Oct 18, 2018)

  • 0.10.0(Oct 18, 2018)

    • Improve documentation
    • Fix warnings in Python 3.7
    • The match_querystring argument for responses.add() now defaults to true if the stubbed URL has a query string.
    • Pass through requests no longer drop keyword arguments like proxies.
    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(Jul 25, 2017)

    • Allow empty list/dict as json object (GH-100).
    • Added response_callback (GH-151).
    • Added Response interfaces (GH-155).
    • Fixed unicode characters in querystring (GH-153).
    • Added support for streaming IO buffers (GH-154).
    • Added support for empty (unset) Content-Type (GH-139).
    • Added reason to mocked responses (GH-132).
    • yapf autoformatting now enforced on codebase.
    Source code(tar.gz)
    Source code(zip)
Owner
Sentry
Real-time crash reporting for your web apps, mobile apps, and games.
Sentry
A mocking library for requests

httmock A mocking library for requests for Python 2.7 and 3.4+. Installation pip install httmock Or, if you are a Gentoo user: emerge dev-python/httm

Patryk Zawadzki 430 Oct 14, 2021
a socket mock framework - for all kinds of socket animals, web-clients included

mocket /mɔˈkɛt/ A socket mock framework for all kinds of socket animals, web-clients included - with gevent/asyncio/SSL support ...and then MicroPytho

Giorgio Salluzzo 219 Oct 5, 2021
Automatically mock your HTTP interactions to simplify and speed up testing

VCR.py ?? This is a Python version of Ruby's VCR library. Source code https://github.com/kevin1024/vcrpy Documentation https://vcrpy.readthedocs.io/ R

Kevin McCarthy 2.1k Oct 15, 2021
Let your Python tests travel through time

FreezeGun: Let your Python tests travel through time FreezeGun is a library that allows your Python tests to travel through time by mocking the dateti

Steve Pulec 3k Oct 22, 2021
Sixpack is a language-agnostic a/b-testing framework

Sixpack Sixpack is a framework to enable A/B testing across multiple programming languages. It does this by exposing a simple API for client libraries

null 1.7k Oct 23, 2021
Green is a clean, colorful, fast python test runner.

Green -- A clean, colorful, fast python test runner. Features Clean - Low redundancy in output. Result statistics for each test is vertically aligned.

Nathan Stocks 712 Oct 23, 2021
livereload server in python (MAINTAINERS NEEDED)

LiveReload Reload webpages on changes, without hitting refresh in your browser. Installation python-livereload is for web developers who know Python,

Hsiaoming Yang 936 Oct 22, 2021
A modern API testing tool for web applications built with Open API and GraphQL specifications.

Schemathesis Schemathesis is a modern API testing tool for web applications built with Open API and GraphQL specifications. It reads the application s

Schemathesis.io 1k Oct 22, 2021
The successor to nose, based on unittest2

Welcome to nose2 nose2 is the successor to nose. It's unittest with plugins. nose2 is a new project and does not support all of the features of nose.

null 691 Oct 22, 2021
Mimesis is a high-performance fake data generator for Python, which provides data for a variety of purposes in a variety of languages.

Mimesis - Fake Data Generator Description Mimesis is a high-performance fake data generator for Python, which provides data for a variety of purposes

Isaak Uchakaev 3.4k Oct 24, 2021
Meinheld is a high performance asynchronous WSGI Web Server (based on picoev)

What's this This is a high performance python wsgi web server. And Meinheld is a WSGI compliant web server. (PEP333 and PEP3333 supported) You can als

Yutaka Matsubara 1.4k Oct 21, 2021
A test fixtures replacement for Python

factory_boy factory_boy is a fixtures replacement based on thoughtbot's factory_bot. As a fixtures replacement tool, it aims to replace static, hard t

FactoryBoy project 2.7k Oct 18, 2021
Mixer -- Is a fixtures replacement. Supported Django, Flask, SqlAlchemy and custom python objects.

The Mixer is a helper to generate instances of Django or SQLAlchemy models. It's useful for testing and fixture replacement. Fast and convenient test-

Kirill Klenov 773 Oct 13, 2021
Scalable user load testing tool written in Python

Locust Locust is an easy to use, scriptable and scalable performance testing tool. You define the behaviour of your users in regular Python code, inst

Locust.io 17.4k Oct 24, 2021
Robyn is an async Python backend server with a runtime written in Rust, btw.

Robyn is an async Python backend server with a runtime written in Rust, btw. Python server running on top of of Rust Async RunTime. Installation

Sanskar Jethi 222 Oct 26, 2021
AWS Lambda & API Gateway support for ASGI

Mangum Mangum is an adapter for using ASGI applications with AWS Lambda & API Gateway. It is intended to provide an easy-to-use, configurable wrapper

Jordan Eremieff 698 Oct 23, 2021
Faker is a Python package that generates fake data for you.

Faker is a Python package that generates fake data for you. Whether you need to bootstrap your database, create good-looking XML documents, fill-in yo

Daniele Faraglia 13.2k Oct 24, 2021
Official mirror of https://gitlab.com/pgjones/hypercorn https://pgjones.gitlab.io/hypercorn/

Hypercorn Hypercorn is an ASGI web server based on the sans-io hyper, h11, h2, and wsproto libraries and inspired by Gunicorn. Hypercorn supports HTTP

Phil Jones 223 Oct 14, 2021
Hypothesis is a powerful, flexible, and easy to use library for property-based testing.

Hypothesis Hypothesis is a family of testing libraries which let you write tests parametrized by a source of examples. A Hypothesis implementation the

Hypothesis 5.4k Oct 23, 2021