Skip to content

Commit 9883cce

Browse files
authored
Merge pull request #42 from volfpeter/fix/src-layout-without-package
Fix: src layout without package
2 parents 9f4bd73 + 4df765b commit 9883cce

File tree

10 files changed

+38
-27
lines changed

10 files changed

+38
-27
lines changed

.coderabbit.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
issue_enrichment:
2+
auto_enrich:
3+
enabled: false

docs/guides/forms.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ from holm import Metadata
106106

107107

108108
@component.context_only
109-
def head(context: Context) -> html.head:
109+
def head(context: Context) -> ComponentType:
110110
"""
111111
Helper component that returns the entire head element of the page.
112112
@@ -130,7 +130,7 @@ def head(context: Context) -> html.head:
130130
Next we can add the search form:
131131

132132
```python
133-
def search_form(q: str, *, autofocus: bool) -> html.form:
133+
def search_form(q: str, *, autofocus: bool) -> ComponentType:
134134
"""
135135
Search form for the layout.
136136
@@ -200,7 +200,7 @@ The description implies that the page looks essentially the same both on initial
200200
from typing import Annotated
201201

202202
from fastapi import Form
203-
from htmy import Component, XBool, html
203+
from htmy import ComponentType, Component, XBool, html
204204
from todo_service import create_todo, find_todos
205205

206206

@@ -211,7 +211,7 @@ def page_content(
211211
title_invalid: bool = False,
212212
description: str = "",
213213
description_invalid: bool = False,
214-
) -> html.div:
214+
) -> ComponentType:
215215
"""
216216
Returns the common page content for `page()` and `handle_submit()`.
217217

docs/guides/path-parameters.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ With that said, let's create the user profile page:
203203
from typing import Annotated
204204

205205
from fastapi import Depends
206-
from htmy import html
206+
from htmy import ComponentType, html
207207

208208
from ..service import User, get_user
209209

@@ -235,7 +235,7 @@ def metadata(id: int, user: DependsUser) -> dict[str, str]:
235235
}
236236

237237

238-
async def page(user: DependsUser) -> html.div:
238+
async def page(user: DependsUser) -> ComponentType:
239239
"""
240240
Page function that uses the `DependsUser` annotated FastAPI dependency
241241
to get the user whose ID was submitted in the `{id}` path parameter.

docs/in-a-hurry.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,17 @@ Example:
4444

4545
```python
4646
# my_app/page.py
47-
from htmy import html
47+
from htmy import ComponentType, html
4848

49-
def page() -> html.div:
49+
def page() -> ComponentType:
5050
return html.div("Hello, world!")
5151
```
5252

5353
```python
5454
# my_app/layout.py
55-
from htmy import html
55+
from htmy import ComponentType, html
5656

57-
def layout(children: html.div) -> html.html:
57+
def layout(children: ComponentType) -> ComponentType:
5858
return html.html(
5959
html.head(html.title("My App")),
6060
html.body(children), # <- The html.div page() returns
@@ -69,30 +69,30 @@ Example:
6969

7070
```python
7171
# my_app/page.py
72-
from htmy import html
72+
from htmy import ComponentType, html
7373

7474
def metadata() -> dict[str, str]:
7575
"""Metadata dependency for the page."""
7676
return {"title": "My App"}
7777

78-
def page() -> html.div:
78+
def page() -> ComponentType:
7979
return html.div("Hello, world!")
8080
```
8181

8282
```python
8383
# my_app/layout.py
84-
from htmy import Context, component, html
84+
from htmy import ComponentType, Context, component, html
8585

8686
from holm import Metadata
8787

8888
@component
89-
def head(default_title: str, context: Context) -> html.head:
89+
def head(default_title: str, context: Context) -> ComponentType:
9090
"""Custom head component that can access page metadata from the htmy context."""
9191
metadata = Metadata.from_context(context) # <- The mapping the `metadata` dependency of the page returned
9292
title = metadata.get("title", default_title)
9393
return html.head(html.title(title))
9494

95-
def layout(children: html.div) -> html.html:
95+
def layout(children: ComponentType) -> ComponentType:
9696
return html.html(
9797
head("My App"), # <- Our custom head component
9898
html.body(children), # <- The html.div page() returns

examples/forms/layout.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
@component.context_only
8-
def head(context: Context) -> html.head:
8+
def head(context: Context) -> ComponentType:
99
"""
1010
Helper component that returns the entire head element of the page.
1111
@@ -25,7 +25,7 @@ def head(context: Context) -> html.head:
2525
)
2626

2727

28-
def search_form(q: str, *, autofocus: bool) -> html.form:
28+
def search_form(q: str, *, autofocus: bool) -> ComponentType:
2929
"""
3030
Search form for the layout.
3131

examples/forms/page.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Annotated
22

33
from fastapi import Form
4-
from htmy import Component, XBool, html
4+
from htmy import Component, ComponentType, XBool, html
55
from todo_service import create_todo, find_todos
66

77

@@ -12,7 +12,7 @@ def page_content(
1212
title_invalid: bool = False,
1313
description: str = "",
1414
description_invalid: bool = False,
15-
) -> html.div:
15+
) -> ComponentType:
1616
"""
1717
Returns the common page content for `page()` and `handle_submit()`.
1818

examples/path-parameters/user/_id_/page.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from typing import Annotated
22

33
from fastapi import Depends
4-
from htmy import html
4+
from htmy import ComponentType, html
55

66
from ..service import User, get_user
77

@@ -33,7 +33,7 @@ def metadata(id: int, user: DependsUser) -> dict[str, str]:
3333
}
3434

3535

36-
async def page(user: DependsUser) -> html.div:
36+
async def page(user: DependsUser) -> ComponentType:
3737
"""
3838
Page function that uses the `DependsUser` annotated FastAPI dependency
3939
to get the user whose ID was submitted in the `{id}` path parameter.

holm/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "0.7.1"
1+
__version__ = "0.7.2"
22

33
from .app import App as App
44
from .fastapi import FastAPIDependency as FastAPIDependency

holm/_model.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ def _find_app_package_name(cls) -> str:
8585
raise ValueError("Could not determine the application package.")
8686

8787

88+
_no_app_package_roots: set[str] = {"", "."}
89+
"""
90+
Special package names that are encountered when the application is not wrapped in a Python package.
91+
92+
- "": src layout
93+
- ".": flat layout
94+
"""
95+
96+
8897
@dataclass(frozen=True, kw_only=True, slots=True)
8998
class PackageInfo:
9099
"""
@@ -131,14 +140,13 @@ def import_module(
131140
ValueError: If the module is invalid.
132141
"""
133142
# Check if the module exists. Trying to import it and catching the exception would hide possible
134-
# import error that occur in within the module, which is undesired because it would be hard for
143+
# import errors that occur within the module, which is undesired because it would be hard for
135144
# users to find why an API is not registered.
136145
if not (self.package_dir / f"{name}.py").is_file():
137146
return None
138147

139148
# Support applications that are not wrapped in a Python package.
140-
# In that case `self.package_name` is ".".
141-
import_name = name if self.package_name == "." else f"{self.package_name}.{name}"
149+
import_name = name if self.package_name in _no_app_package_roots else f"{self.package_name}.{name}"
142150
try:
143151
module = import_module(import_name)
144152
except Exception:

test_app/user/_user_id_/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from fastapi import APIRouter
22
from fasthx.htmy import HTMY
3-
from htmy import html
3+
from htmy import ComponentType, html
44

55

66
def api(htmy: HTMY) -> APIRouter:
@@ -22,7 +22,7 @@ async def get_user(user_id: str) -> dict[str, str]:
2222
return api
2323

2424

25-
def user_card(user: dict[str, str]) -> html.div:
25+
def user_card(user: dict[str, str]) -> ComponentType:
2626
return html.div(
2727
html.h2(user["name"]),
2828
html.p(f"ID: {user['id']}"),

0 commit comments

Comments
 (0)