]> jfr.im git - z_archive/twitter.git/commitdiff
Merge remote-tracking branch 'origin/master' into next_gen
authorMike Verdone <redacted>
Sat, 22 Jun 2013 17:35:35 +0000 (11:35 -0600)
committerMike Verdone <redacted>
Sat, 22 Jun 2013 17:35:35 +0000 (11:35 -0600)
Conflicts:
tests/test_sanity.py
twitter/cmdline.py
twitter/oauth.py

1  2 
setup.py
twitter/__init__.py
twitter/api.py
twitter/cmdline.py
twitter/oauth.py
twitter/oauth2.py

diff --cc setup.py
Simple merge
Simple merge
diff --cc twitter/api.py
Simple merge
index de5bea9c0cb10211970f73f09ff983e6196ccadf,f238d6c297821e5a3fd3248e16ceb1b3d9622944..b2d1765e250254b9fa30d3a6bf4d125995a1e839
@@@ -91,9 -90,14 +90,14 @@@ try
      from urllib.parse import quote
  except ImportError:
      from urllib2 import quote
+ try:
+     import HTMLParser
+ except ImportError:
+     import html.parser as HTMLParser
  import webbrowser
  
 -from .api import Twitter, TwitterError
 +from .api2 import TwitterAPI, TwitterError, search
  from .oauth import OAuth, write_token_file, read_token_file
  from .oauth_dance import oauth_dance
  from . import ansi
@@@ -422,7 -463,7 +457,7 @@@ class ListsAction(StatusAction)
          screen_name = options['extra_args'][0]
  
          if not options['extra_args'][1:]:
-             lists = twitter.get("lists", screen_name=screen_name)['lists']
 -            lists = twitter.lists.list(screen_name=screen_name)
++            lists = twitter.get("lists/list", screen_name=screen_name)
              if not lists:
                  printNicely("This user has no lists.")
              for list in lists:
@@@ -445,18 -484,11 +480,13 @@@ class MyListsAction(ListsAction)
  
  class FriendsAction(StatusAction):
      def getStatuses(self, twitter, options):
 -        return reversed(twitter.statuses.home_timeline(count=options["length"]))
 +        return reversed(twitter.get("statuses/home_timeline",
 +                                    count=options["length"]))
  
- class PublicAction(StatusAction):
-     def getStatuses(self, twitter, options):
-         return reversed(twitter.get("statuses/public_timeline",
-                                     count=options["length"]))
  class RepliesAction(StatusAction):
      def getStatuses(self, twitter, options):
 -        return reversed(twitter.statuses.mentions_timeline(count=options["length"]))
 +        return reversed(twitter.get("statuses/mentions_timeline",
 +                                    count=options["length"]))
  
  class FollowAction(AdminAction):
      def getUser(self, twitter, user):
@@@ -641,13 -668,17 +670,16 @@@ def main(args=sys.argv[1:])
              "the Command-Line Tool", CONSUMER_KEY, CONSUMER_SECRET,
              options['oauth_filename'])
  
+     global ansiFormatter
+     ansiFormatter = ansi.AnsiCmd(options["force-ansi"])
      oauth_token, oauth_token_secret = read_token_file(oauth_filename)
  
 -    twitter = Twitter(
 +    twitter = TwitterAPI(
 +        api_version='1.1',
          auth=OAuth(
              oauth_token, oauth_token_secret, CONSUMER_KEY, CONSUMER_SECRET),
 -        secure=options['secure'],
 -        api_version='1.1',
 -        domain='api.twitter.com')
 +        secure=options['secure'])
  
      try:
          Action()(twitter, options)
index df3d114c2bb8aacfff5cf9fb01f1db53799081e5,5fd995ef698d1dacd68548abc8019b915a9efb26..07248a5d19d39a58dfbada463e953776c8625918
@@@ -68,7 -79,56 +68,6 @@@ def OAuth(token, token_secret, consumer
      """
      An OAuth authenticator.
      """
 -    def __init__(self, token, token_secret, consumer_key, consumer_secret):
 -        """
 -        Create the authenticator. If you are in the initial stages of
 -        the OAuth dance and don't yet have a token or token_secret,
 -        pass empty strings for these params.
 -        """
 -        self.token = token
 -        self.token_secret = token_secret
 -        self.consumer_key = consumer_key
 -        self.consumer_secret = consumer_secret
 -
 -    def encode_params(self, base_url, method, params):
 -        params = params.copy()
 -
 -        if self.token:
 -            params['oauth_token'] = self.token
 -
 -        params['oauth_consumer_key'] = self.consumer_key
 -        params['oauth_signature_method'] = 'HMAC-SHA1'
 -        params['oauth_version'] = '1.0'
 -        params['oauth_timestamp'] = str(int(time()))
 -        params['oauth_nonce'] = str(getrandbits(64))
 -
 -        enc_params = urlencode_noplus(sorted(params.items()))
 -
 -        key = self.consumer_secret + "&" + urllib_parse.quote(self.token_secret, safe='~')
 -
 -        message = '&'.join(
 -            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, safe='~')
 -
 -    def generate_headers(self):
 -        return {}
 -
 -# apparently contrary to the HTTP RFCs, spaces in arguments must be encoded as
 -# %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.
 -def urlencode_noplus(query):
 -    if not PY3:
 -        new_query = []
 -        for k,v in query:
 -            if type(k) is unicode: k = k.encode('utf-8')
 -            if type(v) is unicode: v = v.encode('utf-8')
 -            new_query.append((k, v))
 -        query = new_query
 -        return urlencode(query).replace("+", "%20")
 -
 -    return urlencode(query, safe='~').replace("+", "%20")
 +    return OAuth1(unicode(consumer_key), unicode(consumer_secret),
 +                  unicode(token), unicode(token_secret),
 +                  signature_type="query")
index 0000000000000000000000000000000000000000,0709529488b5dd87f61b9e939fd9a68e053fa128..9611d46a26318dbd24015f7748346d08485e75ef
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,92 +1,91 @@@
 -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.
+ Twitter only supports the application-only flow of OAuth2 for certain
+ API endpoints. This OAuth2 authenticator only supports the application-only
+ flow right now. If twitter supports OAuth2 for other endpoints, this
+ authenticator may be modified as needed.
+ Finally, you can use the OAuth2 authenticator to connect to Twitter. In
+ code it all goes like this::
+     twitter = Twitter(auth=OAuth2(bearer_token=BEARER_TOKEN))
+     # Now work with Twitter
+     twitter.search.tweets(q='keyword')
+ """
+ from __future__ import print_function
+ try:
+     from urllib.parse import quote, urlencode
+ except ImportError:
+     from urllib import quote, urlencode
+ from base64 import b64encode
 -class OAuth2(Auth):
++class OAuth2(object):
+     """
+     An OAuth2 application-only authenticator.
+     """
+     def __init__(self, consumer_key=None, consumer_secret=None,
+                  bearer_token=None):
+         """
+         Create an authenticator. You can supply consumer_key and
+         consumer_secret if you are requesting a bearer_token. Otherwise
+         you must supply the bearer_token.
+         """
+         self.bearer_token = None
+         self.consumer_key = None
+         self.consumer_secret = None
+         if bearer_token:
+             self.bearer_token = bearer_token
+         elif consumer_key and consumer_secret:
+             self.consumer_key = consumer_key
+             self.consumer_secret = consumer_secret
+         else:
+             raise MissingCredentialsError(
+                 'You must supply either a bearer token, or both a '
+                 'consumer_key and a consumer_secret.')
+     def encode_params(self, base_url, method, params):
+         return urlencode(params)
+     def generate_headers(self):
+         if self.bearer_token:
+             headers = {
+                 b'Authorization': 'Bearer {0}'.format(
+                     self.bearer_token).encode('utf8')
+             }
+         elif self.consumer_key and self.consumer_secret:
+             headers = {
+                 b'Content-Type': (b'application/x-www-form-urlencoded;'
+                                   b'charset=UTF-8'),
+                 b'Authorization': 'Basic {0}'.format(
+                     b64encode('{0}:{1}'.format(
+                         quote(self.consumer_key),
+                         quote(self.consumer_secret)).encode('utf8')
+                     ).decode('utf8')
+                 ).encode('utf8')
+             }
+         else:
+             raise MissingCredentialsError(
+                 'You must supply either a bearer token, or both a '
+                 'consumer_key and a consumer_secret.')
+         return headers
+ class MissingCredentialsError(Exception):
+     pass