X-Git-Url: https://jfr.im/git/z_archive/twitter.git/blobdiff_plain/1c11e6d77644ababc01dfe505d1f778232855e49..de072195b64f3535375f1a20b25f457586a29125:/twitter/cmdline.py diff --git a/twitter/cmdline.py b/twitter/cmdline.py index a898b5d..061c0f2 100644 --- a/twitter/cmdline.py +++ b/twitter/cmdline.py @@ -6,7 +6,8 @@ USAGE: ACTIONS: follow add the specified user to your follow list friends get latest tweets from your friends (default action) - leave remove the specified user from your following list + help print this help text that you are currently reading + leave remove the specified user from your following list public get latest public tweets replies get latest replies set set your twitter status @@ -27,10 +28,11 @@ FORMATS for the --format option default one line per status verbose multiple lines per status, more verbose status info urls nothing but URLs. Dare you click them? - + CONFIG FILES - The config file should contain your email and password like so: + The config file should contain a [twitter] header, your email and password + like so: [twitter] email: @@ -39,7 +41,7 @@ password: import sys import time -from getopt import getopt +from getopt import getopt, GetoptError from getpass import getpass import re import os.path @@ -47,6 +49,10 @@ from ConfigParser import SafeConfigParser from api import Twitter, TwitterError +# Please don't change this, it was provided by the fine folks at Twitter. +# If you change it, it will not work. +AGENT_STR = "twittercommandlinetoolpy" + options = { 'email': None, 'password': None, @@ -62,8 +68,8 @@ def parse_args(args, options): long_opts = ['email', 'password', 'help', 'format', 'refresh', 'refresh-rate', 'config'] short_opts = "e:p:f:h?rR:c:" - opts, extra_args = getopt(args, short_opts, long_opts) - + opts, extra_args = getopt(args, short_opts, long_opts) + for opt, arg in opts: if opt in ('-e', '--email'): options['email'] = arg @@ -80,7 +86,7 @@ def parse_args(args, options): sys.exit(0) elif opt in ('-c', '--config'): options['config_filename'] = arg - + if extra_args: options['action'] = extra_args[0] options['extra_args'] = extra_args[1:] @@ -105,21 +111,24 @@ class URLStatusFormatter(object): return u'\n'.join(urls) if urls else "" class AdminFormatter(object): - def __call__(self, action, user): - return(u"%s: %s" %( - "Following" if action == "follow" else "Leaving", user['name'])) - + def __call__(self, action, user): + user_str = u"%s (%s)" %(user['screen_name'], user['name']) + if action == "follow": + return u"You are now following %s.\n" %(user_str) + else: + return u"You are no longer following %s.\n" %(user_str) + class VerboseAdminFormatter(object): - def __call__(self, action, user): - return(u"-- %s: %s (%s): %s" % ( - "Following" if action == "follow" else "Leaving", - user['screen_name'], - user['name'], - user['url'])) - + def __call__(self, action, user): + return(u"-- %s: %s (%s): %s" % ( + "Following" if action == "follow" else "Leaving", + user['screen_name'], + user['name'], + user['url'])) + class URLAdminFormatter(object): - def __call__(self, action, user): - return("Admin actions do not support the URL formatter") + def __call__(self, action, user): + return("Admin actions do not support the URL formatter") status_formatters = { 'default': StatusFormatter, @@ -128,11 +137,11 @@ status_formatters = { } admin_formatters = { - 'default': AdminFormatter, - 'verbose': VerboseAdminFormatter, - 'urls': URLAdminFormatter + 'default': AdminFormatter, + 'verbose': VerboseAdminFormatter, + 'urls': URLAdminFormatter } - + def get_status_formatter(options): sf = status_formatters.get(options['format']) if (not sf): @@ -141,12 +150,12 @@ def get_status_formatter(options): return sf() def get_admin_formatter(options): - sf = admin_formatters.get(options['format']) - if (not sf): - raise TwitterError( - "Unknown formatter '%s'" %(options['format'])) - return sf() - + sf = admin_formatters.get(options['format']) + if (not sf): + raise TwitterError( + "Unknown formatter '%s'" %(options['format'])) + return sf() + class Action(object): pass @@ -165,18 +174,27 @@ class StatusAction(Action): print statusStr.encode(sys.stdout.encoding, 'replace') class AdminAction(Action): - def __call__(self, twitter, options): - if (not options['extra_args'][0]): - raise TwitterError("You need to specify a User (Screen Name)") - af = get_admin_formatter(options) - user = self.getUser(twitter, options['extra_args'][0]) - if(user): - print af(options['action'], user).encode(sys.stdout.encoding, 'replace') - + def __call__(self, twitter, options): + if not options['extra_args'][0]: + raise TwitterError("You need to specify a user (screen name)") + af = get_admin_formatter(options) + try: + user = self.getUser(twitter, options['extra_args'][0]) + except TwitterError, e: + print "There was a problem following or leaving the specified user." + print " You may be trying to follow a user you are already following;" + print " Leaving a user you are not currently following;" + print " Or the user may not exist." + print " Sorry." + print + print e + else: + print af(options['action'], user).encode(sys.stdout.encoding, 'replace') + class FriendsAction(StatusAction): def getStatuses(self, twitter): return reversed(twitter.statuses.friends_timeline()) - + class PublicAction(StatusAction): def getStatuses(self, twitter): return reversed(twitter.statuses.public_timeline()) @@ -186,13 +204,12 @@ class RepliesAction(StatusAction): return reversed(twitter.statuses.replies()) class FollowAction(AdminAction): - def getUser(self, twitter, user): - # Twitter wants /notifications/follow/user.json?id=user - return twitter.notifications.follow.__getattr__(user)(id=user) - + def getUser(self, twitter, user): + return twitter.notifications.follow(id=user) + class LeaveAction(AdminAction): - def getUser(self, twitter, user): - return twitter.notifications.leave.__getattr__(user)(id=user) + def getUser(self, twitter, user): + return twitter.notifications.leave(id=user) class SetStatusAction(Action): def __call__(self, twitter, options): @@ -202,9 +219,14 @@ class SetStatusAction(Action): status = (statusTxt.encode('utf8', 'replace')) twitter.statuses.update(status=status) +class HelpAction(Action): + def __call__(self, twitter, options): + print __doc__ + actions = { - 'follow': FollowAction, + 'follow': FollowAction, 'friends': FriendsAction, + 'help': HelpAction, 'leave': LeaveAction, 'public': PublicAction, 'replies': RepliesAction, @@ -223,37 +245,45 @@ def loadConfig(filename): def main(): return main_with_args(sys.argv[1:]) - + def main_with_args(args): - parse_args(args, options) + try: + parse_args(args, options) + except GetoptError, e: + print >> sys.stderr, "I can't do that, %s." %(e) + print >> sys.stderr + sys.exit(1) email, password = loadConfig(options['config_filename']) if not options['email']: options['email'] = email if not options['password']: options['password'] = password - - #Maybe check for AdminAction here, but whatever you do, don't write TODO - if options['refresh'] and options['action'] == 'set': - print >> sys.stderr, "You can't repeatedly set your status, silly" + + if options['refresh'] and options['action'] not in ( + 'friends', 'public', 'replies'): + print >> sys.stderr, "You can only refresh the friends, public, or replies actions." print >> sys.stderr, "Use 'twitter -h' for help." sys.exit(1) + if options['email'] and not options['password']: options['password'] = getpass("Twitter password: ") - twitter = Twitter(options['email'], options['password']) + + twitter = Twitter(options['email'], options['password'], agent=AGENT_STR) action = actions.get(options['action'], NoSuchAction)() + try: doAction = lambda : action(twitter, options) - + if (options['refresh'] and isinstance(action, StatusAction)): - while True: - doAction() - time.sleep(options['refresh_rate']) + while True: + doAction() + time.sleep(options['refresh_rate']) else: - doAction() - + doAction() + except TwitterError, e: print >> sys.stderr, e.args[0] print >> sys.stderr, "Use 'twitter -h' for help." sys.exit(1) except KeyboardInterrupt: pass - +