1
0
Fork 0

Merging upstream version 0.56+dfsg.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-02 13:03:34 +02:00
parent 683f3a672a
commit aeb0367086
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
23 changed files with 131 additions and 20 deletions

1
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1 @@
github: jpsca

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021-2022 Juan-Pablo Scaletti
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -1,3 +1,7 @@
"""
JinjaX Benchmark
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import timeit
from pathlib import Path

View file

@ -1,3 +1,7 @@
"""
JinjaX Benchmark
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
from pathlib import Path
from jinjax import Catalog, Component

View file

@ -4,7 +4,7 @@ requires = ["setuptools"]
[project]
name = "jinjax"
version = "0.55"
version = "0.56"
description = "Replace your HTML templates with Python server-Side components"
authors = [
{name = "Juan Pablo Scaletti", email = "juanpablo@jpscaletti.com"},
@ -45,7 +45,7 @@ documentation = "https://jinjax.scaletti.dev/guides/"
[dependency-groups]
dev = [
"ipdb >= 0.13",
"pyright >= 1.1",
"pyright >= 1.1.400",
"pre-commit",
"ruff >= 0.2.0",
"tox-uv",

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
from . import utils # noqa
from .catalog import Catalog
from .component import Component

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import os
import typing as t
from collections import UserString
@ -40,6 +44,8 @@ collected_css: dict[int, ContextVar[list[str]]] = {}
collected_js: dict[int, ContextVar[list[str]]] = {}
tmpl_globals: dict[int, ContextVar[dict[str, t.Any]]] = {}
RelPath = Path
class CallerWrapper(UserString):
_content = ""
@ -590,7 +596,7 @@ class Catalog:
html_js.append(f'<script type="module" src="{full_url}"></script>')
rendered_urls.add(full_url)
return Markup("\n".join(html_css + html_js))
return Markup("\n".join(sorted(html_css) + sorted(html_js)))
# Private
@ -712,7 +718,7 @@ class Catalog:
prefix: str,
name: str,
file_ext: str,
) -> tuple[Path, Path] | None:
) -> tuple[Path, RelPath] | None:
root_paths = self.prefixes[prefix].searchpath
name = name.replace(DELIMITER, SLASH)
@ -724,11 +730,21 @@ class Catalog:
root_path, topdown=False, followlinks=True
):
relfolder = os.path.relpath(curr_folder, root_path).strip(".")
if relfolder and not (
name.startswith(relfolder)
or kebab_name.startswith(relfolder)
):
continue
if relfolder:
if not (
name.startswith(relfolder)
or kebab_name.startswith(relfolder)
):
continue
# Allow for index.jinja files in subfolders
# to be used as the folder name
if relfolder in (name, kebab_name):
filename = f"index{file_ext}"
fullpath = Path(curr_folder) / filename
if fullpath.is_file():
relpath = Path(f"{relfolder}/{filename}")
return fullpath, relpath
for filename in files:
if relfolder:
@ -737,7 +753,10 @@ class Catalog:
filepath = filename
if filepath.startswith(dot_names) and filepath.endswith(file_ext):
return Path(curr_folder) / filename, Path(filepath)
fullpath = Path(curr_folder) / filename
relpath = Path(filepath)
if fullpath.is_file():
return fullpath, relpath
def _render_attrs(self, attrs: dict[str, t.Any]) -> Markup:
html_attrs = []

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import ast
import re
import typing as t

View file

@ -1,3 +1,8 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
class ComponentNotFound(Exception):
"""
Raised when JinjaX can't find a component by name in none of the

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import re
import typing as t
from collections import UserString

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import re
import typing as t
from uuid import uuid4

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import re
import typing as t
from pathlib import Path

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import logging
import re
import uuid

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import pytest
import jinjax

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import pytest
import jinjax

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import pytest
from jinjax import Component, DuplicateDefDeclaration, InvalidArgument

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import pytest
from jinjax.html_attrs import HTMLAttrs

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import typing as t
from pathlib import Path

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import jinja2
import pytest
from markupsafe import Markup

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
import time
from textwrap import dedent
@ -243,6 +247,24 @@ def test_subfolder(catalog, folder, autoescape, undefined):
assert html == Markup('<div class="tab">Meh</div>')
@pytest.mark.parametrize("undefined", [jinja2.Undefined, jinja2.StrictUndefined])
@pytest.mark.parametrize("autoescape", [True, False])
def test_subfolder_index_file(catalog, folder, autoescape, undefined):
"""Components named "index.jinja" in subfolders can be called
using the subfolder names.
"""
catalog.jinja_env.autoescape = autoescape
catalog.jinja_env.undefined = undefined
sub = folder / "tab"
sub.mkdir()
(sub / "index.jinja").write_text("Hello")
(sub / "panel.jinja").write_text("World")
assert catalog.render("Tab") == Markup("Hello")
assert catalog.render("Tab.Panel") == Markup("World")
@pytest.mark.parametrize("undefined", [jinja2.Undefined, jinja2.StrictUndefined])
@pytest.mark.parametrize("autoescape", [True, False])
def test_default_attr(catalog, folder, autoescape, undefined):

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
from pathlib import Path
import jinja2
@ -57,14 +61,14 @@ def test_render_assets(catalog, folder, autoescape, undefined):
assert (
"""
<html>
<link rel="stylesheet" href="https://somewhere.com/style.css">
<link rel="stylesheet" href="/static/components/card.css">
<link rel="stylesheet" href="/static/components/greeting.css">
<link rel="stylesheet" href="http://example.com/super.css">
<script type="module" src="https://somewhere.com/blabla.js"></script>
<script type="module" src="/static/components/shared.js"></script>
<link rel="stylesheet" href="https://somewhere.com/style.css">
<script type="module" src="/static/components/card.js"></script>
<script type="module" src="/static/components/greeting.js"></script>
<script type="module" src="/static/components/shared.js"></script>
<script type="module" src="https://somewhere.com/blabla.js"></script>
<section class="card">
<div class="greeting [&_a]:flex">Hello</div>
<button type="button">Close</button>
@ -195,8 +199,8 @@ def test_auto_load_assets_with_same_name(catalog, folder, autoescape, undefined)
<link rel="stylesheet" href="/static/components/Page.css">
<link rel="stylesheet" href="/static/components/common/Form.css">
<script type="module" src="/static/components/Page.js"></script>
<script type="module" src="/static/components/shared.js"></script>
<script type="module" src="/static/components/common/Form.js"></script>
<script type="module" src="/static/components/shared.js"></script>
<form></form>
""".strip()

View file

@ -1,3 +1,7 @@
"""
JinjaX
Copyright (c) Juan-Pablo Scaletti <juanpablo@jpscaletti.com>
"""
from threading import Thread
from markupsafe import Markup

10
uv.lock generated
View file

@ -215,7 +215,7 @@ wheels = [
[[package]]
name = "jinjax"
version = "0.55"
version = "0.56"
source = { editable = "." }
dependencies = [
{ name = "jinja2" },
@ -254,7 +254,7 @@ provides-extras = ["whitenoise"]
dev = [
{ name = "ipdb", specifier = ">=0.13" },
{ name = "pre-commit" },
{ name = "pyright", specifier = ">=1.1" },
{ name = "pyright", specifier = ">=1.1.400" },
{ name = "ruff", specifier = ">=0.2.0" },
{ name = "tox-uv" },
]
@ -451,15 +451,15 @@ wheels = [
[[package]]
name = "pyright"
version = "1.1.396"
version = "1.1.400"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nodeenv" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/bd/73/f20cb1dea1bdc1774e7f860fb69dc0718c7d8dea854a345faec845eb086a/pyright-1.1.396.tar.gz", hash = "sha256:142901f5908f5a0895be3d3befcc18bedcdb8cc1798deecaec86ef7233a29b03", size = 3814400 }
sdist = { url = "https://files.pythonhosted.org/packages/6c/cb/c306618a02d0ee8aed5fb8d0fe0ecfed0dbf075f71468f03a30b5f4e1fe0/pyright-1.1.400.tar.gz", hash = "sha256:b8a3ba40481aa47ba08ffb3228e821d22f7d391f83609211335858bf05686bdb", size = 3846546 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/80/be/ecb7cfb42d242b7ee764b52e6ff4782beeec00e3b943a3ec832b281f9da6/pyright-1.1.396-py3-none-any.whl", hash = "sha256:c635e473095b9138c471abccca22b9fedbe63858e0b40d4fc4b67da041891844", size = 5689355 },
{ url = "https://files.pythonhosted.org/packages/c8/a5/5d285e4932cf149c90e3c425610c5efaea005475d5f96f1bfdb452956c62/pyright-1.1.400-py3-none-any.whl", hash = "sha256:c80d04f98b5a4358ad3a35e241dbf2a408eee33a40779df365644f8054d2517e", size = 5563460 },
]
[[package]]