Skip to content

Commit 743bbb9

Browse files
Improve the template
- Add a fallback in case of Application startup error. - Unpin `pydantic` version. - Set the `APP_SHOW_ERROR_DETAILS` env variable in `dev.py`.
1 parent c2c74e8 commit 743bbb9

6 files changed

Lines changed: 70 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## 2025-03-17
9+
10+
- Add a fallback in case of Application startup error.
11+
- Unpin `pydantic` version.
12+
- Set the `APP_SHOW_ERROR_DETAILS` env variable in `dev.py`.
13+
814
## 2023-11-26
15+
916
- Update the template for BlackSheep v2
1017
- Remove support for Pydantic v1, add support for `pydantic-settings`,
1118
and upgrade `Pydantic` pinned version
1219

1320
## 2023-06-29 :gem:
21+
1422
- New project template
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
from blacksheep import Application, Router, html
2+
from blacksheep.server.errors import ServerErrorDetailsHandler
3+
4+
5+
def _get_response_without_details(request, info, error_page_template: str):
6+
content = error_page_template.format_map(
7+
{
8+
"info": info,
9+
"exctype": "",
10+
"excmessage": "",
11+
"method": request.method,
12+
"path": request.url.value.decode(),
13+
"full_url": "",
14+
}
15+
)
16+
17+
return html(content, status=503)
18+
19+
20+
def get_diagnostic_app(exc: Exception) -> Application:
21+
"""
22+
Returns a fallback application, to help diagnosing start-up errors.
23+
"""
24+
router = Router()
25+
error_details_handler = ServerErrorDetailsHandler()
26+
27+
app = Application(router=router)
28+
29+
@router.get("/*")
30+
async def diagnostic_home(request):
31+
if app.show_error_details:
32+
response = error_details_handler.produce_response(request, exc)
33+
response.status = 503
34+
return response
35+
return _get_response_without_details(
36+
request,
37+
(
38+
"The application failed to start. Error details are hidden for security "
39+
"reasons. To display temporarily error details and investigate the "
40+
"issue, configure temporarily the environment to display error details."
41+
"APP_SHOW_ERROR_DETAILS=1"
42+
),
43+
error_details_handler._error_page_template,
44+
)
45+
46+
return app

{{cookiecutter.project_name}}/app/main.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
from app.docs import configure_docs
1010
{%- endif %}
1111
from app.errors import configure_error_handlers
12+
from app.diagnostics import get_diagnostic_app
1213
from app.services import configure_services
13-
from app.settings import load_settings, Settings
14+
from app.settings import Settings
1415

1516

1617
def configure_application(
@@ -21,8 +22,6 @@ def configure_application(
2122
services=services, show_error_details=settings.app.show_error_details
2223
)
2324

24-
25-
2625
configure_error_handlers(app)
2726
configure_authentication(app, settings)
2827
{%- if cookiecutter.use_openapi %}
@@ -31,4 +30,11 @@ def configure_application(
3130
return app
3231

3332

34-
app = configure_application(*configure_services(load_settings()))
33+
def get_app():
34+
try:
35+
return configure_application(*configure_services())
36+
except Exception as exc:
37+
return get_diagnostic_app(exc)
38+
39+
40+
app = get_app()

{{cookiecutter.project_name}}/app/services.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
https://github.com/Neoteroi/rodi/wiki
88
https://github.com/Neoteroi/rodi/tree/main/examples
99
"""
10+
1011
from typing import Tuple
1112

1213
from rodi import Container
1314

14-
from app.settings import Settings
15+
from app.settings import Settings, load_settings
1516

1617

17-
def configure_services(settings: Settings) -> Tuple[Container, Settings]:
18+
def configure_services() -> Tuple[Container, Settings]:
1819
container = Container()
20+
settings = load_settings()
1921

2022
container.add_instance(settings)
2123

{{cookiecutter.project_name}}/dev.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
if __name__ == "__main__":
2020
os.environ["APP_ENV"] = "dev"
21+
os.environ["APP_SHOW_ERROR_DETAILS"] = "1"
2122
port = int(os.environ.get("APP_PORT", 44777))
2223

2324
console = Console()

{{cookiecutter.project_name}}/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ essentials-configuration[full]
88
pydantic-settings
99
{%- endif %}
1010
MarkupSafe==2.1.3
11-
pydantic==2.5.2
11+
pydantic

0 commit comments

Comments
 (0)