TwitterCmd is an interactive console for twitter built on top of python-twitter library. It provides short, easy to remember commands for most twitter actions and provides a one-way interaction with the Python interpreter, exposing its objects to further inspection by the python-twitter API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | #!/usr/bin/env python
""" TwitterCmd - Interactive, console prompt to twitter
written on top of the python-twitter API.
A lot of credit to DeWitt Clinton and his team of
developers for the excellent 'python-twitter' API on
top of which, this program is written on.
Author: Anand B Pillai ('pythonhacker')
License: BSD License
"""
from twitter import Api
from cmd import Cmd
import sys, os
import re
import urllib2
import optparse
import time
import glob
import cPickle
import subprocess
__version__ = 0.3
__author__ = 'Anand B Pillai'
__lastmodified__ = "Thu Oct 8 14:39:24 IST 2009"
__modifications__ = """This version gets session save feature
and ability to enter Python prompt from TwitterCmd and back
while keeping state same across both. Basically you get the
simplicity of TwitterCmd plus the power of python-twitter
in one go!
Oct 8 - Bug in api attribute fixed, loading it fresh always.
Reduced stuff printed in inspecting timeline & user.
"""
LOADER="""
from twittercmd import *
from twitter import Api
import cPickle, urllib2
obj=cPickle.load(open('%s', 'rb'))
if obj.username:
obj.api=Api(obj.username)
else:
obj.api=Api()
g=globals()
g.update(obj.__dict__)
"""
INTRO="""Welcome to TwitterCmd, a command line interface to twitter,
written in Python. TwitterCmd provides a simple, interactive
interface to Twitter with short, easy to remember commands.
For a full set of commands, type "help" on the prompt.
For help for a specific command try "help <cmd>".
Please send comments/bug reports to <abpillai at gmail dot com>
or tweet them to the ID 'pythonhacker'.
"""
HELP="""
The following commands are available.
User commands
1. l <user> <passwd> - Set login credentials.
2. u <user> - Get details of a user.
3. f - Get friend's details.
4. fo - Get followers' details.
Timeline commands
1. pt - Get public timeline.
2. ut [<user>] - Get current user timeline
(given no arguments), or
timeline of given user.
3. ft - Get all friends' timeline.
Message commands
1. m <msg> - Post a status message.
2. im <user> <msg> - Post a direct message to user.
3. r - Get replies to messages.
4. dm - Get all direct messages.
You can also use the 'inspect' or 'i' command to
inspect live objects. The following object types are
supported as argument.
1. s/status - Inspect current msg status.
2. f/p/friends/peers - Inspect current friends status.
3. t/tl/tline - Inspect current timeline.
4. u/user - Inspect current user.
Version 0.2 also adds the power of entering Python
prompt while keeping state intact. To enter Python
prompt use any of 'shell','py' or 'python' commands.
Examples:
# Post a message
Twitter> l user pass
Twitter> m Hey, I love twitter!
# Get direct messages
Twitter> dm
["'No problem. :-)' => dloss"]
# Get names of all friends
Twitter> f
['dloss', 'gvanrossum', 'MallikaLA', 'BarackObama', 'ShashiTharoor']
# Use Python prompt from TwitterCmd
Twitter> py
Entering Python shell...
>>>
# Inspect objects in shell and use python-twitter
# directly by using the 'api' object.
>>> api
<twitter.Api object at 0x7fb69e6509d0>
# All state of TwitterCmd is available as globals
# in the interpreter...
>>> tline
[<twitter.Status object at 0xe643ad0>, <twitter.Status object at 0xe643d50>]
>>> status
<twitter.Status object at 0x7fb69e643850>
>>> status.text
'Completed session saving and entering Python shell and back from TwitterCmd\
, code will be up in a while, Hooray!'
# Use api just as you would before...!
>>> [s.text for s in api.GetPublicTimeline()]
['tweeting from gravity',...]
# Exit Python prompt
>>> ^D
Exiting Python shell...
Twitter>
To exit a session, type q/quit/exit or Ctrl-D.
"""
class TwitterCmdException(Exception):
pass
class TwitterCmd(Cmd):
""" Python command interpreter to Twitter API. Allows a simple
interactive interface to Twitter to those who prefer twittering
from their *nix console, while providing the flexibility to
switch back and forth from Python interactive prompt keeping
state intact """
commands = {'m' : 'PostUpdate', 'im': 'PostDirectMessage',
'ut': 'GetUserTimeline', 'pt': 'GetPublicTimeline',
'ft': 'GetFriendsTimeline', 'fo': 'GetFollowers',
'f': 'GetFriends', 'r': 'GetReplies',
'dm': 'GetDirectMessages', 'u':'GetUser',
'l': 'SetCredentials'}
prompt = 'Twitter> '
intro = INTRO
onecmd = lambda self, line: (line==None) and True
emptyline = lambda self: None
default = lambda self, line: None
def __init__(self, user='', passwd=''):
self.api = Api()
if user and passwd:
self.api.SetCredentials(user, passwd)
# Current username
self.username = user
# Current command
self.cmd = ''
# Current message status
self.status = None
# Current timeline
self.tline = None
# Current user object
self.user = None
# Current friends/followers
self.peers = None
# System stuff
# Python executable
self.python = sys.executable
Cmd.__init__(self)
# Load previous session
self.load_session()
def __getstate__(self):
odict = self.__dict__.copy()
del odict['stdin']
del odict['stdout']
del odict['api']
return odict
def __setstate__(self, dict):
# Don't update api object...
try:
del dict['api']
except KeyError:
pass
self.__dict__.update(dict)
def precmd(self, line):
line = line.strip()
if len(line)==0:
return line
if line.lower() in ('q','quit','exit','eof'):
print
self.save_session()
return None
if line.lower().startswith('help'):
self.print_help(line)
return line
if line.lower() in ('shell','py','python'):
# Start Python interpreter with current state
self.run_wild()
return line
l = line.split(' ')
cmd, rest = l[0], l[1:]
# Inspect objects ?
if cmd.lower() in ('i','inspect'):
self.inspect(' '.join(l[1:]).lower())
return line
elif cmd not in self.commands:
print "Command '%s' not understood" % cmd
return line
self.cmd = cmd.strip()
try:
self.action(*rest)
except IndexError, e:
print 'Command "%s" requires arguments!' % self.cmd
except urllib2.HTTPError, e:
print 'Twitter says:',e
# Any other exception
except Exception, e:
print 'Twitter API says:',e
return line
def inspect(self, obj_type):
""" Inspect our objects """
if obj_type in ('status', 's', 'st'):
if type(self.status) is list:
if self.status: print [str(i) for i in self.status]
else:
print str(self.status)
elif obj_type in ('tline','t','tl'):
if self.tline: print [i.text for i in self.tline]
elif obj_type in ('user','u'):
print self.user
elif obj_type in ('peers','friends','p','f'):
if self.peers: print [(i.name, i.screen_name) for i in self.peers]
else:
print 'Unknown object type',obj_type
def action(self, *args):
""" Perform a twitter action """
f = getattr(self.api, self.commands.get(self.cmd, None))
if self.cmd == 'l':
if len(args)>=2:
f(args[0], args[1])
else:
f(args[0], '')
print 'Set login credentials'
elif self.cmd == 'm':
# Force IndexError
x = args[0]
self.status = f(' '.join(args))
print repr(self.status)
elif self.cmd == 'im':
# Force IndexError
x = args[0]
self.status = f(args[0], ' '.join(args[1:]))
print repr(self.status)
elif self.cmd == 'ut':
self.tline = [f(args[0]) if len(args) else f()][0]
print [s.text for s in self.tline]
elif self.cmd == 'pt':
self.tline = f()
print [s.text for s in self.tline]
elif self.cmd == 'ft':
self.tline = f()
print [s.text for s in self.tline]
elif self.cmd == 'r':
self.status = f()
print [s.text for s in self.status]
elif self.cmd == 'dm':
self.status = f()
print [' => '.join(("'" + s.text + "'", s._sender_screen_name)) \
for s in self.status]
elif self.cmd in ('f','fo'):
self.peers = f()
print [s.screen_name for s in self.peers]
elif self.cmd=='u':
self.user = f(args[0])
print self.user.name
def load_session(self):
""" Load most recent session from disk, if present """
fnames = glob.glob(os.path.join(os.path.expanduser('~'),'.twitter_session_*'))
if len(fnames):
print 'Loading saved session...'
try:
obj = cPickle.load(open(fnames[0], 'rb'))
self.__setstate__(obj.__dict__)
except cPickle.UnpicklingError, e:
print 'Error loading saved session'
def save_session(self):
""" Save current session to disk """
fname = os.path.join(os.path.expanduser('~'), '.twitter_session_%d' % int(time.time()))
try:
# Remove older sessions
olds = glob.glob(os.path.join(os.path.expanduser('~'),'.twitter_session_*'))
cPickle.dump(self, open(fname, 'wb'))
# Remove older sessions
for f in olds:
try:
os.remove(f)
except OSError, e:
pass
except cPickle.PicklingError, e:
print 'Error saving current session to disk:',e
return fname
def run_wild(self):
session = self.save_session()
# Create a module that will load the saved session
loader = LOADER % session
module = '.twitter_loader.py'
open(module,'w').write(loader)
print 'Entering Python shell...'
subprocess.call([self.python,"-i", module])
print 'Exiting Python shell...'
def print_help(self, line):
if line.lower()=='help':
print HELP
else:
l = line.split(' ')
cmd, rest = l[0], ' '.join(l[1:])
if cmd.lower() != 'help':
return
if rest=='m':
print 'm <msg>: Post status message <msg>'
elif rest=='im':
print 'm <user> <msg>: Post direct message <msg> to user <user>'
elif rest=='ut':
print 'ut [<user>]: Get current user timeline without arguments\n\
and given user timeline with arguments'
elif rest=='pt':
print 'pt: Get twitter public timeline'
elif rest=='ft':
print "ft: Get all friends' timelines"
elif rest=='fo':
print 'fo: Get all follower details'
elif rest=='f':
print "f: Get all friends' details"
elif rest=='dm':
print 'dm: Get all direct messages'
elif rest=='r':
print 'r: Get all replies to direct messages'
elif rest=='u':
print 'u <user>: Get a given user details'
elif rest=='l':
print 'l <user> <passwd>: Set current user credentials'
elif rest in ('i','inspect'):
print 'i <obj_type>: Inspect object of given type'
else:
print 'No such command "%s"' % rest
if __name__ == "__main__":
p = optparse.OptionParser()
p.add_option('-u','--user',dest='user',default='',help='Optional Twitter username')
p.add_option('-p','--passwd',dest='passw',default='',help='Optional Twitter password')
options, args = p.parse_args()
user, passwd = options.user, options.passw
TwitterCmd(user, passwd).cmdloop()
|
TwitterCmd provides easy to use, shortcuts for most twitter actions. Here is a sample session.
Login with username/password
Twitter> l pythonhacker <passwd>
Set login credentials
Post an update
Twitter> m Posting TwitterCmd to Aspn Python cookbook website now... <twitter.Status object at 0x1293490>
User timeline
Twitter> ut
['Posting TwitterCmd to Aspn Python cookbook website now...', 'OK I am done, enuf hacking for 2 days, hope TwitterCmd is useful and worth the effort, drop me a tweet if found useful!,...]
Public timeline
Twitter> pt
['@tiws80 hehehehe... gw juga lupa... siapa yg sok tau ya??? huahahahahaha....', 'got out of class two hours early, good thing sense this night sucks,...]
User timeline of another user
Twitter> ut dloss
['Principal Programming Paradigms Poster http://bit.ly/krgct "More is not better (or worse) than less, just different"',...]
Direct messages
Twitter> dm
["'No problem. :-)' => dloss", "'Well done! BTW: You seem to be using Scapy v1. Check out Scapy v2 and its new Sphinx-based docs: http://is.gd/3PkI0' => dloss"]
Replies
Twitter> r
['@ershad_k http://bit.ly/1HoxQT by @pythonhacker', "testing @pythonhacker's command line client",...]
Send a direct message to another user
Twitter> im pythonhacker2 Hey dude, how about soccer tonight ?
<twitter.DirectMessage object at 0x11045b0>
Get name of a user
Twitter> u crackpot
Shirley
Twitter> u pythonhacker
Anand B Pillai
Inspect commands
Inspect the most recent status message
Twitter> i s
{"created_at": "Wed Oct 07 04:24:08 +0000 2009", "id": 434985222, "recipient_id": 79802660, "recipient_screen_name": "pythonhacker2", "sender_id": 6158512, "sender_screen_name": "pythonhacker", "text": "Hey dude, how about soccer tonight ?"}
Inspect the most recent user
Twitter> i u
{"description": "Developer, Programmer, Hacker, Python Enthusiast...", "favourites_count": 1, "followers_count": 47, "friends_count": 5, "id": 6158512, "location": "Bangalore, India", "name": "Anand B Pillai", "profile_background_color": "0099B9", "profile_background_tile": false, "profile_image_url": "http://a1.twimg.com/profile_images/288309206/python_normal.png", "profile_link_color": "0099B9", "profile_sidebar_fill_color": "http://s.twimg.com/a/1254855407/images/themes/theme4/bg.gif", "profile_text_color": "3C3940", "protected": false, "screen_name": "pythonhacker", "status": {"created_at": "Wed Oct 07 04:22:17 +0000 2009", "favorited": false, "id": 4674679432, "source": "<a href=\"http://apiwiki.twitter.com/\" rel=\"nofollow\">API</a>", "text": "Posting TwitterCmd to Aspn Python cookbook website now...", "truncated": false}, "statuses_count": 40, "time_zone": "Chennai", "url": "http://harvestmanontheweb.com", "utc_offset": 19800}
Inspect the most recent timeline
Twitter> i t
['{"created_at": "Mon Oct 05 21:47:07 +0000 2009", "favorited": false, "id": 4638567339, "source": "<a href=\\"http://www.mrrsoftware.com/MRRSoftware/Syrinx.html\\" rel=\\"nofollow\\">Syrinx</a>", "text": "Principal Programming Paradigms Poster http://bit.ly/krgct \"More is not better (or worse) than less, just different\"",...]
This also allows to jump to Python prompt carrying its state across, thereby allowing the more avid Python developer to use it as a tool for twittering plus a channel for further inspection using python-twitter.
Twitter> py
Entering Python shell...
All state is available in the same name...
>>> status
<twitter.DirectMessage object at 0x10fa910>
>>> status.text
'Hey dude, how about soccer tonight ?'
>>> tline
[<twitter.Status object at 0x10facd0>, <twitter.Status object at 0x11034d0>, <twitter.Status object at 0x1103850>, <twitter.Status object at 0x1103bd0>, <twitter.Status object at 0x1103f50>, <twitter.Status object at 0x11052f0>, <twitter.Status object at 0x1105670>, <twitter.Status object at 0x1105a10>, <twitter.Status object at 0x1105dd0>, <twitter.Status object at 0x11081b0>, <twitter.Status object at 0x1108530>, <twitter.Status object at 0x11088b0>, <twitter.Status object at 0x1108c30>, <twitter.Status object at 0x1108fb0>, <twitter.Status object at 0x1109350>, <twitter.Status object at 0x11096d0>, <twitter.Status object at 0x1109a50>, <twitter.Status object at 0x1109dd0>, <twitter.Status object at 0x110b170>, <twitter.Status object at 0x110b510>]
>>> [i.text for i in tline]
['Principal Programming Paradigms Poster http://bit.ly/krgct "More is not better (or worse) than less, just different"', 'RT @justinvincent: Entire Cities Recreated Using Thousands of Flickr Photos http://bit.ly/4lFOaF', 'The Google Technology Stack http://bit.ly/18fN10 (via @justinvincent) - Maybe I should read more science papers instead of buying books...',...]
>>> user
<twitter.User object at 0x110bd10>
>>> user.name
'Anand B Pillai'
>>> user.name, user.screen_name
('Anand B Pillai', 'pythonhacker')
Exit the Python shell
>>> ^D
Exiting Python shell...
Twitter>
<h4>Exit TwitterCmd</h4>
Twitter> ^D
anand-b-pillais-computer-2:~/programs/python/twitter>
State transfer is done using Pickled files and a custom loader script which is saved to the current directory. Session files are saved and loaded automatically when exiting and entering the prompt.
Find the most uptodate version of this script at http://harvestmanontheweb.com/python/twitter/ always.