fasthtml
fasthtml copied to clipboard
[BUG] Route handlers convert falsy values (0, False) to empty strings
Describe the bug FastHTML route handlers convert falsy values to empty strings when rendering responses. Specifically:
- The integer
0is converted to''(empty string) instead of'0' - The boolean
Falseis converted to''instead of'False'
This behavior is inconsistent with how other primitive values are handled, where integers like 1 correctly convert to '1' and True correctly converts to 'True'.
Minimal Reproducible Example
from fasthtml.core import FastHTML, Client
app, cli, rt = (app := FastHTML()), Client(app), app.route
@rt('/zero')
def get(): return 0
@rt('/one')
def get(): return 1
@rt('/true')
def get(): return True
@rt('/false')
def get(): return False
assert cli.get('/zero').text == '0' # Fails: returns ''
assert cli.get('/one').text == '1' # Passes
assert cli.get('/true').text == 'True' # Passes
assert cli.get('/false').text == 'False' # Fails: returns ''
Expected behavior
- Route handlers returning
0should render as'0'in the response - Route handlers returning
Falseshould render as'False'in the response
This would be consistent with how other primitive values are handled, where:
1renders as'1'Truerenders as'True'
Environment Information
- fasthtml version: 0.9.0
- fastcore version: 1.7.19
- fastlite version: 0.0.13
Confirmation
- [x] I have read the FAQ (https://docs.fastht.ml/explains/faq.html)
- [x] I have provided a minimal reproducible example
- [X] I have included the versions of fastlite, fastcore, and fasthtml
- [x] I understand that this is a volunteer open source project with no commercial support.
Additional context
The current behavior makes it impossible to distinguish between an empty response and a response containing 0 or False.
Similar but unrelated bug #567, this one caused by line 188 ...v not in (False, None, '')... in to_xml.
This happens because the initial check if not resp: resp=() in _resp() treats these valid values as falsy conditions, preventing them from reaching the string conversion at the end of the function.
I don't know if this is intended, but i can imagine cases where 0 can be a valid response. At least, it think it should be deocumented so we can intercept this cases and return strings.
The above examples are contrived, but consider this simple component with a readout that never shows the 0 (running in a notebook):
import dataclasses as DC
from fasthtml.components import Label, Input, Text
_n = '\n'
@DC.dataclass
class IntSlider:
value:int=-1; min:int=-1; max:int=1; step:int=1
def __ft__(self):
return Div()(
Label(_for='value')('Value'), _n,
Input(type='range', name='value', **DC.asdict(self),
hx_post=f"/value", hx_trigger='input changed', hx_target='next text', hx_swap='textContent'),
Text(style='inline')(self.value), _n
)
rp = IntSlider()
@rt('/value')
def changed(value:int):
rp.value = value
return value
show(rp)
Screenshots