AnswerDotAI/fasthtml

[BUG] function name that is decorated by route controls if route can be matched or not rather than the route

Closed this issue · 3 comments

Describe the bug

I get an error starlette.routing.NoMatchFound: No route exists for name "get_lesson" and params "". if the function name that is decorated by @app.route does not match the get= argument in a component.

for example, in the below cascading dropdowns example I want to show a different dropdown based on the selection in an initial dropdown. The function name get_lesson_bug, is incompatible with get=get_lesson and causes the NoMatchFound error. If I change the function name to get_lesson it works, but this is unexpected behavior.

Minimal Reproducible Example

from fasthtml.common import *

app, rt = fast_app()

chapters = ['ch1', 'ch2', 'ch3']
lessons = {
    'ch1': ['lesson1', 'lesson2', 'lesson3'],
    'ch2': ['lesson4', 'lesson5', 'lesson6'],
}

def mk_opts(nm, cs):
    return (
        Option(f'-- select {nm} --', disabled='', selected='', value=''),
        *map(Option, cs))

@app.get('/get_lesson')
def get_lesson_bug(chapter: str):
    return Select(*mk_opts('lesson', lessons[chapter]), name='lesson')

@app.get('/')
def homepage():
    chapter_dropdown = Select(
        *mk_opts('chapter', chapters),
        name='chapter',
        get='get_lesson', hx_target='#lesson')

    return Div(
        Div(
            Label("Chapter:", for_="chapter"),
            chapter_dropdown),
        Div(
            Label("Lesson:", for_="lesson"),
            Div(Div(id='lesson')),
    ))

serve()

removing _bug allows the route to be found

Expected behavior

If I use the function name get_lesson_bug, with @app.get('/get_lesson') I expect the argument get=get_lesson to use the value supplied to @app.get not the function name. similar to how values are passed to hx_post that refer to routes.

Environment Information
Please provide the following version information:

  • fastlite version: 0.0.9
  • fastcore version: 1.7.8
  • fasthtml version: 0.6.4

Confirmation
Please confirm the following:

  • I have read the FAQ (https://docs.fastht.ml/explains/faq.html)
  • I have provided a minimal reproducible example
  • I have included the versions of fastlite, fastcore, and fasthtml
  • I understand that this is a volunteer open source project with no commercial support.

Additional context

the docs for @app.get() say

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.

so I think the issue above illustrates there is a conflict with the docs https://docs.fastht.ml/explains/routes.html

@pydanny you want to look at this one? (@Isaac-Flath could possibly help point you in the right direction)

@pydanny @jph00 Based on my understanding, I don't think this is a bug, but here are my thoughts and some background. Let me know if I am misunderstanding something.

get and post take route names as the argument. The default name of a route is the function name, but you can name it something different via @app.get('/get_lesson',name='myCustomName'). However, in the example provided in this issue the name of the route is get_lesson_bug because the default route name is the python function name (no name was passed to @app.get)

hx_get and hx_post take routes as arguments so that you can specify routes. You could do hx_get='/get_lesson', which would route it to the /get_lesson route. You could also do hx_get='get_lesson', which would route it to the same place unless you're doing something special with mounting (it's like a relative path without the leading /). But in both these cases, it refers to the route path and not the route's name.

I think using the function name as the route name is a good default. Otherwise, we need to transform the route to a valid python name, such as replacing slashes with underscores or something and removing {params}. I think it's clearer to have the default route name be the python function name.

Oh right thanks @Isaac-Flath -- in the version @rbavery shared on Discord I thought the names matched. But perhaps it was just a misunderstanding. I'll close this issue, but feel free to reopen it if it still doesn't work when the function name matches the get value.