{"id":8217,"library":"htpy","title":"htpy - HTML in Python","description":"htpy is a Python library designed for generating HTML in plain Python code, eliminating the need for separate templating languages. It aims to make writing HTML fun and efficient, leveraging Python's features like static typing and debugging. The current version is 25.12.0, and it follows a frequent release cadence, often monthly.","status":"active","version":"25.12.0","language":"en","source_language":"en","source_url":"https://github.com/pelme/htpy","tags":["html","templating","frontend","web","async"],"install":[{"cmd":"pip install htpy","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Required for execution","package":"python","optional":false}],"imports":[{"note":"Commonly imported HTML elements for building pages.","symbol":"html, body, div, p, ul, li","correct":"from htpy import html, body, div, p, ul, li"},{"note":"Alternative import style, allowing access to elements via 'h.div', 'h.html', etc.","symbol":"htpy","correct":"import htpy as h"},{"note":"Helper class for integrating with Starlette/FastAPI applications.","symbol":"HtpyResponse","correct":"from htpy.starlette import HtpyResponse"},{"note":"For creating and managing context for data passing between components.","symbol":"Context","correct":"from htpy import Context"},{"note":"Decorator for defining custom components that accept children nodes.","symbol":"with_children","correct":"from htpy import with_children"},{"note":"Protocol for consistent API to render htpy objects as HTML or iterate over them.","symbol":"Renderable","correct":"from htpy import Renderable"}],"quickstart":{"code":"from htpy import body, h1, head, html, li, title, ul\n\nmenu = [\"egg+bacon\", \"bacon+spam\", \"eggs+spam\"]\n\npage = html[\n    head[title[\"Today's menu\"]],\n    body[\n        h1[\"Menu\"],\n        ul(\".menu\")[(li[item] for item in menu)],\n    ],\n]\n\nprint(page)","lang":"python","description":"This quickstart demonstrates creating a simple HTML page with a head, title, body, heading, and an unordered list dynamically generated from a Python list. The `print(page)` call renders the entire structure to an HTML string."},"warnings":[{"fix":"Use dot notation to separate multiple classes: `div(\".foo.bar\")`.","message":"Specifying multiple CSS classes using whitespace in the shorthand syntax (e.g., `div(\".foo bar\")`) will now raise a `ValueError`.","severity":"breaking","affected_versions":">=25.10.0"},{"fix":"Ensure generators are consumed only once. If content needs to be rendered multiple times, convert the generator to a list or tuple: `ul[list(li[item] for item in my_list)]`.","message":"Rendering a generator (e.g., a generator comprehension used as children) more than once will now raise an exception, as generators are single-use iterators.","severity":"breaking","affected_versions":">=25.7.0"},{"fix":"To render an element to a string, use `str(element)`. For streaming or iterating over chunks, use `element.iter_chunks()`. The `Renderable` protocol provides a consistent API.","message":"The methods `render_node()` and `iter_node()` are deprecated, along with direct iteration over `htpy` elements.","severity":"deprecated","affected_versions":">=25.4.1"},{"fix":"When using ASGI frameworks, leverage `htpy.starlette.HtpyResponse` for returning async-rendered content. Refer to the async documentation for details.","message":"Asynchronous rendering capabilities were added, impacting how `htpy` can be used with ASGI frameworks like Starlette and FastAPI.","severity":"gotcha","affected_versions":">=25.12.0"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Replace spaces with dots for multiple classes: `div(\".class1.class2\")` instead of `div(\".class1 class2\")`.","cause":"Attempting to specify multiple CSS classes using spaces instead of dots in the shorthand syntax.","error":"ValueError: Invalid whitespace in class shorthand. Expected '.foo.bar', not '.foo bar'"},{"fix":"If the content needs to be processed multiple times, ensure the generator is converted to a list or tuple (e.g., `ul[tuple(li[item] for item in items)]`) or recreate the generator for each use.","cause":"An `htpy` element with a generator as a child was rendered or iterated over more than once.","error":"RuntimeError: Generator was already consumed."},{"fix":"Use `str(element)` to get the full HTML string, or `element.iter_chunks()` for iterable streaming output.","cause":"Using deprecated methods `render_node()` or `iter_node()`, or directly iterating over `htpy` elements in newer versions.","error":"AttributeError: 'Element' object has no attribute 'render_node' OR TypeError: 'Element' object is not iterable"},{"fix":"Add the missing element to your imports: `from htpy import div` (or `from htpy import html, body, div` for multiple elements).","cause":"An HTML element (like `div`, `p`, `html`) was used without being imported from the `htpy` module.","error":"NameError: name 'div' is not defined"}]}