{"id":13482179,"url":"https://github.com/aresponses/aresponses","last_synced_at":"2025-03-27T12:32:27.561Z","repository":{"id":40237002,"uuid":"102586271","full_name":"aresponses/aresponses","owner":"aresponses","description":"Asyncio http mocking. Similar to the responses library used for 'requests'","archived":false,"fork":false,"pushed_at":"2024-02-04T20:25:21.000Z","size":150,"stargazers_count":100,"open_issues_count":0,"forks_count":19,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-04-22T12:32:32.661Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aresponses.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-06T08:54:59.000Z","updated_at":"2024-06-18T18:20:56.701Z","dependencies_parsed_at":"2024-06-18T18:31:52.007Z","dependency_job_id":null,"html_url":"https://github.com/aresponses/aresponses","commit_stats":{"total_commits":114,"total_committers":19,"mean_commits":6.0,"dds":0.6140350877192983,"last_synced_commit":"a8fb95842a1646b597d9e7ec29c20ae1b3398281"},"previous_names":["circleup/aresponses"],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aresponses%2Faresponses","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aresponses%2Faresponses/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aresponses%2Faresponses/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aresponses%2Faresponses/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aresponses","download_url":"https://codeload.github.com/aresponses/aresponses/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222252103,"owners_count":16955967,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T17:00:59.696Z","updated_at":"2024-10-30T15:31:49.442Z","avatar_url":"https://github.com/aresponses.png","language":"Python","funding_links":[],"categories":["Testing","Python","Web Testing"],"sub_categories":[],"readme":"\n\n# aresponses\n\n[![image](https://img.shields.io/pypi/v/aresponses.svg)](https://pypi.org/project/aresponses/)\n[![image](https://img.shields.io/pypi/pyversions/aresponses.svg)](https://pypi.org/project/aresponses/)\n[![build status](https://github.com/CircleUp/aresponses/workflows/Python%20Checks/badge.svg)](https://github.com/CircleUp/aresponses/actions?query=branch%3Amaster)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n\n\nan asyncio testing server for mocking external services\n\n## Features\n - Fast mocks using actual network connections\n - allows mocking some types of network issues\n - use regular expression matching for domain, path, method, or body\n - works with https requests as well (by switching them to http requests)\n - works with callables\n \n## Usage\n\nAdd routes and responses via the `aresponses.add` method:\n\n```python\ndef add(\n    host_pattern=ANY, \n    path_pattern=ANY, \n    method_pattern=ANY, \n    response=\"\", \n    *, \n    route=None, \n    body_pattern=ANY, m\n    match_querystring=False, \n    repeat=1\n    )\n```\n\nWhen a request is received the first matching response will be returned\nand removed from the routing table.  The `response` argument can be\neither a string, Response, dict, or list.  Use `aresponses.Response`\nwhen you need to do something more complex.\n\n\n**Note that version \u003e=2.0 requires explicit assertions!**\n```python\n@pytest.mark.asyncio\nasync def test_simple(aresponses):\n    aresponses.add(\"google.com\", \"/api/v1/\", \"GET\", response=\"OK\")\n    aresponses.add('foo.com', '/', 'get', aresponses.Response(text='error', status=500))\n\n    async with aiohttp.ClientSession() as session:\n        async with session.get(\"http://google.com/api/v1/\") as response:\n            text = await response.text()\n            assert text == \"OK\"\n        \n        async with session.get(\"https://foo.com\") as response:\n            text = await response.text()\n            assert text == \"error\"\n\n    aresponses.assert_plan_strictly_followed()\n```\n\n#### Assertions\nIn aresponses 1.x requests that didn't match a route stopped the event\nloop and thus forced an exception.  In aresponses \u003e2.x it's required to\nmake assertions at the end of the test.\n\nThere are three assertion functions provided:\n- `aresponses.assert_no_unused_routes` Raises `UnusedRouteError` if all\nthe routes defined were not used up.\n- `aresponses.assert_called_in_order` - Raises `UnorderedRouteCallError`\nif the routes weren't called in the order they were defined.\n- `aresponses.assert_all_requests_matched` - Raises `NoRouteFoundError`\nif any requests were made that didn't match to a route.  It's likely\nbut not guaranteed that your code will throw an exception in this\nsituation before the assertion is reached.\n\nInstead of calling these individually, **it's recommended to call\n`aresponses.assert_plan_strictly_followed()` at the end of each test as\nit runs all three of the above assertions.**\n\n\n#### Regex and Repeat\n`host_pattern`, `path_pattern`, `method_pattern` and `body_pattern` may\nbe either strings (exact match) or regular expressions.\n\nThe repeat argument permits a route to be used multiple times.\n\nIf you want to just blanket mock a service, without concern for how many\ntimes its called, you could set repeat to a large number and not call\n`aresponses.assert_plan_strictly_followed` or\n`arespones.assert_no_unused_routes`.\n\n```python\n@pytest.mark.asyncio\nasync def test_regex_repetition(aresponses):\n    aresponses.add(re.compile(r\".*\\.?google\\.com\"), response=\"OK\", repeat=2)\n\n    async with aiohttp.ClientSession() as session:\n        async with session.get(\"http://google.com\") as response:\n            text = await response.text()\n            assert text == \"OK\"\n\n        async with session.get(\"http://api.google.com\") as response:\n            text = await response.text()\n            assert text == \"OK\"\n\n    aresponses.assert_plan_strictly_followed()\n```\n\n#### Json Responses\nAs a convenience, if a dict or list is passed to `response` then it will\ncreate a json response. A `aiohttp.web_response.json_response` object\ncan be used for more complex situations.\n\n```python\n@pytest.mark.asyncio\nasync def test_json(aresponses):\n    aresponses.add(\"google.com\", \"/api/v1/\", \"GET\", response={\"status\": \"OK\"})\n\n    async with aiohttp.ClientSession() as session:\n        async with session.get(\"http://google.com/api/v1/\") as response:\n            assert {\"status\": \"OK\"} == await response.json()\n\n    aresponses.assert_plan_strictly_followed()\n```\n\n#### Custom Handler\n\nCustom functions can be used for whatever other complex logic is\ndesired. In the example below, the handler is set to repeat infinitely\nand always return 500.\n\n```python\nimport math\n\n@pytest.mark.asyncio\nasync def test_handler(aresponses):\n    def break_everything(request):\n        return aresponses.Response(status=500, text=str(request.url))\n\n    aresponses.add(response=break_everything, repeat=math.inf)\n\n    async with aiohttp.ClientSession() as session:\n        async with session.get(\"http://google.com/api/v1/\") as response:\n            assert response.status == 500\n```\n\n\n#### Passthrough\nPass `aresponses.passthrough` into the response argument to allow a\nrequest to bypass mocking.\n\n```python\n    aresponses.add('httpstat.us', '/200', 'get', aresponses.passthrough)\n```\n\n#### Inspecting history\nHistory of calls can be inspected via `aresponses.history` which returns\nthe namedTuple `RoutingLog(request, route, response)`\n\n```python\n@pytest.mark.asyncio\nasync def test_history(aresponses):\n    aresponses.add(response=aresponses.Response(text=\"hi\"), repeat=2)\n\n    async with aiohttp.ClientSession() as session:\n        async with session.get(\"http://foo.com/b\") as response:\n            await response.text()\n        async with session.get(\"http://bar.com/a\") as response:\n            await response.text()\n\n    assert len(aresponses.history) == 2\n    assert aresponses.history[0].request.host == \"foo.com\"\n    assert aresponses.history[1].request.host == \"bar.com\"\n    assert \"Route(\" in repr(aresponses.history[0].route)\n    aresponses.assert_plan_strictly_followed()\n```\n\n#### Context manager usage\n```python\nimport aiohttp\nimport pytest\nimport aresponses\n\n\n@pytest.mark.asyncio\nasync def test_foo(event_loop):\n    async with aresponses.ResponsesMockServer(loop=event_loop) as arsps:\n        arsps.add('foo.com', '/', 'get', 'hi there!!')\n        arsps.add(arsps.ANY, '/', 'get', arsps.Response(text='hey!'))\n        \n        async with aiohttp.ClientSession(loop=event_loop) as session:\n            async with session.get('http://foo.com') as response:\n                text = await response.text()\n                assert text == 'hi'\n            \n            async with session.get('https://google.com') as response:\n                text = await response.text()\n                assert text == 'hey!'\n        \n```\n\n#### working with [pytest-aiohttp](https://github.com/aio-libs/pytest-aiohttp)\n\nIf you need to use aresponses together with pytest-aiohttp, you should re-initialize the main aresponses fixture with the `loop` fixture\n```python\nfrom aresponses import ResponsesMockServer\n\n@pytest.fixture\nasync def aresponses(loop):\n    async with ResponsesMockServer(loop=loop) as server:\n        yield server\n```\n\nIf you're trying to use the `aiohttp_client` test fixture then you'll need to mock out the aiohttp `loop` fixture\ninstead:\n```python\n@pytest.fixture\ndef loop(event_loop):\n    \"\"\"replace aiohttp loop fixture with pytest-asyncio fixture\"\"\"\n    return event_loop\n```\n\n## Contributing\n\n### Dev environment setup\n  - **install pyenv and pyenv-virtualenv**  - Makes it easy to install specific versions of python and switch between them. Make sure you install the virtualenv bash hook\n  - `git clone` the repo and `cd` into it.\n  - `make init` - installs proper version of python, creates the virtual environment, activates it and installs all the requirements\n  \n### Submitting a feature request  \n  - **`git checkout -b my-feature-branch`** \n  - **make some cool changes**\n  - **`make autoformat`**\n  - **`make test`**\n  - **`make lint`**\n  - **create pull request**\n\n### Updating package on pypi\n  - `make deploy`\n\n\n## Changelog\n\n#### 3.0.0\n- fix: start using `asyncio.get_running_loop()` instead of `event_loop` per the error:\n    ```\n    PytestDeprecationWarning: aresponses is asynchronous and explicitly requests the \"event_loop\" fixture. \n    Asynchronous fixtures and test functions should use \"asyncio.get_running_loop()\" instead.\n    ```\n- drop support for python 3.6\n- add comprehensive matrix testing of all supported python and aiohttp versions\n- tighten up the setup.py requirements\n\n#### 2.1.6\n- fix: incorrect pytest plugin entrypoint name (#72)\n\n#### 2.1.5\n- support asyncio_mode = strict (#68)\n \n#### 2.1.4\n- fix: don't assume utf8 request contents\n\n#### 2.1.3\n- accidental no-op release\n\n#### 2.1.2\n- documentation: add pypi documentation\n\n#### 2.1.1\n\n- bugfix: RecursionError when aresponses is used in more than 1000 tests (#63)\n\n#### 2.1.0\n- feature: add convenience method `add_local_passthrough`\n- bugfix: fix https subrequest mocks. support aiohttp_client compatibility\n\n#### 2.0.2\n- bugfix: ensure request body is available in history\n\n#### 2.0.0\n**Warning! Breaking Changes!**\n- breaking change: require explicit assertions for test failures\n- feature: autocomplete works in intellij/pycharm\n- feature: can match on body of request\n- feature: store calls made\n- feature: repeated responses\n- bugfix: no longer stops event loop\n- feature: if dict or list is passed into `response`, a json response\nwill be generated\n\n\n#### 1.1.2\n- make passthrough feature work with binary data\n\n#### 1.1.1\n- regex fix for Python 3.7.0\n\n#### 1.1.0\n- Added passthrough option to permit live network calls\n- Added example of using a callable as a response\n\n#### 1.0.0\n\n- Added an optional `match_querystring` argument that lets you match on querystring as well\n\n\n## Contributors\n* Bryce Drennan, CircleUp \u003caresponses@brycedrennan.com\u003e\n* Marco Castelluccio, Mozilla \u003cmcastelluccio@mozilla.com\u003e\n* Jesse Vogt, CircleUp \u003cjesse.vogt@gmail.com\u003e\n* Pavol Vargovcik, Kiwi.com \u003cpavol.vargovcik@gmail.com\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faresponses%2Faresponses","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faresponses%2Faresponses","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faresponses%2Faresponses/lists"}