I am writing a web-framework for Python, of which the goal is to be as "small" as possible (currently under 100 lines of code).. You can see the current code on github
Basically it's written to be as simple to use as possible. An example "Hello World" like site:
from pyerweb import GET, runner
@GET("/")
def index():
return "<strong>This</strong> would be the output HTML for the URL / "
@GET("/view/([0-9]+?)$")
def view_something(id):
return "Viewing id %s" % (id) # URL /view/123 would output "Viewing id 123"
runner(url = "/", # url would be from a web server, in actual use
output_helper = "html_tidy" # run returned HTML though "HTML tidy"
Basically you have a function that returns HTML, and the GET decorator maps this to a URL.
When runner()
is called, each decorated function is checked, if the URL regex matches the request URL, the function is run, and the output is sent to the browser.
Now, the problem - outputting headers. Currently for development I've just put a line before the runner()
call which does print Content-type:text/html\n
- this is obviously a bit limiting..
My first ideas was to have the functions return a dict, something like..
@GET("/")
def index():
return {
"html": "<html><body>...</body></html>",
"headers": {"Location":"http://google.com"}
}
I really don't like this - having to return a dict with a specifically named key isn't nearly as nice as just returning a string..
I could check if the returned data is a dict, if so use returned_data['html']
as the output, if it's a string, there is no custom headers to be sent... but this means to go from no headers (which would be the case a huge majority of the time) to headers, you'd have to change the return function from return my_html
to return {'html':my_html}
which isn't very elegant either..
After writing this, I discovered "Sinatra" - a similar-in-use Ruby library, and looked at how it dealt with headers:
get "/" do
content_type 'text/css', :charset => 'utf-8'
end
This seems like it could be nice enough in Python:
@GET("/")
def index():
header("location", "http://google.com")
To implement this, I was considering changing how the functions are executed - instead of simply using the return value, I would change sys.stdout
to a StringIO, so you could do..
def index():
print "<html>"
print "<head><title>Something</title></head>"
print "<body>...</body>"
print "</html>
..without having to worry about concatenating a bunch of strings together. The upshot of this is I could have a separate stream for headers, so the above header()
function would write to this.. Something like:
def header(name, value):
pyerweb.header_stream.write("%s: %s" % (name, value))
Basically, the question is, how would you output headers from this web-framework (mostly in terms of use, but to a lesser extent implementation)?