diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..82391d9 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include requirements.pip + diff --git a/Makefile b/Makefile index d890c2c..42fb581 100644 --- a/Makefile +++ b/Makefile @@ -11,15 +11,17 @@ check_dependencies: python -c "import $$dependency" 2>/dev/null || (echo "You must install $$dependency in order to run httpretty's tests" && exit 3) ; \ done -unit: clean +test: unit functional doctests + +unit: @echo "Running unit tests ..." @nosetests -s --verbosity=2 --with-coverage --cover-erase --cover-inclusive tests/unit --cover-package=httpretty -functional: clean +functional: @echo "Running functional tests ..." @nosetests -s --verbosity=2 --with-coverage --cover-erase --cover-inclusive tests/functional --cover-package=httpretty -doctests: clean +doctests: @echo "Running documentation tests tests ..." @steadymark README.md diff --git a/httpretty/__init__.py b/httpretty/__init__.py index 5ed9fdf..d7d08e6 100644 --- a/httpretty/__init__.py +++ b/httpretty/__init__.py @@ -31,14 +31,40 @@ import functools import itertools import warnings import logging +import sys import traceback +PY3 = sys.version_info[0] == 3 +if PY3: + text_type = str + binary_type = bytes + import io + StringIO = io.StringIO + + class Compat_Repr(object): + def __repr__(self): + return self.__unicode__() +else: + text_type = unicode + binary_type = str + import StringIO + StringIO = StringIO.StringIO + + class Compat_Repr(object): + def __repr__(self): + return self.__unicode__().encode('utf-8') + from datetime import datetime from datetime import timedelta -from StringIO import StringIO -from urlparse import urlsplit +try: + from urllib.parse import urlsplit +except ImportError: + from urlparse import urlsplit -from BaseHTTPServer import BaseHTTPRequestHandler +try: + from http.server import BaseHTTPRequestHandler +except ImportError: + from BaseHTTPServer import BaseHTTPRequestHandler old_socket = socket.socket old_create_connection = socket.create_connection @@ -59,7 +85,8 @@ except ImportError: try: import ssl old_ssl_wrap_socket = ssl.wrap_socket - old_sslwrap_simple = ssl.sslwrap_simple + if not PY3: + old_sslwrap_simple = ssl.sslwrap_simple old_sslsocket = ssl.SSLSocket except ImportError: ssl = None @@ -70,10 +97,10 @@ class HTTPrettyError(Exception): def utf8(s): - if isinstance(s, unicode): + if isinstance(s, text_type): s = s.encode('utf-8') - return str(s) + return binary_type(s) def parse_requestline(s): @@ -97,7 +124,7 @@ def parse_requestline(s): raise ValueError('Not a Request-Line') -class HTTPrettyRequest(BaseHTTPRequestHandler, object): +class HTTPrettyRequest(BaseHTTPRequestHandler, Compat_Repr, object): def __init__(self, headers, body=''): self.body = utf8(body) self.raw_headers = utf8(headers) @@ -107,7 +134,7 @@ class HTTPrettyRequest(BaseHTTPRequestHandler, object): self.parse_request() self.method = self.command - def __repr__(self): + def __unicode__(self): return 'HTTPrettyRequest(headers={0}, body="{1}")'.format( self.headers, self.body, @@ -229,6 +256,7 @@ class fakesock(object): hostnames = [i.hostname for i in HTTPretty._entries.keys()] self.fd.seek(0) try: + print("data", data) requestline, _ = data.split('\r\n', 1) method, path, version = parse_requestline(requestline) is_parsing_headers = True @@ -244,7 +272,7 @@ class fakesock(object): try: return HTTPretty.historify_request(headers, body, False) - except Exception, e: + except Exception as e: logging.error(traceback.format_exc(e)) return self._true_sendall(data, *args, **kw) @@ -390,7 +418,7 @@ STATUSES = { } -class Entry(object): +class Entry(Compat_Repr, object): def __init__(self, method, uri, body, adding_headers=None, forcing_headers=None, @@ -443,7 +471,7 @@ class Entry(object): ) ) - def __repr__(self): + def __unicode__(self): return r'' % ( self.method, self.uri, self.status) @@ -511,7 +539,7 @@ class Entry(object): fk.seek(0) -class URIInfo(object): +class URIInfo(Compat_Repr, object): def __init__(self, username='', password='', @@ -564,16 +592,13 @@ class URIInfo(object): 'path', ) fmt = ", ".join(['%s="%s"' % (k, getattr(self, k, '')) for k in attrs]) - return ur'' % fmt - - def __repr__(self): - return unicode(self) + return r'' % fmt def __hash__(self): - return hash(unicode(self)) + return hash(text_type(self)) def __eq__(self, other): - return unicode(self) == unicode(other) + return text_type(self) == text_type(other) @classmethod def from_uri(cls, uri, entry): @@ -589,7 +614,7 @@ class URIInfo(object): entry) -class HTTPretty(object): +class HTTPretty(Compat_Repr, object): u"""The URI registration class""" _entries = {} latest_requests = [] @@ -646,7 +671,7 @@ class HTTPretty(object): cls._entries[info] = entries_for_this_uri - def __repr__(self): + def __unicode__(self): return u'' % len(self._entries) @classmethod @@ -688,12 +713,14 @@ class HTTPretty(object): if ssl: ssl.wrap_socket = old_ssl_wrap_socket - ssl.sslwrap_simple = old_sslwrap_simple ssl.SSLSocket = old_sslsocket ssl.__dict__['wrap_socket'] = old_ssl_wrap_socket - ssl.__dict__['sslwrap_simple'] = old_sslwrap_simple ssl.__dict__['SSLSocket'] = old_sslsocket + if not PY3: + ssl.sslwrap_simple = old_sslwrap_simple + ssl.__dict__['sslwrap_simple'] = old_sslwrap_simple + @classmethod def enable(cls): socket.socket = fakesock.socket @@ -722,13 +749,15 @@ class HTTPretty(object): if ssl: ssl.wrap_socket = fake_wrap_socket - ssl.sslwrap_simple = fake_wrap_socket ssl.SSLSocket = FakeSSLSocket ssl.__dict__['wrap_socket'] = fake_wrap_socket - ssl.__dict__['sslwrap_simple'] = fake_wrap_socket ssl.__dict__['SSLSocket'] = FakeSSLSocket + if not PY3: + ssl.sslwrap_simple = fake_wrap_socket + ssl.__dict__['sslwrap_simple'] = fake_wrap_socket + def httprettified(test): "A decorator tests that use HTTPretty" diff --git a/requirements.pip b/requirements.pip index 80c03a3..049c02c 100644 --- a/requirements.pip +++ b/requirements.pip @@ -1,7 +1,5 @@ -bolacha==0.6.0 -couleur==0.4.1 +distribute==0.6.31 coverage==3.5.3 -distribute==0.6.30 httplib2==0.7.6 ipdb==0.7 ipython==0.13.1 diff --git a/setup.py b/setup.py index da37fe5..d94aaa7 100755 --- a/setup.py +++ b/setup.py @@ -42,11 +42,20 @@ def get_packages(): return packages + +def test_packages(): + test_reqs = os.path.join(os.getcwd(), 'requirements.pip') + tests_require = [ + line.strip() for line in open(test_reqs).readlines() + if not line.startswith("#") + ] + setup(name='httpretty', version=version, description='HTTP client mock for Python', author=u'Gabriel Falcao', author_email='gabriel@nacaolivre.org', url='http://github.com/gabrielfalcao/httpretty', - packages=get_packages() + packages=get_packages(), + tests_require=test_packages() ) diff --git a/tests/functional/test_bypass.py b/tests/functional/test_bypass.py index 423f5db..eebc7b2 100644 --- a/tests/functional/test_bypass.py +++ b/tests/functional/test_bypass.py @@ -24,6 +24,8 @@ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. +from __future__ import unicode_literals + import urllib2 from testserver import Server from sure import expect, that_with_context diff --git a/tests/functional/test_httplib2.py b/tests/functional/test_httplib2.py index 181426d..e72ae67 100644 --- a/tests/functional/test_httplib2.py +++ b/tests/functional/test_httplib2.py @@ -24,6 +24,7 @@ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. +from __future__ import unicode_literals import httplib2 from sure import expect, within, microseconds diff --git a/tests/functional/test_requests.py b/tests/functional/test_requests.py index 9788247..4ef7fa9 100644 --- a/tests/functional/test_requests.py +++ b/tests/functional/test_requests.py @@ -24,6 +24,7 @@ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. +from __future__ import unicode_literals import requests from sure import within, microseconds, expect @@ -224,7 +225,7 @@ def test_httpretty_ignores_querystrings_from_registered_uri(now): u"HTTPretty should ignore querystrings from the registered uri (requests library)" HTTPretty.register_uri(HTTPretty.GET, "http://yipit.com/?id=123", - body="Find the best daily deals") + body=b"Find the best daily deals") response = requests.get('http://yipit.com/', params={'id': 123}) expect(response.text).to.equal('Find the best daily deals') @@ -257,9 +258,9 @@ def test_streaming_responses(now): #XXX this obviously isn't a fully functional twitter streaming client! twitter_response_lines = [ - '{"text":"If \\"for the boobs\\" requests to follow me one more time I\'m calling the police. http://t.co/a0mDEAD8"}\r\n', - '\r\n', - '{"text":"RT @onedirection: Thanks for all your #FollowMe1D requests Directioners! We\u2019ll be following 10 people throughout the day starting NOW. G ..."}\r\n' + b'{"text":"If \\"for the boobs\\" requests to follow me one more time I\'m calling the police. http://t.co/a0mDEAD8"}\r\n', + b'\r\n', + b'{"text":"RT @onedirection: Thanks for all your #FollowMe1D requests Directioners! We\u2019ll be following 10 people throughout the day starting NOW. G ..."}\r\n' ] TWITTER_STREAMING_URL = "https://stream.twitter.com/1/statuses/filter.json" diff --git a/tests/functional/test_urllib2.py b/tests/functional/test_urllib2.py index 174be82..2d87beb 100644 --- a/tests/functional/test_urllib2.py +++ b/tests/functional/test_urllib2.py @@ -24,7 +24,15 @@ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. -import urllib2 +from __future__ import unicode_literals + +try: + from urllib.request import urlopen + import urllib as urllib2 +except ImportError: + import urllib2 + urlopen = urllib2.urlopen + from sure import * from httpretty import HTTPretty, httprettified @@ -37,7 +45,7 @@ def test_httpretty_should_mock_a_simple_get_with_urllib2_read(): HTTPretty.register_uri(HTTPretty.GET, "http://yipit.com/", body="Find the best daily deals") - fd = urllib2.urlopen('http://yipit.com') + fd = urlopen('http://yipit.com') got = fd.read() fd.close() @@ -53,7 +61,7 @@ def test_httpretty_should_mock_headers_urllib2(now): body="this is supposed to be the response", status=201) - request = urllib2.urlopen('http://github.com') + request = urlopen('http://github.com') headers = dict(request.headers) request.close() @@ -82,7 +90,7 @@ def test_httpretty_should_allow_adding_and_overwritting_urllib2(now): 'Content-Type': 'application/json', }) - request = urllib2.urlopen('http://github.com') + request = urlopen('http://github.com') headers = dict(request.headers) request.close() @@ -108,7 +116,7 @@ def test_httpretty_should_allow_forcing_headers_urllib2(): 'Content-Type': 'application/xml', }) - request = urllib2.urlopen('http://github.com') + request = urlopen('http://github.com') headers = dict(request.headers) request.close() @@ -129,7 +137,7 @@ def test_httpretty_should_allow_adding_and_overwritting_by_kwargs_u2(now): content_length='111111', content_type='application/json') - request = urllib2.urlopen('http://github.com') + request = urlopen('http://github.com') headers = dict(request.headers) request.close() @@ -157,20 +165,20 @@ def test_httpretty_should_support_a_list_of_successive_responses_urllib2(now): HTTPretty.Response(body='second and last response', status=202), ]) - request1 = urllib2.urlopen('https://api.yahoo.com/test') + request1 = urlopen('https://api.yahoo.com/test') body1 = request1.read() request1.close() expect(request1.code).to.equal(201) expect(body1).to.equal('first response') - request2 = urllib2.urlopen('https://api.yahoo.com/test') + request2 = urlopen('https://api.yahoo.com/test') body2 = request2.read() request2.close() expect(request2.code).to.equal(202) expect(body2).to.equal('second and last response') - request3 = urllib2.urlopen('https://api.yahoo.com/test') + request3 = urlopen('https://api.yahoo.com/test') body3 = request3.read() request3.close() expect(request3.code).to.equal(202) @@ -192,7 +200,7 @@ def test_can_inspect_last_request(now): 'content-type': 'text/json', }, ) - fd = urllib2.urlopen(request) + fd = urlopen(request) got = fd.read() fd.close() @@ -221,7 +229,7 @@ def test_can_inspect_last_request_with_ssl(now): 'content-type': 'text/json', }, ) - fd = urllib2.urlopen(request) + fd = urlopen(request) got = fd.read() fd.close() @@ -243,7 +251,7 @@ def test_httpretty_ignores_querystrings_from_registered_uri(): HTTPretty.register_uri(HTTPretty.GET, "http://yipit.com/?id=123", body="Find the best daily deals") - fd = urllib2.urlopen('http://yipit.com/?id=123') + fd = urlopen('http://yipit.com/?id=123') got = fd.read() fd.close() diff --git a/tests/functional/testserver.py b/tests/functional/testserver.py index b170be4..67cb9e7 100644 --- a/tests/functional/testserver.py +++ b/tests/functional/testserver.py @@ -24,9 +24,17 @@ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. +from __future__ import unicode_literals + import os -import sys -from StringIO import StringIO + +try: + import io + StringIO = io.StringIO +except ImportError: + import StringIO + StringIO = StringIO.StringIO + from tornado.web import Application from tornado.web import RequestHandler from tornado.httpserver import HTTPServer diff --git a/tests/unit/test_httpretty.py b/tests/unit/test_httpretty.py index f9a7e0a..f2af816 100644 --- a/tests/unit/test_httpretty.py +++ b/tests/unit/test_httpretty.py @@ -24,6 +24,7 @@ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. +from __future__ import unicode_literals from sure import expect from httpretty import HTTPretty, HTTPrettyError, STATUSES diff --git a/tox.ini b/tox.ini index 6926d7f..3d30cd7 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,7 @@ [tox] -envlist = py26, py27 +envlist = py26, py27, py33 [testenv] commands = - pip install --use-mirrors -q -r requirements.pip - make + python setup.py test + make test