Skip to content

Commit

Permalink
Fix: Use lazy imports to avoid Django side-effects
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuatz committed Nov 4, 2024
1 parent 21a19ca commit f37c8e7
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 3 deletions.
21 changes: 21 additions & 0 deletions django_utils_lib/lazy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class LazyDjango:
"""
Django has a few modules where if you import something from them,
they trigger side-effects that can crash the app if called at import-time
vs run-time. Notably things related to auth that trigger apps / settings
checks.
This class is a workaround, without using a full app registration system,
to just use lazy-imports.
"""

@property
def redirect_to_login(self):
if self._redirect_to_login is None:
from django.contrib.auth.views import redirect_to_login

self._redirect_to_login = redirect_to_login
return self._redirect_to_login


lazy_django = LazyDjango()
5 changes: 3 additions & 2 deletions django_utils_lib/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import pydantic
from django.conf import settings
from django.contrib.auth.views import redirect_to_login
from django.http import (
FileResponse,
HttpRequest,
Expand All @@ -15,6 +14,8 @@
from django.urls import re_path
from django.views.static import serve

from django_utils_lib.lazy import lazy_django


class SimpleStaticFileServerConfig(pydantic.BaseModel):
auth_required_path_patterns: Optional[List[re.Pattern]] = pydantic.Field(default=None)
Expand Down Expand Up @@ -76,7 +77,7 @@ def guard_path(self, request: HttpRequest, url_path: str) -> Optional[HttpRespon
# Check for attempted access to an auth-required path from a non-authed user
if self.config.auth_required_path_patterns and not request.user.is_authenticated:
if any(pattern.search(url_path) for pattern in self.config.auth_required_path_patterns):
return redirect_to_login(next=request.get_full_path())
return lazy_django.redirect_to_login(next=request.get_full_path())

# Pass request forward / noop
return None
Expand Down
5 changes: 4 additions & 1 deletion django_utils_lib/tests/test_simplestaticfileserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ class StaticFileServerTestCase(TypedDict):
),
],
)
@mock.patch("django_utils_lib.requests.redirect_to_login", return_value=HttpResponseRedirect(""))
@mock.patch(
"django_utils_lib.lazy.LazyDjango.redirect_to_login",
new_callable=mock.PropertyMock(return_value=mock.MagicMock(return_value=HttpResponseRedirect(""))),
)
@mock.patch("django_utils_lib.requests.serve", return_value=FileResponse())
def test_path_guarding(
mock_serve: mock.Mock,
Expand Down

0 comments on commit f37c8e7

Please sign in to comment.