diff --git a/docs/conf.py b/docs/conf.py index 3aab35b..17de998 100755 --- a/docs/conf.py +++ b/docs/conf.py @@ -266,5 +266,7 @@ texinfo_documents = [ requests_uri = 'http://docs.python-requests.org/en/latest/' urllib3_uri = 'http://urllib3.readthedocs.org/en/latest' +python_uri = 'http://docs.python.org/3.3' intersphinx_mapping = {'requests': (requests_uri, None), - 'urllib3': (urllib3_uri, None)} + 'urllib3': (urllib3_uri, None), + 'python': (python_uri, None)} diff --git a/docs/matching.rst b/docs/matching.rst index 8df2826..3072e68 100644 --- a/docs/matching.rst +++ b/docs/matching.rst @@ -74,3 +74,22 @@ It can be used as a replace for the method and/or the URL. 'resp' >>> session.post('mock://whatever/you/like') 'resp' + + +Regular Expressions +=================== + +URLs can be specified with a regular expression using the python :py:mod:`re` module. +To use this you should pass an object created by :py:meth:`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. + +.. code:: python + + >>> 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. diff --git a/requests_mock/adapter.py b/requests_mock/adapter.py index 8d9e2c3..ce4578d 100644 --- a/requests_mock/adapter.py +++ b/requests_mock/adapter.py @@ -168,6 +168,10 @@ class _Matcher(object): if self.url is ANY: return True + # regular expression matching + if hasattr(self.url, 'search'): + return self.url.search(request.url) is not None + url = urlparse.urlparse(request.url.lower()) if self.url_parts.scheme and url.scheme != self.url_parts.scheme: diff --git a/requests_mock/tests/test_adapter.py b/requests_mock/tests/test_adapter.py index 5767ab2..b13eb85 100644 --- a/requests_mock/tests/test_adapter.py +++ b/requests_mock/tests/test_adapter.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import re + import requests import six @@ -287,3 +289,10 @@ class SessionAdapterTests(base.TestCase): for u in ('mock://a', 'mock://b', 'mock://c'): resp = self.session.get(u) self.assertEqual('resp', resp.text) + + def test_with_regexp(self): + self.adapter.register_uri('GET', re.compile('tester.com'), text='resp') + + for u in ('mocK://www.tester.com/a', 'mock://abc.tester.com'): + resp = self.session.get(u) + self.assertEqual('resp', resp.text) diff --git a/requests_mock/tests/test_matcher.py b/requests_mock/tests/test_matcher.py index 205774e..933e07e 100644 --- a/requests_mock/tests/test_matcher.py +++ b/requests_mock/tests/test_matcher.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import re + import requests from requests_mock import adapter @@ -180,3 +182,15 @@ class TestMatcher(base.TestCase): self.assertNoMatch('http://www.test.com', 'http://another', matcher_method=ANY) + + def test_match_with_regex(self): + r1 = re.compile('test.com/a') + r2 = re.compile('/b/c') + + self.assertMatch(r1, 'http://mock.test.com/a/b') + self.assertMatch(r1, 'http://test.com/a/') + self.assertMatch(r1, 'mock://test.com/a/b') + self.assertNoMatch(r1, 'mock://test.com/') + + self.assertMatch(r2, 'http://anything/a/b/c/d') + self.assertMatch(r2, 'mock://anything/a/b/c/d')