Skip to content

Conversation

@volfpeter
Copy link
Owner

@volfpeter volfpeter commented Jul 23, 2025

Summary of changes:

  • All Jinja-related code now lives in fasthx.jinja and can only be imported from that package, and not directly from fasthx. See V3 plan #45 for details
  • Renamed *HTMLRenderer types to *RenderFunction to prepare for non-HTML rendering. See Support non-HTML responses #44
  • Documentation and example updates.
  • Updated the required htmy version (if used with htmy).
  • Updated development dependencies.

Summary by CodeRabbit

  • New Features

    • Added a migration guide and a Testimonials section.
  • Refactor

    • Simplified and renamed the rendering/templating API surface; converted class-based examples to function-based components; renamed HTMY renderer property.
  • Bug Fixes

    • Corrected typos and unified import/usage examples across docs and samples.
  • Chores

    • Bumped major version; updated dependencies, build/test tooling, and CI commands.
  • Documentation

    • Consolidated API docs into module-level references and updated site navigation.
  • Tests

    • Updated tests to cover renamed/relocated APIs and new no-selector routes.

@volfpeter volfpeter added the enhancement New feature or request label Jul 23, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 23, 2025

Walkthrough

Renames HTMLRenderer → RenderFunction; moves Jinja public symbols into fasthx.jinja; adds JinjaContext/JinjaContextFactory and ComponentHeader; renames HTMY field htmyrenderer; converts several example components from classes to functions; consolidates API docs; adds v2→v3 migration docs; bumps project to 3.0.0 and updates dependencies and tooling.

Changes

Cohort / File(s) Change Summary
Project metadata
pyproject.toml
Bumped version to 3.0.0; updated htmy constraint/extras; upgraded dev deps; added typing-extensions; added build-backend and pytest/poe tooling config.
Top-level docs & README
README.md, docs/index.md
Added Testimonials; wording and typo fixes; updated examples to from fasthx.jinja import Jinja and renamed TemplateHeaderComponentHeader in docs.
Docs consolidation
docs/api/core-decorators.md, docs/api/dependencies.md, docs/api/jinja.md, docs/api/typing.md
Replaced multiple per-entity sections with single module-level directives, simplifying API docs.
Docs nav & migrations
mkdocs.yaml, docs/migrations/2-to-3.md, docs/migrations/1-to-2.md
Added migration guide migrations/2-to-3.md; adjusted navigation order/labels; renamed migration heading to "Migrating from v1 to v2".
Examples — HTMY refactor
docs/examples/htmy.md, examples/htmy-rendering/htmy_app.py
Converted class/dataclass HTMY components to function factories (UserListItem/IndexPageuser_list_item/index_page); adjusted routes and signatures; added Any where needed.
Examples — templating & custom rendering
docs/examples/jinja-templating.md, docs/examples/custom-templating.md, examples/custom-rendering/custom_rendering_app.py, examples/jinja-rendering/jinja_app.py
Updated imports to fasthx.jinja; replaced TemplateHeaderComponentHeader in examples; generalized some type hints; removed some # type: ignore comments; minor typo fixes.
Package exports
fasthx/__init__.py
Removed direct exports of Jinja-related symbols and HTMLRenderer/JinjaContextFactory; added exports RenderFunction and RequestComponentSelector.
Core decorators
fasthx/core_decorators.py
Replaced HTMLRenderer with RenderFunction in signatures/imports; hx/page decorators now always wrap rendered output in an HTMLResponse (render function expected to return str).
HTMY implementation
fasthx/htmy.py
Typings switched to RenderFunction; renamed field htmyrenderer; updated all render call sites; component_selector parameter now optional with a new _default_component_selector.
Jinja module
fasthx/jinja.py
Added JinjaContextFactory Protocol and JinjaContext helpers; replaced local TemplateHeader with ComponentHeader; render pipeline now produces str directly (inlined TemplateResponse body); removed _make_response.
Typing module
fasthx/typing.py
Declared MaybeAsyncFunc as TypeAlias; renamed Sync/Async renderer protocols to Sync/AsyncRenderFunction and HTMLRendererRenderFunction; narrowed renderer return type to str; removed JinjaContextFactory.
Tests
tests/test_jinja.py, tests/test_htmy.py
Updated imports/usages from TemplateHeaderComponentHeader; added HTMY no-selector endpoints and tests verifying string responses.
CI / tooling
.github/workflows/linters.yml
Linter step renamed and command changed to poetry run poe check.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant FastAPI
    participant Decorator
    participant RenderFunction
    participant HTMLResponse

    Client->>FastAPI: HTTP request
    FastAPI->>Decorator: invoke route handler -> result
    Decorator->>RenderFunction: pass result + context + request
    RenderFunction-->>Decorator: return rendered HTML (str)
    Decorator->>HTMLResponse: wrap HTML -> Response
    HTMLResponse->>Client: HTTP response
Loading
sequenceDiagram
    participant Client
    participant FastAPI
    participant JinjaDecorator
    participant ComponentHeader
    participant JinjaContextFactory
    participant JinjaRenderer

    Client->>FastAPI: HTTP request (may include header)
    FastAPI->>JinjaDecorator: handler returns result
    JinjaDecorator->>ComponentHeader: select component/template
    JinjaDecorator->>JinjaContextFactory: build template context
    JinjaDecorator->>JinjaRenderer: render selected component with context -> str
    JinjaRenderer->>JinjaDecorator: return HTML string
    JinjaDecorator->>FastAPI: wrap/return Response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I hopped through docs and code today,
I nudged some names and cleared the way.
Templates moved to a cozy den,
RenderFunction now leads the pen.
Version three — a carrot grin 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The title is overly generic and does not convey the specific scope of the refactoring; while it signals a version 3 update, it fails to summarize the primary changes such as moving Jinja APIs, renaming render types, and updating documentation and dependencies. Please update the title to more clearly reflect the main changes, for example “Move Jinja APIs to fasthx.jinja and rename HTMLRenderer to RenderFunction for v3 refactor,” so that readers immediately understand the core modifications.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/v3

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 6d821a4 and 9e14226.

📒 Files selected for processing (2)
  • fasthx/htmy.py (12 hunks)
  • tests/test_htmy.py (2 hunks)
🔇 Additional comments (12)
fasthx/htmy.py (9)

12-12: LGTM! Type alias import correctly updated.

The import change correctly reflects the refactoring from HTMLRenderer to RenderFunction type alias.


24-28: The docstring wording improvement has already been flagged in previous reviews - the suggestion to tighten the phrasing from "selects the rendered component based on" to "selects the component to render based on" is valid but was covered in past comments.


115-115: Field renamed from htmy to renderer for clarity.

This rename aligns well with the broader refactoring goals, making the purpose of the field more explicit and preparing for potential non-HTML rendering support.

Also applies to: 118-118, 132-132


137-137: Parameter name updated to reflect type alias change.

The parameter name changes from component_selector maintain consistency with the new HTMYComponentSelector type while preserving functionality.

Also applies to: 146-147, 163-163, 173-174


152-154: The repeated ternary logic _default_component_selector if component_selector is None else component_selector has already been identified in previous reviews as a candidate for extraction into a helper method to reduce duplication.

Also applies to: 178-180


204-204: Correct usage of renamed renderer field.

The method calls correctly use self.renderer instead of the old self.htmy, maintaining consistency with the field rename.

Also applies to: 217-219, 236-238


206-206: Return type correctly updated to RenderFunction.

The return type annotations properly reflect the rename from HTMLRenderer to RenderFunction.

Also applies to: 225-225


266-273: New default component selector function added.

The addition of _default_component_selector function provides a clear, documented default behavior for when no component selector is provided. The function correctly assumes the route result is already a component.


49-49: Minor docstring improvement for clarity.

Consider improving the docstring's error description for better clarity.

-            KeyError: If there is no `Request` in the context.
+            KeyError: If there is no `Request` in the context.

The current phrasing is actually fine - no change needed.

Likely an incorrect or invalid review comment.

tests/test_htmy.py (3)

79-83: The mypy type annotation mismatch for hx_no_selector has already been identified in previous reviews - the type: ignore[arg-type] comment properly addresses the type checker issue where the decorator expects Never or Coroutine[Any, Any, Never] but receives HelloWorld.


84-88: The mypy type annotation mismatch for page_no_selector has already been identified in previous reviews - the same type: ignore[arg-type] solution correctly handles the type mismatch between the function's return annotation and the decorator's expectations.


197-198: Test coverage for new no-selector functionality added.

The test cases properly verify that both hx_no_selector and page_no_selector routes return the expected "Hello World!" response for HTMX requests, demonstrating the new default component selector behavior.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Ruff (0.13.1)
fasthx/htmy.py

�[1;31mruff failed�[0m
�[1mCause:�[0m Failed to load configuration /ruff.toml
�[1mCause:�[0m Failed to parse /ruff.toml
�[1mCause:�[0m TOML parse error at line 26, column 3
|
26 | "RSE100", # Use of assert detected
| ^^^^^^^^
Unknown rule selector: RSE100

tests/test_htmy.py

�[1;31mruff failed�[0m
�[1mCause:�[0m Failed to load configuration /ruff.toml
�[1mCause:�[0m Failed to parse /ruff.toml
�[1mCause:�[0m TOML parse error at line 26, column 3
|
26 | "RSE100", # Use of assert detected
| ^^^^^^^^
Unknown rule selector: RSE100


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🔭 Outside diff range comments (1)
fasthx/jinja.py (1)

316-332: Update docstring to reflect the renamed return type.

The return type annotation has been correctly updated to RenderFunction[Any], but the docstring still references the old HTMLRenderer type.

     def _make_render_function(
         self,
         template: ComponentSelector[str],
         *,
         make_context: JinjaContextFactory,
         prefix: str | None,
         error_renderer: bool = False,
     ) -> RenderFunction[Any]:
         """
-        Creates an `HTMLRenderer` with the given configuration.
+        Creates a `RenderFunction` with the given configuration.
 
         Arguments:
             template: The template the renderer function should use.
             make_context: The Jinja rendering context factory to use.
             prefix: Optional template name prefix.
             error_renderer: Whether this is an error renderer creation.
         """
🧹 Nitpick comments (6)
docs/index.md (1)

46-46: Spelling: “Interally” → “Internally”
Minor typo right after the changed paragraph.

-Interally, FastHX decorators always have access …
+Internally, FastHX decorators always have access …
docs/examples/custom-templating.md (2)

23-23: Loosened type hint may hide bugs
Switching result from a concrete list[dict[str, str]] to Any sacrifices static-type safety and defeats the explanatory comment on lines 21-22. Consider restoring the specific type or introducing a TypeVar/generic if flexibility is required.


14-14: Typo: “dependecy” → “dependency”

-# Create a dependecy to see that its return value …
+# Create a dependency to see that its return value …
pyproject.toml (1)

3-3: Version bump to 3.0.0: remember CHANGELOG & breaking-change notice
Major version implies breaking changes; verify CHANGELOG.md or release notes are updated accordingly.

examples/custom-rendering/custom_rendering_app.py (1)

34-35: Out-of-date comment
The explanatory comment about # type: ignore is now misleading because the ignore directives were removed. Please update or delete the comment block.

-# Note on the type ignore: it seems mypy generic resolution fails at
-# fastapi==0.111.0, at least on the first mypy run when there's no cache.
+# (comment removed – mypy ignore no longer necessary)
docs/migrations/2-to-3.md (1)

17-21: Consider improving readability of the replacement instructions.

While the migration steps are comprehensive and accurate, the repetitive "Replace" beginnings could be improved for better readability.

Consider using a more concise format:

-These are all typing-related changes and most likely not relevant to your project unless you have created custom render functions or integrations.
-
-- Replace `from fasthx import HTMLRenderer` with `from fasthx import RenderFunction`.
-- Replace `from fasthx.typing import HTMLRenderer` with `from fasthx.typing import RenderFunction`.
-- Replace `from fasthx.typing import SyncHTMLRenderer` with `from fasthx.typing import SyncRenderFunction`.
-- Replace `from fasthx.typing import AsyncHTMLRenderer` with `from fasthx.typing import AsyncRenderFunction`.
+These are all typing-related changes and most likely not relevant to your project unless you have created custom render functions or integrations.
+
+**Import changes:**
+- `from fasthx import HTMLRenderer` → `from fasthx import RenderFunction`
+- `from fasthx.typing import HTMLRenderer` → `from fasthx.typing import RenderFunction`
+- `from fasthx.typing import SyncHTMLRenderer` → `from fasthx.typing import SyncRenderFunction`
+- `from fasthx.typing import AsyncHTMLRenderer` → `from fasthx.typing import AsyncRenderFunction`
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08e2a31 and 28a1a2e.

📒 Files selected for processing (21)
  • README.md (2 hunks)
  • docs/api/core-decorators.md (1 hunks)
  • docs/api/dependencies.md (1 hunks)
  • docs/api/jinja.md (1 hunks)
  • docs/api/typing.md (1 hunks)
  • docs/examples/custom-templating.md (1 hunks)
  • docs/examples/htmy.md (6 hunks)
  • docs/examples/jinja-templating.md (3 hunks)
  • docs/index.md (1 hunks)
  • docs/migrations/2-to-3.md (1 hunks)
  • examples/custom-rendering/custom_rendering_app.py (2 hunks)
  • examples/htmy-rendering/htmy_app.py (5 hunks)
  • examples/jinja-rendering/jinja_app.py (1 hunks)
  • fasthx/__init__.py (1 hunks)
  • fasthx/core_decorators.py (2 hunks)
  • fasthx/htmy.py (4 hunks)
  • fasthx/jinja.py (3 hunks)
  • fasthx/typing.py (4 hunks)
  • mkdocs.yaml (1 hunks)
  • pyproject.toml (2 hunks)
  • tests/test_jinja.py (5 hunks)
🧬 Code Graph Analysis (4)
fasthx/htmy.py (2)
fasthx/typing.py (1)
  • RequestComponentSelector (53-84)
fasthx/jinja.py (1)
  • _make_render_function (316-347)
tests/test_jinja.py (2)
fasthx/htmy.py (1)
  • ComponentHeader (24-30)
fasthx/jinja.py (4)
  • ComponentHeader (218-224)
  • Jinja (228-414)
  • JinjaContext (49-215)
  • JinjaPath (35-46)
fasthx/__init__.py (1)
fasthx/typing.py (1)
  • RequestComponentSelector (53-84)
examples/jinja-rendering/jinja_app.py (1)
fasthx/jinja.py (1)
  • Jinja (228-414)
🪛 LanguageTool
docs/examples/htmy.md

[grammar] ~105-~105: Ensure spelling is correct
Context: ...basic HTML document structure with some TailwindCSS styling and metadata. There is also a b...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

docs/migrations/2-to-3.md

[style] ~19-~19: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.typing import RenderFunction. - Replace from fasthx.typing import SyncHTMLRend...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~20-~20: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.typing import SyncRenderFunction. - Replace from fasthx.typing import AsyncHTMLRen...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~28-~28: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...om fasthx.jinja import JinjaContext. - Replace from fasthx import JinjaPathwithfr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~29-~29: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...from fasthx.jinja import JinjaPath. - Replace from fasthx import TemplateHeader wit...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx.jinja import TemplateHeade...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~31-~31: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx import JinjaContextFactory...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.jinja import JinjaContextFactory. - Replace from fasthx.typing import JinjaContext...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🧰 Additional context used
🧬 Code Graph Analysis (4)
fasthx/htmy.py (2)
fasthx/typing.py (1)
  • RequestComponentSelector (53-84)
fasthx/jinja.py (1)
  • _make_render_function (316-347)
tests/test_jinja.py (2)
fasthx/htmy.py (1)
  • ComponentHeader (24-30)
fasthx/jinja.py (4)
  • ComponentHeader (218-224)
  • Jinja (228-414)
  • JinjaContext (49-215)
  • JinjaPath (35-46)
fasthx/__init__.py (1)
fasthx/typing.py (1)
  • RequestComponentSelector (53-84)
examples/jinja-rendering/jinja_app.py (1)
fasthx/jinja.py (1)
  • Jinja (228-414)
🪛 LanguageTool
docs/examples/htmy.md

[grammar] ~105-~105: Ensure spelling is correct
Context: ...basic HTML document structure with some TailwindCSS styling and metadata. There is also a b...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

docs/migrations/2-to-3.md

[style] ~19-~19: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.typing import RenderFunction. - Replace from fasthx.typing import SyncHTMLRend...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~20-~20: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.typing import SyncRenderFunction. - Replace from fasthx.typing import AsyncHTMLRen...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~28-~28: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...om fasthx.jinja import JinjaContext. - Replace from fasthx import JinjaPathwithfr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~29-~29: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...from fasthx.jinja import JinjaPath. - Replace from fasthx import TemplateHeader wit...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx.jinja import TemplateHeade...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~31-~31: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx import JinjaContextFactory...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.jinja import JinjaContextFactory. - Replace from fasthx.typing import JinjaContext...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (35)
docs/index.md (1)

44-44: Grammar fix looks good
The sentence now reads fluently.

pyproject.toml (1)

12-13: Runtime vs dev dependency drift
htmy is specified >=0.7.4 in runtime deps but still duplicated in [tool.poetry.group.dev.dependencies]. Duplication is fine, but ensure the spec stays identical to avoid confusion during upgrades.

examples/jinja-rendering/jinja_app.py (1)

7-7: Import path update acknowledged
Importing Jinja from fasthx.jinja matches the new package structure.

examples/custom-rendering/custom_rendering_app.py (1)

37-55: Good cleanup on removed type: ignores
The code now type-checks without suppressions—nice!

README.md (2)

44-44: Sentence is clear – no action required

The re-worded core-concept paragraph reads well and matches the new architecture.


100-106: Correct import path update looks good

Switching to fasthx.jinja.Jinja reflects the new package layout. No further changes needed here.

docs/examples/jinja-templating.md (4)

5-5: Good update – matches the new public API

The wording and import path (fasthx.jinja.Jinja) align with the refactor.


10-10: Import line updated correctly

ComponentHeader is now exposed from fasthx.jinja; example compiles.


46-49: Nice addition explaining ComponentHeader

Clear explanation, consistent with the type rename.


58-66: Example code LGTM

Decorator usage demonstrates the new selector API accurately.

tests/test_jinja.py (2)

10-10: LGTM: Import path updated correctly for Jinja refactoring.

The import statement correctly reflects the relocation of Jinja-related code to the fasthx.jinja package, which aligns with the PR's objective to modularize Jinja functionality.


53-53: LGTM: Consistent renaming of TemplateHeader to ComponentHeader.

All instances of TemplateHeader have been correctly updated to ComponentHeader throughout the test decorators, maintaining consistency with the broader refactoring that renamed this class to better reflect its purpose in component selection.

Also applies to: 69-69, 84-85, 103-104

mkdocs.yaml (2)

53-54: LGTM: Simplified navigation labels align with documentation restructuring.

The simplification of navigation entries for component_selectors.md and the lowercase labeling of htmy.md are consistent with the broader documentation consolidation approach mentioned in the AI summary.


59-59: LGTM: Essential migration guide added for v3 upgrade.

The addition of migrations/2-to-3.md is crucial for users upgrading from v2 to v3, given the significant structural changes in this release including the Jinja module reorganization and type renaming.

fasthx/__init__.py (1)

7-8: LGTM: Type imports updated to reflect v3 refactoring.

The replacement of HTMLRenderer with RenderFunction and addition of RequestComponentSelector correctly align with the PR objectives to:

  • Generalize rendering functions beyond HTML content
  • Provide the protocol interface for component selection
  • Remove deprecated type aliases while maintaining core functionality

The absence of Jinja-related imports is also appropriate, as they've been moved to the dedicated fasthx.jinja package.

docs/api/jinja.md (1)

1-4: LGTM: Documentation structure simplified to match module reorganization.

The consolidation from multiple explicit sections to a single fasthx.jinja directive correctly reflects the new module structure where all Jinja-related functionality is grouped together. This approach is cleaner, more maintainable, and consistent with the broader documentation restructuring effort.

fasthx/htmy.py (3)

12-12: LGTM: Import updated to use new RenderFunction type.

The replacement of HTMLRenderer with RenderFunction in the import correctly aligns with the global type alias renaming to support more generalized rendering beyond HTML content.


26-26: LGTM: Comment updated to reference correct protocol.

The comment correctly references RequestComponentSelector which is the appropriate protocol for component selection based on request headers.


200-200: LGTM: Return type annotations updated consistently.

Both _make_render_function and _make_error_render_function methods have their return types correctly updated from HTMLRenderer to RenderFunction, maintaining consistency with the global type alias renaming while preserving all functional behavior.

Also applies to: 217-217

docs/examples/htmy.md (2)

26-36: LGTM! Function-based component factory is cleaner.

The conversion from class-based UserListItem to a simple function factory user_list_item improves code readability and reduces boilerplate. The function directly returns the HTML element without requiring instantiation.


108-132: LGTM! Page component refactoring is consistent.

The index_page function factory follows the same pattern as the component refactoring, returning the HTML structure directly as a tuple. The route decorator correctly uses the function directly instead of wrapping it in a lambda.

docs/migrations/2-to-3.md (1)

1-37: Comprehensive migration guide covers all major changes.

The migration guide thoroughly documents all the breaking changes introduced in v3, providing clear upgrade paths for users. The organization into general, Jinja, and htmy sections makes it easy to follow.

fasthx/core_decorators.py (3)

10-10: LGTM! Type import updated consistently.

The import change from HTMLRenderer to RenderFunction aligns with the v3 refactoring goals to support non-HTML rendering.


15-18: LGTM! Decorator signatures updated consistently.

The type annotations in the hx decorator function signature correctly use the new RenderFunction type alias, maintaining the same functionality while supporting the broader rendering capabilities.


88-90: LGTM! Page decorator signature updated consistently.

The page decorator signature updates maintain consistency with the hx decorator changes, using RenderFunction instead of HTMLRenderer.

fasthx/typing.py (4)

11-11: LGTM! TypeAlias annotation added for clarity.

Making MaybeAsyncFunc explicitly a TypeAlias improves type clarity and follows best practices for type alias declarations.


14-27: LGTM! Protocol renamed and generalized appropriately.

The rename from SyncHTMLRenderer to SyncRenderFunction with updated docstring correctly reflects the broader scope of rendering beyond just HTML content.


48-49: LGTM! Union type alias updated consistently.

The RenderFunction type alias properly replaces HTMLRenderer and maintains the same union of sync and async render functions while supporting the generalized naming convention.


87-88: LGTM! ComponentSelector docstring generalized.

The updated docstring for ComponentSelector appropriately removes HTML-specific language to support broader component selection use cases.

examples/htmy-rendering/htmy_app.py (3)

25-31: LGTM! Component factory function is cleaner.

The conversion from UserListItem class to user_list_item function factory eliminates unnecessary boilerplate and directly returns the HTML element. This aligns with the same refactoring pattern used in the documentation examples.


87-110: LGTM! Index page refactored consistently.

The index_page function factory follows the same simplification pattern, returning the HTML structure directly as a tuple. The implementation maintains all original functionality while being more concise.


128-128: LGTM! Route decorator updated correctly.

The route decorator now uses index_page directly instead of requiring a wrapper, which is cleaner and consistent with the function factory approach.

fasthx/jinja.py (3)

1-12: Import changes align with the refactoring goals.

The updated imports properly support the new architecture with the relocated JinjaContextFactory protocol and renamed type annotations.


14-32: Well-structured protocol definition for Jinja context factories.

The JinjaContextFactory protocol is properly documented and its signature correctly matches the usage pattern throughout the codebase.


218-224: Clean implementation of the renamed component selector.

The ComponentHeader class properly inherits from the base _ComponentHeader[str] and maintains backward compatibility through clear documentation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3790558 and 764baac.

📒 Files selected for processing (2)
  • README.md (5 hunks)
  • docs/index.md (2 hunks)
🔇 Additional comments (1)
README.md (1)

106-112: Import path change looks correct

Moving the import to fasthx.jinja reflects the new package layout and removes the old top-level alias. No issues spotted.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
README.md (1)

153-160: Add missing RenderFunction import (repeat of earlier feedback)

Example instructs readers to implement RenderFunction but never shows where it comes from, which may confuse newcomers.

-from fasthx import hx, page
+from fasthx import hx, page
+from fasthx.typing import RenderFunction  # protocol used below
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 764baac and 12745c0.

📒 Files selected for processing (2)
  • README.md (5 hunks)
  • docs/index.md (2 hunks)
🧰 Additional context used
🪛 LanguageTool
README.md

[grammar] ~29-~29: There might be a mistake here.
Context: ... "Thank you for your work on htmy and fasthx, both have been very pleasant to use, an...

(QB_NEW_EN_OTHER)


[grammar] ~50-~50: Use correct spacing
Context: ...er using a declarative, decorator-based approach. Internally, FastHX decorators always hav...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~52-~52: Use correct spacing
Context: ...he rendering engine integration of your choice. The ComponentSelector abstraction make...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~106-~106: There might be a mistake here.
Context: ...you need to do is create an instance of fasthx.jinja.Jinja and use its hx() or page() methods...

(QB_NEW_EN_OTHER)


[grammar] ~106-~106: There might be a mistake here.
Context: ...ally renders HTML. See the example code below: python from fastapi import FastAPI from fastapi.templating import Jinja2Templates from fasthx.jinja import Jinja from pydantic import BaseModel # Pydantic model of the data the example API is using. class User(BaseModel): first_name: str last_name: str # Create the app. app = FastAPI() # Create a FastAPI Jinja2Templates instance and use it to create a # FastHX Jinja instance that will serve as your decorator. jinja = Jinja(Jinja2Templates("templates")) @app.get("/") @jinja.page("index.html") def index() -> None: ... @app.get("/user-list") @jinja.hx("user-list.html") async def htmx_or_data() -> list[User]: return [ User(first_name="John", last_name="Lennon"), User(first_name="Paul", last_name="McCartney"), User(first_name="George", last_name="Harrison"), User(first_name="Ringo", last_name="Starr"), ] @app.get("/admin-list") @jinja.hx("user-list.html", no_data=True) def htmx_only() -> list[User]: return [User(first_name="Billy", last_name="Shears")] ...

(QB_NEW_EN_OTHER)


[grammar] ~153-~153: Use correct spacing
Context: ...to do is implement the RenderFunction protocol. Similarly to the Jinja case, hx() only...

(QB_NEW_EN_OTHER_ERROR_IDS_5)

🔇 Additional comments (2)
docs/index.md (1)

25-30: Consistent “Testimonials” heading looks good

The rename from “Opinions” to “Testimonials” matches the docs style guide and keeps wording in sync with the README.
No further action needed.

README.md (1)

106-112: Correct import path for Jinja — LGTM

Switching the import to from fasthx.jinja import Jinja accurately reflects the new package layout introduced in v3.
Example now compiles without ImportError.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🔭 Outside diff range comments (2)
fasthx/htmy.py (2)

49-51: Typo in docstring

“the there’s” → “there’s”.

-            KeyError: If the there's no `Request` in the context.
+            KeyError: If there's no `Request` in the context.

200-215: Minor duplication: factor out component resolution

The component resolution logic is duplicated in both render functions. Consider a small helper to DRY it up.

def _resolve_component(
    selector: HTMYComponentSelector[Any],
    request: Request,
    error: Exception | None,
) -> h.Component:
    chosen = selector.get_component(request, error) if isinstance(selector, RequestComponentSelector) else selector
    return chosen

And then:

component = self._resolve_component(component_selector, request, None)
# ...
component = self._resolve_component(component_selector, request, result)

Also applies to: 217-235

♻️ Duplicate comments (1)
README.md (1)

155-157: Clarify RenderFunction import in the “Custom templating” section

The text asks users to “implement the RenderFunction protocol,” but the example never shows where that comes from. Add an explicit import to prevent confusion.

Add after the other imports in the example:

from fasthx.typing import RenderFunction  # for type checkers

Also, remove the double space after the period in “…protocol. Similarly…”.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 12745c0 and f00b676.

📒 Files selected for processing (4)
  • README.md (5 hunks)
  • docs/index.md (2 hunks)
  • docs/migrations/2-to-3.md (1 hunks)
  • fasthx/htmy.py (7 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
fasthx/htmy.py (2)
fasthx/typing.py (1)
  • RequestComponentSelector (53-84)
fasthx/jinja.py (2)
  • render (334-345)
  • _make_render_function (316-347)
🪛 LanguageTool
docs/migrations/2-to-3.md

[style] ~19-~19: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.typing import RenderFunction. - Replace from fasthx.typing import SyncHTMLRend...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~20-~20: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.typing import SyncRenderFunction. - Replace from fasthx.typing import AsyncHTMLRen...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~28-~28: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...om fasthx.jinja import JinjaContext. - Replace from fasthx import JinjaPathwithfr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~29-~29: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...from fasthx.jinja import JinjaPath. - Replace from fasthx import TemplateHeader wit...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx.jinja import TemplateHeade...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~31-~31: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx import JinjaContextFactory...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.jinja import JinjaContextFactory. - Replace from fasthx.typing import JinjaContext...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

README.md

[grammar] ~31-~31: There might be a mistake here.
Context: ... "Thank you for your work on htmy and fasthx, both have been very pleasant to use, an...

(QB_NEW_EN_OTHER)


[grammar] ~52-~52: Use correct spacing
Context: ...er using a declarative, decorator-based approach. Internally, FastHX decorators always hav...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~54-~54: Use correct spacing
Context: ...he rendering engine integration of your choice. The ComponentSelector abstraction make...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~108-~108: There might be a mistake here.
Context: ...ally renders HTML. See the example code below: python from fastapi import FastAPI from fastapi.templating import Jinja2Templates from fasthx.jinja import Jinja from pydantic import BaseModel # Pydantic model of the data the example API is using. class User(BaseModel): first_name: str last_name: str # Create the app. app = FastAPI() # Create a FastAPI Jinja2Templates instance and use it to create a # FastHX Jinja instance that will serve as your decorator. jinja = Jinja(Jinja2Templates("templates")) @app.get("/") @jinja.page("index.html") def index() -> None: ... @app.get("/user-list") @jinja.hx("user-list.html") async def htmx_or_data() -> list[User]: return [ User(first_name="John", last_name="Lennon"), User(first_name="Paul", last_name="McCartney"), User(first_name="George", last_name="Harrison"), User(first_name="Ringo", last_name="Starr"), ] @app.get("/admin-list") @jinja.hx("user-list.html", no_data=True) def htmx_only() -> list[User]: return [User(first_name="Billy", last_name="Shears")] ...

(QB_NEW_EN_OTHER)


[grammar] ~155-~155: Use correct spacing
Context: ...to do is implement the RenderFunction protocol. Similarly to the Jinja case, hx() only...

(QB_NEW_EN_OTHER_ERROR_IDS_5)

🔇 Additional comments (6)
docs/index.md (1)

25-32: Good rename to “Testimonials”

This aligns with the docs tone elsewhere and addresses prior consistency feedback.

README.md (3)

25-32: Good addition of “Testimonials”

Consistent with docs/index.md; improves social proof.


108-114: Jinja import path looks good

Using “from fasthx.jinja import Jinja” reflects the new import location.


168-168: Nice touch on showing dependency values in render functions

Good example demonstrating that Depends results are available via the context.

fasthx/htmy.py (2)

115-116: Good: property rename to renderer applied consistently

Docs, field, and call sites all updated (self.renderer.render). Matches the v3 migration notes.

Also applies to: 118-118, 198-199


200-215: No action needed: RequestComponentSelector is runtime-checkable
Verified in fasthx/typing.py (lines 52–53) that RequestComponentSelector is decorated with @runtime_checkable. The isinstance check in _make_render_function is safe.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (2)
fasthx/htmy.py (2)

200-216: Variable naming nit: component holds a factory, not a component.

Renaming improves readability and avoids confusion between a component instance and its factory.

-        async def render(result: T, *, context: dict[str, Any], request: Request) -> str:
-            component = (
+        async def render(result: T, *, context: dict[str, Any], request: Request) -> str:
+            factory = (
                 component_selector.get_component(request, None)
                 if isinstance(component_selector, RequestComponentSelector)
                 else component_selector
             )
-            return await self.renderer.render(
-                component(result), self._make_render_context(request, context)
-            )
+            return await self.renderer.render(
+                factory(result), self._make_render_context(request, context)
+            )

219-235: Apply the same naming tweak in the error renderer.

-        async def render(result: Exception, *, context: dict[str, Any], request: Request) -> str:
-            component = (
+        async def render(result: Exception, *, context: dict[str, Any], request: Request) -> str:
+            factory = (
                 component_selector.get_component(request, result)
                 if isinstance(component_selector, RequestComponentSelector)
                 else component_selector
             )
-            return await self.renderer.render(
-                component(result), self._make_render_context(request, context)
-            )
+            return await self.renderer.render(
+                factory(result), self._make_render_context(request, context)
+            )
♻️ Duplicate comments (3)
docs/migrations/2-to-3.md (3)

3-3: Fix minor grammar for clarity.

Replace “among other, smaller improvements” with “among other smaller improvements”.

-`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set of the project grew significantly since then, for example with error rendering support and `htmy` integration, among other, smaller improvements.
+`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set of the project grew significantly since then, for example with error rendering support and `htmy` integration, among other smaller improvements.

24-24: Correct modal verb usage (“only be imported”).

-These are mostly import changes — all the Jinja-related utilities can now only imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.
+These are mostly import changes — all the Jinja-related utilities can now only be imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.

33-33: Remove unnecessary comma for smoother reading.

-- Instead of the `templates` argument of `TemplateHeader()`, you must use the `components` argument of `ComponentHeader`, if you passed `templates` as a keyword argument.
+- Instead of the `templates` argument of `TemplateHeader()`, you must use the `components` argument of `ComponentHeader` if you passed `templates` as a keyword argument.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f00b676 and f4d5a83.

📒 Files selected for processing (2)
  • docs/migrations/2-to-3.md (1 hunks)
  • fasthx/htmy.py (8 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
fasthx/htmy.py (2)
fasthx/typing.py (1)
  • RequestComponentSelector (53-84)
fasthx/jinja.py (2)
  • render (334-345)
  • _make_render_function (316-347)
🪛 LanguageTool
docs/migrations/2-to-3.md

[grammar] ~1-~1: Use correct spacing
Context: # From v2 to v3 fasthx was first developed with Jinja templati...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~3-~3: There might be a problem here.
Context: ...ndering in mind. The feature set of the project grew significantly since then, for example w...

(QB_NEW_EN_MERGED_MATCH)


[grammar] ~3-~3: Use correct spacing
Context: ...htmy` integration, among other, smaller improvements. More features and integrations are plann...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~5-~5: Use correct spacing
Context: ...is to prepare the project structure for them. Summary of major changes: - All Jinja-r...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~7-~7: There might be a mistake here.
Context: ...t structure for them. Summary of major changes: - All Jinja-related code now lives in `fa...

(QB_NEW_EN_OTHER)


[grammar] ~10-~10: Use correct spacing
Context: ...ted from that package. - *HTMLRenderer types have been renamed to *RenderFunction ...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~11-~11: Use correct spacing
Context: ... Updated the required htmy version to >=0.7.4. ## Upgrade steps (general) These are all t...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~13-~13: Use correct spacing
Context: ...version to >=0.7.4. ## Upgrade steps (general) These are all typing-related changes and...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~15-~15: Use correct spacing
Context: ...have created custom render functions or integrations. - Replace `from fasthx import HTMLRenderer...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[style] ~19-~19: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.typing import RenderFunction. - Replace from fasthx.typing import SyncHTMLRend...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~20-~20: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.typing import SyncRenderFunction. - Replace from fasthx.typing import AsyncHTMLRen...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[grammar] ~20-~20: Use correct spacing
Context: ...x.typing import AsyncHTMLRendererwithfrom fasthx.typing import AsyncRenderFunction`. ## Upgrade steps (Jinja) These are mostly ...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~22-~22: Use correct spacing
Context: ...AsyncRenderFunction`. ## Upgrade steps (Jinja) These are mostly import changes — all th...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~24-~24: There might be a mistake here.
Context: ... steps (Jinja) These are mostly import changes — all the Jinja-related utilities can now ...

(QB_NEW_EN_OTHER)


[grammar] ~24-~24: Use modal and auxiliary verbs correctly
Context: ...all the Jinja-related utilities can now only imported from fasthx.jinja — and the ...

(QB_NEW_EN_OTHER_ERROR_IDS_24)


[grammar] ~24-~24: There might be a mistake here.
Context: ...ed utilities can now only imported from fasthx.jinja — and the renaming of TemplateHeader...

(QB_NEW_EN_OTHER)


[grammar] ~24-~24: Use correct spacing
Context: ...and the renaming of TemplateHeader to ComponentHeader. - Replace from fasthx import Jinja with ...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[style] ~28-~28: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...om fasthx.jinja import JinjaContext. - Replace from fasthx import JinjaPathwithfr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~29-~29: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...from fasthx.jinja import JinjaPath. - Replace from fasthx import TemplateHeader wit...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx.jinja import TemplateHeade...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~31-~31: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx import JinjaContextFactory...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.jinja import JinjaContextFactory. - Replace from fasthx.typing import JinjaContext...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[grammar] ~33-~33: There might be a mistake here.
Context: ...u must use the components argument of ComponentHeader, if you passed templates as a keyword...

(QB_NEW_EN_OTHER)


[grammar] ~33-~33: Use correct spacing
Context: ... if you passed templates as a keyword argument. ## Upgrade steps (htmy) - Make sure you'...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~35-~35: Use correct spacing
Context: ...s a keyword argument. ## Upgrade steps (htmy) - Make sure you're using htmy version `>...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~38-~38: There might be a mistake here.
Context: ...HTMY instance no longer has an htmy property, it is replaced by the renderer proper...

(QB_NEW_EN_OTHER)

🔇 Additional comments (3)
fasthx/htmy.py (3)

12-12: Import/type updates align with v3 API (HTMLRenderer → RenderFunction).

The switch to RenderFunction/MaybeAsyncFunc/P/T is consistent with the broader refactor.


198-199: Render delegation updated to self.renderer — good.

Directly rendering with the injected/default renderer maintains behavior while matching the new API.


118-119: No stale .htmy property references remain — rename to renderer is safe
I’ve searched for any .htmy attribute usage and only found module imports (from fasthx.htmy import …) and documentation mentions, which are expected. There are no remaining .htmy property references in code or docs.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
pyproject.toml (1)

33-35: Build backend explicitly set to poetry-core — good.

This improves build reproducibility. Optionally set a minimal version if you rely on newer features, e.g., requires = ["poetry-core>=1.8.0"].

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between f4d5a83 and 3fbf95d.

📒 Files selected for processing (1)
  • pyproject.toml (2 hunks)
🔇 Additional comments (3)
pyproject.toml (3)

3-3: SemVer major bump to 3.0.0 looks appropriate.

Aligns with breaking API changes in v3 (Jinja relocation, type renames). No concerns.


23-31: Dev docs/tooling bumps: verify compatibility (mkdocs-material, mkdocstrings, ruff, mypy).

These are sizable version jumps. mkdocstrings 0.30 introduced some changes around handlers/config; ruff config keys also evolved across 0.11→0.12 (you’ve already moved to lint.select which is correct). Suggest running a strict docs build and lint pass locally/CI.

Run locally:

  • mkdocs build --strict
  • poe static-checks
  • poe test

If anything fails, I can help generate targeted config changes.


69-79: Ignore the Poe sequence configuration concern – it’s valid as is

The dotted assignments for static-checks.sequence and static-checks.ignore_fail = "return_non_zero" are both supported by TOML and PoeThePoet (v0.36.0). No changes needed here.

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
fasthx/htmy.py (1)

64-66: Typo in docstring: getitem_ has an extra underscore.

Minor doc fix to reference the correct dunder method.

-    `__contains__`, `__getitem___()`, and `get()`. For more complex use-cases, you can rely on the
+    `__contains__`, `__getitem__()`, and `get()`. For more complex use-cases, you can rely on the
♻️ Duplicate comments (2)
docs/migrations/2-to-3.md (1)

3-3: Minor grammar and clarity nits in the migration guide.

Applies small fixes for readability and consistency.

-`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set of the project grew significantly since then, for example with error rendering support and `htmy` integration, among other, smaller improvements.
+`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set of the project grew significantly since then, for example with error rendering support and `htmy` integration, among other smaller improvements.
-These are mostly import changes — all the Jinja-related utilities can now only imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.
+These are mostly import changes — all the Jinja-related utilities can now only be imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.
-- Instead of the `templates` argument of `TemplateHeader()`, you must use the `components` argument of `ComponentHeader`, if you passed `templates` as a keyword argument.
+- Instead of the `templates` argument of `TemplateHeader()`, you must use the `components` argument of `ComponentHeader`, if you passed `templates` as a keyword argument.

Also applies to: 24-24, 33-33

fasthx/htmy.py (1)

26-28: Docstring phrasing nit (make the sentence read naturally).

Tighten the wording.

-    `RequestComponentSelector` for HTMY components that selects the rendered component
-    based on a request header.
+    A `RequestComponentSelector` for HTMY components that selects the component to render
+    based on a request header.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 3fbf95d and 11c2432.

📒 Files selected for processing (3)
  • docs/migrations/2-to-3.md (1 hunks)
  • fasthx/htmy.py (8 hunks)
  • pyproject.toml (2 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/migrations/2-to-3.md

[style] ~19-~19: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.typing import RenderFunction. - Replace from fasthx.typing import SyncHTMLRend...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~20-~20: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.typing import SyncRenderFunction. - Replace from fasthx.typing import AsyncHTMLRen...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~28-~28: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...om fasthx.jinja import JinjaContext. - Replace from fasthx import JinjaPathwithfr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~29-~29: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...from fasthx.jinja import JinjaPath. - Replace from fasthx import TemplateHeader wit...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx.jinja import TemplateHeade...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~31-~31: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx import JinjaContextFactory...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.jinja import JinjaContextFactory. - Replace from fasthx.typing import JinjaContext...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)

🔇 Additional comments (3)
fasthx/htmy.py (3)

198-199: LGTM: Consistent switch to self.renderer for normal render path.

Using self.renderer.render and returning a RenderFunction[T] aligns with the v3 refactor and the new typing.

Also applies to: 200-216


219-233: LGTM: Consistent switch to self.renderer for error render path.

Error renderer now also uses self.renderer and the RenderFunction[Exception] return type. Looks correct.


115-116: RendererType annotation confirmed
htmy 0.8.1+ does export a public type alias RendererType for its renderer call-signature. Using

renderer: RendererType = field(default_factory=Renderer)

in fasthx/htmy.py (lines 115–116 and 118–119) is correct—just ensure you import it via

from htmy import RendererType

and no fallback to Renderer as an annotation is needed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🔭 Outside diff range comments (5)
fasthx/core_decorators.py (2)

101-101: Fix page() wrapper return annotation

The wrapper always returns a Response (either HTMLResponse or a Response returned by the route). The current annotation suggests it might return T, which it never does.

-        ) -> T | Response:
+        ) -> Response:

119-130: Align page() with the str-only RenderFunction contract

With RenderFunction required to return str, the else branch returning “rendered” is dead code. Simplify and always wrap in HTMLResponse, like hx().

-            return (
-                HTMLResponse(
-                    rendered,
-                    # The default status code of the FastAPI Response dependency is None
-                    # (not allowed by the typing but required for FastAPI).
-                    status_code=getattr(response, "status_code", 200) or 200,
-                    headers=getattr(response, "headers", None),
-                    background=getattr(response, "background", None),
-                )
-                if isinstance(rendered, str)
-                else rendered
-            )
+            return HTMLResponse(
+                rendered,
+                # The default status code of the FastAPI Response dependency is None
+                # (not allowed by the typing but required for FastAPI).
+                status_code=getattr(response, "status_code", 200) or 200,
+                headers=getattr(response, "headers", None),
+                background=getattr(response, "background", None),
+            )
fasthx/jinja.py (3)

78-81: Avoid treating str/bytes as generic Collections in unpack_object()

str and bytes are Collections and will currently be wrapped as {"items": obj}, which is surprising. Exclude them from the “Collection” branch.

-        # Covers lists, tuples, sets, etc..
-        if isinstance(obj, Collection):
+        # Covers lists, tuples, sets, etc.; exclude str/bytes-like.
+        if isinstance(obj, Collection) and not isinstance(obj, (str, bytes, bytearray)):
             return {"items": obj}

88-96: Avoid shadowing cls; minor grammar fix

  • Renaming the local cls variable prevents shadowing the classmethod parameter cls, improving readability.
  • Typo: “with with slots”.
-            cls = type(obj)
-            if hasattr(cls, "model_computed_fields"):  # Pydantic computed fields support.
+            obj_cls = type(obj)
+            if hasattr(obj_cls, "model_computed_fields"):  # Pydantic computed fields support.
                 object_keys = [
                     *(() if object_keys is None else object_keys),
-                    *cls.model_computed_fields,
+                    *obj_cls.model_computed_fields,
                 ]
         elif hasattr(obj, "__slots__"):
-            # Covers classes with with __slots__.
+            # Covers classes with __slots__.
             object_keys = obj.__slots__

194-194: Typo in docstring

“whih” → “which”.

-            context_key: The key by whih the `route_context` should be accessible in templates.
+            context_key: The key by which the `route_context` should be accessible in templates.
♻️ Duplicate comments (3)
docs/migrations/2-to-3.md (3)

3-3: Fix verb tense and comma usage in the intro

“grew significantly since then” should be present perfect, and the comma before “smaller improvements” is unnecessary.

-`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set of the project grew significantly since then, for example with error rendering support and `htmy` integration, among other, smaller improvements.
+`fasthx` was first developed with Jinja templating and HTML rendering in mind. The project's feature set has grown significantly since then, for example with error rendering support and `htmy` integration, among other smaller improvements.

25-25: Grammar: missing “be”

“…can now only imported…” → “…can now only be imported…”.

-These are mostly import changes — all the Jinja-related utilities can now only imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.
+These are mostly import changes — all the Jinja-related utilities can now only be imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.

34-34: Minor clarity and comma

Add “of” after “argument” and drop the comma before the conditional clause.

-- Instead of the `templates` argument of `TemplateHeader()`, you must use the `components` argument of `ComponentHeader`, if you passed `templates` as a keyword argument.
+- Instead of the `templates` argument of `TemplateHeader()`, you must use the `components` argument of `ComponentHeader` if you passed `templates` as a keyword argument.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 7bb3df0 and 24aee69.

📒 Files selected for processing (4)
  • docs/migrations/2-to-3.md (1 hunks)
  • fasthx/core_decorators.py (3 hunks)
  • fasthx/jinja.py (4 hunks)
  • fasthx/typing.py (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
fasthx/jinja.py (4)
fasthx/htmy.py (5)
  • ComponentHeader (24-30)
  • hx (135-156)
  • page (158-178)
  • render (205-213)
  • render (224-232)
fasthx/core_decorators.py (2)
  • hx (14-80)
  • page (83-141)
fasthx/typing.py (1)
  • RequestComponentSelector (51-82)
tests/test_jinja.py (1)
  • error (93-98)
🪛 LanguageTool
docs/migrations/2-to-3.md

[grammar] ~1-~1: Use correct spacing
Context: # From v2 to v3 fasthx was first developed with Jinja templati...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~3-~3: Use the right verb tense
Context: ...in mind. The feature set of the project grew significantly since then, for example w...

(QB_NEW_EN_OTHER_ERROR_IDS_13)


[grammar] ~3-~3: Use correct spacing
Context: ...tion, among other, smaller improvements. More features and integrations are plann...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~5-~5: Use correct spacing
Context: ... prepare the project structure for them. Summary of major changes: - All Jinja-r...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~7-~7: Use correct spacing
Context: ...ure for them. Summary of major changes: - All Jinja-related code now lives in `fas...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~10-~10: Use correct spacing
Context: ...ted from that package. - *HTMLRenderer types have been renamed to `*RenderFunct...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~10-~10: There might be a mistake here.
Context: ... prepare for rendering non-HTML content. - The RenderFunction type has changed, `...

(QB_NEW_EN)


[grammar] ~11-~11: There might be a mistake here.
Context: ...ontent. - The RenderFunction type has changed, Response is no longer allowed as the ...

(QB_NEW_EN_OTHER)


[grammar] ~11-~11: There might be a mistake here.
Context: ...s no longer allowed as the return value. - Updated the required htmy version to `...

(QB_NEW_EN)


[grammar] ~12-~12: Use correct spacing
Context: ...he required htmy version to >=0.8.1. ## Upgrade steps (general) These are all t...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~14-~14: Use correct spacing
Context: ...o >=0.8.1. ## Upgrade steps (general) These are all typing-related changes and...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~16-~16: Use correct spacing
Context: ...custom render functions or integrations. - Replace `from fasthx import HTMLRenderer...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[style] ~20-~20: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.typing import RenderFunction. - Replace from fasthx.typing import SyncHTMLRend...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~21-~21: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.typing import SyncRenderFunction. - Replace from fasthx.typing import AsyncHTMLRen...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[grammar] ~21-~21: Use correct spacing
Context: ...sthx.typing import AsyncRenderFunction`. ## Upgrade steps (Jinja) These are mostly ...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~23-~23: Use correct spacing
Context: ...nderFunction`. ## Upgrade steps (Jinja) These are mostly import changes — all th...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~25-~25: There might be a mistake here.
Context: ... steps (Jinja) These are mostly import changes — all the Jinja-related utilities can now onl...

(QB_NEW_EN_OTHER)


[grammar] ~25-~25: Use modal and auxiliary verbs correctly
Context: ...all the Jinja-related utilities can now only imported from fasthx.jinja — and the ...

(QB_NEW_EN_OTHER_ERROR_IDS_24)


[grammar] ~25-~25: There might be a mistake here.
Context: ...ed utilities can now only imported from fasthx.jinja — and the renaming of TemplateHeader to `Co...

(QB_NEW_EN)


[grammar] ~25-~25: Use correct spacing
Context: ...f TemplateHeader to ComponentHeader. - Replace from fasthx import Jinja with ...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[style] ~29-~29: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...om fasthx.jinja import JinjaContext. - Replace from fasthx import JinjaPathwithfr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...from fasthx.jinja import JinjaPath. - Replace from fasthx import TemplateHeader wit...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~31-~31: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx.jinja import TemplateHeade...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx import JinjaContextFactory...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~33-~33: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.jinja import JinjaContextFactory. - Replace from fasthx.typing import JinjaContext...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[grammar] ~34-~34: Use commas correctly
Context: ...omponentsargument ofComponentHeader, if you passed templates` as a keyword ...

(QB_NEW_EN_OTHER_ERROR_IDS_33)


[grammar] ~34-~34: There might be a problem here.
Context: ...assed templates as a keyword argument. - Jinja._make_response() has been removed to simplify the codebas...

(QB_NEW_EN_MERGED_MATCH)


[grammar] ~35-~35: Use correct spacing
Context: ...Jinja._make_render_function() instead. ## Upgrade steps (htmy) - Make sure you'...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~37-~37: Use correct spacing
Context: ...n() instead. ## Upgrade steps (htmy) - Make sure you're using htmyversion>...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~40-~40: Use correct spacing
Context: ...een replaced by the renderer property. ## Upgrade steps (custom rendering) - `Ren...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~43-~43: There might be a problem here.
Context: ...y. ## Upgrade steps (custom rendering) - RenderFunction must return a str, Response is no lo...

(QB_NEW_EN_MERGED_MATCH)


[grammar] ~45-~45: There might be a mistake here.
Context: ...ring) - RenderFunction must return a str, Response is no longer allowed.

(QB_NEW_EN_OTHER)


[grammar] ~45-~45: There might be a mistake here.
Context: ... str, Response is no longer allowed.

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.17.2)
docs/migrations/2-to-3.md

42-42: Multiple consecutive blank lines
Expected: 1; Actual: 2

(MD012, no-multiple-blanks)

🔇 Additional comments (2)
fasthx/typing.py (1)

14-18: Rename to RenderFunction and str-only contracts look correct

The type and protocol renames are consistent with the v3 migration. Enforcing str return type for renderers aligns with the updated decorators.

Also applies to: 30-33, 46-47

fasthx/core_decorators.py (1)

62-69: Good: hx now consistently returns HTMLResponse for rendered strings

Wrapping the rendered content in HTMLResponse ensures consistent response semantics and aligns with the new str-only renderer contract.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (3)
docs/migrations/2-to-3.md (3)

3-3: Fix tense and punctuation for readability

Use present perfect with “since then” and remove the unnecessary comma.

-`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set of the project grew significantly since then, for example with error rendering support and `htmy` integration, among other, smaller improvements.
+`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set has grown significantly since then—for example, with error rendering support and `htmy` integration—among other smaller improvements.

25-25: Grammar: insert missing auxiliary verb

“can now only imported” → “can now only be imported.”

-These are mostly import changes — all the Jinja-related utilities can now only imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.
+These are mostly import changes — all the Jinja-related utilities can now only be imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.

44-44: Avoid comma splice in list item

Use a semicolon for two independent clauses.

-`RenderFunction` must return a `str`, `Response` is no longer allowed.
+`RenderFunction` must return a `str`; `Response` is no longer allowed.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 24aee69 and fa8ff79.

📒 Files selected for processing (1)
  • docs/migrations/2-to-3.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/migrations/2-to-3.md

[grammar] ~1-~1: Use correct spacing
Context: # From v2 to v3 fasthx was first developed with Jinja templati...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~3-~3: Use the right verb tense
Context: ...in mind. The feature set of the project grew significantly since then, for example w...

(QB_NEW_EN_OTHER_ERROR_IDS_13)


[grammar] ~3-~3: Use correct spacing
Context: ...tion, among other, smaller improvements. More features and integrations are plann...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~5-~5: Use correct spacing
Context: ... prepare the project structure for them. Summary of major changes: - All Jinja-r...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~7-~7: Use correct spacing
Context: ...ure for them. Summary of major changes: - All Jinja-related code now lives in `fas...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~10-~10: Use correct spacing
Context: ...ted from that package. - *HTMLRenderer types have been renamed to `*RenderFunct...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~10-~10: There might be a mistake here.
Context: ... prepare for rendering non-HTML content. - The RenderFunction type has changed: `...

(QB_NEW_EN)


[grammar] ~12-~12: Use correct spacing
Context: ...he required htmy version to >=0.8.1. ## Upgrade steps (general) These are all t...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~14-~14: Use correct spacing
Context: ...o >=0.8.1. ## Upgrade steps (general) These are all typing-related changes and...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~16-~16: Use correct spacing
Context: ...custom render functions or integrations. - Replace `from fasthx import HTMLRenderer...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[style] ~20-~20: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.typing import RenderFunction. - Replace from fasthx.typing import SyncHTMLRend...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~21-~21: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.typing import SyncRenderFunction. - Replace from fasthx.typing import AsyncHTMLRen...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[grammar] ~21-~21: Use correct spacing
Context: ...sthx.typing import AsyncRenderFunction`. ## Upgrade steps (Jinja) These are mostly ...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~23-~23: Use correct spacing
Context: ...nderFunction`. ## Upgrade steps (Jinja) These are mostly import changes — all th...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~25-~25: There might be a mistake here.
Context: ... steps (Jinja) These are mostly import changes — all the Jinja-related utilities can now onl...

(QB_NEW_EN_OTHER)


[grammar] ~25-~25: Use modal and auxiliary verbs correctly
Context: ...all the Jinja-related utilities can now only imported from fasthx.jinja — and the ...

(QB_NEW_EN_OTHER_ERROR_IDS_24)


[grammar] ~25-~25: There might be a mistake here.
Context: ...ed utilities can now only imported from fasthx.jinja — and the renaming of TemplateHeader to `Co...

(QB_NEW_EN)


[grammar] ~25-~25: Use correct spacing
Context: ...f TemplateHeader to ComponentHeader. - Replace from fasthx import Jinja with ...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[style] ~29-~29: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...om fasthx.jinja import JinjaContext. - Replace from fasthx import JinjaPathwithfr...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~30-~30: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...from fasthx.jinja import JinjaPath. - Replace from fasthx import TemplateHeader wit...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~31-~31: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx.jinja import TemplateHeade...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~32-~32: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...fasthx.jinja import ComponentHeader. - Replace from fasthx import JinjaContextFactory...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[style] ~33-~33: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...hx.jinja import JinjaContextFactory. - Replace from fasthx.typing import JinjaContext...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[grammar] ~34-~34: Use commas correctly
Context: ...omponentsargument ofComponentHeader, if you passed templates` as a keyword ...

(QB_NEW_EN_OTHER_ERROR_IDS_33)


[grammar] ~34-~34: There might be a problem here.
Context: ...assed templates as a keyword argument. - Jinja._make_response() has been removed to simplify the codebas...

(QB_NEW_EN_MERGED_MATCH)


[grammar] ~35-~35: Use correct spacing
Context: ...Jinja._make_render_function() instead. ## Upgrade steps (htmy) - Make sure you'...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~37-~37: Use correct spacing
Context: ...n() instead. ## Upgrade steps (htmy) - Make sure you're using htmyversion>...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~40-~40: Use correct spacing
Context: ...een replaced by the renderer property. ## Upgrade steps (custom rendering) - `Ren...

(QB_NEW_EN_OTHER_ERROR_IDS_5)


[grammar] ~42-~42: There might be a problem here.
Context: ...ty. ## Upgrade steps (custom rendering) - RenderFunction must return a str, Response is no lo...

(QB_NEW_EN_MERGED_MATCH)


[grammar] ~44-~44: There might be a mistake here.
Context: ...ring) - RenderFunction must return a str, Response is no longer allowed.

(QB_NEW_EN_OTHER)


[grammar] ~44-~44: There might be a mistake here.
Context: ... str, Response is no longer allowed.

(QB_NEW_EN)

🔇 Additional comments (3)
docs/migrations/2-to-3.md (3)

11-12: LGTM on summary bullets

Comma splice has been resolved with a colon, and the htmy version aligns with the project pin (>=0.8.1).


39-40: LGTM on htmy migration notes

The version requirement and the property rename are clear and consistent; the semicolon avoids a comma splice.


18-33: No leftover v2 references found — no action required

Ran the provided ripgrep checks (excluding docs/migrations/2-to-3.md). There were no matches for HTMLRenderer / SyncHTMLRenderer / AsyncHTMLRenderer, Jinja root imports (Jinja, JinjaContext, JinjaPath, TemplateHeader), JinjaContextFactory outside fasthx.jinja, Jinja._make_response, or .htmy. Migration doc is accurate and no code changes are needed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
Knowledge Base: Disabled due to Reviews > Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between fa8ff79 and 6771ec4.

📒 Files selected for processing (1)
  • fasthx/core_decorators.py (5 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
fasthx/core_decorators.py (3)
fasthx/utils.py (3)
  • append_to_signature (12-32)
  • execute_maybe_sync_func (35-48)
  • get_response (51-62)
fasthx/jinja.py (2)
  • hx (248-282)
  • render (334-346)
fasthx/htmy.py (3)
  • hx (135-156)
  • render (205-213)
  • render (224-232)
🔇 Additional comments (4)
fasthx/core_decorators.py (4)

15-19: hx() signature change to RenderFunction is correct and consistent.
Generic param usage and the render_error shape look good. No concerns with the public API surface here.


84-86: page() signature change to RenderFunction is correct and consistent.
Matches the v3 rename and the usage pattern elsewhere. Looks good.


101-101: Return annotation to Response is appropriate.
Matches the new unconditional HTMLResponse wrapping behavior.


10-10: No leftover HTMLRenderer usages in code; only migration docs reference it.

Repo-wide search found only:

  • docs/migrations/2-to-3.md — lines 10 and 18–21 mention HTMLRenderer (migration notes).

No code files or imports reference HTMLRenderer, so no changes required in the codebase.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 6771ec4 and 6d821a4.

📒 Files selected for processing (5)
  • docs/migrations/1-to-2.md (1 hunks)
  • docs/migrations/2-to-3.md (1 hunks)
  • fasthx/htmy.py (12 hunks)
  • fasthx/jinja.py (5 hunks)
  • tests/test_htmy.py (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: Linters
tests/test_htmy.py

[error] 80-80: Mypy: Argument 1 has incompatible type "Callable[[], HelloWorld]"; expected "Callable[[], Never] | Callable[[], Coroutine[Any, Any, Never]]".


[error] 85-85: Mypy: Argument 1 has incompatible type "Callable[[], HelloWorld]"; expected "Callable[[], Never] | Callable[[], Coroutine[Any, Any, Never]]".

🔇 Additional comments (10)
docs/migrations/1-to-2.md (1)

1-1: Heading tweak aligns with migration doc naming

The revised title matches the action-oriented style you’re adopting for the migration guides. 👍

docs/migrations/2-to-3.md (3)

3-3: Remove the extra comma in the intro sentence

Drop the comma after “other” to keep the flow natural.

-`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set of the project grew significantly since then, for example with error rendering support and `htmy` integration, among other, smaller improvements.
+`fasthx` was first developed with Jinja templating and HTML rendering in mind. The feature set of the project grew significantly since then, for example with error rendering support and `htmy` integration, among other smaller improvements.

25-25: Fix the missing verb in the import sentence

Add “be” so the sentence reads correctly.

-These are mostly import changes — all the Jinja-related utilities can now only imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.
+These are mostly import changes — all the Jinja-related utilities can now only be imported from `fasthx.jinja` — and the renaming of `TemplateHeader` to `ComponentHeader`.

34-34: Tighten the TemplateHeader/ComponentHeader instruction

Use “argument to” and drop the extra comma to smooth out the sentence.

-Instead of the `templates` argument of `TemplateHeader()`, you must use the `components` argument of `ComponentHeader`, if you passed `templates` as a keyword argument.
+Instead of the `templates` argument to `TemplateHeader()`, use the `components` argument to `ComponentHeader` if you passed `templates` as a keyword argument.
fasthx/jinja.py (1)

341-347: LGTM! Previous TemplateResponse API concern has been resolved.

The code correctly passes request as a keyword argument to TemplateResponse, which is the proper API usage for FastAPI's Jinja2Templates.

tests/test_htmy.py (1)

197-198: Test coverage looks good for the new no-selector endpoints.

The test cases properly validate that both /hx-no-selector and /page-no-selector endpoints return the expected "Hello World!" response for HTMX requests.

fasthx/htmy.py (4)

118-119: Good API rename from htmy to renderer.

The rename from htmy field to renderer is more descriptive and aligns well with the broader refactoring to support non-HTML rendering in the future.


137-147: Excellent addition of optional component_selector parameter.

Making component_selector optional with a sensible default (_default_component_selector) provides a cleaner API for simple use cases where routes directly return components.


266-274: Clear documentation for the default component selector.

The _default_component_selector function is well-documented with clear assumptions about its usage. The identity function pattern is appropriate for this use case.


206-241: Consistent renderer usage throughout the codebase.

All references to self.htmy.render have been properly updated to self.renderer.render, maintaining consistency with the API rename.

@volfpeter volfpeter merged commit 6b9770a into main Sep 26, 2025
3 checks passed
@volfpeter volfpeter deleted the feat/v3 branch September 26, 2025 08:32
This was referenced Sep 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants