I have a class that doesn't extend webapp.RequestHandler, and I can't use self.response.out.write(), I get:
AttributeError: Fetcher instance has no attribute 'response'
If I extend webapp.RequestHandler (I thought it would work), I get:
AttributeError: 'Fetcher' object has no attribute 'response'
How can I use that method properly? Sometimes print doesn't work either; I just get a blank screen.
EDIT:
app.yaml:
application: fbapp-lotsofquotes
version: 1
runtime: python
api_version: 1
handlers:
- url: .*
script: main.py
source (the problematic line is marked with #<- HERE):
import random
import os
from google.appengine.api import users, memcache
from google.appengine.ext import webapp, db
from google.appengine.ext.webapp import util, template
from google.appengine.ext.webapp.util import run_wsgi_app
import facebook
class Quote(db.Model):
author = db.StringProperty()
string = db.StringProperty()
categories = db.StringListProperty()
#rating = db.RatingProperty()
class Fetcher(webapp.RequestHandler):
'''
Memcache keys: all_quotes
'''
def is_cached(self, key):
self.fetched = memcache.get(key)
if self.fetched:
print 'ok'#return True
else:
print 'not ok'#return False
#TODO: Use filters!
def fetch_quotes(self):
quotes = memcache.get('all_quotes')
if not quotes:
#Fetch and cache it, since it's not in the memcache.
quotes = Quote.all()
memcache.set('all_quotes',quotes,3600)
return quotes
def fetch_quote_by_id(self, id):
self.response.out.write(id) #<---------- HERE
class MainHandler(webapp.RequestHandler):
def get(self):
quotes = Fetcher().fetch_quotes()
template_data = {'quotes':quotes}
template_path = 'many.html'
self.response.out.write(template.render(template_path, template_data))
class ViewQuoteHandler(webapp.RequestHandler):
def get(self, obj):
self.response.out.write('viewing quote<br/>\n')
if obj == 'all':
quotes = Fetcher().fetch_quotes()
self.render('view_many.html',quotes=quotes)
else:
quotes = Fetcher().fetch_quote_by_id(obj)
'''for quote in quotes:
print quote.author
print quote.'''
def render(self, type, **kwargs):
if type == 'single':
template_values = {'quote':kwargs['quote']}
template_path = 'single_quote.html'
elif type == 'many':
print 'many'
self.response.out.write(template.render(template_path, template_values))
'''
CREATORS
'''
class NewQuoteHandler(webapp.RequestHandler):
def get(self, action):
if action == 'compose':
self.composer()
elif action == 'do':
print 'hi'
def composer(self):
template_path = 'quote_composer.html'
template_values = ''
self.response.out.write(template.render(template_path,template_values))
def post(self, action):
author = self.request.get('quote_author')
string = self.request.get('quote_string')
print author, string
if not author or not string:
print 'REDIRECT'
quote = Quote()
quote.author = author
quote.string = string
quote.categories = []
quote.put()
def main():
application = webapp.WSGIApplication([('/', MainHandler),
(r'/view/quote/(.*)',ViewQuoteHandler),
(r'/new/quote/(.*)',NewQuoteHandler) ],
debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
You're not routing to Fetcher when you initialize a WSGIApplication. Rather, you create an instance manually in other handlers. Thus, App Engine will not initialize your request and response properties. You can manually do so in from the handlers you route to, such as MainHandler and ViewQuoteHandler. E.g.:
fetcher = Fetcher()
fetcher.initialize(self.request, self.response)
quotes = fetcher.fetch_quotes()
Note that fetcher really doesn't have to be a RequestHandler. It could be a separate class or function. Once you have request and response objects, you can pass them around as you choose.
Related
Attempting to check an in-memory list, plant_list[] against a JSON payload from an api.
If the incoming payload's dict name matches inside of plant_list the if should fire off.
Instead my script only returns null
Please point out my mistakes.
The JSON sent over the api call is:
{ "name":"swizz", "days": "7", "price": 2.00 }
Source Code
from flask import Flask, request
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
#app.route('/', methods=['GET', 'POST'])
def home():
return 'Tiny'
plant_list = []
class Plant(Resource):
def get(self, name):
return {'Name':name}, 200
def post(self, name):
payload = request.get_json()
for x in range(0, len(plant_list)):
if payload['name'] == plant_list[x]['name']:
return {'message': f'''Item {payload['name']} already stored in database.'''}
else:
plant_list.append(payload)
return plant_list, 201
api.add_resource(Plant, '/plant/<string:name>')
if __name__ == '__main__':
app.run(port=9004, debug=True)
You can test for key in dict simply by: if key_name in my_dict:... So, if "price" in plant_list[x]:
You are setting plant_list as a global. If you want to use that inside a Class, you should define it inside the function in your class:
plant_list = []
class Plant(Resource):
....
def post(self, name):
global plant_list
....
Not sure why you need it as a global variable. Perhaps you want:
class Plant(Resource):
plant_list = []
....
def post(self, name):
....
I'm trying to build an api using Flask-restplus and Flask-Flask-Injector.
I searched and couldn't find an example on these two together.
All examples are on Flask, not the restplus one.
I tried to build using the following:
``
from flask import Flask
from flask_restplus import Api, Resource
from flask_injector import FlaskInjector, Injector, inject, singleton
app = Flask(__name__)
app.secret_key = "123"
api = Api(app=app)
class MyConf():
def __init__(self, val: int):
self.val = val
class MyApi(Resource):
#inject
def __init__(self, conf: MyConf):
self.val = conf.val
def get(conf: MyConf):
return {'x': conf.val}, 200
api.add_resource(MyApi, '/myapi')
def configure(binder):
myConf = MyConf(456)
binder.bind(
MyConf,
to=MyConf(456),
scope=singleton
)
binder.bind(
MyApi,
to=MyApi(myConf)
)
FlaskInjector(app=app, modules=[configure])
app.run(port=555, debug=True)
I'm new to python, actually I don't know if this usage of Flask-Injector is correct, so I'm getting this error when calling the api (myapi) with get method using the browser:
injector.CallError: Call to MyApi.init(conf=<main.MyConf object at 0x0000026575726988>, api=) failed: init() got an unexpected keyword argument 'api' (injection stack: [])
I was able to solve this with the help of an issue I opened on github, here's the updated working version of the code:
app = Flask(__name__)
app.secret_key = "123"
api = Api(app=app)
class MyConf():
def __init__(self, val: int):
self.val = val
class MyApi(Resource):
#inject
def __init__(self, conf: MyConf, **kwargs): # <- here just added **kwargs to receice the extra passed `api` parameter
self.val = conf.val
# Don't know if really needed
super().__init__(**kwargs)
def get(conf: MyConf):
return {'x': conf.val}, 200
api.add_resource(MyApi, '/myapi')
def configure(binder):
myConf = MyConf(456)
binder.bind(
MyConf,
to=MyConf(456),
scope=singleton
)
# No need to bind the resource itself
#binder.bind(
# MyApi,
# to=MyApi(myConf)
#)
FlaskInjector(app=app, modules=[configure])
app.run(port=555, debug=True)
I need to convert a string type, from and get call on web.py, into an integer, but I'm getting this error:
invalid literal for int() with base 10
Here is my code:
import web
render = web.template.render('templates/')
urls = ('/webservices/test', 'Test')
app = web.application(urls, globals())
class Test:
def __init__(self):
pass
def GET(self):
user_data = web.input(id="")
id = int(user_data.id)
return id
application = app.wsgifunc()
if __name__ == "__main__":
app.run()
I've seen this documentation:
http://webpy.readthedocs.org/en/latest/input.html
You give a default constructor of user_data.id as "". If this is not specified by the browser, you will be calling
int("")
which is what is throwing your error. Try
user_data = web.input(id="0")
In the following way I bind "hello.py" and "goodbye.py" with the corresponding classes (functions) and it works. If I go to "0.0.0.0:8080/hello.py" or "0.0.0.0:8080/goodbye.py", I see what I expect to see.
import web
urls = ('/(hello.py)', 'hello', '/(goodbye.py)', 'goodbye')
app = web.application(urls, globals())
class hello:
def GET(self, name):
if not name:
name = 'World'
return 'Hello, ' + name + '!'
class goodbye:
def GET(self, name):
if not name:
name = 'World'
return 'Goodbye, ' + name + '!'
if __name__ == "__main__":
app.run()
However, I do not understand why I need to use brackets. If I replace '/(hello.py)' by '/hello.py', it does not work. However, in the example here no brackets are used.
From the examples that I see (I don't know web.py too well) the get parameters should not be passed in as method parameters, but rather acquired via the web.input method, like so:
import web
urls = (
'/SomePageHello','SomePageHello',
'/SomePageGoodbye','SomePageGoodbye',
)
app = web.application(urls, globals())
class SomePageHello:
def GET(self):
user_data = web.input(name="no data")
return "<h1> Hello " + user_data.name + "</h1>"
class SomePageGoodbye:
def GET(self):
user_data = web.input(name="no data")
return "<h1> Goodbye " + user_data.name + "</h1>"
if __name__ == "__main__":
app.run()
The url should be something like:
http://127.0.0.1:8081/SomePageHello?name=dasfasd
I need to access a global variable that keeps its state over diffferent server requsts.
In this example the global variable is r and it is incremented at each request.
How can I make r global in cherrypy?
import cherrypy
import urllib
class Root(object):
#cherrypy.expose
def index(self, **params):
jsondict = [('foo', '1'), ('fo', '2')]
p = urllib.urlencode(jsondict)
if r!=1
r=r+1
raise cherrypy.HTTPRedirect("/index?" + p)
return "hi"
cherrypy.config.update({
'server.socketPort': 8080
})
cherrypy.quickstart(Root())
if __name__ == '__main__':
r=1
To access a global variable, you have to use the global keyword followed by the name of the variable. However, if r is going to be used only in the Root class, I recommend you to declare it as a class variable:
class Root(object):
r = 1
#cherrypy.expose
def index(self, **params):
#...
if Root.r != 1:
Root.r += 1
#...
I had the same problem. It was solved after realizing my program could access the member variables of an imported library.
First, make a file called myglobals.py and put this in it
r=0
visitors = 0
Then in your server:
import myglobals
class Root(object):
#cherrypy.expose
def index(self, **params):
#...
if myglobals.r != 1:
myglobals.r += 1
#...