Skip to content

Commit 05a8118

Browse files
docs: update CHANGELOG and enhance Django/pytest startup logging
- Updated `CHANGELOG.md` to reflect improvements in logging visibility during Django and pytest startup processes, including the installation of `CiPytestStartupTracer` for better tracking of `AppConfig.ready()` calls. - Enhanced logging in `api/models.py` to indicate when Django will call `AppConfig.ready()` for each installed app. - Removed unnecessary import from `api/apps.py` to streamline the code. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 5801b6f commit 05a8118

5 files changed

Lines changed: 40 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ All contributors (including maintainers) should update `CHANGELOG.md` when creat
8484

8585
### Improved
8686

87-
- **Django / pytest startup visibility**: [`api/utils/utils.py`](api/utils/utils.py) **`print_django`** uses **`flush=True`**. [`api/settings.py`](api/settings.py) logs that **`django.setup()`** follows settings. [`api/models.py`](api/models.py) logs before/after the **`api`** model import chain (often the long gap before **`api.urls`**). [`api/urls.py`](api/urls.py) logs start/end of URLconf import; [`api/apps.py`](api/apps.py) **`ApiConfig.ready()`** logs when the **`api`** app **`ready()`** runs. [`api/test/tests/conftest.py`](api/test/tests/conftest.py) keeps **`[pytest]`** session/collection progress.
87+
- **Django / pytest startup visibility**: [`api/utils/utils.py`](api/utils/utils.py) **`print_django`** uses **`flush=True`**. [`api/settings.py`](api/settings.py) logs that **`django.setup()`** follows settings and installs [`api/CiPytestStartupTracer.py`](api/CiPytestStartupTracer.py) **`CiPytestStartupTracer`** (logs every **`AppConfig.ready()`** start/end in pytest/CI so a stall after **`api.models`** points at the right installed app). [`api/models.py`](api/models.py) logs before/after the **`api`** model import chain and notes that **`ready()`** runs next. [`api/urls.py`](api/urls.py) logs start/end of URLconf import (loads after **`apps.populate()`**). [`api/test/tests/conftest.py`](api/test/tests/conftest.py) keeps **`[pytest]`** session/collection progress.
8888

8989
### Changed
9090

api/CiPytestStartupTracer.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
import sys
3+
from collections.abc import Callable
4+
5+
from django.apps import AppConfig
6+
7+
8+
class CiPytestStartupTracer:
9+
"""Logs each AppConfig.ready() in CI/pytest so hangs after model import are attributable to a specific app."""
10+
11+
@staticmethod
12+
def is_ci_or_pytest_argv() -> bool:
13+
if os.environ.get("ENV") == "ci_test":
14+
return True
15+
if "pytest" in (sys.argv[0] or ""):
16+
return True
17+
return any(a == "pytest" for a in sys.argv)
18+
19+
@staticmethod
20+
def install_appconfig_ready_tracer() -> None:
21+
if not CiPytestStartupTracer.is_ci_or_pytest_argv():
22+
return
23+
original_ready: Callable[[AppConfig], None] = AppConfig.ready
24+
25+
def traced_ready(self: AppConfig) -> None:
26+
print(f"[Django] AppConfig.ready() start: {self.label}", flush=True)
27+
original_ready(self)
28+
print(f"[Django] AppConfig.ready() end: {self.label}", flush=True)
29+
30+
AppConfig.ready = traced_ready # type: ignore[method-assign]

api/apps.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
from django.apps import AppConfig
55

6-
from . import settings
7-
86

97
class ApiConfig(AppConfig):
108
name = "api"

api/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,9 @@
1313

1414
if "pytest" in sys.argv[0] or os.environ.get("ENV") == "ci_test":
1515
print("[Django] api.models: core model imports finished.", flush=True)
16+
print(
17+
"[Django] api.models: Django will now call AppConfig.ready() on each installed app (api is last).",
18+
flush=True,
19+
)
1620

1721
__all__ = ["SpotifyArtist", "SpotifyLibTrack", "User"]

api/settings.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -913,8 +913,11 @@ def set_secret_key():
913913

914914
print_django("Finished loading settings.")
915915
if "pytest" in sys.argv[0] or os.environ.get("ENV") == "ci_test":
916+
from api.CiPytestStartupTracer import CiPytestStartupTracer
917+
918+
CiPytestStartupTracer.install_appconfig_ready_tracer()
916919
print(
917-
"[Django] Next: django.setup() loads apps/models and ROOT_URLCONF (api.urls); "
918-
"this can take minutes in CI with no further [Django] lines until complete.",
920+
"[Django] Next: django.setup() runs apps.populate() (models, then one AppConfig.ready() per app); "
921+
"ROOT_URLCONF (api.urls) loads only after that. Long gaps: watch which ready() starts but never ends.",
919922
flush=True,
920923
)

0 commit comments

Comments
 (0)