Skip to content

Commit ed96eda

Browse files
Remove deprecated view-based asset serving and related code (#171)
* Remove deprecated view-based asset serving and related code * update changelog * remove newline * remove prints * make mypy happy * add views to coverage ignore * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 8519dfa commit ed96eda

File tree

10 files changed

+71
-273
lines changed

10 files changed

+71
-273
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/
2222

2323
- Added the `{% bird:var %}` templatetag for managing local context variables within components, including support for appending, overwriting, and resetting values. Variables are scoped to components and automatically are cleaned up when the component finishes rendering, with optional explicit cleanup via `{% endbird:var %}`.
2424

25+
### Removed
26+
27+
- Removed the deprecated asset serving view (`asset_view`) and its URL configuration. Use `BirdAssetFinder` with Django's staticfiles app instead.
28+
2529
## [0.13.2]
2630

2731
### Fixed

docs/assets.md

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -133,27 +133,3 @@ python manage.py collectstatic
133133
```
134134

135135
This will collect all component assets into your static files directory, allowing you to serve them via your web server, [WhiteNoise](https://whitenoise.readthedocs.io), or a CDN.
136-
137-
### Deprecated View-Based Serving
138-
139-
```{warning}
140-
**Warning:** The built-in asset serving view is deprecated and will be removed in a future release. Please switch to using the custom staticfiles finder and serve assets through Django's static files system.
141-
```
142-
143-
If you still need to use the view-based asset serving during the transition, you can enable it by adding django-bird's URLs to your project's URL configuration:
144-
145-
```{code-block} python
146-
:caption: urls.py
147-
148-
from django.conf import settings
149-
from django.urls import include
150-
from django.urls import path
151-
152-
153-
if settings.DEBUG:
154-
urlpatterns = [
155-
path("__bird__/", include("django_bird.urls")),
156-
]
157-
```
158-
159-
This will make component assets available at `/__bird__/assets/<component_name>/<asset_filename>` when `DEBUG` is `True`.

pyproject.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,12 @@ exclude_lines = [
117117
fail_under = 98
118118

119119
[tool.coverage.run]
120-
omit = ["src/django_bird/migrations/*", "src/django_bird/_typing.py", "tests/*"]
120+
omit = [
121+
"src/django_bird/migrations/*",
122+
"src/django_bird/_typing.py",
123+
"src/django_bird/views.py", # TODO: remove when not empty
124+
"tests/*"
125+
]
121126
source = ["src/django_bird"]
122127

123128
[tool.django-stubs]

src/django_bird/staticfiles.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
from django.contrib.staticfiles.storage import StaticFilesStorage
1717
from django.core.checks import CheckMessage
1818
from django.core.files.storage import FileSystemStorage
19-
from django.urls import reverse
2019

2120
from ._typing import override
2221
from .apps import DjangoBirdAppConfig
@@ -70,6 +69,9 @@ def exists(self) -> bool:
7069
return self.path.exists()
7170

7271
def render(self):
72+
if self.url is None:
73+
return ""
74+
7375
match self.type:
7476
case AssetType.CSS:
7577
return f'<link rel="stylesheet" href="{self.url}">'
@@ -101,18 +103,12 @@ def template_dir(self):
101103
return template_dir.parent
102104

103105
@property
104-
def url(self) -> str:
106+
def url(self) -> str | None:
105107
static_path = finders.find(str(self.relative_path))
106-
if static_path is not None:
107-
static_relative_path = Path(static_path).relative_to(self.template_dir)
108-
return self.storage.url(str(static_relative_path))
109-
return reverse(
110-
"django_bird:asset",
111-
kwargs={
112-
"component_name": self.path.stem,
113-
"asset_filename": self.path.name,
114-
},
115-
)
108+
if static_path is None:
109+
return None
110+
static_relative_path = Path(static_path).relative_to(self.template_dir)
111+
return self.storage.url(str(static_relative_path))
116112

117113
@classmethod
118114
def from_path(cls, path: Path, asset_type: AssetType):

src/django_bird/urls.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
from __future__ import annotations
22

3-
from django.urls import path
4-
53
from .apps import DjangoBirdAppConfig
6-
from .views import asset_view
74

85
app_name = DjangoBirdAppConfig.label
96

10-
urlpatterns = [
11-
path("assets/<str:component_name>/<str:asset_filename>", asset_view, name="asset"),
12-
]
7+
urlpatterns = [] # type: ignore[var-annotated]

src/django_bird/views.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1 @@
11
from __future__ import annotations
2-
3-
import warnings
4-
from io import BytesIO
5-
6-
from django.conf import settings
7-
from django.http import FileResponse
8-
from django.http import Http404
9-
from django.http.request import HttpRequest
10-
from django.template.exceptions import TemplateDoesNotExist
11-
12-
from .components import components
13-
14-
15-
def asset_view(request: HttpRequest, component_name: str, asset_filename: str):
16-
warnings.warn(
17-
"The 'asset_view' is deprecated and will be removed in a future release. "
18-
"Use the 'BirdAssetFinder' with Django's static files system instead.",
19-
DeprecationWarning,
20-
stacklevel=2,
21-
)
22-
23-
if not settings.DEBUG:
24-
warnings.warn(
25-
"Serving assets through this view in production is not recommended.",
26-
RuntimeWarning,
27-
stacklevel=2,
28-
)
29-
30-
try:
31-
component = components.get_component(component_name)
32-
except (KeyError, TemplateDoesNotExist) as err:
33-
raise Http404("Component not found") from err
34-
35-
asset = component.get_asset(asset_filename)
36-
if not asset or not asset.path.exists():
37-
raise Http404("Asset not found")
38-
39-
content = asset.path.read_bytes()
40-
41-
return FileResponse(BytesIO(content), content_type=asset.type.content_type)

tests/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ def pytest_configure(config):
3737
"django.contrib.staticfiles",
3838
],
3939
"STATIC_URL": "/static/",
40+
"STATICFILES_FINDERS": [
41+
"django.contrib.staticfiles.finders.FileSystemFinder",
42+
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
43+
"django_bird.staticfiles.BirdAssetFinder",
44+
],
4045
"TEMPLATES": [
4146
{
4247
"BACKEND": "django.template.backends.django.DjangoTemplates",

tests/templatetags/test_asset.py

Lines changed: 14 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
from __future__ import annotations
22

33
import pytest
4-
from django.conf import settings
54
from django.template.base import Parser
65
from django.template.base import Token
76
from django.template.base import TokenType
87
from django.template.context import Context
98
from django.template.exceptions import TemplateSyntaxError
109
from django.template.loader import get_template
11-
from django.test import override_settings
1210

13-
from django_bird.conf import DJANGO_BIRD_FINDER
1411
from django_bird.staticfiles import AssetType
1512
from django_bird.templatetags.tags.asset import CSS_TAG
1613
from django_bird.templatetags.tags.asset import JS_TAG
@@ -20,18 +17,6 @@
2017
from tests.utils import TestComponent
2118

2219

23-
@pytest.fixture(autouse=True)
24-
def reset_staticfiles_finders():
25-
with override_settings(
26-
STATICFILES_FINDERS=[
27-
finder
28-
for finder in settings.STATICFILES_FINDERS
29-
if finder != DJANGO_BIRD_FINDER
30-
]
31-
):
32-
yield
33-
34-
3520
class TestTemplateTag:
3621
@pytest.mark.parametrize(
3722
"tag,expected",
@@ -115,21 +100,15 @@ def test_template_inheritence(self, create_template, templates_dir, registry):
115100
rendered = template.render({})
116101

117102
assert (
118-
f'<link rel="stylesheet" href="/__bird__/assets/{alert.name}/{alert_css.file.name}">'
119-
in rendered
120-
)
121-
assert (
122-
f'<link rel="stylesheet" href="/__bird__/assets/{button.name}/{button_css.file.name}">'
123-
in rendered
124-
)
125-
assert (
126-
f'<script src="/__bird__/assets/{alert.name}/{alert_js.file.name}"></script>'
103+
f'<link rel="stylesheet" href="/static/bird/{alert_css.file.name}">'
127104
in rendered
128105
)
129106
assert (
130-
f'<script src="/__bird__/assets/{button.name}/{button_js.file.name}"></script>'
107+
f'<link rel="stylesheet" href="/static/bird/{button_css.file.name}">'
131108
in rendered
132109
)
110+
assert f'<script src="/static/bird/{alert_js.file.name}"></script>' in rendered
111+
assert f'<script src="/static/bird/{button_js.file.name}"></script>' in rendered
133112

134113
def test_with_no_assets(self, create_template, templates_dir):
135114
TestComponent(
@@ -206,21 +185,21 @@ def test_component_render_order(self, create_template, templates_dir, registry):
206185

207186
head_end = rendered.find("</head>")
208187
assert (
209-
f'<link rel="stylesheet" href="/__bird__/assets/{first.name}/{first_css.file.name}">'
188+
f'<link rel="stylesheet" href="/static/bird/{first_css.file.name}">'
210189
in rendered[:head_end]
211190
)
212191
assert (
213-
f'<link rel="stylesheet" href="/__bird__/assets/{second.name}/{second_css.file.name}">'
192+
f'<link rel="stylesheet" href="/static/bird/{second_css.file.name}">'
214193
in rendered[:head_end]
215194
)
216195

217196
body_start = rendered.find("<body")
218197
assert (
219-
f'<script src="/__bird__/assets/{first.name}/{first_js.file.name}"></script>'
198+
f'<script src="/static/bird/{first_js.file.name}"></script>'
220199
in rendered[body_start:]
221200
)
222201
assert (
223-
f'<script src="/__bird__/assets/{second.name}/{second_js.file.name}"></script>'
202+
f'<script src="/static/bird/{second_js.file.name}"></script>'
224203
in rendered[body_start:]
225204
)
226205

@@ -267,18 +246,15 @@ def test_asset_duplication(self, create_template, templates_dir, registry):
267246
template = get_template(child_path.name)
268247

269248
rendered = template.render({})
270-
print(f"{rendered=}")
271249

272250
assert (
273251
rendered.count(
274-
f'<link rel="stylesheet" href="/__bird__/assets/{alert.name}/{alert_css.file.name}">'
252+
f'<link rel="stylesheet" href="/static/bird/{alert_css.file.name}">'
275253
)
276254
== 1
277255
)
278256
assert (
279-
rendered.count(
280-
f'<script src="/__bird__/assets/{alert.name}/{alert_js.file.name}"></script>'
281-
)
257+
rendered.count(f'<script src="/static/bird/{alert_js.file.name}"></script>')
282258
== 1
283259
)
284260

@@ -337,19 +313,16 @@ def test_unused_component_asset_not_rendered(
337313
rendered = template.render({})
338314

339315
assert (
340-
f'<link rel="stylesheet" href="/__bird__/assets/{alert.name}/{alert_css.file.name}">'
341-
in rendered
342-
)
343-
assert (
344-
f'<script src="/__bird__/assets/{alert.name}/{alert_js.file.name}"></script>'
316+
f'<link rel="stylesheet" href="/static/bird/{alert_css.file.name}">'
345317
in rendered
346318
)
319+
assert f'<script src="/static/bird/{alert_js.file.name}"></script>' in rendered
347320
assert (
348-
f'<link rel="stylesheet" href="/__bird__/assets/{button.name}/{button_css.file.name}">'
321+
f'<link rel="stylesheet" href="/static/bird/{button_css.file.name}">'
349322
not in rendered
350323
)
351324
assert (
352-
f'<script src="/__bird__/assets/{button.name}/{button_js.file.name}"></script>'
325+
f'<script src="/static/bird/{button_js.file.name}"></script>'
353326
not in rendered
354327
)
355328

tests/test_staticfiles.py

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44
from pathlib import Path
55

66
import pytest
7-
from django.conf import settings
87
from django.contrib.staticfiles import finders
98
from django.core.management import call_command
109
from django.template.base import Template
1110
from django.template.context import Context
1211
from django.test import override_settings
1312

1413
from django_bird.components import Component
15-
from django_bird.conf import DJANGO_BIRD_FINDER
1614
from django_bird.staticfiles import Asset
1715
from django_bird.staticfiles import AssetType
1816
from django_bird.staticfiles import BirdAssetFinder
@@ -49,15 +47,38 @@ def test_exists_nonexistent(self):
4947
@pytest.mark.parametrize(
5048
"asset,expected_html_tag_bits",
5149
[
52-
(Asset(Path("static.css"), AssetType.CSS), 'link rel="stylesheet" href='),
53-
(Asset(Path("static.js"), AssetType.JS), "script src="),
50+
(
51+
TestAsset(
52+
component=None,
53+
content=".button { color: blue; }",
54+
asset_type=AssetType.CSS,
55+
),
56+
'link rel="stylesheet" href=',
57+
),
58+
(
59+
TestAsset(
60+
component=None,
61+
content="console.log('button');",
62+
asset_type=AssetType.JS,
63+
),
64+
"script src=",
65+
),
5466
],
5567
)
56-
def test_render(self, asset, expected_html_tag_bits):
57-
rendered = asset.render()
68+
def test_render(self, asset, expected_html_tag_bits, templates_dir):
69+
button = TestComponent(
70+
name="button", content="<button>Click me</button>"
71+
).create(templates_dir)
72+
asset.component = button
73+
asset.create()
74+
75+
component = Component.from_name(button.name)
76+
component_asset = component.get_asset(asset.file.name)
77+
78+
rendered = component_asset.render()
5879

5980
assert expected_html_tag_bits in rendered
60-
assert asset.url in rendered
81+
assert component_asset.url in rendered
6182

6283
def test_storage(self, templates_dir, settings):
6384
button = TestComponent(
@@ -141,7 +162,7 @@ def test_relative_path_nested(self, templates_dir):
141162

142163
assert asset.relative_path == Path("bird/nested/button.css")
143164

144-
def test_url_with_staticfiles_finder(self, templates_dir):
165+
def test_url(self, templates_dir):
145166
button = TestComponent(
146167
name="button",
147168
content="<button>Click me</button>",
@@ -159,7 +180,7 @@ def test_url_with_staticfiles_finder(self, templates_dir):
159180
asset.url == f"/static/{button_css.file.parent.name}/{button_css.file.name}"
160181
)
161182

162-
def test_url_with_reverse_fallback(self, templates_dir):
183+
def test_url_nonexistent(self, templates_dir):
163184
button = TestComponent(
164185
name="button",
165186
content="<button>Click me</button>",
@@ -173,14 +194,9 @@ def test_url_with_reverse_fallback(self, templates_dir):
173194
component = Component.from_name(button.name)
174195
asset = component.get_asset(button_css.file.name)
175196

176-
with override_settings(
177-
STATICFILES_FINDERS=[
178-
finder
179-
for finder in settings.STATICFILES_FINDERS
180-
if finder != DJANGO_BIRD_FINDER
181-
]
182-
):
183-
assert asset.url == f"/__bird__/assets/{component.name}/{asset.path.name}"
197+
button_css.file.unlink()
198+
199+
assert asset.url is None
184200

185201
def test_from_path(self, templates_dir):
186202
button = TestComponent(

0 commit comments

Comments
 (0)