23
23
"""
24
24
25
25
import base64
26
- import urllib
26
+ from hashlib import sha1
27
27
import time
28
28
import random
29
- import urlparse
30
29
import hmac
31
30
import binascii
32
31
import httplib2
33
32
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__
51
43
52
44
OAUTH_VERSION = '1.0' # Hi Blaine!
53
45
HTTP_METHOD = 'GET'
@@ -87,7 +79,7 @@ def build_xoauth_string(url, consumer, token=None):
87
79
request .sign_request (signing_method , consumer , token )
88
80
89
81
params = []
90
- for k , v in sorted (request .iteritems ()):
82
+ for k , v in sorted (request .items ()):
91
83
if v is not None :
92
84
params .append ('%s="%s"' % (k , escape (v )))
93
85
@@ -97,32 +89,33 @@ def build_xoauth_string(url, consumer, token=None):
97
89
def to_unicode (s ):
98
90
""" Convert to unicode, raise exception with instructive error
99
91
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 ):
102
94
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 ))
104
96
try :
105
97
s = s .decode ('utf-8' )
106
98
except UnicodeDecodeError as le :
107
99
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'
112
105
% (s , le ,))
113
106
return s
114
107
115
108
def to_utf8 (s ):
116
109
return to_unicode (s ).encode ('utf-8' )
117
110
118
111
def to_unicode_if_string (s ):
119
- if isinstance (s , basestring ):
112
+ if isinstance (s , STRING_TYPES ):
120
113
return to_unicode (s )
121
114
else :
122
115
return s
123
116
124
117
def to_utf8_if_string (s ):
125
- if isinstance (s , basestring ):
118
+ if isinstance (s , STRING_TYPES ):
126
119
return to_utf8 (s )
127
120
else :
128
121
return s
@@ -132,7 +125,7 @@ def to_unicode_optional_iterator(x):
132
125
Raise TypeError if x is a str containing non-utf8 bytes or if x is
133
126
an iterable which contains such a str.
134
127
"""
135
- if isinstance (x , basestring ):
128
+ if isinstance (x , STRING_TYPES ):
136
129
return to_unicode (x )
137
130
138
131
try :
@@ -148,7 +141,7 @@ def to_utf8_optional_iterator(x):
148
141
Raise TypeError if x is a str or if x is an iterable which
149
142
contains a str.
150
143
"""
151
- if isinstance (x , basestring ):
144
+ if isinstance (x , STRING_TYPES ):
152
145
return to_utf8 (x )
153
146
154
147
try :
@@ -161,7 +154,7 @@ def to_utf8_optional_iterator(x):
161
154
162
155
def escape (s ):
163
156
"""Escape a URL including any /."""
164
- return urllib . quote (s .encode ('utf-8' ), safe = '~' )
157
+ return quote (s .encode ('utf-8' ), safe = '~' )
165
158
166
159
def generate_timestamp ():
167
160
"""Get seconds since epoch (UTC)."""
@@ -212,7 +205,7 @@ def __str__(self):
212
205
data = {'oauth_consumer_key' : self .key ,
213
206
'oauth_consumer_secret' : self .secret }
214
207
215
- return urllib . urlencode (data )
208
+ return urlencode (data )
216
209
217
210
218
211
class Token (object ):
@@ -256,13 +249,13 @@ def set_verifier(self, verifier=None):
256
249
def get_callback_url (self ):
257
250
if self .callback and self .verifier :
258
251
# Append the oauth_verifier.
259
- parts = urlparse . urlparse (self .callback )
252
+ parts = urlparse (self .callback )
260
253
scheme , netloc , path , params , query , fragment = parts [:6 ]
261
254
if query :
262
255
query = '%s&oauth_verifier=%s' % (query , self .verifier )
263
256
else :
264
257
query = 'oauth_verifier=%s' % self .verifier
265
- return urlparse . urlunparse ((scheme , netloc , path , params ,
258
+ return urlunparse ((scheme , netloc , path , params ,
266
259
query , fragment ))
267
260
return self .callback
268
261
@@ -280,7 +273,7 @@ def to_string(self):
280
273
281
274
if self .callback_confirmed is not None :
282
275
data ['oauth_callback_confirmed' ] = self .callback_confirmed
283
- return urllib . urlencode (data )
276
+ return urlencode (data )
284
277
285
278
@staticmethod
286
279
def from_string (s ):
@@ -351,7 +344,7 @@ def __init__(self, method=HTTP_METHOD, url=None, parameters=None,
351
344
self .url = to_unicode (url )
352
345
self .method = method
353
346
if parameters is not None :
354
- for k , v in parameters .iteritems ():
347
+ for k , v in parameters .items ():
355
348
k = to_unicode (k )
356
349
v = to_unicode_optional_iterator (v )
357
350
self [k ] = v
@@ -363,8 +356,7 @@ def __init__(self, method=HTTP_METHOD, url=None, parameters=None,
363
356
def url (self , value ):
364
357
self .__dict__ ['url' ] = value
365
358
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 )
368
360
369
361
# Exclude default port numbers.
370
362
if scheme == 'http' and netloc [- 3 :] == ':80' :
@@ -375,7 +367,7 @@ def url(self, value):
375
367
raise ValueError ("Unsupported URL %s (%s)." % (value , scheme ))
376
368
377
369
# Normalized URL excludes params, query, and fragment.
378
- self .normalized_url = urlparse . urlunparse (
370
+ self .normalized_url = urlunparse (
379
371
(scheme , netloc , path , None , None , None ))
380
372
else :
381
373
self .normalized_url = None
@@ -390,7 +382,7 @@ def _get_timestamp_nonce(self):
390
382
391
383
def get_nonoauth_parameters (self ):
392
384
"""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 ()
394
386
if not k .startswith ('oauth_' )])
395
387
396
388
def to_header (self , realm = '' ):
@@ -410,17 +402,17 @@ def to_header(self, realm=''):
410
402
def to_postdata (self ):
411
403
"""Serialize as post data for a POST request."""
412
404
d = {}
413
- for k , v in self .iteritems ():
405
+ for k , v in self .items ():
414
406
d [k .encode ('utf-8' )] = to_utf8_optional_iterator (v )
415
407
416
408
# tell urlencode to deal with sequence values and map them correctly
417
409
# to resulting querystring. for example self["k"] = ["v1", "v2"] will
418
410
# 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' )
420
412
421
413
def to_url (self ):
422
414
"""Serialize as a URL for a GET request."""
423
- base_url = urlparse . urlparse (self .url )
415
+ base_url = urlparse (self .url )
424
416
try :
425
417
query = base_url .query
426
418
except AttributeError : #pragma NO COVER
@@ -445,8 +437,8 @@ def to_url(self):
445
437
fragment = base_url [5 ]
446
438
447
439
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 )
450
442
451
443
def get_parameter (self , parameter ):
452
444
ret = self .get (parameter )
@@ -458,12 +450,12 @@ def get_parameter(self, parameter):
458
450
def get_normalized_parameters (self ):
459
451
"""Return a string that contains the parameters that must be signed."""
460
452
items = []
461
- for key , value in self .iteritems ():
453
+ for key , value in self .items ():
462
454
if key == 'oauth_signature' :
463
455
continue
464
456
# 1.0a/9.1.1 states that kvp must be sorted by key, then by value,
465
457
# so we unpack sequence values into multiple items for sorting.
466
- if isinstance (value , basestring ):
458
+ if isinstance (value , STRING_TYPES ):
467
459
items .append ((to_utf8_if_string (key ), to_utf8 (value )))
468
460
else :
469
461
try :
@@ -478,15 +470,15 @@ def get_normalized_parameters(self):
478
470
for item in value )
479
471
480
472
# Include any query string parameters from the provided URL
481
- query = urlparse . urlparse (self .url )[4 ]
473
+ query = urlparse (self .url )[4 ]
482
474
483
475
url_items = self ._split_url_string (query ).items ()
484
476
url_items = [(to_utf8 (k ), to_utf8 (v ))
485
477
for k , v in url_items if k != 'oauth_signature' ]
486
478
items .extend (url_items )
487
479
488
480
items .sort ()
489
- encoded_str = urllib . urlencode (items )
481
+ encoded_str = urlencode (items )
490
482
# Encode signature parameters per Oauth Core 1.0 protocol
491
483
# spec draft 7, section 3.6
492
484
# (http://tools.ietf.org/html/draft-hammer-oauth-07#section-3.6)
@@ -503,7 +495,7 @@ def sign_request(self, signature_method, consumer, token):
503
495
# section 4.1.1 "OAuth Consumers MUST NOT include an
504
496
# oauth_body_hash parameter on requests with form-encoded
505
497
# request bodies."
506
- self ['oauth_body_hash' ] = base64 .b64encode (sha (self .body ).digest ())
498
+ self ['oauth_body_hash' ] = base64 .b64encode (sha1 (self .body ).digest ())
507
499
508
500
if 'oauth_consumer_key' not in self :
509
501
self ['oauth_consumer_key' ] = consumer .key
@@ -551,7 +543,7 @@ def from_request(cls, http_method, http_url, headers=None, parameters=None,
551
543
parameters .update (query_params )
552
544
553
545
# URL parameters.
554
- param_str = urlparse . urlparse (http_url )[4 ] # query
546
+ param_str = urlparse (http_url )[4 ] # query
555
547
url_params = cls ._split_url_string (param_str )
556
548
parameters .update (url_params )
557
549
@@ -613,16 +605,16 @@ def _split_header(header):
613
605
# Split key-value.
614
606
param_parts = param .split ('=' , 1 )
615
607
# 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 ('\" ' ))
617
609
return params
618
610
619
611
@staticmethod
620
612
def _split_url_string (param_str ):
621
613
"""Turn URL string into parameters."""
622
614
parameters = parse_qs (param_str .encode ('utf-8' ),
623
615
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 ])
626
618
return parameters
627
619
628
620
@@ -676,8 +668,8 @@ def request(self, uri, method="GET", body='', headers=None,
676
668
677
669
req .sign_request (self .method , self .consumer , self .token )
678
670
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 ))
681
673
682
674
if is_form_encoded :
683
675
body = req .to_postdata ()
@@ -842,7 +834,7 @@ def sign(self, request, consumer, token):
842
834
"""Builds the base signature string."""
843
835
key , raw = self .signing_base (request , consumer , token )
844
836
845
- hashed = hmac .new (key , raw , sha )
837
+ hashed = hmac .new (key , raw , sha1 )
846
838
847
839
# Calculate the digest base 64.
848
840
return binascii .b2a_base64 (hashed .digest ())[:- 1 ]
0 commit comments