]> jfr.im git - z_archive/twitter.git/blobdiff - twitter/oauth.py
Compare lowercase hostnames when testing.
[z_archive/twitter.git] / twitter / oauth.py
index e9c790f9948bc3018130ced9c140505677e20a5c..2df5ff0a1eb9a0319d6ad959ac21702d2edd05de 100644 (file)
@@ -1,13 +1,65 @@
-from twitter.auth import Auth
+"""
+Visit the Twitter developer page and create a new application:
+
+    https://dev.twitter.com/apps/new
+
+This will get you a CONSUMER_KEY and CONSUMER_SECRET.
+
+When users run your application they have to authenticate your app
+with their Twitter account. A few HTTP calls to twitter are required
+to do this. Please see the twitter.oauth_dance module to see how this
+is done. If you are making a command-line app, you can use the
+oauth_dance() function directly.
+
+Performing the "oauth dance" gets you an ouath token and oauth secret
+that authenticate the user with Twitter. You should save these for
+later so that the user doesn't have to do the oauth dance again.
+
+read_token_file and write_token_file are utility methods to read and
+write OAuth token and secret key values. The values are stored as
+strings in the file. Not terribly exciting.
+
+Finally, you can use the OAuth authenticator to connect to Twitter. In
+code it all goes like this::
+
+    from twitter import *
+
+    MY_TWITTER_CREDS = os.path.expanduser('~/.my_app_credentials')
+    if not os.path.exists(MY_TWITTER_CREDS):
+        oauth_dance("My App Name", CONSUMER_KEY, CONSUMER_SECRET,
+                    MY_TWITTER_CREDS)
+
+    oauth_token, oauth_secret = read_token_file(MY_TWITTER_CREDS)
+
+    twitter = Twitter(auth=OAuth(
+        oauth_token, oauth_token_secret, CONSUMER_KEY, CONSUMER_SECRET))
+
+    # Now work with Twitter
+    twitter.statuses.update(status='Hello, world!')
+
+"""
+
+from __future__ import print_function
 
-from time import time
 from random import getrandbits
 from time import time
-import urllib.request, urllib.parse, urllib.error
+
+from .util import PY_3_OR_HIGHER
+
+try:
+    import urllib.parse as urllib_parse
+    from urllib.parse import urlencode
+except ImportError:
+    import urllib2 as urllib_parse
+    from urllib import urlencode
+
 import hashlib
 import hmac
 import base64
 
+from .auth import Auth
+
+
 def write_token_file(filename, oauth_token, oauth_token_secret):
     """
     Write a token file to hold the oauth token and oauth token secret.
@@ -54,15 +106,15 @@ class OAuth(Auth):
 
         enc_params = urlencode_noplus(sorted(params.items()))
 
-        key = self.consumer_secret + "&" + urllib.parse.quote(self.token_secret, '')
+        key = self.consumer_secret + "&" + urllib_parse.quote(self.token_secret, safe='~')
 
         message = '&'.join(
-            urllib.parse.quote(i, '') for i in [method.upper(), base_url, enc_params])
+            urllib_parse.quote(i, safe='~') for i in [method.upper(), base_url, enc_params])
 
         signature = (base64.b64encode(hmac.new(
                     key.encode('ascii'), message.encode('ascii'), hashlib.sha1)
                                       .digest()))
-        return enc_params + "&" + "oauth_signature=" + urllib.parse.quote(signature, '')
+        return enc_params + "&" + "oauth_signature=" + urllib_parse.quote(signature, safe='~')
 
     def generate_headers(self):
         return {}
@@ -71,21 +123,18 @@ class OAuth(Auth):
 # %20 rather than '+' when constructing an OAuth signature (and therefore
 # also in the request itself.)
 # So here is a specialized version which does exactly that.
+# In Python2, since there is no safe option for urlencode, we force it by hand
 def urlencode_noplus(query):
-    if hasattr(query,"items"):
-        # mapping objects
-        query = list(query.items())
-
-    encoded_bits = []
-    for n, v in query:
-        # and do unicode here while we are at it...
-        if isinstance(n, str):
-            n = n.encode('utf-8')
-        else:
-            n = str(n)
-        if isinstance(v, str):
-            v = v.encode('utf-8')
-        else:
-            v = str(v)
-        encoded_bits.append("%s=%s" % (urllib.parse.quote(n, ""), urllib.parse.quote(v, "")))
-    return "&".join(encoded_bits)
+    if not PY_3_OR_HIGHER:
+        new_query = []
+        TILDE = '____TILDE-PYTHON-TWITTER____'
+        for k,v in query:
+            if type(k) is unicode: k = k.encode('utf-8')
+            k = str(k).replace("~", TILDE)
+            if type(v) is unicode: v = v.encode('utf-8')
+            v = str(v).replace("~", TILDE)
+            new_query.append((k, v))
+        query = new_query
+        return urlencode(query).replace(TILDE, "~").replace("+", "%20")
+
+    return urlencode(query, safe='~').replace("+", "%20")