1Third-Party Packages 2==================== 3 4Betamax was created to be a very close imitation of `VCR`_. As such, it has 5the default set of request matchers and a subset of the supported cassette 6serializers for VCR. 7 8As part of my own usage of Betamax, and supporting other people's usage of 9Betamax, I've created (and maintain) two third party packages that provide 10extra request matchers and cassette serializers. 11 12- `betamax-matchers`_ 13- `betamax-serializers`_ 14 15For simplicity, those modules will be documented here instead of on their own 16documentation sites. 17 18Request Matchers 19---------------- 20 21There are three third-party request matchers provided by the 22`betamax-matchers`_ package: 23 24- :class:`~betamax_matchers.form_urlencoded.URLEncodedBodyMatcher`, 25 ``'form-urlencoded-body'`` 26- :class:`~betamax_matchers.json_body.JSONBodyMatcher`, ``'json-body'`` 27- :class:`~betamax_matchers.multipart.MultipartFormDataBodyMatcher`, 28 ``'multipart-form-data-body'`` 29 30In order to use any of these we have to register them with Betamax. Below we 31will register all three but you do not need to do that if you only need to use 32one: 33 34.. code-block:: python 35 36 import betamax 37 from betamax_matchers import form_urlencoded 38 from betamax_matchers import json_body 39 from betamax_matchers import multipart 40 41 betamax.Betamax.register_request_matcher( 42 form_urlencoded.URLEncodedBodyMatcher 43 ) 44 betamax.Betamax.register_request_matcher( 45 json_body.JSONBodyMatcher 46 ) 47 betamax.Betamax.register_request_matcher( 48 multipart.MultipartFormDataBodyMatcher 49 ) 50 51All of these classes inherit from :class:`betamax.BaseMatcher` which means 52that each needs a name that will be used when specifying what matchers to use 53with Betamax. I have noted those next to the class name for each matcher 54above. Let's use the JSON body matcher in an example though: 55 56.. code-block:: python 57 58 import betamax 59 from betamax_matchers import json_body 60 # This example requires at least requests 2.5.0 61 import requests 62 63 betamax.Betamax.register_request_matcher( 64 json_body.JSONBodyMatcher 65 ) 66 67 68 def main(): 69 session = requests.Session() 70 recorder = betamax.Betamax(session, cassette_library_dir='.') 71 url = 'https://httpbin.org/post' 72 json_data = {'key': 'value', 73 'other-key': 'other-value', 74 'yet-another-key': 'yet-another-value'} 75 matchers = ['method', 'uri', 'json-body'] 76 77 with recorder.use_cassette('json-body-example', match_requests_on=matchers): 78 r = session.post(url, json=json_data) 79 80 81 if __name__ == '__main__': 82 main() 83 84If we ran that request without those matcher with hash seed randomization, 85then we would occasionally receive exceptions that a request could not be 86matched. That is because dictionaries are not inherently ordered so the body 87string of the request can change and be any of the following: 88 89.. code-block:: js 90 91 {"key": "value", "other-key": "other-value", "yet-another-key": 92 "yet-another-value"} 93 94.. code-block:: js 95 96 {"key": "value", "yet-another-key": "yet-another-value", "other-key": 97 "other-value"} 98 99.. code-block:: js 100 101 {"other-key": "other-value", "yet-another-key": "yet-another-value", 102 "key": "value"} 103 104 105.. code-block:: js 106 107 {"yet-another-key": "yet-another-value", "key": "value", "other-key": 108 "other-value"} 109 110.. code-block:: js 111 112 {"yet-another-key": "yet-another-value", "other-key": "other-value", 113 "key": "value"} 114 115.. code-block:: js 116 117 {"other-key": "other-value", "key": "value", "yet-another-key": 118 "yet-another-value"} 119 120But using the ``'json-body'`` matcher, the matcher will parse the request and 121compare python dictionaries instead of python strings. That will completely 122bypass the issues introduced by hash randomization. I use this matcher 123extensively in `github3.py`_\ 's tests. 124 125Cassette Serializers 126-------------------- 127 128By default, Betamax only comes with the JSON serializer. 129`betamax-serializers`_ provides extra serializer classes that users have 130contributed. 131 132For example, as we've seen elsewhere in our documentation, the default JSON 133serializer does not create beautiful or easy to read cassettes. As a 134substitute for that, we have the 135:class:`~betamax_serializers.pretty_json.PrettyJSONSerializer` that does that 136for you. 137 138.. code-block:: python 139 140 from betamax import Betamax 141 from betamax_serializers import pretty_json 142 143 import requests 144 145 Betamax.register_serializer(pretty_json.PrettyJSONSerializer) 146 147 session = requests.Session() 148 recorder = Betamax(session) 149 with recorder.use_cassette('testpretty', serialize_with='prettyjson'): 150 session.request(method=method, url=url, ...) 151 152 153This will give us a pretty-printed cassette like: 154 155.. literalinclude:: ../examples/cassettes/more-complicated-cassettes.json 156 :language: js 157 158.. links 159 160.. _VCR: 161 https://relishapp.com/vcr/vcr 162.. _betamax-matchers: 163 https://pypi.python.org/pypi/betamax-matchers 164.. _betamax-serializers: 165 https://pypi.python.org/pypi/betamax-serializers 166.. _github3.py: 167 https://github.com/sigmavirus24/github3.py 168