diff --git a/pyproject.toml b/pyproject.toml index 6fe7e7c..f865827 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ requires = ["setuptools"] [project] name = "jinjax" -version = "0.53" +version = "0.54" description = "Replace your HTML templates with Python server-Side components" authors = [ {name = "Juan Pablo Scaletti", email = "juanpablo@jpscaletti.com"}, @@ -15,7 +15,6 @@ classifiers = [ "Development Status :: 4 - Beta", "Environment :: Web Environment", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", diff --git a/src/jinjax/catalog.py b/src/jinjax/catalog.py index 367ef11..949fa43 100644 --- a/src/jinjax/catalog.py +++ b/src/jinjax/catalog.py @@ -430,41 +430,10 @@ class Catalog: """ content = (kw.pop("_content", kw.pop("__content", "")) or "").strip() attrs = kw.pop("_attrs", kw.pop("__attrs", None)) or {} - source = kw.pop("_source", kw.pop("__source", "")) - file_ext = kw.pop("_file_ext", kw.pop("__file_ext", "")) or self.file_ext - caller_prefix = kw.pop("__prefix", "") - - cname = __name - prefix, name = self._split_name(cname) - component = None - - if source: - logger.debug("Rendering from source %s", cname) - self.jinja_env.loader = self.prefixes[prefix] - component = self._get_from_source(prefix=prefix, name=name, source=source) - else: - logger.debug("Rendering from cache or file %s", cname) - get_from = self._get_from_cache if self.use_cache else self._get_from_file - - if caller_prefix: - self.jinja_env.loader = self.prefixes[caller_prefix] - component = get_from( - prefix=caller_prefix, - name=cname, - file_ext=file_ext - ) - if not component: - self.jinja_env.loader = self.prefixes[prefix] - component = get_from( - prefix=prefix, - name=name, - file_ext=file_ext - ) - - if not component: - raise ComponentNotFound(cname, file_ext) + component = self._get_component(__name, **kw) root_path = component.path.parent if component.path else None + # Get current assets lists css_list = self.collected_css js_list = self.collected_js @@ -633,6 +602,39 @@ class Catalog: return f"{parent}{stem}-{fingerprint}{ext}" + def _get_component(self, cname: str, **kw) -> Component: + source = kw.pop("_source", kw.pop("__source", "")) + file_ext = kw.pop("_file_ext", kw.pop("__file_ext", "")) or self.file_ext + caller_prefix = kw.pop("__prefix", "") + + prefix, name = self._split_name(cname) + component = None + + if source: + logger.debug("Rendering from source %s", cname) + self.jinja_env.loader = self.prefixes[prefix] + return self._get_from_source(prefix=prefix, name=name, source=source) + + logger.debug("Rendering from cache or file %s", cname) + get_from = self._get_from_cache if self.use_cache else self._get_from_file + if caller_prefix: + self.jinja_env.loader = self.prefixes[caller_prefix] + component = get_from( + prefix=caller_prefix, + name=cname, + file_ext=file_ext + ) + if not component: + self.jinja_env.loader = self.prefixes[prefix] + component = get_from( + prefix=prefix, + name=name, + file_ext=file_ext + ) + if component: + return component + raise ComponentNotFound(cname, file_ext) + def _get_from_source( self, *, @@ -706,9 +708,7 @@ class Catalog: root_paths = self.prefixes[prefix].searchpath name = name.replace(DELIMITER, SLASH) - name_path = Path(name) - kebab_stem = kebab_case(name_path.stem) - kebab_name = str(name_path.with_name(kebab_stem)) + kebab_name = kebab_case(name) dot_names = (f"{name}.", f"{kebab_name}.") for root_path in root_paths: @@ -716,7 +716,10 @@ class Catalog: root_path, topdown=False, followlinks=True ): relfolder = os.path.relpath(curr_folder, root_path).strip(".") - if relfolder and not name.startswith(relfolder): + if relfolder and not ( + name.startswith(relfolder) + or kebab_name.startswith(relfolder) + ): continue for filename in files: @@ -724,6 +727,7 @@ class Catalog: filepath = f"{relfolder}/{filename}" else: filepath = filename + if filepath.startswith(dot_names) and filepath.endswith(file_ext): return Path(curr_folder) / filename, Path(filepath) diff --git a/src/jinjax/utils.py b/src/jinjax/utils.py index 26270eb..1748844 100644 --- a/src/jinjax/utils.py +++ b/src/jinjax/utils.py @@ -32,6 +32,10 @@ def kebab_case(word: str) -> str: 'html' >>> kebab_case("ui.AwesomeDialog") 'ui.awesome-dialog' + >>> kebab_case("MyFolder/DeviceType") + 'my-folder/device-type' + >>> kebab_case("MyFolder.DeviceType") + 'my-folder.device-type' """ word = re.sub(r"([A-Z]+)([A-Z][a-z])", r"\1-\2", word) diff --git a/tests/test_render.py b/tests/test_render.py index b8b92d9..a9ec75c 100644 --- a/tests/test_render.py +++ b/tests/test_render.py @@ -805,12 +805,15 @@ def test_slots(catalog, folder, autoescape): @pytest.mark.parametrize("autoescape", [True, False]) -def test_alt_cased_component_names(catalog, folder, autoescape): - (folder / "a_tricky-FOLDER").mkdir() +def test_kebab_cased_component_names(catalog, folder, autoescape): catalog.jinja_env.autoescape = autoescape + (folder / "a_tricky-FOLDER").mkdir() + (folder / "kebab-folder").mkdir() (folder / "kebab-cased.jinja").write_text("kebab") (folder / "a_tricky-FOLDER" / "Greeting.jinja").write_text("pascal") + (folder / "kebab-folder" / "kebab-cased.jinja").write_text("superkebab") assert catalog.render("KebabCased") == Markup("kebab") assert catalog.render("a_tricky-FOLDER.Greeting") == Markup("pascal") + assert catalog.render("KebabFolder.KebabCased") == Markup("superkebab") diff --git a/uv.lock b/uv.lock index 1aa19f4..64a29ce 100644 --- a/uv.lock +++ b/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 1 requires-python = ">=3.11, <4" [[package]] @@ -214,7 +215,7 @@ wheels = [ [[package]] name = "jinjax" -version = "0.53" +version = "0.54" source = { editable = "." } dependencies = [ { name = "jinja2" }, @@ -247,6 +248,7 @@ requires-dist = [ { name = "markupsafe", specifier = ">=2.0" }, { name = "whitenoise", marker = "extra == 'whitenoise'" }, ] +provides-extras = ["whitenoise"] [package.metadata.requires-dev] dev = [