Giter Site home page Giter Site logo

captivus / fasthtml Goto Github PK

View Code? Open in Web Editor NEW

This project forked from answerdotai/fasthtml

0.0 0.0 0.0 5.33 MB

The fastest way to create an HTML app

Home Page: https://AnswerDotAI.github.io/fasthtml

License: Apache License 2.0

Python 6.09% CSS 0.03% Jupyter Notebook 93.88%

fasthtml's Introduction

fasthtml

Please note: this repo is public so that we can build in the open, and interested folks can participate and/or observe. But it’s not released yet, so please don’t share links to this project on social media etc – the project is not ready yet for public use and it would be very distracting to deal with publicity of an unreleased project.


fasthtml is a library for writing fast and scalable Starlette-powered web applications, without having to learn much (if any!) Starlette. Instead, you just use plain python functions for each page in your app – you don’t even need to learn Javascript. The finished app will be about as fast as a Python web server can be (which is pretty fast – e.g. Instagram runs on Python), and you can create pretty much anything. This isn’t one of those stripped-down dashboard making thingies.

This is a way to write real web applications, without the fuss.

To learn how to use it, please visit the documentation.

Install

pip install python-fasthtml

For a minimal app, create a file “main.py” as follows:

main.py

from fasthtml.all import *
import uvicorn

app = FastHTML()
rt = app.route

@rt("/")
def get():
  return Title("FastHTML"), H1("Hello World!")

if __name__ == '__main__':
    uvicorn.run(app, host='0.0.0.0', port=int(os.getenv("PORT", default=8000)))

How to use

Import from fasthtml.all:

from fasthtml.all import *

Create your app.

app = FastHTML()

Create your routes. The syntax is largely the same as the wonderful FastAPI (which is what you should be using instead of this if you’re creating a JSON service. FastHTML is for mainly for making HTML web apps, not APIs).

Note that you need to include the types of your parameters, so that FastHTML knows what to pass to your function. Here, we’re just expecting a string:

@app.get('/user/{nm}')
def get_nm(nm:str): return f"Good day to you, {nm}!"

Normally you’d save this into a file such as main.py, and then run it in uvicorn using:

uvicorn main:app

However, for testing, we can use Starlette’s TestClient to try it out:

from starlette.testclient import TestClient
client = TestClient(app)
r = client.get('/user/Jeremy')
r
<Response [200 OK]>

TestClient uses httpx behind the scenes, so it returns a httpx.Response, which has a text attribute with our response body:

r.text
'Good day to you, Jeremy!'

In the previous example, the function name (get_nm) didn’t actually matter – we could have just called it _, for instance, since we never actually call it directly. It’s just called through HTTP. In fact, we often do call our functions _ when using this style of route, since that’s one less thing we have to worry about naming.

An alternative approach to creating a route is to use app.route instead, in which case you make the function name the HTTP method you want. Since this is such a common pattern, you might like to give a shorter name to app.route – we normally use rt:

rt = app.route

@rt('/')
def post(): return "Going postal!"

client.post('/').text
'Going postal!'

FastHTML has special handling of tags created using fastcore.xml, so you can return web pages without worrying about Jinja, templates, or any of that stuff. This also means you can pip install styled rich component libraries, since it’s all just pure python:

@app.get('/html/{idx}')
async def _(idx:int):
    return Body(
        H4("Wow look here"),
        P(f'It looks like you are visitor {idx}! Next is {idx+1}.')
    )
from IPython import display
display.HTML(client.get('/html/1').text)

Wow look here

It looks like you are visitor 1! Next is 2.

Features

Here’s a brief demo of all the features of the library:

from starlette.responses import Response
from datetime import datetime
from fastcore.utils import *
from dataclasses import dataclass, asdict
def todict(req): return {k:str(v) for k,v in req.items()}
app = FastHTML()
rt = app.route

@app.get("/")
def _(req): return todict(req.scope)
cli = TestClient(app)
r = cli.get('/')
print(r.text)
{"type":"http","http_version":"1.1","method":"GET","path":"/","raw_path":"b'/'","root_path":"","scheme":"http","query_string":"b''","headers":"[(b'host', b'testserver'), (b'accept', b'*/*'), (b'accept-encoding', b'gzip, deflate, br'), (b'connection', b'keep-alive'), (b'user-agent', b'testclient')]","client":"['testclient', 50000]","server":"['testserver', 80]","extensions":"{'http.response.debug': {}}","state":"{}","app":"<fasthtml.core.FastHTML object>","session":"{}","starlette.exception_handlers":"({<class 'starlette.exceptions.HTTPException'>: <bound method ExceptionMiddleware.http_exception of <starlette.middleware.exceptions.ExceptionMiddleware object>>, <class 'starlette.exceptions.WebSocketException'>: <bound method ExceptionMiddleware.websocket_exception of <starlette.middleware.exceptions.ExceptionMiddleware object>>}, {})","router":"<fasthtml.core.RouterX object>","endpoint":"<function _wrap_ep.<locals>._f>","path_params":"{}"}
@app.get('/user/{nm}')
def _(nm:str): return f"Good day to you, {nm}!"

cli.get('/user/jph').text
'Good day to you, jph!'
@rt('/html/{idx}')
async def get(idx:int):
    return Body(
        H4("Wow look here"),
        P(f'It looks like you are visitor {idx}! Next is {idx+1}.')
    )

display.HTML(cli.get('/html/1').text)

Wow look here

It looks like you are visitor 1! Next is 2.

reg_re_param("imgext", "ico|gif|jpg|jpeg|webm")

@app.get(r'/static/{path:path}{fn}.{ext:imgext}')
def get_img(fn:str, path:str, ext:str): return f"Getting {fn}.{ext} from /{path}"

cli.get('/static/foo/jph.ico').text
'Getting jph.ico from /foo/'
ModelName = str_enum('ModelName', "alexnet", "resnet", "lenet")

@app.get("/models/{nm}")
def model(nm:ModelName): return nm

print(cli.get('/models/alexnet').text)
alexnet
@app.get("/files/{path}")
async def txt(path: Path): return path.with_suffix('.txt')

print(cli.get('/files/foo').text)
foo.txt
fake_db = [{"name": "Foo"}, {"name": "Bar"}]

@app.get("/items/")
def read_item(idx:int|None = 0): return fake_db[idx]

print(cli.get('/items/?idx=1').text)
{"name":"Bar"}
print(cli.get('/items/').text)
{"name":"Foo"}
@app.get("/booly/")
def booly(coming:bool=True): return 'Coming' if coming else 'Not coming'

print(cli.get('/booly/?coming=true').text)
Coming
print(cli.get('/booly/?coming=no').text)
Not coming
@app.get("/datie/")
def datie(d:date): return d

date_str = "17th of May, 2024, 2p"
print(cli.get(f'/datie/?d={date_str}').text)
2024-05-17 14:00:00
@dataclass
class Bodie:
    a:int;b:str

@rt("/bodie/{nm}")
async def post(nm:str, data:Bodie):
    res = asdict(data)
    res['nm'] = nm
    return res

cli.post('/bodie/me', data=dict(a=1, b='foo')).text
'{"a":1,"b":"foo","nm":"me"}'
@app.get("/setcookie")
async def setc(req):
    now = datetime.now()
    res = Response(f'Set to {now}')
    res.set_cookie('now', str(now))
    return res

cli.get('/setcookie').text
'Set to 2024-06-01 19:55:03.088788'
@app.get("/getcookie")
async def getc(now:date): return f'Cookie was set at time {now.time()}'

cli.get('/getcookie').text
'Cookie was set at time 19:55:03.088788'
@app.get("/ua")
async def ua(user_agent:str): return user_agent

cli.get('/ua', headers={'User-Agent':'FastHTML'}).text
'FastHTML'
@app.get("/hxtest")
def hxtest(htmx): return htmx.request

cli.get('/hxtest', headers={'HX-Request':'1'}).text
'1'

fasthtml's People

Contributors

jph00 avatar johnowhitaker avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.