refactor: Fix path resolution relative to COMPONENTS.dirs + add CI test to ensure sampleproject works (#1075)

* refactor: Fix path resolution relative to COMPONENTS.dirs + add CI test to ensure sampleproject works

* refactor: fix compat with Windows by explicitly using utf8 encoding to read component files

* refactor: add missing components to tests

* docs: update changelog

* refactor: fix formatting
This commit is contained in:
Juro Oravec 2025-03-31 16:09:37 +02:00 committed by GitHub
parent f07818fc7d
commit 9f68f0f1a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 100 additions and 14 deletions

View file

@ -67,3 +67,35 @@ jobs:
python -m pip install -e .
- name: Build documentation
run: mkdocs build --verbose
# Verify that the sample project works
test_sampleproject:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: ['3.13']
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
- name: Install dependencies
run: |
cd sampleproject
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
# Install django-components locally
python -m pip install -e ..
- name: Check Django project
run: |
cd sampleproject
python manage.py check
python manage.py migrate --noinput
# Start the server, make request, and exit with error if it fails
python manage.py runserver & sleep 5
curl http://127.0.0.1:8000/ || exit 1

View file

@ -56,6 +56,11 @@ where each class name or style property can be managed separately.
%}
```
#### Fix
- Fix compat with Windows when reading component files ([#1074](https://github.com/django-components/django-components/issues/1074))
- Fix resolution of component media files edge case ([#1073](https://github.com/django-components/django-components/issues/1073))
## v0.134
#### Fix

View file

@ -874,12 +874,16 @@ def resolve_media_file(
if is_url_path:
return [filepath], False
# The path may be a glob. So before we check if the file exists,
# we need to resolve the glob.
# The path may be a glob, which we need to resolve
if allow_glob and is_glob(filepath_abs_or_glob):
# Since globs are matched against the files, then we know that these files exist.
matched_abs_filepaths = glob.glob(filepath_abs_or_glob)
else:
matched_abs_filepaths = [filepath_abs_or_glob]
# But if we were given non-glob file path, then we need to check if it exists.
if Path(filepath_abs_or_glob).exists():
matched_abs_filepaths = [filepath_abs_or_glob]
else:
matched_abs_filepaths = []
# If there are no matches, return the original filepath
if not matched_abs_filepaths:
@ -968,6 +972,8 @@ def _get_asset(
if full_path is None:
# NOTE: The short name, e.g. `js` or `css` is used in the error message for convenience
raise ValueError(f"Could not find {inlined_attr} file {asset_file}")
asset_content = Path(full_path).read_text()
# NOTE: Use explicit encoding for compat with Windows, see #1074
asset_content = Path(full_path).read_text(encoding="utf8")
return asset_content

View file

@ -376,16 +376,6 @@ def djc_test(
param_names, values = parametrize
ids = None
for value in values:
# Validate that the first user-provided element in each value tuple is a dictionary,
# since it's meant to be used for overriding django-components settings
value_overrides = value[0]
if not isinstance(value_overrides, dict):
raise ValueError(
"The first element in each value tuple in `parametrize`"
f"must be a dictionary, but got {value_overrides}"
)
# NOTE: Lazily import pytest, so user can still run tests with plain `unittest`
# if they choose not to use parametrization.
import pytest

View file

@ -23,6 +23,35 @@ class GlobComponentRootDir(GlobComponent):
js = "glob/glob_*.js"
# The Media JS / CSS are NOT globs and are relative to the directory given in
# `COMPONENTS.dirs` and `COMPONENTS.app_dirs`. These should NOT be modified.
class NonGlobComponentRootDir(Component):
template = """
{% load component_tags %}
{% component_js_dependencies %}
{% component_css_dependencies %}
"""
class Media:
css = "glob/glob_1.css"
js = "glob/glob_1.js"
# The Media JS / CSS are NOT globs. While relative to the directory given in
# `COMPONENTS.dirs` and `COMPONENTS.app_dirs`, these files do not exist.
# These paths should NOT be modified.
class NonGlobNonexistComponentRootDir(Component):
template = """
{% load component_tags %}
{% component_js_dependencies %}
{% component_css_dependencies %}
"""
class Media:
css = "glob/glob_nonexist.css"
js = "glob/glob_nonexist.js"
# The Media JS / CSS are NOT globs, but URLs.
class UrlComponent(Component):
template = """

View file

@ -414,6 +414,30 @@ class TestComponentMedia:
assertInHTML('<script src="glob/glob_1.js"></script>', rendered)
assertInHTML('<script src="glob/glob_2.js"></script>', rendered)
@djc_test(
django_settings={
"INSTALLED_APPS": ("django_components", "tests"),
}
)
def test_non_globs_not_modified(self):
from tests.components.glob.glob import NonGlobComponentRootDir
rendered = NonGlobComponentRootDir.render()
assertInHTML('<link href="glob/glob_1.css" media="all" rel="stylesheet">', rendered)
assertInHTML('<script src="glob/glob_1.js"></script>', rendered)
@djc_test(
django_settings={
"INSTALLED_APPS": ("django_components", "tests"),
}
)
def test_non_globs_not_modified_nonexist(self):
from tests.components.glob.glob import NonGlobNonexistComponentRootDir
rendered = NonGlobNonexistComponentRootDir.render()
assertInHTML('<link href="glob/glob_nonexist.css" media="all" rel="stylesheet">', rendered)
assertInHTML('<script src="glob/glob_nonexist.js"></script>', rendered)
def test_glob_pattern_does_not_break_urls(self):
from tests.components.glob.glob import UrlComponent
rendered = UrlComponent.render()