makejinja 2.8.0__tar.gz → 2.8.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,10 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.3
2
2
  Name: makejinja
3
- Version: 2.8.0
3
+ Version: 2.8.2
4
4
  Summary: Generate entire directory structures using Jinja templates with support for external data and custom plugins
5
- Author-email: Mirko Lenz <mirko@mirkolenz.com>
6
- Project-URL: Repository, https://github.com/mirkolenz/makejinja
7
- Project-URL: Homepage, https://mirkolenz.github.io/makejinja/
8
- Project-URL: Documentation, https://mirkolenz.github.io/makejinja/makejinja/cli.html
9
- Project-URL: Issues, https://github.com/mirkolenz/makejinja/issues
10
- Project-URL: Changelog, https://github.com/mirkolenz/makejinja/releases
11
5
  Keywords: jinja2,home-assistant,hassio,dashboard,lovelace,template,generator,cli,tool,library
6
+ Author: Mirko Lenz
7
+ Author-email: Mirko Lenz <mirko@mirkolenz.com>
12
8
  Classifier: Development Status :: 5 - Production/Stable
13
9
  Classifier: Environment :: Console
14
10
  Classifier: Framework :: Pytest
@@ -18,9 +14,9 @@ Classifier: Intended Audience :: System Administrators
18
14
  Classifier: License :: OSI Approved :: MIT License
19
15
  Classifier: Natural Language :: English
20
16
  Classifier: Operating System :: OS Independent
21
- Classifier: Programming Language :: Python :: 3.11
22
17
  Classifier: Programming Language :: Python :: 3.12
23
18
  Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
24
20
  Classifier: Programming Language :: Python :: 3
25
21
  Classifier: Topic :: File Formats
26
22
  Classifier: Topic :: Home Automation
@@ -31,15 +27,18 @@ Classifier: Topic :: System :: Systems Administration
31
27
  Classifier: Topic :: Text Processing :: Markup
32
28
  Classifier: Topic :: Utilities
33
29
  Classifier: Typing :: Typed
34
- Requires-Python: >=3.11
30
+ Requires-Dist: frozendict>=2,<3
31
+ Requires-Dist: jinja2>=3,<4
32
+ Requires-Dist: pyyaml>=6,<7
33
+ Requires-Dist: rich-click>=1,<2
34
+ Requires-Dist: typed-settings[attrs,cattrs,click]>=23,<26
35
+ Requires-Python: >=3.12, <4
36
+ Project-URL: Changelog, https://github.com/mirkolenz/makejinja/releases
37
+ Project-URL: Documentation, https://mirkolenz.github.io/makejinja/makejinja/cli.html
38
+ Project-URL: Homepage, https://mirkolenz.github.io/makejinja/
39
+ Project-URL: Issues, https://github.com/mirkolenz/makejinja/issues
40
+ Project-URL: Repository, https://github.com/mirkolenz/makejinja
35
41
  Description-Content-Type: text/markdown
36
- License-File: LICENSE
37
- Requires-Dist: jinja2<4,>=3
38
- Requires-Dist: pyyaml<7,>=6
39
- Requires-Dist: rich-click<2,>=1
40
- Requires-Dist: typed-settings[attrs,cattrs,click]<25,>=23
41
- Requires-Dist: immutables<1,>=0.20
42
- Dynamic: license-file
43
42
 
44
43
  <!-- markdownlint-disable MD033 MD041 -->
45
44
  <h1><p align="center">makejinja</p></h1>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "makejinja"
3
- version = "2.8.0"
3
+ version = "2.8.2"
4
4
  description = "Generate entire directory structures using Jinja templates with support for external data and custom plugins"
5
5
  authors = [{ name = "Mirko Lenz", email = "mirko@mirkolenz.com" }]
6
6
  readme = "README.md"
@@ -26,9 +26,9 @@ classifiers = [
26
26
  "License :: OSI Approved :: MIT License",
27
27
  "Natural Language :: English",
28
28
  "Operating System :: OS Independent",
29
- "Programming Language :: Python :: 3.11",
30
29
  "Programming Language :: Python :: 3.12",
31
30
  "Programming Language :: Python :: 3.13",
31
+ "Programming Language :: Python :: 3.14",
32
32
  "Programming Language :: Python :: 3",
33
33
  "Topic :: File Formats",
34
34
  "Topic :: Home Automation",
@@ -40,13 +40,13 @@ classifiers = [
40
40
  "Topic :: Utilities",
41
41
  "Typing :: Typed",
42
42
  ]
43
- requires-python = ">=3.11"
43
+ requires-python = ">=3.12,<4"
44
44
  dependencies = [
45
+ "frozendict>=2,<3",
45
46
  "jinja2>=3,<4",
46
47
  "pyyaml>=6,<7",
47
48
  "rich-click>=1,<2",
48
- "typed-settings[attrs,cattrs,click]>=23,<25",
49
- "immutables>=0.20,<1",
49
+ "typed-settings[attrs,cattrs,click]>=23,<26",
50
50
  ]
51
51
 
52
52
  [project.urls]
@@ -60,25 +60,18 @@ Changelog = "https://github.com/mirkolenz/makejinja/releases"
60
60
  makejinja = "makejinja.cli:makejinja_cli"
61
61
 
62
62
  [dependency-groups]
63
- test = ["pytest>=8,<9", "pytest-cov>=6,<7"]
64
- docs = ["pdoc>=15,<16"]
63
+ test = ["pytest>=9,<10", "pytest-cov>=7,<8"]
64
+ docs = ["pdoc>=16,<17"]
65
65
 
66
66
  [build-system]
67
- requires = ["setuptools>=61"]
68
- build-backend = "setuptools.build_meta"
67
+ requires = ["uv-build>=0.9,<1"]
68
+ build-backend = "uv_build"
69
69
 
70
70
  [tool.uv]
71
71
  default-groups = ["test", "docs"]
72
72
 
73
- [tool.pytest.ini_options]
74
- addopts = "--cov makejinja --cov-report term-missing"
75
-
76
- [tool.ruff]
77
- target-version = "py311"
78
-
79
- [tool.ruff.lint]
80
- select = ["E", "W", "F", "B", "UP"]
81
- ignore = ["E501"]
73
+ [tool.pytest]
74
+ addopts = ["--cov=makejinja", "--cov-report=term-missing"]
82
75
 
83
76
  [tool.ruff.lint.pydocstyle]
84
77
  convention = "google"
@@ -10,11 +10,11 @@ from inspect import signature
10
10
  from pathlib import Path
11
11
  from typing import Any
12
12
 
13
+ import rich_click as click
13
14
  import yaml
14
15
  from jinja2 import BaseLoader, ChoiceLoader, DictLoader, Environment, FileSystemLoader
15
16
  from jinja2.environment import load_extensions
16
17
  from jinja2.utils import import_string
17
- from rich import print
18
18
 
19
19
  from makejinja.config import Config
20
20
  from makejinja.plugin import Data, MutableData, PathFilter, Plugin
@@ -26,15 +26,15 @@ STDIN_PATH = Path("/dev/stdin").resolve()
26
26
 
27
27
 
28
28
  def log(message: str, config: Config) -> None:
29
- if not config.quiet and config.output != STDOUT_PATH:
30
- print(message)
29
+ if not config.quiet:
30
+ click.echo(message, err=True)
31
31
 
32
32
 
33
33
  def exec(cmd: str) -> None:
34
34
  subprocess.run(cmd, shell=True, check=True)
35
35
 
36
36
 
37
- def makejinja(config: Config):
37
+ def makejinja(config: Config) -> None:
38
38
  """makejinja can be used to automatically generate files from [Jinja templates](https://jinja.palletsprojects.com/en/3.1.x/templates/)."""
39
39
 
40
40
  for cmd in config.exec_pre:
@@ -231,7 +231,7 @@ def init_jinja_env(
231
231
  line_comment_prefix=config.prefix.line_comment,
232
232
  trim_blocks=config.whitespace.trim_blocks,
233
233
  lstrip_blocks=config.whitespace.lstrip_blocks,
234
- newline_sequence=config.whitespace.newline_sequence, # type: ignore
234
+ newline_sequence=config.whitespace.newline_sequence,
235
235
  keep_trailing_newline=config.whitespace.keep_trailing_newline,
236
236
  optimized=config.internal.optimized,
237
237
  undefined=config.undefined.value,
@@ -254,19 +254,38 @@ def from_yaml(path: Path) -> dict[str, Any]:
254
254
 
255
255
  with path.open("rb") as fp:
256
256
  for doc in yaml.safe_load_all(fp):
257
- data |= doc
257
+ if isinstance(doc, abc.Mapping):
258
+ data |= doc
259
+ else:
260
+ raise TypeError(
261
+ f"Expected YAML documents in '{path}' to be mappings but found {type(doc).__name__}"
262
+ )
258
263
 
259
264
  return data
260
265
 
261
266
 
262
267
  def from_toml(path: Path) -> dict[str, Any]:
263
268
  with path.open("rb") as fp:
264
- return tomllib.load(fp)
269
+ data = tomllib.load(fp)
270
+
271
+ if isinstance(data, abc.Mapping):
272
+ return dict(data)
273
+
274
+ raise TypeError(
275
+ f"Expected TOML documents in '{path}' to be mappings but found {type(data).__name__}"
276
+ )
265
277
 
266
278
 
267
279
  def from_json(path: Path) -> dict[str, Any]:
268
280
  with path.open("rb") as fp:
269
- return json.load(fp)
281
+ data = json.load(fp)
282
+
283
+ if isinstance(data, abc.Mapping):
284
+ return data
285
+
286
+ raise TypeError(
287
+ f"Expected JSON documents in '{path}' to be mappings but found {type(data).__name__}"
288
+ )
270
289
 
271
290
 
272
291
  DATA_LOADERS: dict[str, abc.Callable[[Path], dict[str, Any]]] = {
@@ -29,7 +29,7 @@ def makejinja_cli(config: Config):
29
29
 
30
30
  Instead of passing CLI options, you can also write them to a file called `makejinja.toml` in your working directory.
31
31
  **Note**: In this file, options may be named differently.
32
- Please refer to the file [`makejinja/config.py`](https://github.com/mirkolenz/makejinja/blob/main/makejinja/config.py) to see their actual names.
32
+ Please refer to the file [`makejinja/config.py`](https://github.com/mirkolenz/makejinja/blob/main/src/makejinja/config.py) to see their actual names.
33
33
  You will also find an example here: [`makejinja/tests/data/makejinja.toml`](https://github.com/mirkolenz/makejinja/blob/main/tests/data/makejinja.toml).
34
34
  To override its location, you can set the environment variable `MAKEJINJA_SETTINGS` to the path of your config file.
35
35
  """
@@ -2,17 +2,15 @@ from collections import abc
2
2
  from enum import Enum
3
3
  from pathlib import Path
4
4
 
5
- import immutables
6
5
  import rich_click as click
7
6
  import typed_settings as ts
7
+ from frozendict import frozendict
8
8
  from jinja2 import (
9
9
  ChainableUndefined,
10
10
  DebugUndefined,
11
11
  StrictUndefined,
12
12
  )
13
- from jinja2 import (
14
- Undefined as DefaultUndefined,
15
- )
13
+ from jinja2 import Undefined as DefaultUndefined
16
14
  from jinja2.defaults import (
17
15
  BLOCK_END_STRING,
18
16
  BLOCK_START_STRING,
@@ -24,9 +22,9 @@ from jinja2.defaults import (
24
22
  VARIABLE_END_STRING,
25
23
  VARIABLE_START_STRING,
26
24
  )
25
+ from rich_click.utils import OptionGroupDict
27
26
 
28
27
  __all__ = ["Config", "Delimiter", "Internal", "Prefix", "Whitespace", "Undefined"]
29
- frozendict = immutables.Map
30
28
 
31
29
 
32
30
  class Undefined(Enum):
@@ -40,9 +38,10 @@ class Undefined(Enum):
40
38
 
41
39
  def _exclude_patterns_validator(instance, attribute, value) -> None:
42
40
  if any("**" in pattern for pattern in value):
43
- # raise ValueError("The recursive wildcard `**` is not supported by `exclude_patterns`.")
44
- print(
41
+ # todo: for next major release, raise ValueError instead of printing a warning
42
+ click.echo(
45
43
  "The recursive wildcard `**` is not supported by `exclude_patterns` (it acts like non-recursive `*`).",
44
+ err=True,
46
45
  )
47
46
 
48
47
 
@@ -182,7 +181,7 @@ class Config:
182
181
  Path to a directory containing template files or a single template file.
183
182
  It is passed to Jinja's [FileSystemLoader](https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.FileSystemLoader) when creating the environment.
184
183
  **Note:** This option may be passed multiple times to pass a list of values.
185
- If a template exists in multiple inputs, the last value with be used.
184
+ If a template exists in multiple inputs, the first matching template in the provided order will be used.
186
185
  """,
187
186
  )
188
187
  output: Path = ts.option(
@@ -385,7 +384,7 @@ class Config:
385
384
  internal: Internal = Internal()
386
385
 
387
386
 
388
- OPTION_GROUPS = {
387
+ OPTION_GROUPS: dict[str, list[OptionGroupDict]] = {
389
388
  "makejinja": [
390
389
  {
391
390
  "name": "Input/Output",
makejinja-2.8.0/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2022 Mirko Lenz
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
makejinja-2.8.0/PKG-INFO DELETED
@@ -1,137 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: makejinja
3
- Version: 2.8.0
4
- Summary: Generate entire directory structures using Jinja templates with support for external data and custom plugins
5
- Author-email: Mirko Lenz <mirko@mirkolenz.com>
6
- Project-URL: Repository, https://github.com/mirkolenz/makejinja
7
- Project-URL: Homepage, https://mirkolenz.github.io/makejinja/
8
- Project-URL: Documentation, https://mirkolenz.github.io/makejinja/makejinja/cli.html
9
- Project-URL: Issues, https://github.com/mirkolenz/makejinja/issues
10
- Project-URL: Changelog, https://github.com/mirkolenz/makejinja/releases
11
- Keywords: jinja2,home-assistant,hassio,dashboard,lovelace,template,generator,cli,tool,library
12
- Classifier: Development Status :: 5 - Production/Stable
13
- Classifier: Environment :: Console
14
- Classifier: Framework :: Pytest
15
- Classifier: Intended Audience :: Developers
16
- Classifier: Intended Audience :: End Users/Desktop
17
- Classifier: Intended Audience :: System Administrators
18
- Classifier: License :: OSI Approved :: MIT License
19
- Classifier: Natural Language :: English
20
- Classifier: Operating System :: OS Independent
21
- Classifier: Programming Language :: Python :: 3.11
22
- Classifier: Programming Language :: Python :: 3.12
23
- Classifier: Programming Language :: Python :: 3.13
24
- Classifier: Programming Language :: Python :: 3
25
- Classifier: Topic :: File Formats
26
- Classifier: Topic :: Home Automation
27
- Classifier: Topic :: Software Development :: Code Generators
28
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
29
- Classifier: Topic :: System :: Software Distribution
30
- Classifier: Topic :: System :: Systems Administration
31
- Classifier: Topic :: Text Processing :: Markup
32
- Classifier: Topic :: Utilities
33
- Classifier: Typing :: Typed
34
- Requires-Python: >=3.11
35
- Description-Content-Type: text/markdown
36
- License-File: LICENSE
37
- Requires-Dist: jinja2<4,>=3
38
- Requires-Dist: pyyaml<7,>=6
39
- Requires-Dist: rich-click<2,>=1
40
- Requires-Dist: typed-settings[attrs,cattrs,click]<25,>=23
41
- Requires-Dist: immutables<1,>=0.20
42
- Dynamic: license-file
43
-
44
- <!-- markdownlint-disable MD033 MD041 -->
45
- <h1><p align="center">makejinja</p></h1>
46
-
47
- <p align="center">
48
- <img width="256px" alt="makejinja logo" src="https://raw.githubusercontent.com/mirkolenz/makejinja/main/assets/logo.png" />
49
- </p>
50
-
51
- <p align="center">
52
- <a href="https://pypi.org/project/makejinja/">PyPI</a> |
53
- <a href="https://github.com/users/mirkolenz/packages/container/package/makejinja">Docker</a> |
54
- <a href="https://mirkolenz.github.io/makejinja">Docs</a> |
55
- <a href="https://github.com/mirkolenz/makejinja/tree/main/tests/data">Example</a> |
56
- <a href="https://jinja.palletsprojects.com/en/3.1.x/templates">Jinja reference</a>
57
- </p>
58
-
59
- <p align="center">
60
- Generate entire directory structures using Jinja templates with support for external data and custom plugins.
61
- </p>
62
-
63
- <p align="center">
64
- <img alt="makejinja demonstration" src="https://mirkolenz.github.io/makejinja/assets/demo.gif" />
65
- </p>
66
-
67
- ---
68
-
69
- <!-- PDOC_START -->
70
-
71
- makejinja can be used to automatically generate files from [Jinja templates](https://jinja.palletsprojects.com/en/3.1.x/templates).
72
- It is conceptually similar to [Ansible templates](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.html) since both are built on top of Jinja.
73
- However, makejinja is a standalone tool that can be used without Ansible and offers some advanced features like custom plugins.
74
-
75
- A popular use case is generating config files for [Home Assistant](https://www.home-assistant.io/):
76
- Using the same Jinja language that Home Assistant's built-in templates use, you can greatly simplify your configuration management.
77
- makejinja's custom delimiter support prevents conflicts with Home Assistant's own template syntax, while file-specific data loading enables modular dashboard and automation generation.
78
- Our comprehensive [Home Assistant example](https://github.com/mirkolenz/makejinja/tree/main/tests/data) demonstrates dashboard generation with custom plugins, multiple data sources, and advanced template organization.
79
-
80
- ## Key Features
81
-
82
- - **Multi-Source Data Integration**: Load variables from YAML, TOML, and Python files, with support for file-specific data sources and runtime variable injection.
83
- - **Custom Template Delimiters**: Configure Jinja delimiters (e.g., `<% %>` instead of `{{ }}`) to avoid conflicts with target file formats like Home Assistant, Kubernetes, or Terraform.
84
- - **Flexible Directory Processing**: Process multiple input directories with complex nested structures, preserving hierarchy while applying powerful template transformations.
85
- - **Extensible Plugin System**: Create custom [plugins](https://mirkolenz.github.io/makejinja/makejinja/plugin.html#Plugin) with filters, functions, and path filtering logic for specialized requirements.
86
- - **Production-Ready**: Comprehensive CLI interface, configuration file support, and Python library API for seamless workflow integration.
87
-
88
- ## Use Cases
89
-
90
- - **Configuration Management**: Generate environment-specific configs (dev/staging/prod) from shared templates with different data sources.
91
- - **Home Assistant Dashboards**: Create complex dashboards and automations using Jinja syntax without conflicts. See our [complete example](https://github.com/mirkolenz/makejinja/tree/main/tests/data).
92
- - **Infrastructure as Code**: Generate Kubernetes manifests, Terraform modules, or Docker Compose files with consistent patterns across environments.
93
- - **Web Development**: Generate HTML pages, CSS files, or JavaScript configs from data sources for static sites or multi-tenant applications.
94
- - **Database Schemas**: Create SQL migration scripts, database configurations, or ORM models based on structured schema definitions.
95
- - **Network Configuration**: Generate router configs, firewall rules, or network device settings from centralized network topology data.
96
- - **Monitoring & Alerting**: Create Grafana dashboards, Prometheus rules, or alerting configurations from service inventories.
97
- - **Documentation & CI/CD**: Create project docs, API specifications, or pipeline definitions from structured data sources.
98
-
99
- ## Installation
100
-
101
- The tool is written in Python and can be installed via uv, nix, and docker.
102
- It can be used as a CLI tool or as a Python library.
103
-
104
- ### UV
105
-
106
- makejinja is available on [PyPI](https://pypi.org/project/makejinja/) and can be installed via `uv`:
107
-
108
- ```shell
109
- uv tool install makejinja
110
- makejinja -i ./input -o ./output
111
- ```
112
-
113
- ### Nix
114
-
115
- makejinja is packaged in nixpkgs.
116
- To use the most recent version, you can run it via `nix run`:
117
-
118
- ```shell
119
- nix run github:mirkolenz/makejinja -- -i ./input -o ./output
120
- ```
121
-
122
- Alternatively, you can add this repository as an input to your flake and use `makejinja.packages.${system}.default`.
123
-
124
- ### Docker
125
-
126
- We automatically publish an image to the [GitHub Container Registry](https://ghcr.io/mirkolenz/makejinja).
127
- To use it, mount a directory to the container and pass the options as the command:
128
-
129
- ```shell
130
- docker run --rm -v $(pwd)/data:/data ghcr.io/mirkolenz/makejinja:latest -i /data/input -o /data/output
131
- ```
132
-
133
- ## Usage in Terminal / Command Line
134
-
135
- In its default configuration, makejinja searches the input directory recursively for files ending in `.jinja`.
136
- It then renders these files and writes them to the output directory, preserving the directory structure.
137
- Our [documentation](https://mirkolenz.github.io/makejinja/makejinja/cli.html) contains a detailed description of all options and can also be accessed via `makejinja --help`.
makejinja-2.8.0/setup.cfg DELETED
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
@@ -1,17 +0,0 @@
1
- LICENSE
2
- README.md
3
- pyproject.toml
4
- src/makejinja/__init__.py
5
- src/makejinja/__main__.py
6
- src/makejinja/app.py
7
- src/makejinja/cli.py
8
- src/makejinja/config.py
9
- src/makejinja/plugin.py
10
- src/makejinja/py.typed
11
- src/makejinja.egg-info/PKG-INFO
12
- src/makejinja.egg-info/SOURCES.txt
13
- src/makejinja.egg-info/dependency_links.txt
14
- src/makejinja.egg-info/entry_points.txt
15
- src/makejinja.egg-info/requires.txt
16
- src/makejinja.egg-info/top_level.txt
17
- tests/test_makejinja.py
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- makejinja = makejinja.cli:makejinja_cli
@@ -1,5 +0,0 @@
1
- jinja2<4,>=3
2
- pyyaml<7,>=6
3
- rich-click<2,>=1
4
- typed-settings[attrs,cattrs,click]<25,>=23
5
- immutables<1,>=0.20
@@ -1 +0,0 @@
1
- makejinja
@@ -1,152 +0,0 @@
1
- from dataclasses import dataclass
2
- from pathlib import Path
3
-
4
- import pytest
5
- from click.testing import CliRunner
6
-
7
-
8
- @dataclass(slots=True, frozen=True)
9
- class MakejinjaPaths:
10
- """Paths used in makejinja test execution.
11
-
12
- Attributes:
13
- input: Path to input template directories
14
- baseline: Path to expected output files
15
- output: Path to actual generated output files
16
- """
17
-
18
- input: Path
19
- baseline: Path
20
- output: Path
21
-
22
- def __repr__(self) -> str:
23
- return "makejinja"
24
-
25
-
26
- @pytest.fixture(scope="session")
27
- def test_run(tmp_path_factory: pytest.TempPathFactory) -> MakejinjaPaths:
28
- """Execute makejinja on test data and return paths to input, expected, and actual output."""
29
- assert __package__ is not None
30
- data_path = Path(__package__, "data")
31
- input_path = data_path / "input"
32
- baseline_path = data_path / "output"
33
- output_path = tmp_path_factory.mktemp("data")
34
-
35
- with pytest.MonkeyPatch.context() as m:
36
- m.chdir(data_path)
37
- runner = CliRunner()
38
-
39
- # Need to import it AFTER chdir
40
- from makejinja.cli import makejinja_cli
41
-
42
- runner.invoke(
43
- makejinja_cli,
44
- [
45
- # Override it here to use our tmp_path
46
- "--output",
47
- str(output_path),
48
- ],
49
- catch_exceptions=False,
50
- color=True,
51
- )
52
-
53
- return MakejinjaPaths(input_path, baseline_path, output_path)
54
-
55
-
56
- def _dir_content(path: Path) -> set[Path]:
57
- return {item.relative_to(path) for item in path.rglob("*")}
58
-
59
-
60
- def test_output_structure(test_run: MakejinjaPaths):
61
- """Test that makejinja generates the expected directory structure."""
62
- expected_files = _dir_content(test_run.baseline)
63
- actual_files = _dir_content(test_run.output)
64
-
65
- if expected_files != actual_files:
66
- missing = sorted(expected_files - actual_files)
67
- extra = sorted(actual_files - expected_files)
68
- pytest.fail(f"Directory structure mismatch. Missing: {missing}, Extra: {extra}")
69
-
70
-
71
- def test_template_rendering(test_run: MakejinjaPaths):
72
- """Test that makejinja renders all templates with correct content."""
73
- paths = _dir_content(test_run.baseline)
74
-
75
- for item in paths:
76
- baseline_path = test_run.baseline / item
77
- output_path = test_run.output / item
78
-
79
- if baseline_path.is_file() and output_path.is_file():
80
- expected_content = baseline_path.read_text()
81
- actual_content = output_path.read_text()
82
-
83
- if expected_content.strip() != actual_content.strip():
84
- pytest.fail(
85
- f"Content mismatch in {item}: expected '{expected_content.strip()}', got '{actual_content.strip()}'"
86
- )
87
-
88
-
89
- def test_custom_delimiters(test_run: MakejinjaPaths):
90
- """Test that custom Jinja delimiters (<< >>, <% %>) work correctly."""
91
- not_empty_file = test_run.output / "not-empty.yaml"
92
- content = not_empty_file.read_text()
93
-
94
- assert "NOT EMPTY" in content, (
95
- f"Custom delimiters not working. Expected 'NOT EMPTY' in {not_empty_file}"
96
- )
97
-
98
-
99
- def test_file_specific_data(test_run: MakejinjaPaths):
100
- """Test that file-specific data loading works correctly."""
101
- file_specific_output = test_run.output / "file-specific.yaml"
102
- content = file_specific_output.read_text()
103
-
104
- # Should contain data from data1.yaml
105
- assert "Value from data1" in content, (
106
- f"File-specific data not loaded. Expected 'Value from data1' in {file_specific_output}"
107
- )
108
- assert "item1" in content and "item2" in content, (
109
- f"File-specific list data not loaded correctly in {file_specific_output}"
110
- )
111
-
112
-
113
- def test_plugin_features(test_run: MakejinjaPaths):
114
- """Test that custom plugin filters and functions work."""
115
- # Test that secret files are excluded by plugin path filter
116
- secret_file = test_run.output / "secret.yaml"
117
- assert not secret_file.exists(), (
118
- f"Secret file should be excluded by plugin but exists: {secret_file}"
119
- )
120
-
121
-
122
- def test_partial_inclusion(test_run: MakejinjaPaths):
123
- """Test that partial template inclusion works."""
124
- ui_lovelace_file = test_run.output / "ui-lovelace.yaml"
125
- content = ui_lovelace_file.read_text()
126
-
127
- # Should contain content from include.yaml.partial
128
- assert "icon: mdi:home" in content, (
129
- f"Partial inclusion not working. Expected 'icon: mdi:home' in {ui_lovelace_file}"
130
- )
131
-
132
-
133
- def test_empty_template_handling(test_run: MakejinjaPaths):
134
- """Test that empty templates are handled correctly."""
135
- # The empty.yaml.jinja should not produce output (contains only comments)
136
- empty_file = test_run.output / "empty.yaml"
137
- assert not empty_file.exists(), (
138
- f"Empty template should not generate output file but {empty_file} exists"
139
- )
140
-
141
-
142
- def test_nested_directory_processing(test_run: MakejinjaPaths):
143
- """Test that nested directories are processed correctly."""
144
- nested_file = test_run.output / "views" / "home.yaml"
145
- assert nested_file.exists(), (
146
- f"Nested directory processing failed. Expected {nested_file} to exist"
147
- )
148
-
149
- content = nested_file.read_text()
150
- assert len(content.strip()) > 0, (
151
- f"Nested template should have content but {nested_file} is empty"
152
- )
File without changes