Doctest fixups

This commit is contained in:
Jamie Lennox 2014-06-23 22:37:36 +10:00
parent 4040a190d6
commit 97fb2bce39
6 changed files with 114 additions and 50 deletions

View File

@ -5,9 +5,9 @@ Adapter Usage
Creating an Adapter Creating an Adapter
=================== ===================
The standard `requests`_ means of using an adapter is to :py:meth:`requests.Session.mount` it on a created session. This is not the only way to load the adapter, however the same interactions will be used. The standard `requests`_ means of using an adapter is to :py:meth:`~requests.Session.mount` it on a created session. This is not the only way to load the adapter, however the same interactions will be used.
.. code:: python .. doctest::
>>> import requests >>> import requests
>>> import requests_mock >>> import requests_mock
@ -24,14 +24,14 @@ Registering Responses
Responses are registered with the :py:meth:`requests_mock.Adapter.register_uri` function on the adapter. Responses are registered with the :py:meth:`requests_mock.Adapter.register_uri` function on the adapter.
.. code:: python .. doctest::
>>> adapter.register_uri('GET', 'mock://test.com', text='Success') >>> adapter.register_uri('GET', 'mock://test.com', text='Success')
>>> resp = session.get('mock://test.com') >>> resp = session.get('mock://test.com')
>>> resp.text >>> resp.text
'Success' 'Success'
:py:meth:`requests_mock.Adapter.register_uri` takes the HTTP method, the URI and then information that is used to build the response. This information includes: :py:meth:`~requests_mock.Adapter.register_uri` takes the HTTP method, the URI and then information that is used to build the response. This information includes:
:status_code: The HTTP status response to return. Defaults to 200. :status_code: The HTTP status response to return. Defaults to 200.
:reason: The reason text that accompanies the Status (e.g. 'OK' in '200 OK') :reason: The reason text that accompanies the Status (e.g. 'OK' in '200 OK')
@ -47,7 +47,7 @@ To specify the body of the response there are a number of options that depend on
These options are named to coincide with the parameters on a :py:class:`requests.Response` object. For example: These options are named to coincide with the parameters on a :py:class:`requests.Response` object. For example:
.. code:: python .. doctest::
>>> adapter.register_uri('GET', 'mock://test.com/1', json={'a': 'b'}, status_code=200) >>> adapter.register_uri('GET', 'mock://test.com/1', json={'a': 'b'}, status_code=200)
>>> resp = session.get('mock://test.com/1') >>> resp = session.get('mock://test.com/1')
@ -85,9 +85,9 @@ The available properties on the `context` are:
:status_code: The status code that is to be returned in the response. :status_code: The status code that is to be returned in the response.
:reason: The string HTTP status code reason that is to be returned in the response. :reason: The string HTTP status code reason that is to be returned in the response.
These parameters are populated initially from the variables provided to the :py:meth:`requests_mock.Adapter.register_uri` function and if they are modified on the context object then those changes will be reflected in the response. These parameters are populated initially from the variables provided to the :py:meth:`~requests_mock.Adapter.register_uri` function and if they are modified on the context object then those changes will be reflected in the response.
.. code:: python .. doctest::
>>> def text_callback(request, context): >>> def text_callback(request, context):
... context.status_code = 200 ... context.status_code = 200
@ -109,7 +109,7 @@ Response Lists
Multiple responses can be provided to be returned in order by specifying the keyword parameters in a list. Multiple responses can be provided to be returned in order by specifying the keyword parameters in a list.
If the list is exhausted then the last response will continue to be returned. If the list is exhausted then the last response will continue to be returned.
.. code:: python .. doctest::
>>> adapter.register_uri('GET', 'mock://test.com/4', [{'text': 'resp1', 'status_code': 300}, >>> adapter.register_uri('GET', 'mock://test.com/4', [{'text': 'resp1', 'status_code': 300},
... {'text': 'resp2', 'status_code': 200}]) ... {'text': 'resp2', 'status_code': 200}])

View File

@ -39,6 +39,7 @@ import requests_mock # noqa
# Add any Sphinx extension module names here, as strings. They can be # Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', extensions = ['sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.viewcode', 'sphinx.ext.viewcode',
'sphinx.ext.intersphinx'] 'sphinx.ext.intersphinx']

View File

@ -14,16 +14,16 @@ The fixture mocks the :py:meth:`requests.Session.get_adapter` method so that all
The fixture provides the same interfaces as the adapter. The fixture provides the same interfaces as the adapter.
.. code:: python .. doctest::
>>> import requests >>> import requests
>>> from requests_mock.contrib import fixture >>> from requests_mock.contrib import fixture
>>> import testtools >>> import testtools
>>> class MyTestCase(testtools.TestCase): >>> class MyTestCase(testtools.TestCase):
...
... TEST_URL = 'http://www.google.com' ... TEST_URL = 'http://www.google.com'
...
... def setUp(self): ... def setUp(self):
... super(MyTestCase, self).setUp() ... super(MyTestCase, self).setUp()
... self.requests_mock = self.useFixture(requests_mock.Mock()) ... self.requests_mock = self.useFixture(requests_mock.Mock())

View File

@ -4,39 +4,70 @@ Request Matching
Whilst it is preferable to provide the whole URI to :py:meth:`requests_mock.Adapter.register_uri` it is possible to just specify components. Whilst it is preferable to provide the whole URI to :py:meth:`requests_mock.Adapter.register_uri` it is possible to just specify components.
The examples in this file are loaded with:
.. doctest::
>>> import requests
>>> import requests_mock
>>> adapter = requests_mock.Adapter()
>>> session = requests.Session()
>>> session.mount('mock', adapter)
Basic Basic
===== =====
.. doctest::
:hide:
>>> import requests
>>> import requests_mock
>>> adapter = requests_mock.Adapter()
>>> session = requests.Session()
>>> session.mount('mock', adapter)
You can specify a protocol-less path: You can specify a protocol-less path:
.. code:: python .. doctest::
>>> adapter.register_uri('GET', '//test.com/5', text='resp') .. >>> adapter.register_uri('GET', '//test.com/', text='resp')
>>> session.get('mock://test.com/5').text .. >>> session.get('mock://test.com/').text
'resp' .. 'resp'
or you can specify just a path: or you can specify just a path:
.. code:: python .. doctest::
>>> adapter.register_uri('GET', '/6', text='resp')
>>> session.get('mock://test.com/6').text
'resp'
>>> session.get('mock://another.com/6').text
'resp'
.. >>> adapter.register_uri('GET', '/path', text='resp')
.. >>> session.get('mock://test.com/path').text
.. 'resp'
.. >>> session.get('mock://another.com/path').text
.. 'resp'
Query Strings Query Strings
============= =============
.. doctest::
:hide:
>>> import requests
>>> import requests_mock
>>> adapter = requests_mock.Adapter()
>>> session = requests.Session()
>>> session.mount('mock', adapter)
Query strings provided to a register will match so long as at least those provided form part of the request. Query strings provided to a register will match so long as at least those provided form part of the request.
.. code:: python .. doctest::
>>> adapter.register_uri('GET', '/7?a=1', text='resp') >>> adapter.register_uri('GET', '/7?a=1', text='resp')
>>> session.get('mock://test.com/7?a=1&b=2').text >>> session.get('mock://test.com/7?a=1&b=2').text
'resp' 'resp'
If any part of the query string is wrong then it will not match.
.. doctest::
>>> session.get('mock://test.com/7?a=3') >>> session.get('mock://test.com/7?a=3')
Traceback (most recent call last): Traceback (most recent call last):
... ...
@ -44,7 +75,7 @@ Query strings provided to a register will match so long as at least those provid
This can be a problem in certain situations, so if you wish to match only the complete query string there is a flag `complete_qs`: This can be a problem in certain situations, so if you wish to match only the complete query string there is a flag `complete_qs`:
.. code:: python .. doctest::
>>> adapter.register_uri('GET', '/8?a=1', complete_qs=True, text='resp') >>> adapter.register_uri('GET', '/8?a=1', complete_qs=True, text='resp')
>>> session.get('mock://test.com/8?a=1&b=2') >>> session.get('mock://test.com/8?a=1&b=2')
@ -59,7 +90,16 @@ Matching ANY
There is a special symbol at `requests_mock.ANY` which acts as the wildcard to match anything. There is a special symbol at `requests_mock.ANY` which acts as the wildcard to match anything.
It can be used as a replace for the method and/or the URL. It can be used as a replace for the method and/or the URL.
.. code:: python .. doctest::
:hide:
>>> import requests
>>> import requests_mock
>>> adapter = requests_mock.Adapter()
>>> session = requests.Session()
>>> session.mount('mock', adapter)
.. doctest::
>>> adapter.register_uri(requests_mock.ANY, 'mock://test.com/8', text='resp') >>> adapter.register_uri(requests_mock.ANY, 'mock://test.com/8', text='resp')
>>> session.get('mock://test.com/8').text >>> session.get('mock://test.com/8').text
@ -67,15 +107,14 @@ It can be used as a replace for the method and/or the URL.
>>> session.post('mock://test.com/8').text >>> session.post('mock://test.com/8').text
'resp' 'resp'
.. code:: python .. doctest::
>>> adapter.register_uri(requests_mock.ANY, requests_mock.ANY, text='resp') >>> adapter.register_uri(requests_mock.ANY, requests_mock.ANY, text='resp')
>>> session.get('mock://whatever/you/like') >>> session.get('mock://whatever/you/like').text
'resp' 'resp'
>>> session.post('mock://whatever/you/like') >>> session.post('mock://whatever/you/like').text
'resp' 'resp'
Regular Expressions Regular Expressions
=================== ===================
@ -84,13 +123,22 @@ To use this you should pass an object created by :py:func:`re.compile`.
The URL is then matched using :py:meth:`re.regex.search` which means that it will match any component of the url, so if you want to match the start of a URL you will have to anchor it. The URL is then matched using :py:meth:`re.regex.search` which means that it will match any component of the url, so if you want to match the start of a URL you will have to anchor it.
.. code:: python .. doctest::
:hide:
>>> import re >>> import requests
>>> matcher = re.compile('tester.com/a') >>> import requests_mock
>>> adapter.register_uri('GET', matcher, text='resp') >>> adapter = requests_mock.Adapter()
>>> session.get('mock://www.tester.com/a/b').text >>> session = requests.Session()
'resp' >>> session.mount('mock', adapter)
.. doctest::
.. >>> import re
.. >>> matcher = re.compile('tester.com/a')
.. >>> adapter.register_uri('GET', matcher, text='resp')
.. >>> session.get('mock://www.tester.com/a/b').text
.. 'resp'
If you use regular expression matching then *requests-mock* can't do it's normal query string or path only matching, that will need to be part of the expression. If you use regular expression matching then *requests-mock* can't do it's normal query string or path only matching, that will need to be part of the expression.
@ -101,12 +149,21 @@ Request Headers
A dictionary of headers can be supplied such that the request will only match if the available headers also match. A dictionary of headers can be supplied such that the request will only match if the available headers also match.
Only the headers that are provided need match, any additional headers will be ignored. Only the headers that are provided need match, any additional headers will be ignored.
.. code:: python .. doctest::
:hide:
>>> adapter.register_uri('POST', 'mock://test.com', request_headers={'key', 'val'}, text='resp') >>> import requests
>>> session.post('mock://test.com', headers={'key': 'val', 'another': 'header'}).text >>> import requests_mock
>>> adapter = requests_mock.Adapter()
>>> session = requests.Session()
>>> session.mount('mock', adapter)
.. doctest::
>>> adapter.register_uri('POST', 'mock://test.com/headers', request_headers={'key': 'val'}, text='resp')
>>> session.post('mock://test.com/headers', headers={'key': 'val', 'another': 'header'}).text
'resp' 'resp'
>>> session.post('mock://test.com') >>> resp = session.post('mock://test.com/headers')
Traceback (most recent call last): Traceback (most recent call last):
... ...
requests_mock.exceptions.NoMockAddress: No mock address: POST mock://test.com/ requests_mock.exceptions.NoMockAddress: No mock address: POST mock://test.com/headers

View File

@ -9,7 +9,7 @@ Context Manager
The Mocker object can work as a context manager. The Mocker object can work as a context manager.
.. code:: python .. doctest::
>>> import requests >>> import requests
>>> import requests_mock >>> import requests_mock
@ -25,7 +25,7 @@ Decorator
Mocker can also be used as a decorator. The created object will then be passed as the last positional argument. Mocker can also be used as a decorator. The created object will then be passed as the last positional argument.
.. code:: python .. doctest::
>>> @requests_mock.Mocker() >>> @requests_mock.Mocker()
... def test_function(m): ... def test_function(m):
@ -37,14 +37,14 @@ Mocker can also be used as a decorator. The created object will then be passed a
If the position of the mock is likely to conflict with other arguments you can pass the `kw` argument to the Mocker to have the mocker object passed as that keyword argument instead. If the position of the mock is likely to conflict with other arguments you can pass the `kw` argument to the Mocker to have the mocker object passed as that keyword argument instead.
.. code:: python .. doctest::
>>> @requests_mock.Mocker(kw='mock') >>> @requests_mock.Mocker(kw='mock')
... def test_function(**kwargs): ... def test_kw_function(**kwargs):
... kwargs['mock'].register_uri('GET', 'http://test.com', test='resp') ... kwargs['mock'].register_uri('GET', 'http://test.com', text='resp')
... return requests.get('http://test.com').text ... return requests.get('http://test.com').text
... ...
>>> test_function() >>> test_kw_function()
'resp' 'resp'
Real HTTP Requests Real HTTP Requests
@ -54,12 +54,12 @@ The Mocker object takes the following parameters:
:real_http (bool): If True then any requests that are not handled by the mocking adapter will be forwarded to the real server. Defaults to False. :real_http (bool): If True then any requests that are not handled by the mocking adapter will be forwarded to the real server. Defaults to False.
.. code:: python .. doctest::
>>> with requests_mock.Mocker(real_http=True) as m: >>> with requests_mock.Mocker(real_http=True) as m:
... m.register_uri('GET', 'http://test.com', text='resp') ... m.register_uri('GET', 'http://test.com', text='resp')
... print requests.get('http:/test.com').text ... print(requests.get('http://test.com').text)
... print requests.get('http://www.google.com').status_code ... print(requests.get('http://www.google.com').status_code) # doctest: +SKIP
... ...
'resp' 'resp'
200 200

View File

@ -28,6 +28,12 @@ deps =
# note this only works under python 3 because of unicode literals # note this only works under python 3 because of unicode literals
commands = commands =
python -m doctest README.rst python -m doctest README.rst
[testenv:sphinx-doctest]
# note this only works under python 3 because of unicode literals
commands =
mkdir build/sphinx/doctest
sphinx-build -b doctest docs build/sphinx/doctest
deps = deps =
ipdb pbr
{[testenv]deps} {[testenv]deps}