fasthtml icon indicating copy to clipboard operation
fasthtml copied to clipboard

[BUG] Missing function type hints result in `None` for function inputs in FastHTML

Open mratanusarkar opened this issue 11 months ago • 0 comments

Description

When using FastHTML, omitting type hints for function parameters causes input values to default to None, resulting in a TypeError. This behavior is inconsistent with the expected functionality where inputs should retain their values regardless of type hints.

Issue

Below is a sample code (adapted from FastHTML Tutorials):

import fasthtml.components as fh_components
from fasthtml.core import FastHTML, serve

app = FastHTML()
route = app.route

@app.get("/")
def home():
    return fh_components.Form(
        fh_components.Input(type="text", id="input_1", name="input 1"),
        fh_components.Input(type="text", id="input_2", name="input 2"),
        fh_components.Button("Submit", id="submit", hx_post="/submit", hx_target="#response"),
    ), fh_components.Div(id="response")

@app.post("/submit")
def demo_fn(input_1: str, input_2: str):
    response = inp_1 + " " + inp_2
    return response

serve()

The above code works perfectly!

but if we change the demo_fn removing the type hints as:

@app.post("/submit")
def demo_fn(input_1, input_2):
    response = inp_1 + " " + inp_2
    return response

This throws error:

  File "/workspaces/demoapp/test.py", line 17, in demo_fn
    response = inp_1 + " " + inp_2
               ~~~~~~^~~~~
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'

on debugging, we found that missing types are making the values None for some weird reason. This must be a bug in how fastHTL handles the data!

Expected behavior

FastHTML should not convert the function inputs to None if the function input param type hints are missing.

Found workaround/fix

A workaround was found, by tapping into the form request. but this should work without this hack/workaround. here is the workaround:

import fasthtml.components as fh_components
from fasthtml.core import FastHTML, serve, Request

app = FastHTML()
route = app.route

@app.get("/")
def home():
    return fh_components.Form(
        fh_components.Input(type="text", id="input_1", name="input 1"),
        fh_components.Input(type="text", id="input_2", name="input 2"),
        fh_components.Button("Submit", id="submit", hx_post="/submit", hx_target="#response"),
    ), fh_components.Div(id="response")

@app.post("/submit")
async def demo_fn(request: Request):
    form_data = await request.form()
    input_1 = form_data.get("input_1")
    input_2 = form_data.get("input_2")
    return input_1 + input_2

serve()

PS: discovered this bug & workaround while working on a project with @soumik12345

mratanusarkar avatar Jan 06 '25 19:01 mratanusarkar