Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,12 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version-file: ".python-version"

# ADJUST THIS: install all dependencies (including pdoc)
- run: uv sync --all-extras --dev
# ADJUST THIS: build your documentation into docs/.
# We use a custom build script for pdoc itself, ideally you just run `pdoc -o docs/ ...` here.
- run: uv run pdoc src/dash_builder -o docs/
- run: uv run mkdocs build

- uses: actions/upload-pages-artifact@v3
with:
path: docs/
path: site/

# Deploy the artifact to GitHub pages.
# This is a separate job so that only actions/deploy-pages has the necessary permissions.
Expand Down
34 changes: 34 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Welcome to MkDocs

For full documentation visit [mkdocs.org](https://www.mkdocs.org).

## Commands

* `mkdocs new [dir-name]` - Create a new project.
* `mkdocs serve` - Start the live-reloading docs server.
* `mkdocs build` - Build the documentation site.
* `mkdocs -h` - Print help message and exit.

## Project layout

mkdocs.yml # The configuration file.
docs/
index.md # The documentation homepage.
... # Other markdown pages, images and other files.

## Termynal

<!-- termynal -->

```
$ uv -h

...
```

::: dash_builder.dash_page.DashPage
options:
members:
- valid_layout
- layout
inherited_members: true
6 changes: 6 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
site_name: My Docs
theme:
name: material
plugins:
- termynal
- mkdocstrings
12 changes: 10 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "dash-builder"
version = "0.1.4"
version = "0.1.5"
description = "A tool and framework to simplify construction of Python Dash applications."
readme = "README.md"
authors = [{ name = "robfs", email = "robfoxsimms@gmail.com" }]
Expand All @@ -26,7 +26,15 @@ venvPath = "."
venv = ".venv"

[dependency-groups]
dev = ["pdoc>=15.0.1", "pytest>=8.3.4", "pytest-cov>=6.0.0", "ruff>=0.9.7"]
dev = [
"mkdocs>=1.6.1",
"mkdocs-material>=9.6.9",
"mkdocstrings-python>=1.16.7",
"pytest>=8.3.4",
"pytest-cov>=6.0.0",
"ruff>=0.9.7",
"termynal>=0.13.0",
]

[tool.ruff]
# Exclude a variety of commonly ignored directories.
Expand Down
10 changes: 9 additions & 1 deletion src/dash_builder/_dash_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
import traceback

import dash_mantine_components as dmc
from dash import html

__all__ = ["DashObject"]
Expand Down Expand Up @@ -54,7 +55,14 @@ def error_container(cls, message: str) -> html.Div:
`dash.html.Div` container.

"""
return html.Div(html.Pre(message))
return dmc.Container(
dmc.Code(
message,
block=True,
color="var(--mantine-color-red-2)",
style={"whiteSpace": "pre-wrap"},
)
)

@classmethod
@abc.abstractmethod
Expand Down
46 changes: 35 additions & 11 deletions src/dash_builder/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def create_new_page_module(self, template: PageTemplate):
def add_view_import_to_init_file(self, template: ViewTemplate):
"""Add a view import to the init file."""
init_file = template.file_path.parent / "__init__.py"
module_name = template.file_name.strip(".py")
module_name = template.file_name.replace(".py", "")
if not init_file.exists():
init_file.write_text('"""Views module."""\n\n__all__ = []\n')

Expand Down Expand Up @@ -213,7 +213,7 @@ def add_view(self, view_name: str):
f"[bold green]CREATED[/bold green] {template.class_name} view."
)

def add_page(self, page_name: str, url_path: str):
def add_page(self, page_name: str, url_path: str | None = None):
"""Add a new page to the project."""
page_path = self.project / "pages"
template = PageTemplate(page_name, page_path, url_path)
Expand Down Expand Up @@ -253,33 +253,57 @@ def build(

@app.command("view")
def create_view(
view_name: Annotated[str, typer.Argument(help="The name of the view to add.")],
view_names: Annotated[
list[str], typer.Argument(help="The name of the view(s) to add.")
],
location: Annotated[
str, typer.Option(help="The destination directory for the project.")
] = "",
):
"""Add a new view to the project.

Args:
view_name: the name of the view to add.
view_names: the name(s) of the view(s) to add.
location: the destination directory for the project.

"""
project = Project.detect(location=location)
project.add_view(view_name)

for view_name in view_names:
project.add_view(view_name)


@app.command("page")
def create_page(
page_name: Annotated[str, typer.Argument(help="The name of the page to add.")],
url_path: Annotated[str, typer.Option(help="The URL path of the page.")] = None,
page_names: Annotated[
list[str], typer.Argument(help="The name of the page(s) to add.")
],
location: Annotated[
str, typer.Option(help="The destination directory for the project.")
] = "",
url_path: Annotated[
str,
typer.Option(
help="The URL path of the page. Only available for single page creation."
),
] = None,
):
"""Add a new page to the project.

Args:
page_name: the name of the page to add.
url_path: the URL path of the page.
page_names: the name of the page to add.
location: the destination directory for the project.
url_path: the URL path of the page. Only available for single page creation.

"""
project = Project.detect()
project.add_page(page_name, url_path)
project = Project.detect(location=location)
if len(page_names) > 1:
if url_path:
project.console.print(
"[bold red]ERROR[/bold red] URL path is only available for single page creation."
)
return
for page_name in page_names:
project.add_page(page_name)
else:
project.add_page(page_names[0], url_path)
4 changes: 3 additions & 1 deletion src/dash_builder/examples/basic-mantine/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

import dash
import dash_mantine_components as dmc
from dash import dcc
from typing_extensions import override
from views import FooterView, HeaderView, SidebarView

from dash_builder import DashPage
from views import FooterView, HeaderView, SidebarView

dash._dash_renderer._set_react_version("18.2.0")

Expand Down Expand Up @@ -293,6 +294,7 @@ def valid_layout(cls, **kwargs):
SidebarView.layout("sidebar"),
dmc.AppShellMain(dash.page_container),
FooterView.layout("footer"),
dcc.Location(id="url"),
],
header={"height": 60},
footer={"height": 30},
Expand Down
9 changes: 5 additions & 4 deletions tests/test_dash_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pytest
from dash import html
import dash_mantine_components as dmc

from src.dash_builder import DashPage

Expand All @@ -10,17 +11,17 @@ def test_page_error(test_page):
container = test_page.error_container("test message")
inner = container.children
inner_text = inner.children
assert isinstance(container, html.Div)
assert isinstance(inner, html.Pre)
assert isinstance(container, dmc.Container)
assert isinstance(inner, dmc.Code)
assert inner_text == "test message"


def test_page_on_error(error_page):
container = error_page.layout()
inner = container.children
inner_text = inner.children
assert isinstance(container, html.Div)
assert isinstance(inner, html.Pre)
assert isinstance(container, dmc.Container)
assert isinstance(inner, dmc.Code)
assert "ZeroDivisionError: division by zero" in inner_text


Expand Down
Loading