From 2122f6528d88da31d2e72a8a2bc6e1809c38950d Mon Sep 17 00:00:00 2001 From: Ryan McGrath Date: Sun, 7 Nov 2010 02:18:24 -0500 Subject: [PATCH] Minor Streaming work; not official, just hackery for fun. Fork and patch or look away. --- oauth_django_example/__init__.py | 0 oauth_django_example/manage.py | 11 --- oauth_django_example/settings.py | 94 --------------------- oauth_django_example/templates/tweets.html | 3 - oauth_django_example/test.db | Bin 65536 -> 0 bytes oauth_django_example/twitter/__init__.py | 0 oauth_django_example/twitter/models.py | 7 -- oauth_django_example/twitter/views.py | 73 ---------------- oauth_django_example/urls.py | 9 -- twython/streaming.py | 44 ++++++---- 10 files changed, 26 insertions(+), 215 deletions(-) delete mode 100644 oauth_django_example/__init__.py delete mode 100644 oauth_django_example/manage.py delete mode 100644 oauth_django_example/settings.py delete mode 100644 oauth_django_example/templates/tweets.html delete mode 100644 oauth_django_example/test.db delete mode 100644 oauth_django_example/twitter/__init__.py delete mode 100644 oauth_django_example/twitter/models.py delete mode 100644 oauth_django_example/twitter/views.py delete mode 100644 oauth_django_example/urls.py diff --git a/oauth_django_example/__init__.py b/oauth_django_example/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oauth_django_example/manage.py b/oauth_django_example/manage.py deleted file mode 100644 index 5e78ea9..0000000 --- a/oauth_django_example/manage.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python -from django.core.management import execute_manager -try: - import settings # Assumed to be in the same directory. -except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) - sys.exit(1) - -if __name__ == "__main__": - execute_manager(settings) diff --git a/oauth_django_example/settings.py b/oauth_django_example/settings.py deleted file mode 100644 index 8ceb7a5..0000000 --- a/oauth_django_example/settings.py +++ /dev/null @@ -1,94 +0,0 @@ -import os.path - -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -ADMINS = ( - ('Ryan McGrath', 'ryan@venodesigns.net'), -) - -MANAGERS = ADMINS - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': os.path.join(os.path.dirname(__file__), 'test.db'), # Or path to database file if using sqlite3. - 'USER': '', # Not used with sqlite3. - 'PASSWORD': '', # Not used with sqlite3. - 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. - 'PORT': '', # Set to empty string for default. Not used with sqlite3. - } -} - - -AUTH_PROFILE_MODULE = 'twitter.Profile' - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# On Unix systems, a value of None will cause Django to use the same -# timezone as the operating system. -# If running in a Windows environment this must be set to the same as your -# system time zone. -TIME_ZONE = 'America/New_York' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-us' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# If you set this to False, Django will not format dates, numbers and -# calendars according to the current locale -USE_L10N = True - -# Absolute path to the directory that holds media. -# Example: "/home/media/media.lawrence.com/" -MEDIA_ROOT = '' - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash if there is a path component (optional in other cases). -# Examples: "http://media.lawrence.com", "http://example.com/media/" -MEDIA_URL = '' - -# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a -# trailing slash. -# Examples: "http://foo.com/media/", "/media/". -ADMIN_MEDIA_PREFIX = '/media/' - -# Make this unique, and don't share it with anybody. -SECRET_KEY = '&!_t1t^gmenaid9mkmkuw=4nthj7f)o+!@$#ipfp*s11380t*)' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', -# 'django.template.loaders.eggs.Loader', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', -) - -ROOT_URLCONF = 'twython_testing.urls' - -TEMPLATE_DIRS = ( - os.path.join(os.path.dirname(__file__), 'templates'), -) - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.messages', - 'twitter', -) diff --git a/oauth_django_example/templates/tweets.html b/oauth_django_example/templates/tweets.html deleted file mode 100644 index a2ec453..0000000 --- a/oauth_django_example/templates/tweets.html +++ /dev/null @@ -1,3 +0,0 @@ -{% for tweet in tweets %} - {{ tweet.text }} -{% endfor %} diff --git a/oauth_django_example/test.db b/oauth_django_example/test.db deleted file mode 100644 index 3082a95365c31ec03e2a58e9352abe89008a2011..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 H|DXQ@eXup& diff --git a/oauth_django_example/twitter/__init__.py b/oauth_django_example/twitter/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oauth_django_example/twitter/models.py b/oauth_django_example/twitter/models.py deleted file mode 100644 index 3a07664..0000000 --- a/oauth_django_example/twitter/models.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User - -class Profile(models.Model): - user = models.ForeignKey(User) - oauth_token = models.CharField(max_length = 200) - oauth_secret = models.CharField(max_length = 200) diff --git a/oauth_django_example/twitter/views.py b/oauth_django_example/twitter/views.py deleted file mode 100644 index cb3f182..0000000 --- a/oauth_django_example/twitter/views.py +++ /dev/null @@ -1,73 +0,0 @@ -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.models import User -from django.http import HttpResponse, HttpResponseRedirect -from django.shortcuts import render_to_response -from django.contrib.auth.decorators import login_required - -from twython import Twython -from twitter.models import Profile - -CONSUMER_KEY = "YOUR CONSUMER KEY HERE" -CONSUMER_SECRET = "YOUR CONSUMER SECRET HERE" - -def twitter_logout(request): - logout(request) - return HttpResponseRedirect('/') - -def twitter_begin_auth(request): - # Instantiate Twython with the first leg of our trip. - twitter = Twython( - twitter_token = CONSUMER_KEY, - twitter_secret = CONSUMER_SECRET - ) - - # Request an authorization url to send the user to... - auth_props = twitter.get_authentication_tokens() - - # Then send them over there, durh. - request.session['request_token'] = auth_props - return HttpResponseRedirect(auth_props['auth_url']) - -def twitter_thanks(request): - # Now that we've got the magic tokens back from Twitter, we need to exchange - # for permanent ones and store them... - twitter = Twython( - twitter_token = CONSUMER_KEY, - twitter_secret = CONSUMER_SECRET, - oauth_token = request.session['request_token']['oauth_token'], - oauth_token_secret = request.session['request_token']['oauth_token_secret'] - ) - - # Retrieve the tokens we want... - authorized_tokens = twitter.get_authorized_tokens() - - # If they already exist, grab them, login and redirect to a page displaying stuff. - try: - user = User.objects.get(username = authorized_tokens['screen_name']) - except User.DoesNotExist: - # We mock a creation here; no email, password is just the token, etc. - user = User.objects.create_user(authorized_tokens['screen_name'], "fjdsfn@jfndjfn.com", authorized_tokens['oauth_token_secret']) - profile = Profile() - profile.user = user - profile.oauth_token = authorized_tokens['oauth_token'] - profile.oauth_secret = authorized_tokens['oauth_token_secret'] - profile.save() - - user = authenticate( - username = authorized_tokens['screen_name'], - password = authorized_tokens['oauth_token_secret'] - ) - login(request, user) - return HttpResponseRedirect('/timeline') - -def twitter_timeline(request): - user = request.user.get_profile() - twitter = Twython( - twitter_token = CONSUMER_KEY, - twitter_secret = CONSUMER_SECRET, - oauth_token = user.oauth_token, - oauth_token_secret = user.oauth_secret - ) - my_tweets = twitter.getHomeTimeline() - print my_tweets - return render_to_response('tweets.html', {'tweets': my_tweets}) diff --git a/oauth_django_example/urls.py b/oauth_django_example/urls.py deleted file mode 100644 index 9344f4d..0000000 --- a/oauth_django_example/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.conf.urls.defaults import * -from twitter.views import twitter_begin_auth, twitter_thanks, twitter_logout, twitter_timeline - -urlpatterns = patterns('', - (r'^login/?$', twitter_begin_auth), - (r'^/logout?$', twitter_logout), - (r'^thanks/?$', twitter_thanks), # Where they're redirect to after authorizing - (r'^timeline/?$', twitter_timeline), -) diff --git a/twython/streaming.py b/twython/streaming.py index f6df1a3..8020116 100644 --- a/twython/streaming.py +++ b/twython/streaming.py @@ -1,37 +1,50 @@ #!/usr/bin/python """ - Yes, this is just in __init__ for now, hush. + TwythonStreamer is an implementation of the Streaming API for Twython. + Pretty self explanatory by reading the code below. It's worth noting + that the end user should, ideally, never import this library, but rather + this is exposed via a linking method in Twython's core. - The beginnings of Twitter Streaming API support in Twython. Don't expect this to work at all, - consider it a stub for now. -- Ryan - Questions, comments? ryan@venodesigns.net """ -import httplib, urllib, urllib2, mimetypes, mimetools, socket, time +__author__ = "Ryan McGrath " +__version__ = "1.0.0" + +import urllib +import urllib2 +import urlparse +import httplib +import httplib2 +import re from urllib2 import HTTPError +# There are some special setups (like, oh, a Django application) where +# simplejson exists behind the scenes anyway. Past Python 2.6, this should +# never really cause any problems to begin with. try: - import simplejson + # Python 2.6 and up + import json as simplejson except ImportError: try: - import json as simplejson + # Python 2.6 and below (2.4/2.5, 2.3 is not guranteed to work with this library to begin with) + import simplejson except ImportError: try: + # This case gets rarer by the day, but if we need to, we can pull it from Django provided it's there. from django.utils import simplejson except: - raise Exception("Twython (Streaming) requires the simplejson library (or Python 2.6) to work. http://www.undefined.org/python/") - -__author__ = "Ryan McGrath " -__version__ = "0.1" + # Seriously wtf is wrong with you if you get this Exception. + raise Exception("Twython requires the simplejson library (or Python 2.6) to work. http://www.undefined.org/python/") class TwythonStreamingError(Exception): def __init__(self, msg): self.msg = msg + def __str__(self): - return repr(self.msg) + return "%s" % str(self.msg) feeds = { "firehose": "http://stream.twitter.com/firehose.json", @@ -43,10 +56,5 @@ feeds = { "track": "http://stream.twitter.com/track.json", } -class stream: +class Stream(object): def __init__(self, username = None, password = None, feed = "spritzer", user_agent = "Twython Streaming"): - self.username = username - self.password = password - self.feed = feeds[feed] - self.user_agent = user_agent - self.connection_open = False