Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Inconsistency in URI compution with route URLs on attributes and uri() and url_for() #627

Open
4 tasks done
ctheune opened this issue Jan 7, 2025 · 0 comments
Open
4 tasks done
Labels
bug Something isn't working

Comments

@ctheune
Copy link

ctheune commented Jan 7, 2025

Describe the bug

There's a difference in handling URL generation depending on the use of directly passing a routed function (is that a term?) to an attribute or using the uri or url_for functions.

The documentation mentions that the uri function computes "The function is used to generate URLs for named routes". However, this seems to be implemented with a split responsibility in that the uri function only computes an intermediate step and then the link= attribute does something to actually do this. So this causes hx_get=uri(...) to fail. Also, both the uri() and url_for() functions do not accept passing a function that has a route attached directly which is a big convenience in the FastHTML design and I guess this should be available there too (it did surprise me when I intuitively tried to use them this way).

Minimal Reproducible Example
Provide a minimal code snippet that reproduces the issue. This is crucial for us to understand and fix the bug quickly.

from fasthtml.common import *
import traceback

app = FastHTML()

cli = Client(app)


@app.get("/user/{nm}", name="gday")
def greeting(nm: str = ""):
    return f"Good day to you, {nm}!"


cli.get("/user/Alexis").text


def example1():
    @app.get("/autolink")
    def autolink():
        return Html(Div("Text.", link=uri("gday", nm="Alexis")))

    print("Using `uri` with `link=`")
    print(cli.get("/autolink").text)

# Correctly results in:
# Using `uri` with `link=`
#  <html>
#    <div href="/user/Alexis">Text.</div>
#  </html>

def example2():
    @app.get("/autolink2")
    def autolink2():
        return Html(Div("Text.", hx_get=uri("gday", nm="Alexis")))

    print("Using `uri` with `hx_get=`")
    print(cli.get("/autolink2").text)

# Incorrectly results in:
# Using `uri` with `hx_get=`
#  <html>
#    <div hx-get="gday/nm=Alexis">Text.</div>
#  </html>


def example3():
    @app.get("/autolink3")
    def autolink3():
        return Html(Div("Text.", hx_get=uri(greeting, nm="Alexis")))

    print("Using `uri` with `hx_get=` and function reference")
    print(cli.get("/autolink3").text)


# (Incorrectly) results in:
# Using `uri` with `hx_get=` and function reference
# Traceback (most recent call last):
#   File "/tmp/example.py", line 57, in <module>
# ...
#   File "/Users/ctheune/Code/menage3/.venv/lib/python3.10/site-packages/fasthtml/core.py", line 299, in uri
#     return f"{quote(_arg)}/{urlencode(kwargs, doseq=True)}"
#   File "/nix/store/4aqgxznpnrdmqw22k7qg208lv046ayyp-python3-3.10.15/lib/python3.10/urllib/parse.py", line 881, in quote
#     return quote_from_bytes(string, safe)
#   File "/nix/store/4aqgxznpnrdmqw22k7qg208lv046ayyp-python3-3.10.15/lib/python3.10/urllib/parse.py", line 906, in quote_from_bytes
#     raise TypeError("quote_from_bytes() expected bytes")
# TypeError: quote_from_bytes() expected bytes

def example4():
    @app.get("/autolink4")
    def autolink4(request):
        return Html(
            Div("Text.", hx_get=request.url_for(greeting, nm="Alexis"))
        )

    print("Using `url_for` with `hx_get=` and function reference")
    print(cli.get("/autolink4").text)

# (Incorrectly) results in:
# Using `url_for` with `hx_get=` and function reference
# Traceback (most recent call last):
#   File "/tmp/example.py", line 57, in <module>
#     example()
#   File "/tmp/example.py", line 52, in example4
#     print(cli.get("/autolink4").text)
#   File "/Users/ctheune/Code/menage3/.venv/lib/python3.10/site-packages/fasthtml/core.py", line 660, in _sync
# ...
#   File "/Users/ctheune/Code/menage3/.venv/lib/python3.10/site-packages/starlette/requests.py", line 186, in url_for
#     url_path = url_path_provider.url_path_for(name, **path_params)
#   File "/Users/ctheune/Code/menage3/.venv/lib/python3.10/site-packages/starlette/routing.py", line 662, in url_path_for
#     raise NoMatchFound(name, path_params)
# starlette.routing.NoMatchFound: No route exists for name "/user/{nm}" and params "nm".

for example in [example1, example2, example3, example4]:
    try:
        example()
    except:
        traceback.print_exc()

Expected behavior

All examples, not just the first should run successfully and produce the proper route. Note that example 2 does run but causes an incorrect URL.

Environment Information
Please provide the following version information:

  • fastlite version: v0.1.1
  • fastcore version: v1.7.28
  • fasthtml version: v0.12.0

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.
@ctheune ctheune added the bug Something isn't working label Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant