Giter VIP home page Giter VIP logo

httmock's Introduction

httmock

A mocking library for requests for Python 2.7 and 3.4+.

Installation

pip install httmock

Or, if you are a Gentoo user:

emerge dev-python/httmock

Usage

You can use it to mock third-party APIs and test libraries that use requests internally, conditionally using mocked replies with the urlmatch decorator:

from httmock import urlmatch, HTTMock
import requests

@urlmatch(netloc=r'(.*\.)?google\.com$')
def google_mock(url, request):
    return 'Feeling lucky, punk?'

with HTTMock(google_mock):
    r = requests.get('http://google.com/')
print r.content  # 'Feeling lucky, punk?'

The all_requests decorator doesn't conditionally block real requests. If you return a dictionary, it will map to the requests.Response object returned:

from httmock import all_requests, HTTMock
import requests

@all_requests
def response_content(url, request):
	return {'status_code': 200,
	        'content': 'Oh hai'}

with HTTMock(response_content):
	r = requests.get('https://foo_bar')

print r.status_code
print r.content

If you pass in Set-Cookie headers, requests.Response.cookies will contain the values. You can also use response method directly instead of returning a dict:

from httmock import all_requests, response, HTTMock
import requests

@all_requests
def response_content(url, request):
	headers = {'content-type': 'application/json',
	           'Set-Cookie': 'foo=bar;'}
	content = {'message': 'API rate limit exceeded'}
	return response(403, content, headers, None, 5, request)

with HTTMock(response_content):
	r = requests.get('https://api.github.com/users/whatever')

print r.json().get('message')
print r.cookies['foo']

httmock's People

Contributors

ddeka2910 avatar derekschrock avatar dplyakin avatar frewsxcv avatar garetht avatar garyvdm avatar gmmephisto avatar immerrr avatar jnovinger avatar jpmelos avatar k4ml avatar kitsunde avatar koobs avatar larryweya avatar nightblues avatar patrys avatar renatgalimov avatar simon-weber avatar ukanga avatar wieslander avatar xrotwang avatar zcourts avatar zen4ever avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

httmock's Issues

Incompatible with origin Response.raw.read

Hi!

I find that the raw.read would raise TypeError when I call raw.read(decode_content=True) in my project. Here is the error message:

TypeError: read() got an unexpected keyword argument 'decode_content'

The reason is that StringIO.read is deferent from HTTPResponse.read and there is no compatiblity in current code.

Mocked requests are more permissive with args, causing tests to pass when they should fail

I ran into this issue today, where everything worked in tests but failed when not mocked.

>>> import requests
>>> requests.post('http://example.com', 2.0)
TypeError: 'float' object is not iterable

Compare to

>>> import requests
>>> import httmock
>>> with httmock.HTTMock(lambda url, req: ''): requests.post('http://example.com', 2.0)
<Response [200]>

This is because 2.0 becomes the value of data, which must be iterable in requests, but can be anything in _fake_send, Putting in a type check for data would at least fix this (perhaps most common variant) even if it's not perfect

poor documentation

please elaborate on how to capture complex urls with urlmatch. the query, scheme etc parameters are not mentioned anywhere in the documentation, neither is the fact that you cannot match for exacts complex urls with the url parameter. Otherwise great tool, but it took several hours to figure out how to use it.

Allow content=None when stream=True

Right now if content=None when stream=True, then you get:

  File "/Users/alex/.virtualenvs/media/lib/python2.7/site-packages/httmock.py", line 194, in intercept
    stream=kwargs.get('stream', False))
  File "/Users/alex/.virtualenvs/media/lib/python2.7/site-packages/httmock.py", line 63, in response
    res.raw = BytesIO(content)
TypeError: must be string or buffer, not None

Support content encodings other than utf-8

The content attribute is always encoded as "utf-8" (source).

However, we've noticed that https://google.com/ (as of 9/29) now returns content encoded as 'ISO-8859-1'.

This breaks some tests that do an actual http request then play back the result and compare the content attributes.

If you're curious, here is a demo of what happens in a (non-mocked) google.com result:

import requests

url = "https://google.com/"
res = requests.get(url)

print(res.headers['Content-Type']) # 'text/html; charset=ISO-8859-1'
print(res.encoding)  # 'ISO-8859-1'

try:
    res.content.decode("utf8")
except Exception as e:
    print(e)

content = res.content.decode(res.encoding)

Autoserialization should work not only for dicts, but for lists too

I hit this issue on httmock==1.2.3.

Traceback (most recent call last):
  File "/home/sslypushenko/projects/refstack/refstack/tests/unit/test_api.py", line 255, in test_get_capabilities
    result = self.controller.get()
  File "/home/sslypushenko/projects/refstack/refstack/api/controllers/v1.py", line 206, in get
    json = response.json()
  File "/home/sslypushenko/projects/refstack/.tox/py34/lib/python3.4/site-packages/requests/models.py", line 809, in json
    encoding = guess_json_utf(self.content)
  File "/home/sslypushenko/projects/refstack/.tox/py34/lib/python3.4/site-packages/requests/utils.py", line 631, in guess_json_utf
    nullcount = sample.count(_null)
TypeError: Can't convert 'bytes' object to str implicitly

I know that you fixed this issue for dicts, but content response can be a list too.
It is a kind of example for from our code:

        @httmock.all_requests
        def api_mock(url, request):
            headers = {'content-type': 'application/json'}
            content = [1,2,3]
            content = json.dumps(content)
            return httmock.response(200, content, headers, None, 5, request)

Travis-CI?

It looks like you have a Travis-CI config file, but I don't see any current builds, or builds being triggered by pull requests:

https://travis-ci.org/patrys/httmock

I wanted to know if #23 was working on all the necessary platforms. :)

Include tests.py in pypi package

I'm in the process of adding httmock to the FreeBSD ports tree. One standard for most python port is to include tests.

Looking at the httmock-1.2.6.tar.gz from https://pypi.python.org/pypi/httmock this tarball does not include tests.py.

Would it be possible to include the tests.py file in the pypi package? If so I can add do-tests to the FreeBSD port.

Outbox?

It would be pretty handy to have an outbox where all requests that received a mock response would be stored for reference later by a test, similar to Django's Email Outbox.

Thoughts?

No longer works with mock objects

The 1.1.0 release no longer works when used as the return value for a mock object.

Failing test case:

class PutTest(unittest.TestCase):
    def test_put(self):
        res = httmock.response(status_code=204)
        put_mock = mock.Mock()
        put_mock.return_value = res
        response = put_mock('http://example.org', data={'foo', 'bar'})

Fails with an exception:

======================================================================
ERROR: test_put (main.PutTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/jimrollenhagen/code/httmock-bug/main.py", line 13, in test_put
    res = httmock.response(status_code=204)
  File "/Users/jimrollenhagen/virtualenvs/httmockbug/lib/python2.7/site-packages/httmock.py", line 43, in response
    res.url = request.url
AttributeError: 'NoneType' object has no attribute 'url'

----------------------------------------------------------------------

Treats False results as handling failure

Requests treats responses with status codes from 400 to 600 as False, but HTTMock's _fake_send treats False return values as lookup failures. This means that HTTMock cannot simulate an error result. It will fall back to the real Session.send, which will do a real network operation, which may produce an error result. (Suggestion: emit a DEBUG log when HTTMock falls back to a real network operation.)

Python 3.5?

I was just wondering if this project is Python 3.5 compliant?

how to use httmock with fixtures

I have a set of increasingly complicated data from an outside platform I need to mock. I would like to simplify that with fixtures, if possible. Are there any recommended libraries that work nicely with httmock?

mock by request method

Perhaps I am mistaken, but it looks like your library does not support mocking by method, e.g. how would you distinguish between a GET and a POST with the same request url?

Missing LICENSE breaks install

The PYPI tarball, httmock-1.0.2.tar.gz (sha1sum 72db99d70f7997435a2de1ee42f83a065428dd52) lacks a LICENSE, preventing setup.py from working:

Downloading/unpacking httmock==1.0.2 (from -r requirements.txt (line 13))
  Running setup.py egg_info for package httmock
    Traceback (most recent call last):
      File "", line 14, in 
      File "/home/abentley/canonical/charmworld/build/httmock/setup.py", line 7, in 
        os.path.join(os.path.dirname(__file__), 'LICENSE')).read().strip()
    IOError: [Errno 2] No such file or directory: '/home/abentley/canonical/charmworld/build/httmock/LICENSE'
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):

  File "", line 14, in 

  File "/home/abentley/canonical/charmworld/build/httmock/setup.py", line 7, in 

    os.path.join(os.path.dirname(__file__), 'LICENSE')).read().strip()

IOError: [Errno 2] No such file or directory: '/home/abentley/canonical/charmworld/build/httmock/LICENSE'

Add changelog

It would be great to have a changelog file where the changes between releases were detailed.
It would probably be too tedious to add all previous releases, but at least creating one just with the last release and updating it on future releases would be very helpful for people using this library.

Problem with requests and iter_lines

I am trying to mock a response for requests but httmock breaks iter_lines from requests.

With

import requests
from httmock import urlmatch, HTTMock


@urlmatch(netloc=r'uw.edu')
def local_mock(url, request):
    return {'status_code': 200, 'content': 'Hello, World'}


def main():
    with HTTMock(local_mock):
        print list(requests.get('http://uw.edu').iter_lines())

if __name__ == '__main__':
    main()

I get the following error

Traceback (most recent call last):
  File "mock_bug.py", line 15, in <module>
    main()
  File "mock_bug.py", line 12, in main
    print list(requests.get('http://uw.edu').iter_lines())
  File ".../python2.7/site-packages/requests/models.py", line 648, in iter_lines
    decode_unicode=decode_unicode):
  File ".../python2.7/site-packages/requests/models.py", line 625, in generate
    chunk = self.raw.read(chunk_size)
AttributeError: 'NoneType' object has no attribute 'read'

Running the same code without the mock works fine.

Provide mock with a Request, not PreparedRequest

Providing a Request instead of a PreparedRequest would make complicated mocking much easier: Request basically holds the kwargs to requests.method, while PreparedRequest only stores encoded versions of the kwargs.

For example, if you'd like to replay request params (maybe when testing an OAuth flow), PreparedRequest requires reparsing request.path_url, while Request would provide request.params directly.

Is it possible to mock connection errors?

>>> import requests
>>> requests.get('http://fake.fake')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 55, in get
    return request('get', url, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 44, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/adapters.py", line 378, in send
    raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='fake.fake', port=80): Max retries exceeded with url: / (Caused by <class 'socket.gaierror'>: [Errno 8] nodename nor servname provided, or not known)

I want to throw the ConnectionError above.

requests.Session.prepare_request require requests > 2.0

The latest version - https://github.com/patrys/httmock/blob/master/httmock.py#L109

When running with requests-1.2.0, got the following:-

Traceback (most recent call last):
  File "/home/kamal/clean/marimore_m7msgezsms/branches/219-private-routing-ordered/src/m7msgezsms/apps/ezsms_api_test/tests/tests_call_api.py", line 376, in test_valid_update_call_status
    with httmock.HTTMock(_get_response):
  File "/home/kamal/clean/marimore_m7msgezsms/branches/219-private-routing-ordered/eggs/httmock-1.2.3-py2.7.egg/httmock.py", line 109, in __enter__
    self._real_session_prepare_request = requests.Session.prepare_request
AttributeError: type object 'Session' has no attribute 'prepare_request'

setup.py should be updated to require requests>=2.0.

Reference - https://github.com/kennethreitz/requests/blob/master/HISTORY.rst#200-2013-09-24

Response doesn't always receive request's URL

When a mock function returns a string, the response's URL is not set with the request's. I'm not sure if this is on purpose, but it seems the request is not passed as a parameter here:

        elif isinstance(res, (text_type, binary_type)):
            return response(content=res, stream=kwargs.get('stream', False))

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.