2323"""
2424
2525import base64
26- import urllib
26+ from hashlib import sha1
2727import time
2828import random
29- import urlparse
3029import hmac
3130import binascii
3231import httplib2
3332
34- try :
35- from urlparse import parse_qs
36- except ImportError : #pragma NO COVER
37- # fall back for Python 2.5
38- from cgi import parse_qs
39- else : #pragma NO COVER
40- parse_qs # placate pyflakes
41-
42- try :
43- from hashlib import sha1 as sha
44- except ImportError : #pragma NO COVER
45- # hashlib was added in Python 2.5
46- import sha
47-
48- import _version
49-
50- __version__ = _version .__version__
33+ from ._compat import quote
34+ from ._compat import STRING_TYPES
35+ from ._compat import TEXT
36+ from ._compat import unquote
37+ from ._compat import unquote_to_bytes
38+ from ._compat import urlencode
39+ from ._compat import urlparse
40+ from ._compat import urlunparse
41+ from ._compat import parse_qs
42+ from ._version import __version__
5143
5244OAUTH_VERSION = '1.0' # Hi Blaine!
5345HTTP_METHOD = 'GET'
@@ -87,7 +79,7 @@ def build_xoauth_string(url, consumer, token=None):
8779 request .sign_request (signing_method , consumer , token )
8880
8981 params = []
90- for k , v in sorted (request .iteritems ()):
82+ for k , v in sorted (request .items ()):
9183 if v is not None :
9284 params .append ('%s="%s"' % (k , escape (v )))
9385
@@ -97,32 +89,33 @@ def build_xoauth_string(url, consumer, token=None):
9789def to_unicode (s ):
9890 """ Convert to unicode, raise exception with instructive error
9991 message if s is not unicode, ascii, or utf-8. """
100- if not isinstance (s , unicode ):
101- if not isinstance (s , str ):
92+ if not isinstance (s , TEXT ):
93+ if not isinstance (s , bytes ):
10294 raise TypeError ('You are required to pass either unicode or '
103- 'string here, not: %r (%s)' % (type (s ), s ))
95+ 'bytes here, not: %r (%s)' % (type (s ), s ))
10496 try :
10597 s = s .decode ('utf-8' )
10698 except UnicodeDecodeError as le :
10799 raise TypeError ('You are required to pass either a unicode '
108- 'object or a utf-8 string here. You passed a '
109- 'Python string object which contained non-utf-8: '
110- '%r. The UnicodeDecodeError that resulted from '
111- 'attempting to interpret it as utf-8 was: %s'
100+ 'object or a utf-8-enccoded bytes string here. '
101+ 'You passed a bytes object which contained '
102+ 'non-utf-8: %r. The UnicodeDecodeError that '
103+ 'resulted from attempting to interpret it as '
104+ 'utf-8 was: %s'
112105 % (s , le ,))
113106 return s
114107
115108def to_utf8 (s ):
116109 return to_unicode (s ).encode ('utf-8' )
117110
118111def to_unicode_if_string (s ):
119- if isinstance (s , basestring ):
112+ if isinstance (s , STRING_TYPES ):
120113 return to_unicode (s )
121114 else :
122115 return s
123116
124117def to_utf8_if_string (s ):
125- if isinstance (s , basestring ):
118+ if isinstance (s , STRING_TYPES ):
126119 return to_utf8 (s )
127120 else :
128121 return s
@@ -132,7 +125,7 @@ def to_unicode_optional_iterator(x):
132125 Raise TypeError if x is a str containing non-utf8 bytes or if x is
133126 an iterable which contains such a str.
134127 """
135- if isinstance (x , basestring ):
128+ if isinstance (x , STRING_TYPES ):
136129 return to_unicode (x )
137130
138131 try :
@@ -148,7 +141,7 @@ def to_utf8_optional_iterator(x):
148141 Raise TypeError if x is a str or if x is an iterable which
149142 contains a str.
150143 """
151- if isinstance (x , basestring ):
144+ if isinstance (x , STRING_TYPES ):
152145 return to_utf8 (x )
153146
154147 try :
@@ -161,7 +154,7 @@ def to_utf8_optional_iterator(x):
161154
162155def escape (s ):
163156 """Escape a URL including any /."""
164- return urllib . quote (s .encode ('utf-8' ), safe = '~' )
157+ return quote (s .encode ('utf-8' ), safe = '~' )
165158
166159def generate_timestamp ():
167160 """Get seconds since epoch (UTC)."""
@@ -212,7 +205,7 @@ def __str__(self):
212205 data = {'oauth_consumer_key' : self .key ,
213206 'oauth_consumer_secret' : self .secret }
214207
215- return urllib . urlencode (data )
208+ return urlencode (data )
216209
217210
218211class Token (object ):
@@ -256,13 +249,13 @@ def set_verifier(self, verifier=None):
256249 def get_callback_url (self ):
257250 if self .callback and self .verifier :
258251 # Append the oauth_verifier.
259- parts = urlparse . urlparse (self .callback )
252+ parts = urlparse (self .callback )
260253 scheme , netloc , path , params , query , fragment = parts [:6 ]
261254 if query :
262255 query = '%s&oauth_verifier=%s' % (query , self .verifier )
263256 else :
264257 query = 'oauth_verifier=%s' % self .verifier
265- return urlparse . urlunparse ((scheme , netloc , path , params ,
258+ return urlunparse ((scheme , netloc , path , params ,
266259 query , fragment ))
267260 return self .callback
268261
@@ -280,7 +273,7 @@ def to_string(self):
280273
281274 if self .callback_confirmed is not None :
282275 data ['oauth_callback_confirmed' ] = self .callback_confirmed
283- return urllib . urlencode (data )
276+ return urlencode (data )
284277
285278 @staticmethod
286279 def from_string (s ):
@@ -351,7 +344,7 @@ def __init__(self, method=HTTP_METHOD, url=None, parameters=None,
351344 self .url = to_unicode (url )
352345 self .method = method
353346 if parameters is not None :
354- for k , v in parameters .iteritems ():
347+ for k , v in parameters .items ():
355348 k = to_unicode (k )
356349 v = to_unicode_optional_iterator (v )
357350 self [k ] = v
@@ -363,8 +356,7 @@ def __init__(self, method=HTTP_METHOD, url=None, parameters=None,
363356 def url (self , value ):
364357 self .__dict__ ['url' ] = value
365358 if value is not None :
366- scheme , netloc , path , params , query , fragment = urlparse .urlparse (
367- value )
359+ scheme , netloc , path , params , query , fragment = urlparse (value )
368360
369361 # Exclude default port numbers.
370362 if scheme == 'http' and netloc [- 3 :] == ':80' :
@@ -375,7 +367,7 @@ def url(self, value):
375367 raise ValueError ("Unsupported URL %s (%s)." % (value , scheme ))
376368
377369 # Normalized URL excludes params, query, and fragment.
378- self .normalized_url = urlparse . urlunparse (
370+ self .normalized_url = urlunparse (
379371 (scheme , netloc , path , None , None , None ))
380372 else :
381373 self .normalized_url = None
@@ -390,7 +382,7 @@ def _get_timestamp_nonce(self):
390382
391383 def get_nonoauth_parameters (self ):
392384 """Get any non-OAuth parameters."""
393- return dict ([(k , v ) for k , v in self .iteritems ()
385+ return dict ([(k , v ) for k , v in self .items ()
394386 if not k .startswith ('oauth_' )])
395387
396388 def to_header (self , realm = '' ):
@@ -410,17 +402,17 @@ def to_header(self, realm=''):
410402 def to_postdata (self ):
411403 """Serialize as post data for a POST request."""
412404 d = {}
413- for k , v in self .iteritems ():
405+ for k , v in self .items ():
414406 d [k .encode ('utf-8' )] = to_utf8_optional_iterator (v )
415407
416408 # tell urlencode to deal with sequence values and map them correctly
417409 # to resulting querystring. for example self["k"] = ["v1", "v2"] will
418410 # result in 'k=v1&k=v2' and not k=%5B%27v1%27%2C+%27v2%27%5D
419- return urllib . urlencode (d , True ).replace ('+' , '%20' )
411+ return urlencode (d , True ).replace ('+' , '%20' )
420412
421413 def to_url (self ):
422414 """Serialize as a URL for a GET request."""
423- base_url = urlparse . urlparse (self .url )
415+ base_url = urlparse (self .url )
424416 try :
425417 query = base_url .query
426418 except AttributeError : #pragma NO COVER
@@ -445,8 +437,8 @@ def to_url(self):
445437 fragment = base_url [5 ]
446438
447439 url = (scheme , netloc , path , params ,
448- urllib . urlencode (query , True ), fragment )
449- return urlparse . urlunparse (url )
440+ urlencode (query , True ), fragment )
441+ return urlunparse (url )
450442
451443 def get_parameter (self , parameter ):
452444 ret = self .get (parameter )
@@ -458,12 +450,12 @@ def get_parameter(self, parameter):
458450 def get_normalized_parameters (self ):
459451 """Return a string that contains the parameters that must be signed."""
460452 items = []
461- for key , value in self .iteritems ():
453+ for key , value in self .items ():
462454 if key == 'oauth_signature' :
463455 continue
464456 # 1.0a/9.1.1 states that kvp must be sorted by key, then by value,
465457 # so we unpack sequence values into multiple items for sorting.
466- if isinstance (value , basestring ):
458+ if isinstance (value , STRING_TYPES ):
467459 items .append ((to_utf8_if_string (key ), to_utf8 (value )))
468460 else :
469461 try :
@@ -478,15 +470,15 @@ def get_normalized_parameters(self):
478470 for item in value )
479471
480472 # Include any query string parameters from the provided URL
481- query = urlparse . urlparse (self .url )[4 ]
473+ query = urlparse (self .url )[4 ]
482474
483475 url_items = self ._split_url_string (query ).items ()
484476 url_items = [(to_utf8 (k ), to_utf8 (v ))
485477 for k , v in url_items if k != 'oauth_signature' ]
486478 items .extend (url_items )
487479
488480 items .sort ()
489- encoded_str = urllib . urlencode (items )
481+ encoded_str = urlencode (items )
490482 # Encode signature parameters per Oauth Core 1.0 protocol
491483 # spec draft 7, section 3.6
492484 # (http://tools.ietf.org/html/draft-hammer-oauth-07#section-3.6)
@@ -503,7 +495,7 @@ def sign_request(self, signature_method, consumer, token):
503495 # section 4.1.1 "OAuth Consumers MUST NOT include an
504496 # oauth_body_hash parameter on requests with form-encoded
505497 # request bodies."
506- self ['oauth_body_hash' ] = base64 .b64encode (sha (self .body ).digest ())
498+ self ['oauth_body_hash' ] = base64 .b64encode (sha1 (self .body ).digest ())
507499
508500 if 'oauth_consumer_key' not in self :
509501 self ['oauth_consumer_key' ] = consumer .key
@@ -551,7 +543,7 @@ def from_request(cls, http_method, http_url, headers=None, parameters=None,
551543 parameters .update (query_params )
552544
553545 # URL parameters.
554- param_str = urlparse . urlparse (http_url )[4 ] # query
546+ param_str = urlparse (http_url )[4 ] # query
555547 url_params = cls ._split_url_string (param_str )
556548 parameters .update (url_params )
557549
@@ -613,16 +605,16 @@ def _split_header(header):
613605 # Split key-value.
614606 param_parts = param .split ('=' , 1 )
615607 # Remove quotes and unescape the value.
616- params [param_parts [0 ]] = urllib . unquote (param_parts [1 ].strip ('\" ' ))
608+ params [param_parts [0 ]] = unquote (param_parts [1 ].strip ('\" ' ))
617609 return params
618610
619611 @staticmethod
620612 def _split_url_string (param_str ):
621613 """Turn URL string into parameters."""
622614 parameters = parse_qs (param_str .encode ('utf-8' ),
623615 keep_blank_values = True )
624- for k , v in parameters .iteritems ():
625- parameters [k ] = urllib . unquote (v [0 ])
616+ for k , v in parameters .items ():
617+ parameters [k ] = unquote_to_bytes (v [0 ])
626618 return parameters
627619
628620
@@ -676,8 +668,8 @@ def request(self, uri, method="GET", body='', headers=None,
676668
677669 req .sign_request (self .method , self .consumer , self .token )
678670
679- scheme , netloc , path , params , query , fragment = urlparse . urlparse (uri )
680- realm = urlparse . urlunparse ((scheme , netloc , '' , None , None , None ))
671+ scheme , netloc , path , params , query , fragment = urlparse (uri )
672+ realm = urlunparse ((scheme , netloc , '' , None , None , None ))
681673
682674 if is_form_encoded :
683675 body = req .to_postdata ()
@@ -842,7 +834,7 @@ def sign(self, request, consumer, token):
842834 """Builds the base signature string."""
843835 key , raw = self .signing_base (request , consumer , token )
844836
845- hashed = hmac .new (key , raw , sha )
837+ hashed = hmac .new (key , raw , sha1 )
846838
847839 # Calculate the digest base 64.
848840 return binascii .b2a_base64 (hashed .digest ())[:- 1 ]
0 commit comments