[Python-modules-commits] [responses] 01/03: Import responses_0.5.1.orig.tar.gz
Ondřej Nový
onovy-guest at moszumanska.debian.org
Mon Apr 4 20:14:47 UTC 2016
This is an automated email from the git hooks/post-receive script.
onovy-guest pushed a commit to branch master
in repository responses.
commit 99e17f1ae8ec5db6b89b1231dfcf0b64469e0949
Author: Ondřej Nový <novy at ondrej.org>
Date: Mon Apr 4 22:04:37 2016 +0200
Import responses_0.5.1.orig.tar.gz
---
CHANGES | 22 +++++
LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++
MANIFEST.in | 2 +
PKG-INFO | 83 +++++++++++++----
README.rst | 75 +++++++++++----
responses.egg-info/PKG-INFO | 83 +++++++++++++----
responses.egg-info/SOURCES.txt | 3 +
responses.egg-info/requires.txt | 10 +-
responses.py | 182 +++++++++++++++++++++---------------
setup.cfg | 3 +
setup.py | 44 +++++++--
11 files changed, 567 insertions(+), 141 deletions(-)
diff --git a/CHANGES b/CHANGES
new file mode 100644
index 0000000..636e038
--- /dev/null
+++ b/CHANGES
@@ -0,0 +1,22 @@
+0.5.0
+-----
+
+- Allow passing a JSON body to `response.add` (GH-82)
+- Improve ConnectionError emulation (GH-73)
+- Correct assertion in assert_all_requests_are_fired (GH-71)
+
+0.4.0
+-----
+
+- Requests 2.0+ is required
+- Mocking now happens on the adapter instead of the session
+
+0.3.0
+-----
+
+- Add the ability to mock errors (GH-22)
+- Add responses.mock context manager (GH-36)
+- Support custom adapters (GH-33)
+- Add support for regexp error matching (GH-25)
+- Add support for dynamic bodies via `responses.add_callback` (GH-24)
+- Preserve argspec when using `responses.activate` decorator (GH-18)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..52b44b2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright 2015 David Cramer
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..ef90168
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,2 @@
+include README.rst CHANGES LICENSE
+global-exclude *~
diff --git a/PKG-INFO b/PKG-INFO
index ff94bb9..33c16c3 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,19 +1,21 @@
Metadata-Version: 1.1
Name: responses
-Version: 0.3.0
+Version: 0.5.1
Summary: A utility library for mocking out the `requests` Python library.
-Home-page: UNKNOWN
+Home-page: https://github.com/getsentry/responses
Author: David Cramer
Author-email: UNKNOWN
-License: UNKNOWN
+License: Apache 2.0
Description: Responses
=========
- .. image:: https://travis-ci.org/dropbox/responses.png?branch=master
- :target: https://travis-ci.org/dropbox/responses
+ .. image:: https://travis-ci.org/getsentry/responses.png?branch=master
+ :target: https://travis-ci.org/getsentry/responses
A utility library for mocking out the `requests` Python library.
+ .. note:: Responses requires Requests >= 2.0
+
Response body as string
-----------------------
@@ -36,6 +38,26 @@ Description: Responses
assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'
assert responses.calls[0].response.text == '{"error": "not found"}'
+ You can also specify a JSON object instead of a body string.
+
+ .. code-block:: python
+
+ import responses
+ import requests
+
+ @responses.activate
+ def test_my_api():
+ 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"}'
+
Request callback
----------------
@@ -56,7 +78,7 @@ Description: Responses
return (200, headers, json.dumps(resp_body))
responses.add_callback(
- responses.GET, 'http://calc.com/sum',
+ responses.POST, 'http://calc.com/sum',
callback=request_callback,
content_type='application/json',
)
@@ -111,30 +133,51 @@ Description: Responses
# All calls to 'http://twitter.com/api/1/foobar' will throw exception.
- .. note:: Responses requires Requests >= 1.0
+ Responses as a context manager
+ ------------------------------
+ .. code-block:: python
- License
- =======
+ import responses
+ import requests
- ::
- Copyright 2013 Dropbox, Inc.
+ 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
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ Assertions on declared responses
+ --------------------------------
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ By default Responses will 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:
+
+ .. code-block:: python
+
+ 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')
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development
diff --git a/README.rst b/README.rst
index e425fec..d64bbe2 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,13 @@
Responses
=========
-.. image:: https://travis-ci.org/dropbox/responses.png?branch=master
- :target: https://travis-ci.org/dropbox/responses
+.. image:: https://travis-ci.org/getsentry/responses.png?branch=master
+ :target: https://travis-ci.org/getsentry/responses
A utility library for mocking out the `requests` Python library.
+.. note:: Responses requires Requests >= 2.0
+
Response body as string
-----------------------
@@ -28,6 +30,26 @@ Response body as string
assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'
assert responses.calls[0].response.text == '{"error": "not found"}'
+You can also specify a JSON object instead of a body string.
+
+.. code-block:: python
+
+ import responses
+ import requests
+
+ @responses.activate
+ def test_my_api():
+ 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"}'
+
Request callback
----------------
@@ -48,7 +70,7 @@ Request callback
return (200, headers, json.dumps(resp_body))
responses.add_callback(
- responses.GET, 'http://calc.com/sum',
+ responses.POST, 'http://calc.com/sum',
callback=request_callback,
content_type='application/json',
)
@@ -103,24 +125,43 @@ A response can also throw an exception as follows.
# All calls to 'http://twitter.com/api/1/foobar' will throw exception.
-.. note:: Responses requires Requests >= 1.0
+Responses as a context manager
+------------------------------
+.. code-block:: python
-License
-=======
+ import responses
+ import requests
-::
- Copyright 2013 Dropbox, Inc.
+ 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
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+Assertions on declared responses
+--------------------------------
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+By default Responses will 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:
+
+.. code-block:: python
+
+ 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')
diff --git a/responses.egg-info/PKG-INFO b/responses.egg-info/PKG-INFO
index ff94bb9..33c16c3 100644
--- a/responses.egg-info/PKG-INFO
+++ b/responses.egg-info/PKG-INFO
@@ -1,19 +1,21 @@
Metadata-Version: 1.1
Name: responses
-Version: 0.3.0
+Version: 0.5.1
Summary: A utility library for mocking out the `requests` Python library.
-Home-page: UNKNOWN
+Home-page: https://github.com/getsentry/responses
Author: David Cramer
Author-email: UNKNOWN
-License: UNKNOWN
+License: Apache 2.0
Description: Responses
=========
- .. image:: https://travis-ci.org/dropbox/responses.png?branch=master
- :target: https://travis-ci.org/dropbox/responses
+ .. image:: https://travis-ci.org/getsentry/responses.png?branch=master
+ :target: https://travis-ci.org/getsentry/responses
A utility library for mocking out the `requests` Python library.
+ .. note:: Responses requires Requests >= 2.0
+
Response body as string
-----------------------
@@ -36,6 +38,26 @@ Description: Responses
assert responses.calls[0].request.url == 'http://twitter.com/api/1/foobar'
assert responses.calls[0].response.text == '{"error": "not found"}'
+ You can also specify a JSON object instead of a body string.
+
+ .. code-block:: python
+
+ import responses
+ import requests
+
+ @responses.activate
+ def test_my_api():
+ 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"}'
+
Request callback
----------------
@@ -56,7 +78,7 @@ Description: Responses
return (200, headers, json.dumps(resp_body))
responses.add_callback(
- responses.GET, 'http://calc.com/sum',
+ responses.POST, 'http://calc.com/sum',
callback=request_callback,
content_type='application/json',
)
@@ -111,30 +133,51 @@ Description: Responses
# All calls to 'http://twitter.com/api/1/foobar' will throw exception.
- .. note:: Responses requires Requests >= 1.0
+ Responses as a context manager
+ ------------------------------
+ .. code-block:: python
- License
- =======
+ import responses
+ import requests
- ::
- Copyright 2013 Dropbox, Inc.
+ 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
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
+ Assertions on declared responses
+ --------------------------------
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ By default Responses will 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:
+
+ .. code-block:: python
+
+ 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')
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development
diff --git a/responses.egg-info/SOURCES.txt b/responses.egg-info/SOURCES.txt
index aecad05..bafa0ab 100644
--- a/responses.egg-info/SOURCES.txt
+++ b/responses.egg-info/SOURCES.txt
@@ -1,3 +1,6 @@
+CHANGES
+LICENSE
+MANIFEST.in
README.rst
responses.py
setup.cfg
diff --git a/responses.egg-info/requires.txt b/responses.egg-info/requires.txt
index 65bcbef..f6ae218 100644
--- a/responses.egg-info/requires.txt
+++ b/responses.egg-info/requires.txt
@@ -1,8 +1,12 @@
-requests
-mock
+requests>=2.0
+cookies
six
+[:python_version in "2.6, 2.7, 3.2"]
+mock
+
[tests]
pytest
+coverage >= 3.7.1, < 5.0.0
pytest-cov
-flake8
\ No newline at end of file
+flake8
diff --git a/responses.py b/responses.py
index cc75d60..edc4dd2 100644
--- a/responses.py
+++ b/responses.py
@@ -1,80 +1,83 @@
-"""
-Copyright 2013 Dropbox, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-"""
-
from __future__ import (
absolute_import, print_function, division, unicode_literals
)
+import inspect
+import json as json_module
import re
import six
-if six.PY2:
- try:
- from six import cStringIO as BufferIO
- except ImportError:
- from six import StringIO as BufferIO
-else:
- from io import BytesIO as BufferIO
-
-import inspect
from collections import namedtuple, Sequence, Sized
-from functools import update_wrapper as _update_wrapper
+from functools import update_wrapper
+from cookies import Cookies
+from requests.utils import cookiejar_from_dict
from requests.exceptions import ConnectionError
+from requests.sessions import REDIRECT_STATI
+
try:
from requests.packages.urllib3.response import HTTPResponse
except ImportError:
from urllib3.response import HTTPResponse
+
if six.PY2:
from urlparse import urlparse, parse_qsl
else:
from urllib.parse import urlparse, parse_qsl
+if six.PY2:
+ try:
+ from six import cStringIO as BufferIO
+ except ImportError:
+ from six import StringIO as BufferIO
+else:
+ from io import BytesIO as BufferIO
+
Call = namedtuple('Call', ['request', 'response'])
_wrapper_template = """\
-def _wrapper_(%(signature)s):
- return %(tgt_func)s(%(signature)s)
+def wrapper%(signature)s:
+ with responses:
+ return func%(funcargs)s
"""
-def update_wrapper(wrapper, wrapped):
- """Preserves the argspec for a wrapped function so that testing tools such
- as pytest can continue to use their fixture injection.
+def _is_string(s):
+ return isinstance(s, (six.string_types, six.text_type))
- :param wrapper: the wrapper function to update
- :param wrapped: the decorated test function
- """
- newargspec = inspect.getargspec(wrapped)
- need_self = len(newargspec[0]) > 0 and newargspec[0][0] == 'self'
- if need_self:
- newargspec = (newargspec[0],) + newargspec[1:]
+def _is_redirect(response):
+ try:
+ # 2.0.0 <= requests <= 2.2
+ return response.is_redirect
+ except AttributeError:
+ # requests > 2.2
+ return (
+ # use request.sessions conditional
+ response.status_code in REDIRECT_STATI and
+ 'location' in response.headers
+ )
- signature = inspect.formatargspec(*newargspec)[1:-1]
- ctx = {'signature': signature, 'tgt_func': 'tgt_func'}
- evaldict = {'tgt_func': wrapper}
+def get_wrapped(func, wrapper_template, evaldict):
+ # Preserve the argspec for the wrapped function so that testing
+ # tools such as pytest can continue to use their fixture injection.
+ args, a, kw, defaults = inspect.getargspec(func)
- six.exec_(_wrapper_template % ctx, evaldict)
+ signature = inspect.formatargspec(args, a, kw, defaults)
+ is_bound_method = hasattr(func, '__self__')
+ if is_bound_method:
+ args = args[1:] # Omit 'self'
+ callargs = inspect.formatargspec(args, a, kw, None)
- wrapper = evaldict['_wrapper_']
- if hasattr(wrapped, 'func_defaults'):
- wrapper.func_defaults = wrapped.func_defaults
- _update_wrapper(wrapper, wrapped)
+ ctx = {'signature': signature, 'funcargs': callargs}
+ six.exec_(wrapper_template % ctx, evaldict)
+
+ wrapper = evaldict['wrapper']
+
+ update_wrapper(wrapper, func)
+ if is_bound_method:
+ wrapper = wrapper.__get__(func.__self__, type(func.__self__))
return wrapper
@@ -98,6 +101,15 @@ class CallList(Sequence, Sized):
self._calls = []
+def _ensure_url_default_path(url, match_querystring):
+ if _is_string(url) and url.count('/') == 2:
+ if match_querystring:
+ return url.replace('?', '/?', 1)
+ else:
+ return url + '/'
+ return url
+
+
class RequestsMock(object):
DELETE = 'DELETE'
GET = 'GET'
@@ -107,9 +119,10 @@ class RequestsMock(object):
POST = 'POST'
PUT = 'PUT'
- def __init__(self):
+ def __init__(self, assert_all_requests_are_fired=True):
self._calls = CallList()
self.reset()
+ self.assert_all_requests_are_fired = assert_all_requests_are_fired
def reset(self):
self._urls = []
@@ -117,12 +130,16 @@ class RequestsMock(object):
def add(self, method, url, body='', match_querystring=False,
status=200, adding_headers=None, stream=False,
- content_type='text/plain'):
+ content_type='text/plain', json=None):
+
+ # if we were passed a `json` argument,
+ # override the body and content_type
+ if json:
+ body = json_module.dumps(json)
+ content_type = 'application/json'
# ensure the url has a default path set if the url is a string
- if self._is_string(url) and url.count('/') == 2:
- url = url.replace('?', '/?', 1) if match_querystring \
- else url + '/'
+ url = _ensure_url_default_path(url, match_querystring)
# body must be bytes
if isinstance(body, six.text_type):
@@ -141,6 +158,8 @@ class RequestsMock(object):
def add_callback(self, method, url, callback, match_querystring=False,
content_type='text/plain'):
+ # ensure the url has a default path set if the url is a string
+ # url = _ensure_url_default_path(url, match_querystring)
self._urls.append({
'url': url,
@@ -156,16 +175,15 @@ class RequestsMock(object):
def __enter__(self):
self.start()
+ return self
def __exit__(self, *args):
self.stop()
self.reset()
def activate(self, func):
- def wrapped(*args, **kwargs):
- with self:
- return func(*args, **kwargs)
- return update_wrapper(wrapped, func)
+ evaldict = {'responses': self, 'func': func}
+ return get_wrapped(func, _wrapper_template, evaldict)
def _find_match(self, request):
for match in self._urls:
@@ -175,14 +193,18 @@ class RequestsMock(object):
if not self._has_url_match(match, request.url):
continue
- return match
-
- return None
+ break
+ else:
+ return None
+ if self.assert_all_requests_are_fired:
+ # for each found match remove the url from the stack
+ self._urls.remove(match)
+ return match
def _has_url_match(self, match, request_url):
url = match['url']
- if self._is_string(url):
+ if _is_string(url):
if match['match_querystring']:
return self._has_strict_url_match(url, request_url)
else:
@@ -204,16 +226,14 @@ class RequestsMock(object):
other_qsl = sorted(parse_qsl(other_parsed.query))
return url_qsl == other_qsl
- def _is_string(self, s):
- return isinstance(s, (six.string_types, six.text_type))
-
- def _on_request(self, session, request, **kwargs):
+ def _on_request(self, adapter, request, **kwargs):
match = self._find_match(request)
-
# TODO(dcramer): find the correct class for this
if match is None:
- error_msg = 'Connection refused: {0}'.format(request.url)
+ error_msg = 'Connection refused: {0} {1}'.format(request.method,
+ request.url)
response = ConnectionError(error_msg)
+ response.request = request
self._calls.add(request, response)
raise response
@@ -246,30 +266,46 @@ class RequestsMock(object):
preload_content=False,
)
- adapter = session.get_adapter(request.url)
-
response = adapter.build_response(request, response)
if not match.get('stream'):
response.content # NOQA
+ try:
+ resp_cookies = Cookies.from_request(response.headers['set-cookie'])
+ response.cookies = cookiejar_from_dict(dict(
+ (v.name, v.value)
+ for _, v
+ in resp_cookies.items()
+ ))
+ except (KeyError, TypeError):
+ pass
+
self._calls.add(request, response)
return response
def start(self):
- import mock
-
- def unbound_on_send(session, requests, *a, **kwargs):
- return self._on_request(session, requests, *a, **kwargs)
- self._patcher = mock.patch('requests.Session.send', unbound_on_send)
+ try:
+ from unittest import mock
+ except ImportError:
+ import mock
+
+ def unbound_on_send(adapter, request, *a, **kwargs):
+ return self._on_request(adapter, request, *a, **kwargs)
+ self._patcher = mock.patch('requests.adapters.HTTPAdapter.send',
+ unbound_on_send)
self._patcher.start()
def stop(self):
self._patcher.stop()
+ if self.assert_all_requests_are_fired and self._urls:
+ raise AssertionError(
+ 'Not all requests have been executed {0!r}'.format(
+ [(url['method'], url['url']) for url in self._urls]))
# expose default mock namespace
-mock = _default_mock = RequestsMock()
+mock = _default_mock = RequestsMock(assert_all_requests_are_fired=False)
__all__ = []
for __attr in (a for a in dir(_default_mock) if not a.startswith('_')):
__all__.append(__attr)
diff --git a/setup.cfg b/setup.cfg
index 2d4181c..0e072ba 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,9 @@
[pytest]
addopts = --tb=short
+[bdist_wheel]
+universal = 1
+
[egg_info]
tag_build =
tag_date = 0
diff --git a/setup.py b/setup.py
... 97 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/responses.git
More information about the Python-modules-commits
mailing list