1- # # !/usr/bin/env python
1+ # !/usr/bin/env python
22# -*- coding: utf-8 -*-
33# <HTTPretty - HTTP client mock for Python>
44# Copyright (C) <2011-2013> Gabriel Falcão <[email protected] > 107107
108108
109109class HTTPrettyRequest (BaseHTTPRequestHandler , BaseClass ):
110+
110111 """Represents a HTTP request. It takes a valid multi-line, `\r \n `
111112 separated string with HTTP headers and parse them out using the
112113 internal `parse_request` method.
@@ -138,6 +139,7 @@ class HTTPrettyRequest(BaseHTTPRequestHandler, BaseClass):
138139 `content-type` headers values: 'application/json' or
139140 'application/x-www-form-urlencoded'
140141 """
142+
141143 def __init__ (self , headers , body = '' ):
142144 # first of all, lets make sure that if headers or body are
143145 # unicode strings, it must be converted into a utf-8 encoded
@@ -229,12 +231,14 @@ class HTTPrettyRequestEmpty(object):
229231
230232
231233class FakeSockFile (StringIO ):
234+
232235 def close (self ):
233236 self .socket .close ()
234237 StringIO .close (self )
235238
236239
237240class FakeSSLSocket (object ):
241+
238242 def __init__ (self , sock , * args , ** kw ):
239243 self ._httpretty_sock = sock
240244
@@ -243,6 +247,7 @@ def __getattr__(self, attr):
243247
244248
245249class fakesock (object ):
250+
246251 class socket (object ):
247252 _entry = None
248253 debuglevel = 0
@@ -380,7 +385,8 @@ def sendall(self, data, *args, **kw):
380385 is_parsing_headers = False
381386
382387 if not self ._entry :
383- # If the previous request wasn't mocked, don't mock the subsequent sending of data
388+ # If the previous request wasn't mocked, don't mock the subsequent sending
389+ # of data
384390 return self .real_sendall (data , * args , ** kw )
385391
386392 self .fd .seek (0 )
@@ -492,6 +498,7 @@ def fake_getaddrinfo(
492498
493499
494500class Entry (BaseClass ):
501+
495502 def __init__ (self , method , uri , body ,
496503 adding_headers = None ,
497504 forcing_headers = None ,
@@ -543,15 +550,15 @@ def validate(self):
543550 igot = int (got )
544551 except ValueError :
545552 warnings .warn (
546- 'HTTPretty got to register the Content-Length header ' \
553+ 'HTTPretty got to register the Content-Length header '
547554 'with "%r" which is not a number' % got ,
548555 )
549556
550557 if igot > self .body_length :
551558 raise HTTPrettyError (
552- 'HTTPretty got inconsistent parameters. The header ' \
553- 'Content-Length you registered expects size "%d" but ' \
554- 'the body you registered for that has actually length ' \
559+ 'HTTPretty got inconsistent parameters. The header '
560+ 'Content-Length you registered expects size "%d" but '
561+ 'the body you registered for that has actually length '
555562 '"%d".' % (
556563 igot , self .body_length ,
557564 )
@@ -588,7 +595,8 @@ def fill_filekind(self, fk):
588595 headers = self .normalize_headers (headers )
589596 status = headers .get ('status' , self .status )
590597 if self .body_is_callable :
591- status , headers , self .body = self .callable_body (self .request , self .info .full_url (), headers )
598+ status , headers , self .body = self .callable_body (
599+ self .request , self .info .full_url (), headers )
592600 headers .update ({
593601 'content-length' : len (self .body )
594602 })
@@ -640,6 +648,7 @@ def url_fix(s, charset='utf-8'):
640648
641649
642650class URIInfo (BaseClass ):
651+
643652 def __init__ (self ,
644653 username = '' ,
645654 password = '' ,
@@ -763,7 +772,7 @@ def __init__(self, uri, entries, match_querystring=False):
763772
764773 self .entries = entries
765774
766- #hash of current_entry pointers, per method.
775+ # hash of current_entry pointers, per method.
767776 self .current_entries = {}
768777
769778 def matches (self , info ):
@@ -787,7 +796,7 @@ def get_next_entry(self, method, info, request):
787796 if method not in self .current_entries :
788797 self .current_entries [method ] = 0
789798
790- #restrict selection to entries that match the requested method
799+ # restrict selection to entries that match the requested method
791800 entries_for_method = [e for e in self .entries if e .method == method ]
792801
793802 if self .current_entries [method ] >= len (entries_for_method ):
@@ -818,6 +827,7 @@ def __eq__(self, other):
818827
819828
820829class httpretty (HttpBaseClass ):
830+
821831 """The URI registration class"""
822832 _entries = {}
823833 latest_requests = []
@@ -840,13 +850,14 @@ def record(cls, filename, indentation=4, encoding='utf-8'):
840850 try :
841851 import urllib3
842852 except ImportError :
843- raise RuntimeError ('HTTPretty requires urllib3 installed for recording actual requests.' )
844-
853+ raise RuntimeError (
854+ 'HTTPretty requires urllib3 installed for recording actual requests.' )
845855
846856 http = urllib3 .PoolManager ()
847857
848858 cls .enable ()
849859 calls = []
860+
850861 def record_request (request , uri , headers ):
851862 cls .disable ()
852863
@@ -885,7 +896,8 @@ def playback(cls, origin):
885896 for item in data :
886897 uri = item ['request' ]['uri' ]
887898 method = item ['request' ]['method' ]
888- cls .register_uri (method , uri , body = item ['response' ]['body' ], forcing_headers = item ['response' ]['headers' ])
899+ cls .register_uri (
900+ method , uri , body = item ['response' ]['body' ], forcing_headers = item ['response' ]['headers' ])
889901
890902 yield
891903 cls .disable ()
@@ -1034,19 +1046,27 @@ def enable(cls):
10341046 ssl .__dict__ ['sslwrap_simple' ] = fake_wrap_socket
10351047
10361048
1037- def httprettified (test ):
1038- "A decorator tests that use HTTPretty"
1039- def decorate_class (klass ):
1040- for attr in dir (klass ):
1041- if not attr .startswith ('test_' ):
1042- continue
1049+ def decorate_class (klass , callable_fn ):
1050+ """
1051+ A helper method to apply callable_fn to class attributes.
1052+ It's not intended for direct use.
1053+ """
1054+ for attr in dir (klass ):
1055+ if not attr .startswith ('test_' ):
1056+ continue
1057+
1058+ attr_value = getattr (klass , attr )
1059+ if not hasattr (attr_value , "__call__" ):
1060+ continue
1061+
1062+ setattr (klass , attr , callable_fn (attr_value ))
1063+ return klass
10431064
1044- attr_value = getattr (klass , attr )
1045- if not hasattr (attr_value , "__call__" ):
1046- continue
10471065
1048- setattr (klass , attr , decorate_callable (attr_value ))
1049- return klass
1066+ def httprettified (test ):
1067+ """
1068+ A decorator that activates HTTPretty.
1069+ """
10501070
10511071 def decorate_callable (test ):
10521072 @functools .wraps (test )
@@ -1060,5 +1080,30 @@ def wrapper(*args, **kw):
10601080 return wrapper
10611081
10621082 if isinstance (test , ClassTypes ):
1063- return decorate_class (test )
1083+ return decorate_class (test , decorate_callable )
10641084 return decorate_callable (test )
1085+
1086+
1087+ def register (** dec_kwargs ):
1088+ """
1089+ A decorator that activates HTTPretty and registers an uri path,
1090+ by given keyword arguments.
1091+ """
1092+
1093+ def decorator (func ):
1094+ def decorate_callable (func ):
1095+ @functools .wraps (func )
1096+ def wrapper (* args , ** kw ):
1097+ httpretty .reset ()
1098+ httpretty .enable ()
1099+ httpretty .register_uri (** dec_kwargs )
1100+ try :
1101+ return func (* args , ** kw )
1102+ finally :
1103+ httpretty .disable ()
1104+ return wrapper
1105+
1106+ if isinstance (func , ClassTypes ):
1107+ return decorate_class (func , decorate_callable )
1108+ return decorate_callable (func )
1109+ return decorator
0 commit comments