GH3 Python WSGI nano framework.
Project description
gh3 Python WSGI nanoframework
if you are not already there, read this doc with API links working
in all their glory on the
[website](https://gh3-website.web.app/README.html)
First App
import gh3
def say_hello(ctx: gh3.Context):
"""A view handler that returns some text."""
ctx.reply_text('hello, world')
# Create the app, add a route, and start the debug server.
app = gh3.App()
app.add_route('/', say_hello)
app.debug()
Here, we create an instance of gh3.App and we add a simple route to it, and start the debug server.
You can immediately see some features of the request handler:
- You modify the response in place from the gh3.Context.
- It is simple to make a simple textual response, using
reply_text and there are analogs for
reply_html and
reply_json. These
reply_
methods are shortcuts to setting the response data, the response content-type, and the response status code.
Testing
We use Werkzeug's testing infrastructure, by calling gh3.App.tester to get a werkzeug test client and use it to make requests against your app. For many examples, check out the gh3 test suite.
You can test the request context in your views, e.g.
def text_view(ctx):
assert '/' == ctx.req.path
ctx.reply_text('ok')
app = gh3.App()
app.add_route('/', text_view)
resp = app.tester().get('/')
assert 200 == resp.status_code
We have made 2 assertions above:
- That the response is a 200
- That the request path at the view was
/
You can use the pattern above to test anything in the context.
Installation
virtualenv -p python3.9 env
./env/bin/pip install gh3
Route handler arguments
Arguments from the route are available in ctx.endpoint_args. They are not passed to the handler functions as all handler functions take only the request context as an argument.
import gh3
def say_hello(ctx: gh3.Context):
"""A view handler that returns some text."""
user = ctx.endpoint_args['user']
ctx.reply_text(f'hello, {user}')
# Create the app, add a route, and start the debug server.
app = gh3.App()
app.add_route('/<user>', say_hello)
app.debug()
Routes, targets, and endpoints
As in the simple example above, there is a route '/'
and a target, the
say_hello
function. What is not described there is that the endpoint is
inferred from the function name, but can be set explicitly:
app.add_route('/', say_hello, endpoint='home')
The endpoint is used for reverse lookup of URLs.
More complex routing
The entire range of Werkzeug's routing is available by using add_rule and add_target. For example, to use Werkzeug's Submount rule factory, you should create the rule and add the target handlers manually.
rule = gh3.wz_routing.Submount(
Rule('/', endpoint='blog/index'),
Rule('/entry/<entry_slug>', endpoint='blog/show')
)
app.add_rule(rule)
app.add_target('blog/index', my_blog_index_handler)
app.add_target('blog/show', my_blog_show_handler)
Why?
I love Werkzeug, but I really don't love Flask (sorry, Armin). I swear I have used Flask a lot, in big production applications that serve billions of pages a year. There are patterns in Flask that have made it extremely hard for me to develop as part of a large (30+) engineering team, and these are the things intentionally left out of gh3. gh3 will never be as featured as Flask, and that's OK too. You'll forgive me these few 100 lines of well-tested code. And if you are still wondering why, please feel free to move on.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.