Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup tests, linting and codestyle checks #77

Merged
merged 12 commits into from
Oct 16, 2023
2 changes: 1 addition & 1 deletion .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ jobs:
- uses: "actions/setup-python@v4"
with:
python-version: 3.x
- uses: "pre-commit/action@v2.0.3"
- uses: "pre-commit/action@v3.0.0"
31 changes: 31 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Run Test Matrix

on:
push:
branches: [master]
pull_request:
branches: [master]

concurrency:
group: ${{ github.head_ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install tox tox-gh-actions
- name: Test with tox
run: tox
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
__pycache__/
.tox
.vscode
.coverage
*.egg-info
9 changes: 2 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: "https://github.com/pre-commit/pre-commit-hooks"
rev: "v4.1.0"
rev: "v4.4.0"
hooks:
- id: "check-toml"
- id: "check-yaml"
Expand All @@ -10,15 +10,10 @@ repos:
- id: "trailing-whitespace"

- repo: "https://github.com/psf/black"
rev: "22.3.0"
rev: "23.3.0"
hooks:
- id: "black"

- repo: "https://github.com/PyCQA/flake8"
rev: "4.0.1"
hooks:
- id: "flake8"

- repo: "https://github.com/commitizen-tools/commitizen"
rev: master
hooks:
Expand Down
13 changes: 7 additions & 6 deletions django_vite/apps.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from contextlib import suppress

from django.apps import AppConfig
from django.core.checks import Warning, register

from .exceptions import DjangoViteManifestError
from .templatetags.django_vite import DjangoViteAssetLoader


Expand All @@ -9,12 +12,10 @@ class DjangoViteAppConfig(AppConfig):
verbose_name = "Django Vite"

def ready(self) -> None:
try:
# Create Loader instance at startup to prevent threading problems.
with suppress(DjangoViteManifestError):
# Create Loader instance at startup to prevent threading problems,
# but do not crash while doing so.
DjangoViteAssetLoader.instance()
except RuntimeError:
# Just continue, the system check below outputs a warning.
pass


@register
Expand All @@ -25,7 +26,7 @@ def check_loader_instance(**kwargs):
# Make Loader instance at startup to prevent threading problems
DjangoViteAssetLoader.instance()
return []
except RuntimeError as exception:
except DjangoViteManifestError as exception:
return [
Warning(
exception,
Expand Down
10 changes: 10 additions & 0 deletions django_vite/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class DjangoViteManifestError(RuntimeError):
"""Manifest parsing failed."""

pass


class DjangoViteAssetNotFoundError(RuntimeError):
"""Vite Asset could not be found."""

pass
86 changes: 32 additions & 54 deletions django_vite/templatetags/django_vite.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import json
from pathlib import Path
from typing import Dict, List, Callable
from typing import Callable, Dict, List
from urllib.parse import urljoin

from django import template
from django.apps import apps
from django.conf import settings
from django.utils.safestring import mark_safe

register = template.Library()
from django_vite.exceptions import DjangoViteAssetNotFoundError, DjangoViteManifestError

register = template.Library()

# If using in development or production mode.
DJANGO_VITE_DEV_MODE = getattr(settings, "DJANGO_VITE_DEV_MODE", False)
Expand All @@ -25,9 +26,7 @@
)

# Default Vite server port.
DJANGO_VITE_DEV_SERVER_PORT = getattr(
settings, "DJANGO_VITE_DEV_SERVER_PORT", 3000
)
DJANGO_VITE_DEV_SERVER_PORT = getattr(settings, "DJANGO_VITE_DEV_SERVER_PORT", 3000)

# Default Vite server path to HMR script.
DJANGO_VITE_WS_CLIENT_URL = getattr(
Expand All @@ -42,12 +41,10 @@
# Must be included in your "STATICFILES_DIRS".
# In Django production mode this folder need to be collected as static
# files using "python manage.py collectstatic".
DJANGO_VITE_ASSETS_PATH = Path(getattr(settings, "DJANGO_VITE_ASSETS_PATH"))
DJANGO_VITE_ASSETS_PATH = Path(settings.DJANGO_VITE_ASSETS_PATH)

# Prefix for STATIC_URL
DJANGO_VITE_STATIC_URL_PREFIX = getattr(
settings, "DJANGO_VITE_STATIC_URL_PREFIX", ""
)
DJANGO_VITE_STATIC_URL_PREFIX = getattr(settings, "DJANGO_VITE_STATIC_URL_PREFIX", "")

DJANGO_VITE_STATIC_ROOT = (
DJANGO_VITE_ASSETS_PATH
Expand All @@ -68,9 +65,7 @@
settings, "DJANGO_VITE_LEGACY_POLYFILLS_MOTIF", "legacy-polyfills"
)

DJANGO_VITE_STATIC_URL = urljoin(
settings.STATIC_URL, DJANGO_VITE_STATIC_URL_PREFIX
)
DJANGO_VITE_STATIC_URL = urljoin(settings.STATIC_URL, DJANGO_VITE_STATIC_URL_PREFIX)

# Make sure 'DJANGO_VITE_STATIC_URL' finish with a '/'
if DJANGO_VITE_STATIC_URL[-1] != "/":
Expand Down Expand Up @@ -110,7 +105,7 @@ def generate_vite_asset(
script tags.

Raises:
RuntimeError: If cannot find the file path in the
DjangoViteAssetNotFoundError: If cannot find the file path in the
manifest (only in production).

Returns:
Expand All @@ -125,7 +120,7 @@ def generate_vite_asset(
)

if not self._manifest or path not in self._manifest:
raise RuntimeError(
raise DjangoViteAssetNotFoundError(
f"Cannot find {path} in Vite manifest "
f"at {DJANGO_VITE_MANIFEST_PATH}"
)
Expand Down Expand Up @@ -158,9 +153,7 @@ def generate_vite_asset(
for dep in manifest_entry.get("imports", []):
dep_manifest_entry = self._manifest[dep]
dep_file = dep_manifest_entry["file"]
url = DjangoViteAssetLoader._generate_production_server_url(
dep_file
)
url = DjangoViteAssetLoader._generate_production_server_url(dep_file)
tags.append(
DjangoViteAssetLoader._generate_preload_tag(
url,
Expand Down Expand Up @@ -188,7 +181,7 @@ def preload_vite_asset(
str -- All tags to preload this file in your HTML page.

Raises:
RuntimeError: If cannot find the file path in the
DjangoViteAssetNotFoundError: if cannot find the file path in the
manifest.

Returns:
Expand All @@ -199,7 +192,7 @@ def preload_vite_asset(
return ""

if not self._manifest or path not in self._manifest:
raise RuntimeError(
raise DjangoViteAssetNotFoundError(
f"Cannot find {path} in Vite manifest "
f"at {DJANGO_VITE_MANIFEST_PATH}"
)
Expand All @@ -216,9 +209,7 @@ def preload_vite_asset(
}

manifest_file = manifest_entry["file"]
url = DjangoViteAssetLoader._generate_production_server_url(
manifest_file
)
url = DjangoViteAssetLoader._generate_production_server_url(manifest_file)
tags.append(
DjangoViteAssetLoader._generate_preload_tag(
url,
Expand All @@ -233,9 +224,7 @@ def preload_vite_asset(
for dep in manifest_entry.get("imports", []):
dep_manifest_entry = self._manifest[dep]
dep_file = dep_manifest_entry["file"]
url = DjangoViteAssetLoader._generate_production_server_url(
dep_file
)
url = DjangoViteAssetLoader._generate_production_server_url(dep_file)
tags.append(
DjangoViteAssetLoader._generate_preload_tag(
url,
Expand Down Expand Up @@ -291,10 +280,8 @@ def _generate_css_files_of_asset(
if "css" in manifest_entry:
for css_path in manifest_entry["css"]:
if css_path not in already_processed:
url = (
DjangoViteAssetLoader._generate_production_server_url(
css_path
)
url = DjangoViteAssetLoader._generate_production_server_url(
css_path
)
tags.append(tag_generator(url))

Expand All @@ -311,7 +298,7 @@ def generate_vite_asset_url(self, path: str) -> str:
path {str} -- Path to a Vite asset.

Raises:
RuntimeError: If cannot find the asset path in the
DjangoViteAssetNotFoundError: If cannot find the asset path in the
manifest (only in production).

Returns:
Expand All @@ -322,7 +309,7 @@ def generate_vite_asset_url(self, path: str) -> str:
return DjangoViteAssetLoader._generate_vite_server_url(path)

if not self._manifest or path not in self._manifest:
raise RuntimeError(
raise DjangoViteAssetNotFoundError(
f"Cannot find {path} in Vite manifest "
f"at {DJANGO_VITE_MANIFEST_PATH}"
)
Expand All @@ -346,7 +333,7 @@ def generate_vite_legacy_polyfills(
script tags.

Raises:
RuntimeError: If polyfills path not found inside
DjangoViteAssetNotFoundError: If polyfills path not found inside
the 'manifest.json' (only in production).

Returns:
Expand All @@ -367,7 +354,7 @@ def generate_vite_legacy_polyfills(
attrs=scripts_attrs,
)

raise RuntimeError(
raise DjangoViteAssetNotFoundError(
f"Vite legacy polyfills not found in manifest "
f"at {DJANGO_VITE_MANIFEST_PATH}"
)
Expand All @@ -391,7 +378,7 @@ def generate_vite_legacy_asset(
script tags.

Raises:
RuntimeError: If cannot find the asset path in the
DjangoViteAssetNotFoundError: If cannot find the asset path in the
manifest (only in production).

Returns:
Expand All @@ -402,7 +389,7 @@ def generate_vite_legacy_asset(
return ""

if not self._manifest or path not in self._manifest:
raise RuntimeError(
raise DjangoViteAssetNotFoundError(
f"Cannot find {path} in Vite manifest "
f"at {DJANGO_VITE_MANIFEST_PATH}"
)
Expand All @@ -422,19 +409,19 @@ def _parse_manifest(self) -> None:
Read and parse the Vite manifest file.

Raises:
RuntimeError: if cannot load the file or JSON in file is malformed.
DjangoViteManifestError: if cannot load the file or JSON in file is
malformed.
"""

try:
manifest_file = open(DJANGO_VITE_MANIFEST_PATH, "r")
manifest_content = manifest_file.read()
manifest_file.close()
with open(DJANGO_VITE_MANIFEST_PATH, "r") as manifest_file:
manifest_content = manifest_file.read()
self._manifest = json.loads(manifest_content)
except Exception as error:
raise RuntimeError(
raise DjangoViteManifestError(
f"Cannot read Vite manifest file at "
f"{DJANGO_VITE_MANIFEST_PATH} : {str(error)}"
)
) from error

@classmethod
def instance(cls):
Expand Down Expand Up @@ -496,9 +483,7 @@ def _generate_script_tag(src: str, attrs: Dict[str, str]) -> str:
str -- The script tag.
"""

attrs_str = " ".join(
[f'{key}="{value}"' for key, value in attrs.items()]
)
attrs_str = " ".join([f'{key}="{value}"' for key, value in attrs.items()])

return f'<script {attrs_str} src="{src}"></script>'

Expand Down Expand Up @@ -532,9 +517,7 @@ def _generate_stylesheet_preload_tag(href: str) -> str:

@staticmethod
def _generate_preload_tag(href: str, attrs: Dict[str, str]) -> str:
attrs_str = " ".join(
[f'{key}="{value}"' for key, value in attrs.items()]
)
attrs_str = " ".join([f'{key}="{value}"' for key, value in attrs.items()])

return f'<link href="{href}" {attrs_str} />'

Expand Down Expand Up @@ -682,7 +665,6 @@ def vite_preload_asset(
manifest (only in production).

"""

assert path is not None

return DjangoViteAssetLoader.instance().preload_vite_asset(path)
Expand Down Expand Up @@ -731,9 +713,7 @@ def vite_legacy_polyfills(**kwargs: Dict[str, str]) -> str:
str -- The script tag to the polyfills.
"""

return DjangoViteAssetLoader.instance().generate_vite_legacy_polyfills(
**kwargs
)
return DjangoViteAssetLoader.instance().generate_vite_legacy_polyfills(**kwargs)


@register.simple_tag
Expand Down Expand Up @@ -765,9 +745,7 @@ def vite_legacy_asset(

assert path is not None

return DjangoViteAssetLoader.instance().generate_vite_legacy_asset(
path, **kwargs
)
return DjangoViteAssetLoader.instance().generate_vite_legacy_asset(path, **kwargs)


@register.simple_tag
Expand Down
Loading