Generate a site dynamically using Twisted - python

I want to generate all the pages of a site using twisted. It has to be similar with generating a page dynamically.
I came up with this :
class Home(Resource):
isLeaf = False
def __init__(self, pathname):
Resource.__init__(self)
self.pathname = pathname
def getChild(self, name, request):
if name == '':
return self
return Resource.getChild(self, name, request)
def render_GET(self, request):
path = "/var/www/html/books.toscrape.com/catalogue/"
fname = path + self.pathname
if ".html" in self.pathname:
f = open(fname)
s=f.read()
return s
else:
fname = fname + "/index.html"
f = open(fname)
s=f.read()
return s
class ElseSite(Resource):
def getChild(self,name,request):
return Home(name)
resource = ElseSite()
factory = Site(resource)
I'm able to generate pages with the url localhost:8080/foo, but how can I add more slashes to it, i.e. something like localhost:8080/foo/bar?

Children themselves can have children:
from twisted.web.resource import Resource
class Foo(Resource):
def getChild(self, name, request):
return Bar(name)
class Bar(Resource):
def getChild(self, name, request):
return Data(name)
site = Site(Foo())
...
You may also want to take a look at Klein which provides for a different style of defining your hierarchy. From the Klein docs:
from klein import Klein
app = Klein()
#app.route('/')
def pg_root(request):
return 'I am the root page!'
#app.route('/about')
def pg_about(request):
return 'I am a Klein application!'
app.run("localhost", 8080)
The native Twisted Web style is nice for very dynamic resource hierarchies. The Klein style is nice for relatively fixed hierarchies.

This answer helped me : https://stackoverflow.com/a/37689813/217088.
I defined a single resource with isLeaf = True, and then used request.postpath to get the query after http://localhost:8080/.
My code looks like this now :
class Home(Resource):
isLeaf = True
def __init__(self):
Resource.__init__(self)
def render_GET(self, request):
path = "/var/www/html/books.toscrape.com/"
filepath = '/'.join(request.postpath)
fname = path + filepath
f = open(fname)
s=f.read()
return s
resource = Home()
factory = Site(resource)

Related

Using class in Python/Django testing to make code more reusable [duplicate]

This question already has answers here:
abstract test case using python unittest
(13 answers)
Closed 1 year ago.
I need some help with my testing architecture. My code works but it seems ugly for me. Could you take a look :
The goal is to make the same tests for all my pages in Django :
I wrote a unit testing.py
from django.urls import reverse, resolve
class SinglePageTest(object):
str_reverse = ''
adresse = ''
template = None
template_path = ''
str_contain = ''
def initialize(self):
self.url = reverse(self.str_reverse)
self.view = resolve(self.adresse)
self.response = self.client.get(self.url)
def test_status_200(self):
self.assertEqual(self.response.status_code, 200)
def test_templates_home(self):
self.assertTemplateUsed(self.response, self.template_path)
def test_contains_HTML(self):
self.assertContains(self.response,
self.str_contain)
def test_url_resolve(self):
self.assertEqual(self.view.func.__name__,
self.template.as_view().__name__)
When I need to test a page in test.py I do this :
from django.test import TestCase, SimpleTestCase
from DjangoTools.testing import SinglePageTest
class RetrievePassword(SimpleTestCase, SinglePageTest):
def setUp(self):
self.str_reverse = 'retrieve-password'
self.adresse = '/accounts/retrieve-password'
self.template = RetrievePasswordView
self.template_path = 'accounts/retrieve-password.html'
self.str_contain = '<h1>🔑 Récupérer le <span class="clr-org">mot de passe</span></h1>'
super(RetrievePassword, self).setUp()
SinglePageTest.initialize(self)
The problem is that PyCharm doesn't find the reference for a lot of method in testing.py and that's normal cause I'am using a basic object that doesn't contains these methods.
My questions are :
Is-it well to do like this ?
Can I say that I'm using Mixins ?
How to tell pycharm to find assertTemplateUsed, client.get etc...
Have a nice day,
After using the solution provided unittest is trying to test the testing.py class
Solution of the problem : add to the base class
def setUp(self):
if self.__class__ is BaseSinglePageTest:
raise SkipTest("%s is an abstract base class" % self.__class__)
else:
super(BaseSinglePageTest, self).setUp()
Instead of creating mixins, linear inheritance should work nice on this case.
SimpleTestCase <- SinglePageTest <- RetrievePassword
from django.urls import reverse, resolve
class BaseSinglePageTest(SimpleTestCase):
str_reverse = ''
adresse = ''
template = None
template_path = ''
str_contain = ''
def initialize(self):
self.url = reverse(self.str_reverse)
self.view = resolve(self.adresse)
self.response = self.client.get(self.url)
def test_status_200(self):
self.assertEqual(self.response.status_code, 200)
def test_templates_home(self):
self.assertTemplateUsed(self.response, self.template_path)
def test_contains_HTML(self):
self.assertContains(self.response,
self.str_contain)
def test_url_resolve(self):
self.assertEqual(self.view.func.__name__,
self.template.as_view().__name__)
and then use this class like so
from django.test import TestCase, SimpleTestCase
from DjangoTools.testing import SinglePageTest
class RetrievePassword(BaseSinglePageTest):
def setUp(self):
self.str_reverse = 'retrieve-password'
self.adresse = '/accounts/retrieve-password'
self.template = RetrievePasswordView
self.template_path = 'accounts/retrieve-password.html'
self.str_contain = '<h1>🔑 Récupérer le <span class="clr-org">mot de passe</span></h1>'
super(RetrievePassword, self).setUp()
SinglePageTest.initialize(self)
testing.py
from django.test import SimpleTestCase
from django.urls import reverse, resolve
from unittest import SkipTest
class BaseSinglePageTest(SimpleTestCase):
str_reverse = ''
adresse = ''
template = None
template_path = ''
str_contain = ''
def setUp(self):
if self.__class__ is BaseSinglePageTest:
raise SkipTest("%s is an abstract base class" % self.__class__)
else:
super(BaseSinglePageTest, self).setUp()
def initialize(self):
self.url = reverse(self.str_reverse)
self.view = resolve(self.adresse)
self.response = self.client.get(self.url)
def test_status_200(self):
self.assertEqual(self.response.status_code, 200)
def test_templates_home(self):
self.assertTemplateUsed(self.response, self.template_path)
def test_contains_HTML(self):
self.assertContains(self.response,
self.str_contain)
def test_url_resolve(self):
self.assertEqual(self.view.func.__name__,
self.template.as_view().__name__)
test.py
from django.contrib.auth import get_user_model, authenticate
from DjangoTools.tool_test import BaseSinglePageTest
class RetrievePassword(BaseSinglePageTest):
def setUp(self):
self.str_reverse = 'retrieve-password'
self.adresse = '/accounts/retrieve-password'
self.template = RetrievePasswordView
self.template_path = 'accounts/retrieve-password.html'
self.str_contain = '<h1>🔑 Récupérer le <span class="clr-org">mot de passe</span></h1>'
super(RetrievePassword, self).setUp()
BaseSinglePageTest.initialize(self)

Pyramid: resource tree in URL Dispatch(hybrid) application

I am trying to implement dynamic ACLs(including row-level security) in URL Dispatch app.
Defining Root factory only doesn't seem to be sufficient as I need to perform individual authz checks for each secured endpoint. My setup looks as follows(I was using pyramid docs and mmerickel's tutorials as a guide):
config.py
...
settings = config.registry.settings
config = Configurator(settings=settings, root_factory=RootPermissionFactory)
config.set_authentication_policy(CustomAuthenticationPolicy(settings))
config.set_authorization_policy(ACLAuthorizationPolicy())
...
views.py
#import ...
#view_defaults(renderer='json', permission='secured')
class RecordsView(object):
...
#view_config(request_method='GET', route_name='records_by_id')
def get(self):
record = self.request.context.data
if not record:
return HTTPNotFound()
return record
#view_config(request_method='GET', route_name='records')
def get_by_owners(self):
owner_uids = self.request.params.mixed()['owner_uids']
return records_service.get_records(owner_uids=owner_uids)
def includeme(config):
config.add_route('records', '/records', factory=RecordsResource)
config.add_route('records_by_id', 'records/{record_id}', factory=RecordFactory, traverse='{record_id}')
authorization.py
class RootPermissionFactory(object):
__name__ = None
__parent__ = None
def __acl__(self):
return [
(Allow, 'authenticated_principal', 'secured'),
]
def __init__(self, request):
self.request = request
class RecordFactory(object):
def __init__(self, request):
self.request = request
def __getitem__(self, key):
record_data = records_service.get_record(key)
owner = record_data.get('owner_uid')
return RecordContext(self.request, owner, record_data)
class RecordContext(object):
def __acl__(self):
owner_principal = 'u:{owner}'.format(owner=self.owner)
return [
(Allow, owner_principal, 'secured'),
]
def __init__(self, request, owner, record_data):
self.request = request
self.owner = owner
self.data = record_data
class RecordsResource(object):
def __acl__(self):
request_params = self.request.params.mixed()
request_owner_uids = request_params['owner_uids']
authorized_owner_uids = owners_api_service.get_authorized_owners(self.request.user['auth_data'])
return [(Allow, 'authenticated_principal', 'secured')]\
if set(authorized_owner_uids) == set(request_owner_uids) else []
def __init__(self, request):
self.request = request
My questions are following:
is it acceptable to utilize row-level security checks without having Model layer? i.e. there is no ORM set up for Records data and there is also no plain Model to put persisted data into, so I have to use 'fake' RecordContext class to attach __acl__ rules and pass data to the view
is it acceptable to treat /records endpoint as a Resource despite the fact it is not a resource from Traversal perspective and relies on query parameters rather than path sections?
I think the answer to both of your question is: if it works for you then it's totally acceptable. I've found a lot of success treating URLs as resources as a general pattern to the extent that I have a some tooling to avoid using route_name. For example:
config.add_route('records', '/records', factory=RecordsResource, use_global_views=True)
config.add_route('records_by_id', 'records/{record_id}', factory=RecordFactory, traverse='{record_id}', use_global_views=True)
#view_config(context=RecordsResource, renderer='json')
def records_view(request):
return {}
#view_config(context=RecordContext, renderer='json')
def record_view(request):
return {}

Class variable dictionary not saving with pickle.dump in python 2.7

I am using pickle to save an object graph by dumping the root. When I load the root it has all the instance variables and connected object nodes. However I am saving all the nodes in a class variable of type dictionary. The class variable is full before being saved but after I unpickle the data it is empty.
Here is the class I am using:
class Page():
__crawled = {}
def __init__(self, title = '', link = '', relatedURLs = []):
self.__title = title
self.__link = link
self.__relatedURLs = relatedURLs
self.__related = []
#property
def relatedURLs(self):
return self.__relatedURLs
#property
def title(self):
return self.__title
#property
def related(self):
return self.__related
#property
def crawled(self):
return self.__crawled
def crawl(self,url):
if url not in self.__crawled:
webpage = urlopen(url).read()
patFinderTitle = re.compile('<title>(.*)</title>')
patFinderLink = re.compile('<link rel="canonical" href="([^"]*)" />')
patFinderRelated = re.compile('<li><a href="([^"]*)"')
findPatTitle = re.findall(patFinderTitle, webpage)
findPatLink = re.findall(patFinderLink, webpage)
findPatRelated = re.findall(patFinderRelated, webpage)
newPage = Page(findPatTitle,findPatLink,findPatRelated)
self.__related.append(newPage)
self.__crawled[url] = newPage
else:
self.__related.append(self.__crawled[url])
def crawlRelated(self):
for link in self.__relatedURLs:
self.crawl(link)
I save it like such:
with open('medTwiceGraph.dat','w') as outf:
pickle.dump(root,outf)
and I load it like such:
def loadGraph(filename): #returns root
with open(filename,'r') as inf:
return pickle.load(inf)
root = loadGraph('medTwiceGraph.dat')
All the data loads except for the class variable __crawled.
What am I doing wrong?
Python doesn't really pickle class objects. It simply saves their names and where to find them. From the documentation of pickle:
Similarly, classes are pickled by named reference, so the same
restrictions in the unpickling environment apply. Note that none of
the class’s code or data is pickled, so in the following example the
class attribute attr is not restored in the unpickling environment:
class Foo:
attr = 'a class attr'
picklestring = pickle.dumps(Foo)
These restrictions are why picklable functions and classes must be
defined in the top level of a module.
Similarly, when class instances are pickled, their class’s code and
data are not pickled along with them. Only the instance data are
pickled. This is done on purpose, so you can fix bugs in a class or
add methods to the class and still load objects that were created with
an earlier version of the class. If you plan to have long-lived
objects that will see many versions of a class, it may be worthwhile
to put a version number in the objects so that suitable conversions
can be made by the class’s __setstate__() method.
In your example you could fix your problems changing __crawled to be an instance attribute or a global variable.
By default pickle will only use the contents of self.__dict__ and not use self.__class__.__dict__ which is what you think you want.
I say, "what you think you want" because unpickling an instance should not mutate class level sate.
If you want to change this behavior then look at __getstate__ and __setstate__ in the docs
For anyone interested, what I did was make a superclass Graph which contained an instance variable __crawled and moved my crawling functions into Graph. Page now only contains attributes describing the page and its related pages. I pickle my instance of Graph which contains all my instances of Page. Here is my code.
from urllib import urlopen
#from bs4 import BeautifulSoup
import re
import pickle
###################CLASS GRAPH####################
class Graph(object):
def __init__(self,roots = [],crawled = {}):
self.__roots = roots
self.__crawled = crawled
#property
def roots(self):
return self.__roots
#property
def crawled(self):
return self.__crawled
def crawl(self,page,url):
if url not in self.__crawled:
webpage = urlopen(url).read()
patFinderTitle = re.compile('<title>(.*)</title>')
patFinderLink = re.compile('<link rel="canonical" href="([^"]*)" />')
patFinderRelated = re.compile('<li><a href="([^"]*)"')
findPatTitle = re.findall(patFinderTitle, webpage)
findPatLink = re.findall(patFinderLink, webpage)
findPatRelated = re.findall(patFinderRelated, webpage)
newPage = Page(findPatTitle,findPatLink,findPatRelated)
page.related.append(newPage)
self.__crawled[url] = newPage
else:
page.related.append(self.__crawled[url])
def crawlRelated(self,page):
for link in page.relatedURLs:
self.crawl(page,link)
def crawlAll(self,obj,limit = 2,i = 0):
print 'number of crawled pages:', len(self.crawled)
i += 1
if i > limit:
return
else:
for rel in obj.related:
print 'crawling', rel.title
self.crawlRelated(rel)
for rel2 in obj.related:
self.crawlAll(rel2,limit,i)
def loadGraph(self,filename):
with open(filename,'r') as inf:
return pickle.load(inf)
def saveGraph(self,obj,filename):
with open(filename,'w') as outf:
pickle.dump(obj,outf)
###################CLASS PAGE#####################
class Page(Graph):
def __init__(self, title = '', link = '', relatedURLs = []):
self.__title = title
self.__link = link
self.__relatedURLs = relatedURLs
self.__related = []
#property
def relatedURLs(self):
return self.__relatedURLs
#property
def title(self):
return self.__title
#property
def related(self):
return self.__related
####################### MAIN ######################
def main(seed):
print 'doing some work...'
webpage = urlopen(seed).read()
patFinderTitle = re.compile('<title>(.*)</title>')
patFinderLink = re.compile('<link rel="canonical" href="([^"]*)" />')
patFinderRelated = re.compile('<li><a href="([^"]*)"')
findPatTitle = re.findall(patFinderTitle, webpage)
findPatLink = re.findall(patFinderLink, webpage)
findPatRelated = re.findall(patFinderRelated, webpage)
print 'found the webpage', findPatTitle
#root = Page(findPatTitle,findPatLink,findPatRelated)
G = Graph([Page(findPatTitle,findPatLink,findPatRelated)])
print 'crawling related...'
G.crawlRelated(G.roots[0])
G.crawlAll(G.roots[0])
print 'now saving...'
G.saveGraph(G, 'medTwiceGraph.dat')
print 'done'
return G
#####################END MAIN######################
#'http://medtwice.com/am-i-pregnant/'
#'medTwiceGraph.dat'
#G = main('http://medtwice.com/menopause-overview/')
#print G.crawled
def loadGraph(filename):
with open(filename,'r') as inf:
return pickle.load(inf)
G = loadGraph('MedTwiceGraph.dat')
print G.roots[0].title
print G.roots[0].related
print G.crawled
for key in G.crawled:
print G.crawled[key].title
Using dill can solve this problem.
dill package: https://pypi.python.org/pypi/dill
reference: https://stackoverflow.com/a/28543378/6301132
According Asker's code, into this:
#notice:open the file in binary require
#save
with open('medTwiceGraph.dat','wb') as outf:
dill.dump(root,outf)
#load
def loadGraph(filename): #returns root
with open(filename,'rb') as inf:
return dill.load(inf)
root = loadGraph('medTwiceGraph.dat')
I wrote another example:
#Another example (with Python 3.x)
import dill
import os
class Employee:
def __init__ (self ,name='',contact={}) :
self.name = name
self.contact = contact
def print_self(self):
print(self.name, self.contact)
#save
def save_employees():
global emp
with open('employees.dat','wb') as fh:
dill.dump(emp,fh)
#load
def load_employees():
global emp
if os.path.exists('employees.dat'):
with open('employees.dat','rb') as fh:
emp=dill.load(fh)
#---
emp=[]
load_employees()
print('loaded:')
for tmpe in emp:
tmpe.print_self()
e=Employee() #new employee
if len(emp)==0:
e.name='Jack'
e.contact={'phone':'+086-12345678'}
elif len(emp)==1:
e.name='Jane'
e.contact={'phone':'+01-15555555','email':'a#b.com'}
else:
e.name='sb.'
e.contact={'telegram':'x'}
emp.append(e)
save_employees()

Pyramid traversal is doing my head in

I am trying to get my head around Pyramid traversal with this very simple example. What I haven't quite grasped yet is where to "inject" an Article object from the db.
As it is, /Article correctly finds and renders the article_view but that's fairly useless. How/when/where do I use the next part of the URL to query for a particular Article from the db? eg. /Article/5048230b2485d614ecec341d.
Any clues would be great!
init.py
from pyramid.config import Configurator
from pyramid.events import subscriber
from pyramid.events import NewRequest
import pymongo
from otk.resources import Root
def main(global_config, **settings):
""" This function returns a WSGI application.
"""
config = Configurator(settings=settings, root_factory=Root)
config.add_static_view('static', 'otk:static')
# MongoDB
def add_mongo_db(event):
settings = event.request.registry.settings
url = settings['mongodb.url']
db_name = settings['mongodb.db_name']
db = settings['mongodb_conn'][db_name]
event.request.db = db
db_uri = settings['mongodb.url']
MongoDB = pymongo.Connection
if 'pyramid_debugtoolbar' in set(settings.values()):
class MongoDB(pymongo.Connection):
def __html__(self):
return 'MongoDB: <b>{}></b>'.format(self)
conn = MongoDB(db_uri)
config.registry.settings['mongodb_conn'] = conn
config.add_subscriber(add_mongo_db, NewRequest)
config.include('pyramid_jinja2')
config.include('pyramid_debugtoolbar')
config.scan('otk')
return config.make_wsgi_app()
resources.py
class Root(object):
__name__ = None
__parent__ = None
def __init__(self, request):
self.request = request
def __getitem__(self, key):
if key == 'Article':
return Article(self.request)
else:
raise KeyError
class Article:
__name__ = ''
__parent__ = Root
def __init__(self, request):
self.reqeust = request
# so I guess in here I need to update the Article with
# with the document I get from the db. How?
def __getitem__(self, key):
raise KeyError
views.py
from pyramid.view import view_config
from otk.resources import *
from pyramid.response import Response
#view_config(context=Root, renderer='templates/index.jinja2')
def index(request):
return {'project':'OTK'}
#view_config(context=Article, renderer='templates/view/article.jinja2')
def article_view(context, request):
# I end up with an instance of Article here as the context.. but
# at the moment, the Article is empty
return {}
You'd generally return a Article object from the id part of the URL traversal.
What happens with traversal is that for each element in the URL path, an object is looked up and made the new current object for the next path element lookup.
So for Article, the root object is asked for something matching that name, and the result of that lookup is made the new "current" object, and 5048230b2485d614ecec341d is then looked up on that new object.
So, what you are looking for is a dispatcher object, something that looks up articles based on the longer id you are passed, and that returns your Article instances:
class Root(object):
__name__ = None
__parent__ = None
def __init__(self, request):
self.request = request
def __getitem__(self, key):
if key == 'articles':
dispatch = ArticleDispatcher(self.request)
dispatch.__name__ = key
dispatch.__parent__ = self
return dispatch
raise KeyError(key)
class ArticleDispatcher(object):
__name__ = None
__parent__ = None
def __init__(self, request):
self.request = request
def __getitem__(self, key):
# Get a hold of the database here:
db = findDatabase(self.request)
if db.exists(key):
data = db.load(key)
art = Article(data)
art.__name__ = key
art.__parent__ = self
return art
raise KeyError(key)
class Article:
__name__ = None
__parent__ = None
def __init__(self, data):
self.data = data
Note how I returned a ArticleDispatcher when you use the /articles URL path, and also how I set the __name__ and __parent__ variables; you'll need those to be able to generate URLs for those instances.
The Article object returned now contains the actual article data, and the view can access that information when rendering.
You really want to go and study the Pyramid Traversal tutorial which explains this all in more detail.

Is this the correct way of doing/handling url rewrite in App Engine/ Python?

I'm not sure if this is effective or not. It works, but sometimes i feel...weird about it. Can you please tell me if this is a good way or not?
I threw the code on pastebin, because i think it's a bit too much to put here: http://pastebin.com/662TiQLq
EDIT
I edited the title to make it more objective.
I'm just guessing that the questioner is asking about creating a dictionary of functions in the __ init __ function of the handlers, and then using this dict in the "get" function to look up specific functions. If this is the question, then IMHO a clearer approach would be to set up separate handlers for each different function. For example
class QuotesView(webapp.RequestHandler):
"""Super class for quotes that can accommodate common functionality"""
pass
class QuotesViewSingle(QuotesView):
def get(self):
...
class QuotesViewRandom(QuotesView):
def get(self):
...
class QuotesViewAll(QuotesView):
def get(self):
...
def main():
application = webapp.WSGIApplication([('/quote/new',NewQuote),
(r'/quotes/single',QuotesViewSingle),
(r'/quotes/all',QuotesViewAll),
(r'/quotes/random',QuotesViewRandom),
...
('/', MainHandler)],
debug=True)
BTW. A lot of people use the regex in the WSGIApplication calls to parse out arguments for the get functions. There's nothing particularly wrong with it. I'm not a big fan of that feature, and prefer to parse the arguments in the get functions. But that's just me.
For completeness here's the original code:
class Quote(db.Model):
author = db.StringProperty()
string = db.StringProperty()
class MainHandler(webapp.RequestHandler):
def get(self):
user = users.get_current_user()
quotes = Quote.all()
path = os.path.join(os.path.dirname(__file__),'quotery.html')
template_values = {'quotes':quotes,'user':user,'login_url':users.create_login_url('/')}
self.response.out.write(template.render(path, template_values))
class QuoteHandler(webapp.RequestHandler):
def __init__(self):
self.actions = {'fetch':self.fetch, 'random':self.fetch_random}
#Memcache the number of quotes in the datastore, to minimize datastore calls
self.quote_count = memcache.get('quote_count')
if not self.quote_count:
self.quote_count = self.cache_quote_count()
def cache_quote_count(self):
count = Quote.all().count()
memcache.add(key='quote_count', value=count, time=3600)
return count
def get(self, key):
if key in self.actions:
action = self.actions[key]
action()
def fetch(self):
for quote in Quote.all():
print 'Quote!'
print 'Author: ',quote.author
print 'String: ',quote.string
print
def fetch_random(self):
max_offset = self.quote_count-1
random_offset = random.randint(0,max_offset)
'''self.response.out.write(max_offset)
self.response.out.write('\n<br/>')
self.response.out.write(random_offset)'''
try:
query = db.GqlQuery("SELECT * FROM Quote")
quotes = query.fetch(1,random_offset)
return quotes
'''for quote in quotes:
self.response.out.write(quote.author)
self.response.out.write('\n')
self.response.out.write(quote.string)'''
except BaseException:
raise
class NewQuote(webapp.RequestHandler):
def post(self):
author = self.request.get('quote_author')
string = self.request.get('quote_string')
if not author or not string:
return False
quote = Quote()
quote.author = author
quote.string = string
quote.put()
QuoteHandler().cache_quote_count()
self.redirect("/")
#return True
class QuotesView(webapp.RequestHandler):
def __init__(self):
self.actions = {'all':self.view_all,'random':self.view_random,'get':self.view_single}
def get(self, key):
if not key or key not in self.actions:
self.view_all()
if key in self.actions:
action = self.actions[key]
action()
def view_all(self):
print 'view all'
def view_random(self):
quotes = QuoteHandler().fetch_random()
template_data = {}
for quote in quotes:
template_data['quote'] = quote
template_path = os.path.join(os.path.dirname(__file__),'base_view.html')
self.response.out.write(template.render(template_path, template_data))
def view_single(self):
print 'view single'
def main():
application = webapp.WSGIApplication([('/quote/new',NewQuote),(r'/quotes/(.*)',QuotesView),(r'/quote/(.*)',QuoteHandler),('/', MainHandler)],
debug=True)
util.run_wsgi_app(application)

Categories