makejinja 2.7.2__tar.gz → 2.8.0__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,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: makejinja
3
- Version: 2.7.2
3
+ Version: 2.8.0
4
4
  Summary: Generate entire directory structures using Jinja templates with support for external data and custom plugins
5
5
  Author-email: Mirko Lenz <mirko@mirkolenz.com>
6
6
  Project-URL: Repository, https://github.com/mirkolenz/makejinja
@@ -39,12 +39,15 @@ Requires-Dist: pyyaml<7,>=6
39
39
  Requires-Dist: rich-click<2,>=1
40
40
  Requires-Dist: typed-settings[attrs,cattrs,click]<25,>=23
41
41
  Requires-Dist: immutables<1,>=0.20
42
+ Dynamic: license-file
42
43
 
43
44
  <!-- markdownlint-disable MD033 MD041 -->
44
- <h2><p align="center">makejinja</p></h2>
45
+ <h1><p align="center">makejinja</p></h1>
46
+
45
47
  <p align="center">
46
48
  <img width="256px" alt="makejinja logo" src="https://raw.githubusercontent.com/mirkolenz/makejinja/main/assets/logo.png" />
47
49
  </p>
50
+
48
51
  <p align="center">
49
52
  <a href="https://pypi.org/project/makejinja/">PyPI</a> |
50
53
  <a href="https://github.com/users/mirkolenz/packages/container/package/makejinja">Docker</a> |
@@ -52,51 +55,72 @@ Requires-Dist: immutables<1,>=0.20
52
55
  <a href="https://github.com/mirkolenz/makejinja/tree/main/tests/data">Example</a> |
53
56
  <a href="https://jinja.palletsprojects.com/en/3.1.x/templates">Jinja reference</a>
54
57
  </p>
58
+
55
59
  <p align="center">
56
60
  Generate entire directory structures using Jinja templates with support for external data and custom plugins.
57
61
  </p>
58
62
 
63
+ <p align="center">
64
+ <img alt="makejinja demonstration" src="https://mirkolenz.github.io/makejinja/assets/demo.gif" />
65
+ </p>
66
+
59
67
  ---
60
68
 
61
- # makejinja
69
+ <!-- PDOC_START -->
62
70
 
63
71
  makejinja can be used to automatically generate files from [Jinja templates](https://jinja.palletsprojects.com/en/3.1.x/templates).
64
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.
65
73
  However, makejinja is a standalone tool that can be used without Ansible and offers some advanced features like custom plugins.
66
- A use case for this tool is generating config files for [Home Assistant](https://www.home-assistant.io/):
67
- Using the same language that the built-in templates use, you can greatly simplify your configuration.
68
- An [example for Home Assistant](https://github.com/mirkolenz/makejinja/tree/main/tests/data) can be found in the tests directory.
69
74
 
70
- ## Highlights
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.
71
87
 
72
- - Recursively render nested directories containing template files to a common output directory.
73
- - Load data files containing variables to use in your Jinja templates from YAML, TOML, and Python files.
74
- - Write custom [plugins](https://mirkolenz.github.io/makejinja/makejinja/plugin.html#Plugin) to extend the functionality of makejinja.
75
- - Adjust all Jinja options (e.g., whitespace behavior and delimiters) to your needs via CLI flags or a config file.
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.
76
98
 
77
99
  ## Installation
78
100
 
79
- The tool is written in Python and can be installed via pip, nix, and docker.
101
+ The tool is written in Python and can be installed via uv, nix, and docker.
80
102
  It can be used as a CLI tool or as a Python library.
81
103
 
82
- ### PIP
104
+ ### UV
83
105
 
84
- makejinja is available on [PyPI](https://pypi.org/project/makejinja/) and can be installed via `pip`:
106
+ makejinja is available on [PyPI](https://pypi.org/project/makejinja/) and can be installed via `uv`:
85
107
 
86
108
  ```shell
87
- pip install makejinja
109
+ uv tool install makejinja
88
110
  makejinja -i ./input -o ./output
89
111
  ```
90
112
 
91
113
  ### Nix
92
114
 
93
- If you use the `nix` package manager, you can add this repository as an input to your flake and use `makejinja.packages.${system}.default` or apply the overlay `makejinja.overlays.default`.
94
- You can also run it directly as follows:
115
+ makejinja is packaged in nixpkgs.
116
+ To use the most recent version, you can run it via `nix run`:
95
117
 
96
118
  ```shell
97
119
  nix run github:mirkolenz/makejinja -- -i ./input -o ./output
98
120
  ```
99
121
 
122
+ Alternatively, you can add this repository as an input to your flake and use `makejinja.packages.${system}.default`.
123
+
100
124
  ### Docker
101
125
 
102
126
  We automatically publish an image to the [GitHub Container Registry](https://ghcr.io/mirkolenz/makejinja).
@@ -0,0 +1,94 @@
1
+ <!-- markdownlint-disable MD033 MD041 -->
2
+ <h1><p align="center">makejinja</p></h1>
3
+
4
+ <p align="center">
5
+ <img width="256px" alt="makejinja logo" src="https://raw.githubusercontent.com/mirkolenz/makejinja/main/assets/logo.png" />
6
+ </p>
7
+
8
+ <p align="center">
9
+ <a href="https://pypi.org/project/makejinja/">PyPI</a> |
10
+ <a href="https://github.com/users/mirkolenz/packages/container/package/makejinja">Docker</a> |
11
+ <a href="https://mirkolenz.github.io/makejinja">Docs</a> |
12
+ <a href="https://github.com/mirkolenz/makejinja/tree/main/tests/data">Example</a> |
13
+ <a href="https://jinja.palletsprojects.com/en/3.1.x/templates">Jinja reference</a>
14
+ </p>
15
+
16
+ <p align="center">
17
+ Generate entire directory structures using Jinja templates with support for external data and custom plugins.
18
+ </p>
19
+
20
+ <p align="center">
21
+ <img alt="makejinja demonstration" src="https://mirkolenz.github.io/makejinja/assets/demo.gif" />
22
+ </p>
23
+
24
+ ---
25
+
26
+ <!-- PDOC_START -->
27
+
28
+ makejinja can be used to automatically generate files from [Jinja templates](https://jinja.palletsprojects.com/en/3.1.x/templates).
29
+ 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.
30
+ However, makejinja is a standalone tool that can be used without Ansible and offers some advanced features like custom plugins.
31
+
32
+ A popular use case is generating config files for [Home Assistant](https://www.home-assistant.io/):
33
+ Using the same Jinja language that Home Assistant's built-in templates use, you can greatly simplify your configuration management.
34
+ 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.
35
+ 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.
36
+
37
+ ## Key Features
38
+
39
+ - **Multi-Source Data Integration**: Load variables from YAML, TOML, and Python files, with support for file-specific data sources and runtime variable injection.
40
+ - **Custom Template Delimiters**: Configure Jinja delimiters (e.g., `<% %>` instead of `{{ }}`) to avoid conflicts with target file formats like Home Assistant, Kubernetes, or Terraform.
41
+ - **Flexible Directory Processing**: Process multiple input directories with complex nested structures, preserving hierarchy while applying powerful template transformations.
42
+ - **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.
43
+ - **Production-Ready**: Comprehensive CLI interface, configuration file support, and Python library API for seamless workflow integration.
44
+
45
+ ## Use Cases
46
+
47
+ - **Configuration Management**: Generate environment-specific configs (dev/staging/prod) from shared templates with different data sources.
48
+ - **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).
49
+ - **Infrastructure as Code**: Generate Kubernetes manifests, Terraform modules, or Docker Compose files with consistent patterns across environments.
50
+ - **Web Development**: Generate HTML pages, CSS files, or JavaScript configs from data sources for static sites or multi-tenant applications.
51
+ - **Database Schemas**: Create SQL migration scripts, database configurations, or ORM models based on structured schema definitions.
52
+ - **Network Configuration**: Generate router configs, firewall rules, or network device settings from centralized network topology data.
53
+ - **Monitoring & Alerting**: Create Grafana dashboards, Prometheus rules, or alerting configurations from service inventories.
54
+ - **Documentation & CI/CD**: Create project docs, API specifications, or pipeline definitions from structured data sources.
55
+
56
+ ## Installation
57
+
58
+ The tool is written in Python and can be installed via uv, nix, and docker.
59
+ It can be used as a CLI tool or as a Python library.
60
+
61
+ ### UV
62
+
63
+ makejinja is available on [PyPI](https://pypi.org/project/makejinja/) and can be installed via `uv`:
64
+
65
+ ```shell
66
+ uv tool install makejinja
67
+ makejinja -i ./input -o ./output
68
+ ```
69
+
70
+ ### Nix
71
+
72
+ makejinja is packaged in nixpkgs.
73
+ To use the most recent version, you can run it via `nix run`:
74
+
75
+ ```shell
76
+ nix run github:mirkolenz/makejinja -- -i ./input -o ./output
77
+ ```
78
+
79
+ Alternatively, you can add this repository as an input to your flake and use `makejinja.packages.${system}.default`.
80
+
81
+ ### Docker
82
+
83
+ We automatically publish an image to the [GitHub Container Registry](https://ghcr.io/mirkolenz/makejinja).
84
+ To use it, mount a directory to the container and pass the options as the command:
85
+
86
+ ```shell
87
+ docker run --rm -v $(pwd)/data:/data ghcr.io/mirkolenz/makejinja:latest -i /data/input -o /data/output
88
+ ```
89
+
90
+ ## Usage in Terminal / Command Line
91
+
92
+ In its default configuration, makejinja searches the input directory recursively for files ending in `.jinja`.
93
+ It then renders these files and writes them to the output directory, preserving the directory structure.
94
+ 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`.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "makejinja"
3
- version = "2.7.2"
3
+ version = "2.8.0"
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"
@@ -75,8 +75,10 @@ addopts = "--cov makejinja --cov-report term-missing"
75
75
 
76
76
  [tool.ruff]
77
77
  target-version = "py311"
78
+
79
+ [tool.ruff.lint]
78
80
  select = ["E", "W", "F", "B", "UP"]
79
81
  ignore = ["E501"]
80
82
 
81
- [tool.ruff.pydocstyle]
83
+ [tool.ruff.lint.pydocstyle]
82
84
  convention = "google"
@@ -1,10 +1,10 @@
1
1
  """
2
2
  **[🌟 GitHub Project 🌟](https://github.com/mirkolenz/makejinja)**
3
3
 
4
- ![Screencast demo](../../assets/demo.gif)
4
+ ![makejinja demonstration](../../assets/demo.gif)
5
5
 
6
6
  .. include:: ../../README.md
7
- :start-after: # makejinja
7
+ :start-after: <!-- PDOC_START -->
8
8
 
9
9
  ## Usage as a Library
10
10
 
@@ -332,6 +332,26 @@ def load_data(config: Config) -> dict[str, Any]:
332
332
  return data
333
333
 
334
334
 
335
+ def load_file_data(template_name: str, config: Config) -> dict[str, Any]:
336
+ file_data: dict[str, Any] = {}
337
+
338
+ if data_paths := config.file_data.get(template_name):
339
+ for data_path in data_paths:
340
+ if data_path.exists() and (loader := DATA_LOADERS.get(data_path.suffix)):
341
+ log(
342
+ f"Load file-specific data '{data_path}' for template '{template_name}'",
343
+ config,
344
+ )
345
+ file_data |= loader(data_path)
346
+ else:
347
+ log(
348
+ f"Skip missing or unsupported file-specific data '{data_path}'",
349
+ config,
350
+ )
351
+
352
+ return file_data
353
+
354
+
335
355
  def load_plugin(
336
356
  plugin_name: str, env: Environment, data: Data, config: Config
337
357
  ) -> Plugin:
@@ -396,7 +416,8 @@ def render_file(
396
416
 
397
417
  elif input.suffix == config.jinja_suffix or not enforce_jinja_suffix:
398
418
  template = env.get_template(template_name)
399
- rendered = template.render()
419
+ file_data = load_file_data(template_name, config)
420
+ rendered = template.render(file_data)
400
421
 
401
422
  # Write the rendered template if it has content
402
423
  # Prevents empty macro definitions
@@ -277,6 +277,19 @@ class Config:
277
277
  """,
278
278
  },
279
279
  )
280
+ file_data: abc.Mapping[str, tuple[Path, ...]] = ts.option(
281
+ default=frozendict(),
282
+ click={
283
+ "param_decls": ("--file-data",),
284
+ "help": """
285
+ Load file-specific data for individual templates.
286
+ Format: template_file=data_file1,data_file2,...
287
+ Example: --file-data "home.yaml.jinja=home_data.yaml,common.yaml"
288
+ The data from these files will be available only when rendering the specified template.
289
+ **Note:** This option may be passed multiple times.
290
+ """,
291
+ },
292
+ )
280
293
  loaders: tuple[str, ...] = ts.option(
281
294
  default=tuple(),
282
295
  click={
@@ -392,6 +405,7 @@ OPTION_GROUPS = {
392
405
  "options": [
393
406
  "--data",
394
407
  "--data-var",
408
+ "--file-data",
395
409
  "--plugin",
396
410
  "--import-path",
397
411
  "--extension",
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: makejinja
3
- Version: 2.7.2
3
+ Version: 2.8.0
4
4
  Summary: Generate entire directory structures using Jinja templates with support for external data and custom plugins
5
5
  Author-email: Mirko Lenz <mirko@mirkolenz.com>
6
6
  Project-URL: Repository, https://github.com/mirkolenz/makejinja
@@ -39,12 +39,15 @@ Requires-Dist: pyyaml<7,>=6
39
39
  Requires-Dist: rich-click<2,>=1
40
40
  Requires-Dist: typed-settings[attrs,cattrs,click]<25,>=23
41
41
  Requires-Dist: immutables<1,>=0.20
42
+ Dynamic: license-file
42
43
 
43
44
  <!-- markdownlint-disable MD033 MD041 -->
44
- <h2><p align="center">makejinja</p></h2>
45
+ <h1><p align="center">makejinja</p></h1>
46
+
45
47
  <p align="center">
46
48
  <img width="256px" alt="makejinja logo" src="https://raw.githubusercontent.com/mirkolenz/makejinja/main/assets/logo.png" />
47
49
  </p>
50
+
48
51
  <p align="center">
49
52
  <a href="https://pypi.org/project/makejinja/">PyPI</a> |
50
53
  <a href="https://github.com/users/mirkolenz/packages/container/package/makejinja">Docker</a> |
@@ -52,51 +55,72 @@ Requires-Dist: immutables<1,>=0.20
52
55
  <a href="https://github.com/mirkolenz/makejinja/tree/main/tests/data">Example</a> |
53
56
  <a href="https://jinja.palletsprojects.com/en/3.1.x/templates">Jinja reference</a>
54
57
  </p>
58
+
55
59
  <p align="center">
56
60
  Generate entire directory structures using Jinja templates with support for external data and custom plugins.
57
61
  </p>
58
62
 
63
+ <p align="center">
64
+ <img alt="makejinja demonstration" src="https://mirkolenz.github.io/makejinja/assets/demo.gif" />
65
+ </p>
66
+
59
67
  ---
60
68
 
61
- # makejinja
69
+ <!-- PDOC_START -->
62
70
 
63
71
  makejinja can be used to automatically generate files from [Jinja templates](https://jinja.palletsprojects.com/en/3.1.x/templates).
64
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.
65
73
  However, makejinja is a standalone tool that can be used without Ansible and offers some advanced features like custom plugins.
66
- A use case for this tool is generating config files for [Home Assistant](https://www.home-assistant.io/):
67
- Using the same language that the built-in templates use, you can greatly simplify your configuration.
68
- An [example for Home Assistant](https://github.com/mirkolenz/makejinja/tree/main/tests/data) can be found in the tests directory.
69
74
 
70
- ## Highlights
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.
71
87
 
72
- - Recursively render nested directories containing template files to a common output directory.
73
- - Load data files containing variables to use in your Jinja templates from YAML, TOML, and Python files.
74
- - Write custom [plugins](https://mirkolenz.github.io/makejinja/makejinja/plugin.html#Plugin) to extend the functionality of makejinja.
75
- - Adjust all Jinja options (e.g., whitespace behavior and delimiters) to your needs via CLI flags or a config file.
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.
76
98
 
77
99
  ## Installation
78
100
 
79
- The tool is written in Python and can be installed via pip, nix, and docker.
101
+ The tool is written in Python and can be installed via uv, nix, and docker.
80
102
  It can be used as a CLI tool or as a Python library.
81
103
 
82
- ### PIP
104
+ ### UV
83
105
 
84
- makejinja is available on [PyPI](https://pypi.org/project/makejinja/) and can be installed via `pip`:
106
+ makejinja is available on [PyPI](https://pypi.org/project/makejinja/) and can be installed via `uv`:
85
107
 
86
108
  ```shell
87
- pip install makejinja
109
+ uv tool install makejinja
88
110
  makejinja -i ./input -o ./output
89
111
  ```
90
112
 
91
113
  ### Nix
92
114
 
93
- If you use the `nix` package manager, you can add this repository as an input to your flake and use `makejinja.packages.${system}.default` or apply the overlay `makejinja.overlays.default`.
94
- You can also run it directly as follows:
115
+ makejinja is packaged in nixpkgs.
116
+ To use the most recent version, you can run it via `nix run`:
95
117
 
96
118
  ```shell
97
119
  nix run github:mirkolenz/makejinja -- -i ./input -o ./output
98
120
  ```
99
121
 
122
+ Alternatively, you can add this repository as an input to your flake and use `makejinja.packages.${system}.default`.
123
+
100
124
  ### Docker
101
125
 
102
126
  We automatically publish an image to the [GitHub Container Registry](https://ghcr.io/mirkolenz/makejinja).
@@ -0,0 +1,152 @@
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
+ )
makejinja-2.7.2/README.md DELETED
@@ -1,71 +0,0 @@
1
- <!-- markdownlint-disable MD033 MD041 -->
2
- <h2><p align="center">makejinja</p></h2>
3
- <p align="center">
4
- <img width="256px" alt="makejinja logo" src="https://raw.githubusercontent.com/mirkolenz/makejinja/main/assets/logo.png" />
5
- </p>
6
- <p align="center">
7
- <a href="https://pypi.org/project/makejinja/">PyPI</a> |
8
- <a href="https://github.com/users/mirkolenz/packages/container/package/makejinja">Docker</a> |
9
- <a href="https://mirkolenz.github.io/makejinja">Docs</a> |
10
- <a href="https://github.com/mirkolenz/makejinja/tree/main/tests/data">Example</a> |
11
- <a href="https://jinja.palletsprojects.com/en/3.1.x/templates">Jinja reference</a>
12
- </p>
13
- <p align="center">
14
- Generate entire directory structures using Jinja templates with support for external data and custom plugins.
15
- </p>
16
-
17
- ---
18
-
19
- # makejinja
20
-
21
- makejinja can be used to automatically generate files from [Jinja templates](https://jinja.palletsprojects.com/en/3.1.x/templates).
22
- 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.
23
- However, makejinja is a standalone tool that can be used without Ansible and offers some advanced features like custom plugins.
24
- A use case for this tool is generating config files for [Home Assistant](https://www.home-assistant.io/):
25
- Using the same language that the built-in templates use, you can greatly simplify your configuration.
26
- An [example for Home Assistant](https://github.com/mirkolenz/makejinja/tree/main/tests/data) can be found in the tests directory.
27
-
28
- ## Highlights
29
-
30
- - Recursively render nested directories containing template files to a common output directory.
31
- - Load data files containing variables to use in your Jinja templates from YAML, TOML, and Python files.
32
- - Write custom [plugins](https://mirkolenz.github.io/makejinja/makejinja/plugin.html#Plugin) to extend the functionality of makejinja.
33
- - Adjust all Jinja options (e.g., whitespace behavior and delimiters) to your needs via CLI flags or a config file.
34
-
35
- ## Installation
36
-
37
- The tool is written in Python and can be installed via pip, nix, and docker.
38
- It can be used as a CLI tool or as a Python library.
39
-
40
- ### PIP
41
-
42
- makejinja is available on [PyPI](https://pypi.org/project/makejinja/) and can be installed via `pip`:
43
-
44
- ```shell
45
- pip install makejinja
46
- makejinja -i ./input -o ./output
47
- ```
48
-
49
- ### Nix
50
-
51
- If you use the `nix` package manager, you can add this repository as an input to your flake and use `makejinja.packages.${system}.default` or apply the overlay `makejinja.overlays.default`.
52
- You can also run it directly as follows:
53
-
54
- ```shell
55
- nix run github:mirkolenz/makejinja -- -i ./input -o ./output
56
- ```
57
-
58
- ### Docker
59
-
60
- We automatically publish an image to the [GitHub Container Registry](https://ghcr.io/mirkolenz/makejinja).
61
- To use it, mount a directory to the container and pass the options as the command:
62
-
63
- ```shell
64
- docker run --rm -v $(pwd)/data:/data ghcr.io/mirkolenz/makejinja:latest -i /data/input -o /data/output
65
- ```
66
-
67
- ## Usage in Terminal / Command Line
68
-
69
- In its default configuration, makejinja searches the input directory recursively for files ending in `.jinja`.
70
- It then renders these files and writes them to the output directory, preserving the directory structure.
71
- 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`.
@@ -1,66 +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
9
- class Paths:
10
- input: Path
11
- baseline: Path
12
- output: Path
13
-
14
- def __repr__(self) -> str:
15
- return "makejinja"
16
-
17
-
18
- @pytest.fixture(scope="session")
19
- def exec(tmp_path_factory: pytest.TempPathFactory) -> Paths:
20
- assert __package__ is not None
21
- data_path = Path(__package__, "data")
22
- input_path = data_path / "input"
23
- baseline_path = data_path / "output"
24
- output_path = tmp_path_factory.mktemp("data")
25
-
26
- with pytest.MonkeyPatch.context() as m:
27
- m.chdir(data_path)
28
- runner = CliRunner()
29
-
30
- # Need to import it AFTER chdir
31
- from makejinja.cli import makejinja_cli
32
-
33
- runner.invoke(
34
- makejinja_cli,
35
- [
36
- # Override it here to use our tmp_path
37
- "--output",
38
- str(output_path),
39
- ],
40
- catch_exceptions=False,
41
- color=True,
42
- )
43
-
44
- return Paths(input_path, baseline_path, output_path)
45
-
46
-
47
- def _dir_content(path: Path) -> set[Path]:
48
- return {item.relative_to(path) for item in path.rglob("*")}
49
-
50
-
51
- def test_dir_content(exec: Paths):
52
- assert _dir_content(exec.baseline) == _dir_content(exec.output)
53
-
54
-
55
- def test_file_content(exec: Paths):
56
- paths = _dir_content(exec.baseline)
57
-
58
- for item in paths:
59
- baseline_path = exec.baseline / item
60
- output_path = exec.output / item
61
-
62
- if baseline_path.is_file() and output_path.is_file():
63
- baseline = baseline_path.read_text()
64
- output = output_path.read_text()
65
-
66
- assert baseline.strip() == output.strip(), str(item)
File without changes
File without changes