This is my first outing with CherryPy so forgive any stupidity.
I'm trying to write a RESTful API that in part deals with adding/removing people. I want to be able to GET/PUT/DELETE example.com/people/.
The dispatcher seems to be behaving totally differently for the index method vs a defined function:
class people:
"""This is the class for CherryPy that deals with CRUD on people"""
#cherrypy.expose
def index(self, name):
return name
#cherrypy.expose
def who(self, name):
return name
root = webroot()
root.people = people()
cherrypy.quickstart(root)
If I call example.com/people/tom, I get a 404, if I call example.com/people/who/tom I get 'tom' returned.
Can anyone see what I'm doing wrong? Is there a way I can pass /xxx to index?
Indexes are a bit different when it comes to URL arguments.
The index method has a special role in CherryPy: it handles intermediate URI’s that end in a slash; for example, the URI /orders/items/ might map to root.orders.items.index. The index method can take additional keyword arguments if the request includes querystring or POST params; see Keyword Arguments, next. However, unlike all other page handlers, it cannot take positional arguments
source
However, the url of example.com/people?name=tom should work as you expect.
Related
I have watched a tutorial on Flask and I can't seem to understand how does this code work
def my_home():
return render_template("./index.html")
#app.route('/<string:page_name>')
def html_page(page_name):
return render_template(page_name)```
Specifically /<string:page_name> is confusing to me, how does it understand what is page_name and redirect to that page?
Thank you!
The answer to this is in the magic of decorators and not flask itself. A decorator is a high level function which accepts a function and manipulates it accordingly. See the following example:
def route(func, user_path):
# internal flask mechanisms here
def callback(user_path):
return http.route(user_path, func)
return callback
#route("hello_world")
def render():
return "Hello World"
The decorator is taking your function as an input and performing some actions to correlate the path with your given input. This can obviously be used for many other purposes. For example, flask also allows an additional decorator to define the type of request allowed for the function, such as GET, POST, etc.
To answer your question, flask is accepting a URL parameter and generating the page based on that given parameter. This is known as dynamic routing and is used for database query purposes based on the route (though the given example is trivial). So if someone goes to page_name "John", you can use that value and template it in your html to dynamically say hi to John (and whomever else).
/<string:page_name>
means that Flask expects a customised string after your domain i.e.
www.yourdomain.com/anycustomisedstring
/<data_type:your_variable_name> i.e. /<integer:page_number>
in this case, your variable is passed as a parameter to your function. This function returns the site that is passed in the URL as a string
I have recently been trying to learning about WSGI and moreover, how the web works in regards to Python. So I've been reading through Werkzeug and PEP333 to learn.
However I've run up against a small question, that I think I understand but probably don't, so I would appreciate your steering in the right direction.
PEP333 states:
The application object is simply a callable object that accepts two
arguments. The term "object" should not be misconstrued as requiring
an actual object instance: a function, method, class, or instance with
a call method are all acceptable for use as an application object.
Application objects must be able to be invoked more than once, as
virtually all servers/gateways (other than CGI) will make such
repeated requests.
The implementation:
class AppClass:
"""Produce the same output, but using a class
(Note: 'AppClass' is the "application" here, so calling it
returns an instance of 'AppClass', which is then the iterable
return value of the "application callable" as required by
the spec.
If we wanted to use *instances* of 'AppClass' as application
objects instead, we would have to implement a '__call__'
method, which would be invoked to execute the application,
and we would need to create an instance for use by the
server or gateway.
"""
def __init__(self, environ, start_response):
self.environ = environ
self.start = start_response
def __iter__(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield "Hello world!\n"
My question here is just to clarify if I have understood it correctly.
It states that AppClass is the application, and when we call it, it returns an instance of AppClass. But then further down states that 'if we wanted to use instances of AppClass ass application objects instead', is this saying that when the server side of WSGI calls the AppClass object, there is only one instance running?
For example. The server can issue multiple requests (200 OK's) to the Application for more responses, hence why iter is placed into the class. But each request runs through the same singular AppClass instance, each request to the server basically doesn't instantiate more than one instance of the AppClass?
Sorry if this is long winded, and apologies again if I haven't made much sense. I'm trying to improve atm.
Appreciate your inputs as always.
Thanks.
The server technology will call your app (in this case the class AppClass, causing an object construction) for each request. This is because each request will have a potentially unique environ.
The neat thing about this is it doesn't mean your app has to be a class, I often find it useful to define my wsgi app (or middleware) as a function returning a function:
# I'd strongly suggest using a web framework instead to define your application
def my_application(environ, start_response):
start_response(str('200 OK'), [(str('Content-Type'), str('text/plain'))])
return [b'hello world!\n']
def my_middleware(app):
def middleware_func(environ, start_response):
# do something or call the inner app
return app(environ, start_response)
return middleware_func
# expose `app` for whatever server tech you're using (such as uwsgi)
app = my_application
app = my_middleware(app)
Another common pattern involves defining an object to store some application state which is constructed once:
class MyApplication(object):
def __init__(self):
# potentially some expensive initialization
self.routes = ...
def __call__(self, environ, start_response):
# Called once per request, must call `start_response` and then
# return something iterable -- could even be `return self` if
# this class were to define `__iter__`
...
return [...]
app = MyApplication(...)
As for PEP333, I'd suggest reading PEP3333 instead -- it contains largely the same information, but clarifies the datatypes used throughout.
For background on various ways that WSGI application objects can be implemented read this blog post on the topic.
http://blog.dscpl.com.au/2011/01/implementing-wsgi-application-objects.html
I would also suggest reading the following, which talks about how Python web servers in general work.
https://ruslanspivak.com/lsbaws-part1/
Unless you really have a need you probably just want to use a framework. Avoid trying to write anything from scratch with WSGI.
Code:
class Telegram(tornado.web.RequestHandler):
def my_f(self,number):
return number
def get(self,number):
self.write( self.my_f(number))
application = tornado.web.Application([
(r"/number/(.*?)", Telegram),
])
Using this piece of code, i can trigger Telegram, providing it with something from the (.*?) part.
Question is: i need to make POST queries like:
/number/messenger=telegram&phone=3332223332211
so that I can grab messenger parameter and phone parameter, and trigger the right class with provided phone number (like Telegram with 3332223332211)
POST requests (usually) have a body, so if you want everything in the URL you probably want a GET instead of a POST.
The normal way to pass arguments is by form-encoding them. That starts with a ? and looks like this: /number?messenger=telegram&phone=12345. To use arguments like this in Tornado, you use self.get_argument("messenger") instead of an argument to the get() method.
A second way of passing parameters is to put them in the "path" part of the URL, without a question mark. This is when you use (.*?) in your routing pattern and an argument to get(). Use this when you want to avoid the question mark for some reason (usually aesthetics).
You can also combine the two: pass the messenger parameter in the URL as you've done here, and add ?number=12345 and use get_argument. But unless you really care about what your URLs look like, I recommend the first form.
So I'm pretty new to Flask and I'm trying to make my mind around one thing. So, if I understand well when you write a function within a Flask app and you use the #app.route decorator in that function, it only runs when you hit that path/url.
I have a small oauth app written in Flask that goes through all the authorization flow and then it return the token.
My question is how do I get that token from the #decorated function? For example, lets say I have something like this:
#app.route(/token/)
def getToken(code): #code from the callback url.
#/Stuff to get the Token/
#/**********************/
return token
If I hit the (/token/) url-path the function returns the token. But now I need to get that token and use it in another function to write and read from the API I just got the token from. My initial thought was doing this:
token = getToken(code)
But if I do that, I get this error:
RuntimeError: working outside of request context
So again, my question is, how do I get the token so I can pass it as a parameter to other functions.
Extract the token generation code into a separate function, so that you can call it from anywhere, including the view function. It's a good practice to keep the application logic away from the view, and it also helps with unit testing.
I assume your route includes a placeholder for code, which you skipped:
def generateToken(code):
#/Stuff to get the Token/
#/**********************/
return token
#app.route('/token/<string:code>')
def getToken(code):
return generateToken(code)
Just keep in mind that generateToken shouldn't depend on the request object. If you need any request data (e.g. HTTP header), you should pass it explicitly in arguments. Otherwise you will get the "working outside of request context" exception you mentioned.
It is possible to call request-dependent views directly, but you need to mock the request object, which is a bit tricky. Read the request context documentation to learn more.
not sure what the context is. You could just call the method.
from yourmodule import get_token
def yourmethod():
token = get_token()
Otherwise, you could use the requests library in order to retrieve the data from the route
>>> import requests
>>> response = requests.get('www.yoursite.com/yourroute/')
>>> print response.text
If you're looking for unittests, Flask comes with a mock client
def test_get_token():
resp = self.app.get('/yourroute')
# do something with resp.data
I've looked at documentation, and have searched Google extensively, and haven't found a solution to my problem.
This is my readRSS function (note that 'get' is a method of Kenneth Reitz's requests module):
def readRSS(name, loc):
linkList = []
linkTitles = list(ElementTree.fromstring(get(loc).content).iter('title'))
linkLocs = list(ElementTree.fromstring(get(loc).content).iter('link'))
for title, loc in zip(linkTitles, linkLocs):
linkList.append((title.text, loc.text))
return {name: linkList}
This is one of my MongoAlchemy classes:
class Feed(db.Document):
feedname = db.StringField(max_length=80)
location = db.StringField(max_length=240)
lastupdated = datetime.utcnow()
def __dict__(self):
return readRSS(self.feedname, self.location)
As you can see, I had to call the readRSS function within a function of the class, so I could pass self, because it's dependent on the fields feedname and location.
I want to know if there's a different way of doing this, so I can save the readRSS return value to a field in the Feed document. I've tried assigning the readRSS function's return value to a variable within the function __dict__ -- that didn't work either.
I have the functionality working in my app, but I want to save the results to the Document to lessen the load on the server (the one I am getting my RSS feed from).
Is there a way of doing what I intend to do or am I going about this all wrong?
I found out the answer. I needed to make use of a computed_field decorator, where the first argument was the structure of my return value and deps was a set which contained the fields that this field was dependent on. I then passed the dependent fields into a function's arguments and there you have it.
#fields.computed_field(db.KVField(db.StringField(), db.ListField(db.TupleField(db.StringField()))), deps=[feedname, location])
def getFeedContent(a=[feedname, location]):
return readRSS(a['feedname'], a['location'])
Thanks anyway, everyone.