jinja-tree


Namejinja-tree JSON
Version 0.6.0 PyPI version JSON
download
home_pagehttps://github.com/fabien-marty/jinja-tree
SummaryCLI to process jinja (jinja2) templates in a directory tree
upload_time2024-03-07 18:10:23
maintainer
docs_urlNone
authorFabien MARTY
requires_python>=3.8,<4.0
licenseMIT
keywords jinja jinja2 cli tree
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <!-- *** GENERATED FILE - DO NOT EDIT *** -->
<!-- To modify this file, edit README.md.template and launch 'make doc' -->

# jinja-tree

## What is it?

`jinja-tree` is a CLI utility to process [jinja (jinja2)](https://jinja.palletsprojects.com/) templates
recursively in a directory tree.

It is very configurable and very easy to extend with its included plugin system.

The default behavior is to recursively search for files with a given extension (`.template` for example) and to process the context with [Jinja (Jinja2)](https://jinja.palletsprojects.com/) templates engine reading the context variables from:

- a configuration file
- environment variables 
- dotenv files 

Then, the processed content is written into another file with the same name/path but with the configured extension (`.template` by default) removed. The original file can also be deleted (but this is not the default behavior).

<details>

<summary>Full example about overall operation (in default mode)</summary>

Note: this is only the **default behavior** as you can tune this with your own plugins!

Let's imagine the following directory structure:

```
/foo/
/foo/README.md.template
/foo/bar/baz.py.template
/foo/bar/another.file
```

And execute `jinja-tree /foo` with the default configuration.

We get:

```
/foo/
/foo/README.md.template
/foo/README.md <= NEW FILE FROM README.md.template jinja2 processing
/foo/bar/baz.py.template
/foo/bar/baz.py <= NEW FILE FROM baz.py.template jinja2 processing 
/foo/bar/another.file
```

</details>

## What's it for?

Your imagination is your limit 😅 but it's very useful for maintaining DRY documentation (for example `your-cli --help` output automatically updated in a markdown file), configuration files with default values read in code, including common blocks in different files...

**So it's a great tool for maintaining repositories in general.**

> [!TIP]
> Do you cant real-life examples? You can find some details about how we use it in this repository for:
> 
> - [getting `jinja-tree --help` output automatically added (and updated) in this README](https://github.com/fabien-marty/jinja-tree/blob/main/docs/details-about-real-life-example1.md)
> - [getting a reference TOML configuration file rendered with default values read from code](https://github.com/fabien-marty/jinja-tree/blob/main/docs/details-about-real-life-example2.md)

> [!NOTE]
> Another "action" plugin will be soon 🕒 provided to bootstrap directory trees from templates (like with the [cookiecutter](https://github.com/fabien-marty/jinja-tree/blob/main/https://github.com/cookiecutter/cookiecutter) project).

## Features

#### 1️⃣ Easy to extend 

`jinja-tree` includes a plugin system. You can override the default behavior with your own plugins.

There are two extension points:

- context plugins: to provide context variables to Jinja templates
- file plugins: to change the way how `jinja-tree` finds files to process (including target files)

See [this specification documentation page](https://github.com/fabien-marty/jinja-tree/blob/main/docs/details-about-plugins.md) for more details.

#### 2️⃣ Very configurable

`jinja-tree` is very configurable. You can configure global options via CLI options or a configuration file. 

Plugins are configurable via the configuration file.

See [this specification documentation page](https://github.com/fabien-marty/jinja-tree/blob/main/docs/details-about-configuration.md) for more details.

#### 3️⃣ Embedded extensions

`jinja-tree` includes some extensions to Jinja templates engine:

- [to execute some commands (and get the corresponding output)](https://github.com/fabien-marty/jinja-tree/blob/main/jinja_tree/app/embedded_extensions/shell.py)
- [to parse JSON strings into Python objects)](https://github.com/fabien-marty/jinja-tree/blob/main/jinja_tree/app/embedded_extensions/from_json.py)
- ..

<details>

<summary>Usage examples</summary>

#### `shell` extension


```jinja
{{ "date"|shell() }}
```

=> will render something like: `Sun Jan 28 15:11:44 CET 2024`


#### `from_json` extension


```bash
export MYENV='["foo", "bar", "baz"]'

(
    cat <<EOF
{% for item in MYENV|from_json() -%}
- {{ item }}
{% endfor %}
EOF
) | jinja-stdin
```


=> will render something like:

```
- foo
- bar
- bar
```

</details>

See [this directory](https://github.com/fabien-marty/jinja-tree/blob/main/jinja_tree/app/embedded_extensions/) for others

#### 4️⃣ Full Jinja / Jinja2 support (including "includes" and "inheritance")

`jinja-tree` has several options for Jinja "search paths". So you can use Jinja "includes" and "inheritance" features.

## Installation

`pip install jinja-tree`

> [!TIP]
> If you want to get a better readability of `jinja-tree` output (colors...), you can also use `pip install rich` to install 
> this **optional** dependency.

> [!NOTE]
> A docker image is also available. You can use it to avoid any specific installation.
> See at the end of the "Usage" section for more details.

## Usage

### Main CLI

```
jinja-tree .
```

> [!NOTE]
> The `.` in the previous command in the "root directory" (the directory `jinja-tree` will explore recursively to find files to process). You can replace it with any directory you want. By using `.`, you will process all files in the current directory and its subdirectories.

<details>

<summary>Main CLI options</summary>

```
Usage: jinja-tree [OPTIONS] ROOT_DIR

  Process a directory tree with the Jinja / Jinja2 templating system.

Arguments:
  ROOT_DIR  root directory  [required]

Options:
  --config-file TEXT              config file path (default: first '.jinja-
                                  tree.toml' file found up from current
                                  working dir), can also be see with
                                  JINJA_TREE_CONFIG_FILE env var  [env var:
                                  JINJA_TREE_CONFIG_FILE]
  --log-level TEXT                log level (DEBUG, INFO, WARNING or ERROR)
                                  [default: INFO]
  --verbose / --no-verbose        increase verbosity of the DEBUG log level
                                  (note: this forces log-level = DEBUG)
                                  [default: no-verbose]
  --extra-search-path PATH        Search path to jinja (can be used multiple
                                  times)
  --add-cwd-to-search-path / --no-add-cwd-to-search-path
                                  add current working directory (CWD) to jinja
                                  search path
  --add-root-dir-to-search-path / --no-add-root-dir-to-search-path
                                  add root directory to jinja search path
  --jinja-extension TEXT          jinja extension to load
  --context-plugin TEXT           context plugins (full python class path, can
                                  be used multiple times)
  --action-plugin TEXT            action plugin (full python class path, can
                                  be used multiple times)
  --strict-undefined / --no-strict-undefined
                                  if set, raise an error if a variable does
                                  not exist in context
  --blank-run / --no-blank-run    if set, execute a blank run (without
                                  modifying or deleting anything)  [default:
                                  no-blank-run]
  --disable-embedded-jinja-extensions / --no-disable-embedded-jinja-extensions
                                  disable embedded jinja extensions
  --help                          Show this message and exit.

``` 

</details>

### Bonus CLI (if you want to process only one file but with the same behavior)

```bash
cat /path/to/your/file/to/process | jinja-stdin >/path/to/your/processed/file
```

or (if you want to process only a string):


```console
$ export FOO=bar
$ echo "Hello {{FOO}}" | jinja-stdin
Hello bar
```


<details>

<summary>Bonus CLI options</summary>

```
Usage: jinja-stdin [OPTIONS]

  Process the standard input with Jinja templating system and return the
  result on the standard output.

Options:
  --config-file TEXT              config file path (default: first '.jinja-
                                  tree.toml' file found up from current
                                  working dir), can also be see with
                                  JINJA_TREE_CONFIG_FILE env var  [env var:
                                  JINJA_TREE_CONFIG_FILE]
  --log-level TEXT                log level (DEBUG, INFO, WARNING or ERROR)
                                  [default: INFO]
  --verbose / --no-verbose        increase verbosity of the DEBUG log level
                                  (note: this forces log-level = DEBUG)
                                  [default: no-verbose]
  --extra-search-path PATH        Search path to jinja (can be used multiple
                                  times)
  --add-cwd-to-search-path / --no-add-cwd-to-search-path
                                  add current working directory (CWD) to jinja
                                  search path
  --jinja-extension TEXT          jinja extension to load
  --context-plugin TEXT           context plugins (full python class path, can
                                  be used multiple times)
  --strict-undefined / --no-strict-undefined
                                  if set, raise an error if a variable does
                                  not exist in context
  --disable-embedded-jinja-extensions / --no-disable-embedded-jinja-extensions
                                  disable embedded jinja extensions
  --help                          Show this message and exit.

``` 

</details>

### Docker image

A docker image is also available. You can use it this way:

```bash
docker run -t -v $(pwd):/workdir --user=$(id -u) ghcr.io/fabien-marty/jinja-tree:latest /workdir
```

*(we mount the current directory in the `/workdir` directory in the container and execute `jinja-tree` in this `/workdir` directory)*

> [!WARNING]
> If you plan to use environment variables with the docker image, you will have to use (possibly multiple times) the `-e VAR=VALUE` option to pass them to the container. 
> With docker, it's more practical to use a `.env` (dotenv) file as it will be automatically mounted in the container.

If you want to add some CLI options, you can add them like in this example:

```bash
docker run -t -v $(pwd):/workdir --user=$(id -u) ghcr.io/fabien-marty/jinja-tree:latest --verbose /workdir
```

*(we added `--verbose` just before the `/workdir` argument)*

<details>

<summary>If you want to use the `jinja-stdin` CLI with docker?</summary>


```bash
echo "FOO {{ BAR }}" |docker run -i -v $(pwd):/workdir -e BAR=BAZ --user=$(id -u) --entrypoint jinja-stdin ghcr.io/fabien-marty/jinja-tree:latest
```


*(it will output `FOO BAZ`)*

</details>
            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/fabien-marty/jinja-tree",
    "name": "jinja-tree",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "jinja,jinja2,cli,tree",
    "author": "Fabien MARTY",
    "author_email": "fabien.marty@botify.com",
    "download_url": "https://files.pythonhosted.org/packages/7e/dc/4c7bcd7c5a3d61098cd5930e75c6f30462ce90e804348a82e7017fff94fa/jinja_tree-0.6.0.tar.gz",
    "platform": null,
    "description": "<!-- *** GENERATED FILE - DO NOT EDIT *** -->\n<!-- To modify this file, edit README.md.template and launch 'make doc' -->\n\n# jinja-tree\n\n## What is it?\n\n`jinja-tree` is a CLI utility to process [jinja (jinja2)](https://jinja.palletsprojects.com/) templates\nrecursively in a directory tree.\n\nIt is very configurable and very easy to extend with its included plugin system.\n\nThe default behavior is to recursively search for files with a given extension (`.template` for example) and to process the context with [Jinja (Jinja2)](https://jinja.palletsprojects.com/) templates engine reading the context variables from:\n\n- a configuration file\n- environment variables \n- dotenv files \n\nThen, the processed content is written into another file with the same name/path but with the configured extension (`.template` by default) removed. The original file can also be deleted (but this is not the default behavior).\n\n<details>\n\n<summary>Full example about overall operation (in default mode)</summary>\n\nNote: this is only the **default behavior** as you can tune this with your own plugins!\n\nLet's imagine the following directory structure:\n\n```\n/foo/\n/foo/README.md.template\n/foo/bar/baz.py.template\n/foo/bar/another.file\n```\n\nAnd execute `jinja-tree /foo` with the default configuration.\n\nWe get:\n\n```\n/foo/\n/foo/README.md.template\n/foo/README.md <= NEW FILE FROM README.md.template jinja2 processing\n/foo/bar/baz.py.template\n/foo/bar/baz.py <= NEW FILE FROM baz.py.template jinja2 processing \n/foo/bar/another.file\n```\n\n</details>\n\n## What's it for?\n\nYour imagination is your limit \ud83d\ude05 but it's very useful for maintaining DRY documentation (for example `your-cli --help` output automatically updated in a markdown file), configuration files with default values read in code, including common blocks in different files...\n\n**So it's a great tool for maintaining repositories in general.**\n\n> [!TIP]\n> Do you cant real-life examples? You can find some details about how we use it in this repository for:\n> \n> - [getting `jinja-tree --help` output automatically added (and updated) in this README](https://github.com/fabien-marty/jinja-tree/blob/main/docs/details-about-real-life-example1.md)\n> - [getting a reference TOML configuration file rendered with default values read from code](https://github.com/fabien-marty/jinja-tree/blob/main/docs/details-about-real-life-example2.md)\n\n> [!NOTE]\n> Another \"action\" plugin will be soon \ud83d\udd52 provided to bootstrap directory trees from templates (like with the [cookiecutter](https://github.com/fabien-marty/jinja-tree/blob/main/https://github.com/cookiecutter/cookiecutter) project).\n\n## Features\n\n#### 1\ufe0f\u20e3 Easy to extend \n\n`jinja-tree` includes a plugin system. You can override the default behavior with your own plugins.\n\nThere are two extension points:\n\n- context plugins: to provide context variables to Jinja templates\n- file plugins: to change the way how `jinja-tree` finds files to process (including target files)\n\nSee [this specification documentation page](https://github.com/fabien-marty/jinja-tree/blob/main/docs/details-about-plugins.md) for more details.\n\n#### 2\ufe0f\u20e3 Very configurable\n\n`jinja-tree` is very configurable. You can configure global options via CLI options or a configuration file. \n\nPlugins are configurable via the configuration file.\n\nSee [this specification documentation page](https://github.com/fabien-marty/jinja-tree/blob/main/docs/details-about-configuration.md) for more details.\n\n#### 3\ufe0f\u20e3 Embedded extensions\n\n`jinja-tree` includes some extensions to Jinja templates engine:\n\n- [to execute some commands (and get the corresponding output)](https://github.com/fabien-marty/jinja-tree/blob/main/jinja_tree/app/embedded_extensions/shell.py)\n- [to parse JSON strings into Python objects)](https://github.com/fabien-marty/jinja-tree/blob/main/jinja_tree/app/embedded_extensions/from_json.py)\n- ..\n\n<details>\n\n<summary>Usage examples</summary>\n\n#### `shell` extension\n\n\n```jinja\n{{ \"date\"|shell() }}\n```\n\n=> will render something like: `Sun Jan 28 15:11:44 CET 2024`\n\n\n#### `from_json` extension\n\n\n```bash\nexport MYENV='[\"foo\", \"bar\", \"baz\"]'\n\n(\n    cat <<EOF\n{% for item in MYENV|from_json() -%}\n- {{ item }}\n{% endfor %}\nEOF\n) | jinja-stdin\n```\n\n\n=> will render something like:\n\n```\n- foo\n- bar\n- bar\n```\n\n</details>\n\nSee [this directory](https://github.com/fabien-marty/jinja-tree/blob/main/jinja_tree/app/embedded_extensions/) for others\n\n#### 4\ufe0f\u20e3 Full Jinja / Jinja2 support (including \"includes\" and \"inheritance\")\n\n`jinja-tree` has several options for Jinja \"search paths\". So you can use Jinja \"includes\" and \"inheritance\" features.\n\n## Installation\n\n`pip install jinja-tree`\n\n> [!TIP]\n> If you want to get a better readability of `jinja-tree` output (colors...), you can also use `pip install rich` to install \n> this **optional** dependency.\n\n> [!NOTE]\n> A docker image is also available. You can use it to avoid any specific installation.\n> See at the end of the \"Usage\" section for more details.\n\n## Usage\n\n### Main CLI\n\n```\njinja-tree .\n```\n\n> [!NOTE]\n> The `.` in the previous command in the \"root directory\" (the directory `jinja-tree` will explore recursively to find files to process). You can replace it with any directory you want. By using `.`, you will process all files in the current directory and its subdirectories.\n\n<details>\n\n<summary>Main CLI options</summary>\n\n```\nUsage: jinja-tree [OPTIONS] ROOT_DIR\n\n  Process a directory tree with the Jinja / Jinja2 templating system.\n\nArguments:\n  ROOT_DIR  root directory  [required]\n\nOptions:\n  --config-file TEXT              config file path (default: first '.jinja-\n                                  tree.toml' file found up from current\n                                  working dir), can also be see with\n                                  JINJA_TREE_CONFIG_FILE env var  [env var:\n                                  JINJA_TREE_CONFIG_FILE]\n  --log-level TEXT                log level (DEBUG, INFO, WARNING or ERROR)\n                                  [default: INFO]\n  --verbose / --no-verbose        increase verbosity of the DEBUG log level\n                                  (note: this forces log-level = DEBUG)\n                                  [default: no-verbose]\n  --extra-search-path PATH        Search path to jinja (can be used multiple\n                                  times)\n  --add-cwd-to-search-path / --no-add-cwd-to-search-path\n                                  add current working directory (CWD) to jinja\n                                  search path\n  --add-root-dir-to-search-path / --no-add-root-dir-to-search-path\n                                  add root directory to jinja search path\n  --jinja-extension TEXT          jinja extension to load\n  --context-plugin TEXT           context plugins (full python class path, can\n                                  be used multiple times)\n  --action-plugin TEXT            action plugin (full python class path, can\n                                  be used multiple times)\n  --strict-undefined / --no-strict-undefined\n                                  if set, raise an error if a variable does\n                                  not exist in context\n  --blank-run / --no-blank-run    if set, execute a blank run (without\n                                  modifying or deleting anything)  [default:\n                                  no-blank-run]\n  --disable-embedded-jinja-extensions / --no-disable-embedded-jinja-extensions\n                                  disable embedded jinja extensions\n  --help                          Show this message and exit.\n\n``` \n\n</details>\n\n### Bonus CLI (if you want to process only one file but with the same behavior)\n\n```bash\ncat /path/to/your/file/to/process | jinja-stdin >/path/to/your/processed/file\n```\n\nor (if you want to process only a string):\n\n\n```console\n$ export FOO=bar\n$ echo \"Hello {{FOO}}\" | jinja-stdin\nHello bar\n```\n\n\n<details>\n\n<summary>Bonus CLI options</summary>\n\n```\nUsage: jinja-stdin [OPTIONS]\n\n  Process the standard input with Jinja templating system and return the\n  result on the standard output.\n\nOptions:\n  --config-file TEXT              config file path (default: first '.jinja-\n                                  tree.toml' file found up from current\n                                  working dir), can also be see with\n                                  JINJA_TREE_CONFIG_FILE env var  [env var:\n                                  JINJA_TREE_CONFIG_FILE]\n  --log-level TEXT                log level (DEBUG, INFO, WARNING or ERROR)\n                                  [default: INFO]\n  --verbose / --no-verbose        increase verbosity of the DEBUG log level\n                                  (note: this forces log-level = DEBUG)\n                                  [default: no-verbose]\n  --extra-search-path PATH        Search path to jinja (can be used multiple\n                                  times)\n  --add-cwd-to-search-path / --no-add-cwd-to-search-path\n                                  add current working directory (CWD) to jinja\n                                  search path\n  --jinja-extension TEXT          jinja extension to load\n  --context-plugin TEXT           context plugins (full python class path, can\n                                  be used multiple times)\n  --strict-undefined / --no-strict-undefined\n                                  if set, raise an error if a variable does\n                                  not exist in context\n  --disable-embedded-jinja-extensions / --no-disable-embedded-jinja-extensions\n                                  disable embedded jinja extensions\n  --help                          Show this message and exit.\n\n``` \n\n</details>\n\n### Docker image\n\nA docker image is also available. You can use it this way:\n\n```bash\ndocker run -t -v $(pwd):/workdir --user=$(id -u) ghcr.io/fabien-marty/jinja-tree:latest /workdir\n```\n\n*(we mount the current directory in the `/workdir` directory in the container and execute `jinja-tree` in this `/workdir` directory)*\n\n> [!WARNING]\n> If you plan to use environment variables with the docker image, you will have to use (possibly multiple times) the `-e VAR=VALUE` option to pass them to the container. \n> With docker, it's more practical to use a `.env` (dotenv) file as it will be automatically mounted in the container.\n\nIf you want to add some CLI options, you can add them like in this example:\n\n```bash\ndocker run -t -v $(pwd):/workdir --user=$(id -u) ghcr.io/fabien-marty/jinja-tree:latest --verbose /workdir\n```\n\n*(we added `--verbose` just before the `/workdir` argument)*\n\n<details>\n\n<summary>If you want to use the `jinja-stdin` CLI with docker?</summary>\n\n\n```bash\necho \"FOO {{ BAR }}\" |docker run -i -v $(pwd):/workdir -e BAR=BAZ --user=$(id -u) --entrypoint jinja-stdin ghcr.io/fabien-marty/jinja-tree:latest\n```\n\n\n*(it will output `FOO BAZ`)*\n\n</details>",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "CLI to process jinja (jinja2) templates in a directory tree",
    "version": "0.6.0",
    "project_urls": {
        "Homepage": "https://github.com/fabien-marty/jinja-tree",
        "Repository": "https://github.com/fabien-marty/jinja-tree"
    },
    "split_keywords": [
        "jinja",
        "jinja2",
        "cli",
        "tree"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4aaf5f831f1550bbc4f5b52d57325a10ba668c6073e1c4871ce54d61cb038383",
                "md5": "66cf9da20b3fd48fdf8c012aca027935",
                "sha256": "e17ef36d17383be27f75eb4687270daab7350bdade03c26d09f88df4ca51d725"
            },
            "downloads": -1,
            "filename": "jinja_tree-0.6.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "66cf9da20b3fd48fdf8c012aca027935",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 24088,
            "upload_time": "2024-03-07T18:10:21",
            "upload_time_iso_8601": "2024-03-07T18:10:21.977638Z",
            "url": "https://files.pythonhosted.org/packages/4a/af/5f831f1550bbc4f5b52d57325a10ba668c6073e1c4871ce54d61cb038383/jinja_tree-0.6.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7edc4c7bcd7c5a3d61098cd5930e75c6f30462ce90e804348a82e7017fff94fa",
                "md5": "45d4f41409a00fa556e242b06d7c8992",
                "sha256": "0459a02c2a26d79f8c17754942561e3bb058298b301bddfcdc37d70dc34155df"
            },
            "downloads": -1,
            "filename": "jinja_tree-0.6.0.tar.gz",
            "has_sig": false,
            "md5_digest": "45d4f41409a00fa556e242b06d7c8992",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 19302,
            "upload_time": "2024-03-07T18:10:23",
            "upload_time_iso_8601": "2024-03-07T18:10:23.676071Z",
            "url": "https://files.pythonhosted.org/packages/7e/dc/4c7bcd7c5a3d61098cd5930e75c6f30462ce90e804348a82e7017fff94fa/jinja_tree-0.6.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-07 18:10:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "fabien-marty",
    "github_project": "jinja-tree",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "jinja-tree"
}
        
Elapsed time: 0.20458s