12 ms·
Ludic: New framework for Python with seamless Htmx support
- paveldedik 2y agoI've been working on a lightweight framework called Ludic that focuses on web development using Python, htmx.org, and a somewhat React-like component approach. It leverages Starlette for performance and the latest Python 3.12 typing features. Interested in feedback! * Docs: https://ludic.readthedocs.io/ https://ludic.readthedocs.io/ * Code: https://github.com/paveldedik/ludic/ https://github.com/paveldedik/ludic/ * Examples: https://github.com/paveldedik/ludic/tree/main/examples https://github.com/paveldedik/ludic/tree/main/examples
- sesm 2y agoBy React-like component approach, do you mean using functions instead of templating language?
- paveldedik 2y agoI think it is somewhat similar to React, for example, you can create a Link component like you can see in the README.md Now you can use it in f-strings, and well, other components. The idea from the beginning was to integrate it with htmx.org, so to me, it feels kind of similar when you are writing endpoints using these "components". But I understand why you are raising this question, I also didn't know how to name it, and React is a completely different framework. I didn't know how to describe the framework in just a few sentences but wanted to somehow. I might change the description at some point. I still don't know how useful the framework is, I am playing around with it and I like it. Who knows what other people think, though. // edit - code block don't work here, removed code sample.
- zelphirkalt 2y agoIs there any chance you are considering moving towards structured data as HTML, as in SXML, instead of putting things into fstrings?
- paveldedik 2y agoWell, I would like it if the solution supported standard Python typing. Here I can create a "component" that expects a specific type of the first child and a specific type of the second child. I would probably have to use a separate tool for some kind of type-checking the SXML or something. BTW in Rust, you can create macros, that is something I like a lot as you can see in yew framework - https://yew.rs/docs/getting-started/build-a-sample-app#update-mainrs https://yew.rs/docs/getting-started/build-a-sample-app#updat... - you can write HTML which probably are typed. Python doesn't have anything like that, I don't know about any other way to do this. // edit typo
- zelphirkalt 2y agoWhether compile time guarantees or not, even having HTML elements as objects would be better than putting them into the f-strings. With objects we could probably pattern match on then and traverse the tree, instead of having to rely on other tooling or even regex to search for things inside an f-string.
- TylerE 2y agoFWIW, my reaction to the Link example was pretty much "Why do I have to build this, why isn't such a basic thing that any project would want not batteries-included?". Not the greatest first impression.
- mainframed 2y agoBut `a` is included. You don't have to build a `Link` component. If you want to stylize your links in consistently across your page, you can build your own Link. The example does nothing other than renaming `href` to `to` and adding a style. How should the framework know which styles you want to apply to a link? I think the example explains the component-driven design of the library well.
- TylerE 2y agoHow would you feel if the first example in, say, a ruby tutorial, was how to redefine the ‘+’ operator to use a different symbol? It’s somewhere between pointless and confusing to me, and isn’t illustrative of why one would want to use components, or what a competent even is.
- MrJohz 2y agoInterestingly, the second example on the official Ruby "About" page is almost exactly that: it defines .plus to be an alias of .+, and demonstrates how it might be used. https://www.ruby-lang.org/en/about/ https://www.ruby-lang.org/en/about/ As a web developer (and therefore, I imagine, part of the target demographic for this sort of tool), I personally find this component example very useful. Components are very powerful, but most existing Python templating languages make it difficult or overly verbose to use them to their full extent. This is a really good demonstration of how I can write simple presentational components and use them with server-rendered HTMX. That shows off one of the main things I would want to do with this sort of framework. So from that perspective, this is very much the perfect sort of example.
- TylerE 2y ago
- sergiomattei 2y agoI’ve been burned by ASGI and asynchronous python so much in the past, I wouldn’t touch it again even if someone paid me for it. It’s prone to bugs, hard to debug and for little benefit.
- shinryuu 2y agoHow have you been burned? What kind of bugs did you have, and in what way was it difficult to debug?
- timhh 2y agoHere's a bug I ran into with Python async: https://stackoverflow.com/q/78036302/265521 https://stackoverflow.com/q/78036302/265521 I've written about 200 lines of Python async code in total, so to run into a bug like that so soon was not encouraging. I suspect it's just not a very popular feature and so it doesn't get a lot of use and debugging. And it's Python so it really needs a lot of ton of real world use to detect bugs. Anyway I'm not going to waste my time debugging Python internals so I just switched to Deno.
- PaulHoule 2y agoIt’s pretty easy to make a mistake like that with any concurrency framework. I can tell you stories about all the cases where in Java it was “use ExecutorService and… done” but it is so easy to get it wrong there.
- timhh 2y agoHaha someone didn't like that I'm pointing out flaws in Python and down-voted that question.
- PaulHoule 2y agoMyself I built an RSS reader using aiohttp and then forked the code to make an image sorter. I had a lot of people tell me I was crazy to write aiohttp servers because of the problems the previous poster mentioned but I had a long run of it working pretty well. On the other hand I’ve frequently had the experience of writing something in Python that falls apart like a tower of Jenga blocks the moment somebody else touches it. (Quite different from my experience with Java, Javascript, C#, PHP, …) Once I started serving images along with the text and using the app over a 2Mbps link it seemed to me the aiohttp server was getting a little unreliable. Most basically, an aiohttp server can only use one CPU thread at a time with the consequences that if one request holds the CPU for 5 seconds the server stops processing requests completely.. Although the aiohttp server could be reliable if you are almost entirely waiting for data to get back from the database, the residual amount of CPU load is going to put an upper bound on what the server can handle in the best case. If a coder is not so careful you get burned. My RSS reader has an AI component which runs completely in batch jobs, I don’t do any inference during requests which limits my flexibility and makes the application less “real-time” than it could be. You can imagine systems where one aio server hands tasks off the another aio server but the blocking situation doesn’t get any better and if you want to make the system scalable there has to be at least one multiprocess or multithreaded server somewhere. At some point I am like “I have a 16 core machine but I am only using 1 core like my laptop in the 1990s” It didn’t help that my aio database drivers aren’t in conda which is another build hassle. So last week I tore up the image sorter and rewrote it in Flask (my aio framework looks like Flask so it’s not too hard) and I run it out of gunicorn, I put a reverse proxy in front to deal with some Tailscale problems so I have IIS serving the images.
- rmbyrro 2y agoI don't know, every time I see people sneaking html into Python feels weird and wrong to me...
- andybak 2y agoDo you feel the same about sneaking html into javascript? Just curious if it's a Python-specific objection.
- shinryuu 2y agosame feeling there tbh. Though generally, when it's done in javascript it's done completely in a string, without javascript objects.
- legutierr 2y agoIn general, this usually results in front-end logic being very tightly coupled with back-end logic. In some of the examples given, you even have database access in the same line that is generating the HTML document. https://github.com/paveldedik/ludic/blob/main/examples/click_to_edit.py#L35 https://github.com/paveldedik/ludic/blob/main/examples/click... It's the kind of thing that looks very cool and concise in small examples, but tends to become a nightmare when you are working on larger projects.
- kissgyorgy 2y ago> In some of the examples given, you even have database access in the same line that is generating the HTML document. Python template engines have the exact same problem, just way less obvious. It doesn't have to be that way. Make all the queries up-front and pass the result the same way as you would pass context to templates. This way, all your components are pure. The difference is explicitness. Much easier to spot where side-effects happen than in templates.
- andybak 2y agoI think the issue is orthogonal. I'm not a huge fan of react but it's an example of an architecture where the structure that is (imposed/encouraged) helps avoid the problem you're talking about. I don't think the issue is "markup expressed in another language" - I think it's "poor application architecture". I don't dispute there might be a correlation between libraries and frameworks that do poorly on each - but that doesn't mean it's intrinsic.
- j4mie 2y agoI wrote a library a little while ago which is intended to be the simplest possible expression of this idea: https://github.com/j4mie/hotmetal/ https://github.com/j4mie/hotmetal/ The core implementation is only 85 lines of Python, and has no imports at all, so works nicely on minimal/alternative Pythons like Micropython. I'm using it on a medium-sized side project and it's shockingly productive compared to string templates. I don't think anyone is using it except me, though.
- giovannibonetti 2y agoElm [1] is based on a similar idea. Build your app from pure functions that return HTML tags. [1] https://elm-lang.org/ https://elm-lang.org/
- eddieroger 2y agoWe've come full circle on naming HTML tools! https://en.wikipedia.org/wiki/HoTMetaL https://en.wikipedia.org/wiki/HoTMetaL
- j4mie 2y agoGlad someone got the reference!
- eddieroger 2y agoI'm glad it was intentional. :-) I don't feel as old. Still old. But less so.
- slifin 2y agoSearch for "clojure hiccup"
- egeozcan 2y agoI use gomponents with go, which is very similar. The productivity increase is immense. https://github.com/maragudk/gomponents https://github.com/maragudk/gomponents
- 2y ago
- jpgvm 2y agoI encourage anyone looking to do htmx to consider Kotlin and it's excelent kotlinx-html DSL. Lets you do stuff like this: https://github.com/corlaez/kotlin-htmx/blob/master/src/main/kotlin/friends/html.kt https://github.com/corlaez/kotlin-htmx/blob/master/src/main/... Disclaimer: Not my code, just an example I found.
- Neikius 2y agoThis is a lovely use of the DSL..too bad I prefer plain java.
- smallerfish 2y agoI second this. kotlinx-html is poorly documented and has a couple quirks, but is fantastic. As I've been building one of my current projects, I've also been building a framework based on jooq + kotlinx.html + javalin + htmx + flowbite (+kotlinjs for a few fancy bits, e.g. the charting library). Aside from tailwind, you end up with a fully typed and compiler-checked application end to end, i.e. no magic strings to be seen. I'm exclusively using HX-Retarget, so the backend is in charge of where things land, meaning that the frontend can do things like: div { onClick(loadItems) } I don't know whether I'll ever actually get it in good enough shape to release, but I do plan to blog about how some of the tricks I've found it fitting it together. One thing I definitely need to do before anybody looks at it is clean up how routes and targets are managed.
- hjadal 2y agoThat sounds like a lovely way to develop, what is your blog? So I can watch for your post.
- smallerfish 2y agoThanks! It's http://smaller.fish http://smaller.fish. I have a subscribe form at the bottom which I only use for new post announcements (which, as you can see, are pretty infrequent :)).
- efilife 2y ago
- kissgyorgy 2y agoI also started working on a Python Component library, but it's fully independent of any web framework, and you can generate XML/RSS with it too. I'm using it for months now, I will release the first version soon: https://github.com/kissgyorgy/compone https://github.com/kissgyorgy/compone
- danpalmer 2y agoNice release! This looks good, docs look really nice too. I'd use HTMX anywhere I can to improve a basic HTML site. One word of warning for people considering HTMX though – it's not a framework, it's an appliance. In my experience with it, I ran into problems integrating with HTMX very quickly. Drop it into your project, use the HTML attributes, and it'll be great. However if you need custom Javascript, HTMX provides little in the way of an integration path (the lifecycle events are basic), and nothing in the way of structure, and can even get in the way in places where its lifecycle causes issues in the lifecycle of whatever you're adding. To add your own Javascript you'll almost certainly want Jquery or React/Svelte/etc, and with the latter you'll get interactions between their lifecycles. If you're using it entirely via the HTML API, and you're happy to accept that sometimes it won't do something, you'll be fine. If you're looking to add units of more complex client-side functionality in places, try prototyping with it to make sure it works well, it didn't for me.
- unclebucknasty 2y agoI think those are all good points, but do cringe a little at the idea that "to add your own JavaScript you'll want React". Seems like a lot to bring in if you're really just wanting to add some JavaScript.
- danpalmer 2y agoHa, fair point. I don't mean so much that for any JS you'd want to bring in React, but more that something like that will likely be needed to manage a codebase of any scale. My context here is a mostly server-side application using HTMX, where I wanted to add a few small bits of additional client-side code. I tried to do it without any libraries but rapidly realised that Jquery would simplify things a lot, and managed to do ok with that, but was still fighting HTMX throughout, and I ended up with a lot of poorly managed local state quite quickly. It doesn't take much complexity to need some better form of state management, and something like React provides some direction there, but of course there are other options, my point was only really to say that HTMX will not do any of this for you, and may get in the way depending on what you need to do.
- cipherself 2y agoGenerating `HTML` from lisps has poisoned any other approach for me, see for example https://www.neilvandyke.org/racket/html-writing/ https://www.neilvandyke.org/racket/html-writing/, https://reagent-project.github.io/ https://reagent-project.github.io/, and https://edicl.github.io/cl-who/ https://edicl.github.io/cl-who/
- callamdelaney 2y agoThat's very nice, I wonder if we can write a sort of dsl for this in python.
- skgough 2y agoAirium is close: https://gitlab.com/kamichal/airium https://gitlab.com/kamichal/airium
- cipherself 2y agoThe problem with this is that it doesn’t map nicely to HTML (or more generally XML) as do s-expressions.
- nicwolff 2y agoMy https://pypi.org/project/xml-from-seq/ https://pypi.org/project/xml-from-seq/ is a simple mapper from e.g. ['p', 'This is a ', ['a', {'href': 'https://example.com'}, 'link']] to <p>This is a <a href="https://example.com">link</a></p>
- explorigin 2y agoThe idea of nested function calls to build HTML is not new. Back in the hey-day of JS frameworks, this was a common vdom pattern. I kinda miss [MithrilJS](https://mithril.js.org/#dom-elements https://mithril.js.org/#dom-elements)
- dkuznetsov 2y agoIt is a bit funny. When I started with Python ~18 years ago, the team lead on that project liked this framework "Nevow". It wad plugged into Twisted. Completely async, IIRC JS could have been built in, too. Some ideas are really not new under the sun. Thanks for the wave of nostalgia.
- fermigier 2y agoI have been working on a (currently half-baked) similar project: - <https://github.com/abilian/webbits https://github.com/abilian/webbits> Inspirations for the idea of generating HTML code from Python: - <https://www.yattag.org/ https://www.yattag.org/> - <https://tylerbakke.github.io/MarkupPy/ https://tylerbakke.github.io/MarkupPy/> - <https://github.com/michaeljones/packed https://github.com/michaeljones/packed> - <https://github.com/twidi/mixt/ https://github.com/twidi/mixt/> - <https://github.com/byteface/domonic https://github.com/byteface/domonic> - <https://pypi.org/project/hyperpython/ https://pypi.org/project/hyperpython/> - <https://pypi.org/project/PyHTML/ https://pypi.org/project/PyHTML/> - <https://github.com/jviide/htm.py https://github.com/jviide/htm.py> - <https://viewdom.readthedocs.io/ https://viewdom.readthedocs.io/> - <https://github.com/pcarbonn/fast_html https://github.com/pcarbonn/fast_html> - <https://github.com/sanic-org/html5tagger https://github.com/sanic-org/html5tagger> - <https://github.com/j4mie/hotmetal/ https://github.com/j4mie/hotmetal/>
- hawski 2y agoI can only say that I like fast_html and how simple it is. Very easy source to read and understand. It is based on generators internally. I started using it for some documentation generation purposes. I'm not a web-dev.
- aitchnyu 2y agoWish GVR updates pyxl4(used by Mixt) and includes it into Python. It could be used for html, xml, yaml and its config language friends and declarative UIs like React. IMO if and for are better implemented in Jinja or JSX better than Python's ternary and list comprehension. Comparison at bottom. Most of the frameworks here are calling side effects upon shared objects in the guise of `with` statements. Not to mention the extreme verbosity. > <if cond> > <long code 1> > <else> > <long code 2> > > [longcode1() if cond else longcode2()] > > <for i in ls> > <long code 1> > >[longcode() for i in ls]
- maxpert 2y agoOn similar lines, I've put together a library for myself that is framework agnostic: https://github.com/maxpert/htmxido https://github.com/maxpert/htmxido Hopefully will be useful for people as well
- ta988 2y agoCan it be used to make static html?
- mixmastamyk 2y agoLooks like ludic.html could.
- unclebucknasty 2y agoCall me traumatized by the Web framework wars, but this seems like the path back to some of the issues that HTMX is trying to solve. There is a strong developer instinct to "simplify through complexity". That is, to stuff down so much functionality and saw off all edges in an effort to hide complexity. "Let's expose a simple interface that will allow devs to do everything they want to do." It starts with good intentions and initially provides some improvements in productivity. But it continues to evolve to the point of untenability: the complexity starts to ooze out and become a thing to manage, but with abstractions that make it more difficult; the framework becomes so opinionated that it begins to stifle; performance issues are introduced as we drift farther from the metal. We continue to try to solve with newer constructs and abstractions, frequently introducing more issues. Eventually, it comes full circle ("hey, let's add SSR!"), and we're again looking for another solution. One that's simpler. Then the cycle starts over again. I think there is an inflection point with all of these things, wherein whatever perceived productivity gains are had by pushing more functionality into the framework quietly begins the path to regression. I don't exactly know where it is, but I would bet that it happens far sooner than we suspect. So, I kind of like HTMX where it is, in spirit and implementation. Whatever additional productivity I can pick up via helper functionality and reuse is something I believe there is value in devs doing on their own, for their individual use cases and preferences. There's a tendency to think "well why reinvent the wheel? Let's make it a framework". I've come to believe that impulse is somewhat pernicious in its effect. Ultimately we're going to have to write our own code at some point. I'd suggest that we're better off doing it much sooner than frameworks encourage.
- m_rpn 2y agoSpot on, in my opinion we need at least a 10 years ban on the creation of any new web framework of any kind. Hope that AI coders will make frameworks obsolete, but maybe i'm crazy :-).
- onecandreamz 2y agoI wish someone would sponsor development of HTMX support via NginX or Apache2 modules. That way you don't have to go to python, php, java, etc... to get HTMX support. You would just enable the module, configure a few things and let it rip. Kinda like server side includes in Apache2.
- stefanha 2y agoCan you explain what you mean? htmx is client-side, so you don't need server-side includes. Just host HTML snippets on your web server and let htmx stitch them together in the browser. I'm not sure where you want the web server to play a role?
- sureonesec 2y agoHTMX is a client side JS file which parses the dom and then interprets it in a certain way and then provides some functionality. However the choice whether someone creates the initial html in a SPA context or a full page refresh is up to the developer. Maybe I want to generate the HTML snippets HTMX processes from the server side in PHP/Python and then have HTMX run it's magic on page load.
- ormaybezzzz 2y agoOr maybe if the same HTMX logic is put into server side code equivalent which generates , the server side code can generate that extra functionality and only generate the js that is needed eliminating the step of including HTMX on the client side.
- DrFalkyn 2y agonginx/apache work well as secure reverse-proxies, load-balancers/etc. to the application servers. Complicating them with hooks for a bunch of random APIs is asking for trouble. Let the application servers sit behind them so they don't have to worry about those issues, and nginx/apache don't have to worry about application server issues
- DrFalkyn 2y ago
- polyrand 2y agoI think these kinds of tools are awesome, although I normally prefer not having to rely on getting the functions/classes/types defined for me, I usually find it easier to just use lxml[0] to build HTML components from composable Python functions[1], similar to React. [0]: https://lxml.de/lxmlhtml.html#creating-html-with-the-e-factory https://lxml.de/lxmlhtml.html#creating-html-with-the-e-facto... [1]: https://ricardoanderegg.com/posts/python-build-html-components-lxml/ https://ricardoanderegg.com/posts/python-build-html-componen...
- mixmastamyk 2y agoWhy does it use async? I thought that was for scrapers and the like, not producing a primary web page or app. .js callbacks later to fill stuff in, sure.
- mjf988 2y agocool! Whats wrong with just writing HTML f-strings and using flask tho?
- pelme 2y agoThis looks great! Building HTML on the server with static types and htmx is a very productive combination! At work, we have been exploring alternatives to templates in our Django project and just released it as a lib to help with this: https://htpy.dev/ https://htpy.dev/
- aitchnyu 2y agoWhoa, a creative (in a good way IMO) use of __ getitem__() dunder method to depict attributes and children. No action at a distance using with blocks, static and strongly typing instead of stringly typing, no need to extend Python, composable from fragments. Have you tried to "bring up front" if and for? For example > if_(cond, tag1(), tag2()) # without eagerly execute both branches Instead of > tag1() if cond else tag2() And for_(cars, lambda car: car_details(car)) # while still being type checked Instead of > [car_details(car) for car in cars]
- pelme 2y agoPython's inline if's still read backwards to me and it would be nice to switch the order. But we are kind of stuck with it. I also don't want to introduce new control structures in this lib. Just want to use whatever Python has to offer in terms of control structures/syntax to make it more approachable. htpy supports generators/callables as children (https://htpy.dev/streaming/ https://htpy.dev/streaming/). As long as you are careful to wrap things in generators/lambdas everything is lazy. Implementing if_ and for_ is straightforward and anyone can build constructs like that to use. But will not be lazy unless all arguments are wrapped in lambdas: from htpy import div, li, ul def if_(cond, a, b): return a() if cond() else b() def for_(items, func): return (func(item) for item in items()) print(div[if_(lambda: True, lambda: "True!", lambda: "False!")]) print(div[if_(lambda: False, lambda: "True!", lambda: "False!")]) print(ul[for_(lambda: ["a", "b", "c"], lambda x: li[x])]) output: <div>True!</div> <div>False!</div> <ul><li>a</li><li>b</li><li>c</li></ul>
- yashasolutions 2y agoNice! A bit verbose for my taste but writing for the web in python is a space where all innovation is welcome. I personally like hyperdiv [1] approach (even if no use of Htmx) which is very intuitive for python code. [1]: https://github.com/hyperdiv/hyperdiv https://github.com/hyperdiv/hyperdiv
- pietz 2y agoI've been diving into Python/FastAPI + HTMX development and while I love both separately, I felt like the combined tooling could be a lot better. Jinja2 doesn't really satisfy me. At least not in this tech stack. I'm still a bit sceptical if this is the solution but I'm definitely going to look into it as it fixes a few things I'm annoyed with. Thanks!
- mplemay97 2y agoAgreed. As someone who primarily develops in python, I recently tried this exact same stack as a way of avoiding the inevitable (i.e. learning typescript). After dealing with the complexity of interleaving templates, overly complex information flows, etc. I copied some of the html from the jinja templates I created into a svelte project, added openapi-typescript to glue it all together, and moved on. While I am by no means a fan of typescript and modern web development, it is much easier build things given the extensive ecosystem. And if nothing else, the “frontend” is separate all of the core logic, which makes things easier to understand.