Musha: A python framework built for learning purposes
musha is a Python web framework built for learning purposes.
It's a WSGI framework and can be used with any WSGI application server such as Gunicorn.
- gunicorn
- webob
- parse
- requests-wsgi-adapter
- jinja2
- whitenoise
pip install mushafrommusha.apiimportAPIapp=API()
# Function based views@app.route("/home")defhome(request, response):
response.text="Hello from the HOME page"@app.route("/hello/{name}")defgreeting(request, response, name):
response.text=f"Hello, {name}"@app.route("/sum/{num_1:d}/{num_2:d}")defsum(request, response, num_1, num_2):
total=int(num_1) +int(num_2)
response.text=f"{num_1} + {num_2} = {total}"@app.route("/books")classBookView: # This is a class based viewdefget(self, req, resp):
resp.text="Books Page"defpost(self, req, resp):
resp.text="Endpoint to create a book"# Different data endpoints@app.route("/template")deftemplate_handler(req, resp):
resp.html=app.template("index.html", context={"name": "Musha", "title": "Best Framework"}) #Return a template@app.route("/json")defjson_handler(req, resp):
resp.json= {"name": "data", "type": "JSON"} #return json@app.route("/text")deftext_handler(req, resp):
resp.text="This is a simple text"#return text# Testing Django based routesdefhandler(req, resp):
resp.text="sample"app.add_route("/sample", handler)
gunicorn app:<name-of-app>The recommended way of writing unit tests is with pytest. There are two built in fixtures
that you may want to use when writing unit tests with Musha. The first one is app which is an instance of the main API class:
deftest_route_overlap_throws_exception(app):
@app.route("/")defhome(req, resp):
resp.text="Welcome Home."withpytest.raises(AssertionError):
@app.route("/")defhome2(req, resp):
resp.text="Welcome Home2."The other one is client that you can use to send HTTP requests to your handlers. It is based on the famous requests and it should feel very familiar:
deftest_parameterized_route(app, client):
@app.route("/{name}")defhello(req, resp, name):
resp.text=f"hey {name}"assertclient.get("http://testserver/matthew").text=="hey matthew"The default folder for templates is templates. You can change it when initializing the main API() class:
app=API(templates_dir="templates_dir_name")Then you can use HTML files in that folder like so in a handler:
@app.route("/show/template")defhandler_with_template(req, resp):
resp.html=app.template(
"example.html", context={"title": "Awesome Framework", "body": "welcome to the future!"})Just like templates, the default folder for static files is static and you can override it:
app=API(static_dir="static_dir_name")Then you can use the files inside this folder in HTML files:
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><title>{{title}}</title><linkhref="/static/main.css" rel="stylesheet" type="text/css"></head><body><h1>{{body}}</h1><p>This is a paragraph</p></body></html>You can create custom middleware classes by inheriting from the musha.middleware.Middleware class and overriding its two methods
that are called before and after each request:
frommusha.apiimportAPIfrommusha.middlewareimportMiddlewareapp=API()
classSimpleCustomMiddleware(Middleware):
defprocess_request(self, req):
print("Before dispatch", req.url)
defprocess_response(self, req, res):
print("After dispatch", req.url)
app.add_middleware(SimpleCustomMiddleware)frommusha.apiimportAPIfrommusha.middlewareimportMiddlewareapp=API()
# Custome exception handlersdefcustom_exception_handler(request, response, exception_cls):
response.text=str(exception_cls)
app.add_exception_handler(custom_exception_handler)
classSimpleCustomMiddleware(Middleware):
defprocess_request(self, req):
print("Before dispatch", req.url)
defprocess_response(self, req, res):
print("After dispatch", req.url)
app.add_middleware(SimpleCustomMiddleware)