Skip to content
Browse files

Major refactor to make the project work with virtualenv or App Engine.

  • Loading branch information...
1 parent afb291f commit 03217cac5a1d9daec813a391459f21273e5b7348 @voodoochild committed Dec 12, 2011
View
5 .gitignore
@@ -1,3 +1,8 @@
.DS_Store
*.pyc
venv/
+flask/
+werkzeug/
+simplejson/
+jinja2/
+BeautifulSoup.py
View
26 README.md
@@ -1,4 +1,28 @@
What do you want to read next?
==============================
-This is a 'fail fast' experimental component that aims to provide links to recent and interesting articles for readers.
+This is a 'fail fast' experimental component that aims to provide links to recent and interesting articles for readers.
+
+**To run the project locally with virtualenv:**
+
+ `$ pip install virtualenv`
+
+ `$ virtualenv venv/ --no-site-packages`
+
+ `$ venv/bin/pip install -r requirements.txt`
+
+ `$ venv/bin/python runserver.py`
+
+**To run the project locally with App Engine:**
+
+_Extract the various python libs in lib/ to the document root, e.g._
+
+ `$ tar xzf lib/Flask-0.8.tar.gz`
+
+ `$ mv Flask-0.8/flask/ .`
+
+ `$ rm -rf Flask-0.8/`
+
+_Then run it:_
+
+ `$ dev_appserver.py .`
View
8 app.yaml
@@ -0,0 +1,8 @@
+application: gu-read-next
+version: 1
+runtime: python
+api_version: 1
+
+handlers:
+- url: .*
+ script: main.py
View
BIN lib/BeautifulSoup-3.2.0.tar
Binary file not shown.
View
BIN lib/Flask-0.8.tar.gz
Binary file not shown.
View
BIN lib/Jinja2-2.6.tar
Binary file not shown.
View
BIN lib/Werkzeug-0.8.1.tar
Binary file not shown.
View
BIN lib/simplejson-2.3.0.tar.gz
Binary file not shown.
View
4 main.py
@@ -0,0 +1,4 @@
+from google.appengine.ext.webapp.util import run_wsgi_app
+from readnext import app
+
+run_wsgi_app(app)
View
10 readnext/__init__.py
@@ -0,0 +1,10 @@
+from flask import Flask
+
+CONTENT_API = 'http://content.guardianapis.com/search'
+ITEMS_PER_FEED = 10 # how many items to retrieve per feed
+ITEMS_TO_DISPLAY = 1 # how many items to show in the component per feed
+
+app = Flask(__name__)
+app.config.from_object(__name__)
+
+import readnext.views
View
0 static/css/readnext.css → readnext/static/css/readnext.css
File renamed without changes.
View
0 static/js/jquery-1.6.2.min.js → readnext/static/js/jquery-1.6.2.min.js
File renamed without changes.
View
0 static/js/readnext.js → readnext/static/js/readnext.js
File renamed without changes.
View
0 templates/base.html → readnext/templates/base.html
File renamed without changes.
View
0 templates/component.html → readnext/templates/component.html
File renamed without changes.
View
55 app.py → readnext/views.py
@@ -1,15 +1,9 @@
-from flask import Flask, make_response, render_template, abort, redirect, url_for, request
-import requests
+from flask import make_response, render_template, abort, redirect, url_for, request
+from readnext import app
import random
import simplejson
-import feedparser
+from BeautifulSoup import BeautifulStoneSoup
-CONTENT_API = 'http://content.guardianapis.com/search'
-ITEMS_PER_FEED = 10 # how many items to retrieve per feed
-ITEMS_TO_DISPLAY = 1 # how many items to show in the component per feed
-
-app = Flask(__name__)
-app.config.from_object(__name__)
@app.route('/', methods=['GET'])
def index():
@@ -23,6 +17,7 @@ def readnext():
api = ContentApi(feeds)
rss = RssFeeds(feeds)
+ # API feeds.
api.add_feed('News', 'news')
api.add_feed('Comment', 'commentisfree')
api.add_feed('Sport', 'sport')
@@ -33,6 +28,9 @@ def readnext():
api.add_feed('TV', 'tv-and-radio')
api.add_feed('Life & Style', 'lifeandstyle')
+ # RSS feeds.
+ rss.add_feed('News Leads', 'http://www.guardian.co.uk/world/lead/rss')
+
if not feeds:
abort(404)
random.shuffle(feeds)
@@ -62,9 +60,24 @@ def add_feed(self, title, key):
def get_data(self, key):
"""Attempt to retrieve data."""
- r = requests.get(key)
- if r.status_code == 200:
- return r.content
+ # Try App Engine's urlfetch first.
+ try:
+ from google.appengine.api import urlfetch
+ r = urlfetch.fetch(key, method=urlfetch.GET)
+ if r.status_code == 200:
+ return r.content
+ except ImportError:
+ pass
+
+ # If that wasn't available, try requests.
+ try:
+ import requests
+ r = requests.get(key)
+ if r.status_code == 200:
+ return r.content
+ except ImportError:
+ abort(500)
+
return False
def process_data(self, data):
@@ -119,10 +132,10 @@ class RssFeeds(DataGrabber):
def process_data(self, data):
"""Process Guardian RSS feed data."""
if data:
- rss_data = feedparser.parse(data)
+ soup = BeautifulStoneSoup(data)
items = []
i = 0
- for entry in rss_data.entries:
+ for entry in soup.findAll('item'):
if i < app.config['ITEMS_PER_FEED']:
items.append(self.build_item(entry))
i = i + 1
@@ -134,16 +147,14 @@ def process_data(self, data):
def build_item(self, data):
"""Transform RSS data into a dictionary that the template can use."""
article = {
- 'title': data['title'],
- 'url': data['link'],
+ 'title': data.title.contents[0],
+ 'url': data.link.contents[0],
}
- try:
- for media in data['media_content']:
- if media['width'] == u'140' and media['height'] == u'84':
- article['thumbnail'] = media['url']
- except KeyError:
- pass
+ media = data.findAll('media:content')
+ for m in media:
+ if m['width'] == u'140' and m['height'] == u'84':
+ article['thumbnail'] = m['url']
return article
View
2 runserver.py
@@ -0,0 +1,2 @@
+from readnext import app
+app.run(debug=True)

0 comments on commit 03217ca

Please sign in to comment.
Something went wrong with that request. Please try again.