{"id":13815234,"url":"https://github.com/kblomqvist/yasha","last_synced_at":"2026-01-20T19:04:19.666Z","repository":{"id":49040189,"uuid":"40316600","full_name":"kblomqvist/yasha","owner":"kblomqvist","description":"A command-line tool to render Jinja templates for great good","archived":false,"fork":false,"pushed_at":"2021-06-30T13:53:13.000Z","size":517,"stargazers_count":248,"open_issues_count":16,"forks_count":24,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-10-30T16:58:42.401Z","etag":null,"topics":["cli-utilities","code-generation","jinja2","jinja2-cli"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kblomqvist.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-08-06T16:56:25.000Z","updated_at":"2025-09-09T22:23:20.000Z","dependencies_parsed_at":"2022-09-08T15:12:33.955Z","dependency_job_id":null,"html_url":"https://github.com/kblomqvist/yasha","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/kblomqvist/yasha","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kblomqvist%2Fyasha","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kblomqvist%2Fyasha/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kblomqvist%2Fyasha/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kblomqvist%2Fyasha/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kblomqvist","download_url":"https://codeload.github.com/kblomqvist/yasha/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kblomqvist%2Fyasha/sbom","scorecard":{"id":552614,"data":{"date":"2025-08-11","repo":{"name":"github.com/kblomqvist/yasha","commit":"56bb1f69077957954e1ebeb77f7273e8dc6a891b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 2/21 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'","Warn: branch protection not enabled for branch '5.x-maintenance'","Warn: branch protection not enabled for branch '4.x-maintenance'","Warn: branch protection not enabled for branch '3.x-maintenance'","Warn: branch protection not enabled for branch '2.x-maintenance'","Warn: branch protection not enabled for branch 'v1.5'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 11 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T11:19:04.804Z","repository_id":49040189,"created_at":"2025-08-20T11:19:04.804Z","updated_at":"2025-08-20T11:19:04.804Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28609600,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T18:56:40.769Z","status":"ssl_error","status_checked_at":"2026-01-20T18:54:26.653Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli-utilities","code-generation","jinja2","jinja2-cli"],"created_at":"2024-08-04T04:03:10.511Z","updated_at":"2026-01-20T19:04:19.116Z","avatar_url":"https://github.com/kblomqvist.png","language":"Python","funding_links":[],"categories":["General Purpose Preprocessor","Python","Templating"],"sub_categories":["Snippets Manager","YAML is a **supserset of JSON**"],"readme":"# Yasha\n[![Build](https://img.shields.io/travis/kblomqvist/yasha?logo=travis)](https://travis-ci.org/kblomqvist/yasha)\n![Python](https://img.shields.io/pypi/pyversions/yasha)\n![Downloads](https://img.shields.io/pypi/dw/yasha)\n![License](https://img.shields.io/pypi/l/yasha)\n\nYasha is a code generator based on [Jinja2](http://jinja.pocoo.org/) template engine. At its simplest, a command-line call\n\n```bash\nyasha -v variables.yaml template.txt.j2\n```\n\nwill render `template.txt.j2` into a new file named as `template.txt`. See how the created file name is derived from the template name. The template itself remains unchanged.\n\nThe tool was originally written to generate code for the zinc.rs' [I/O register interface](http://zinc.rs/apidocs/ioreg/index.html) from the [CMSIS-SVD](https://www.keil.com/pack/doc/CMSIS/SVD/html/index.html) description file, and was used to interface with [the peripherals of Nordic nRF51](https://github.com/kblomqvist/yasha/tree/master/tests/fixtures) ARM Cortex-M processor-based microcontroller. Yasha has since evolved to be flexible enough to be used in any project where the code generation is needed. The tool allows extending Jinja by domain specific filters, tests and extensions, and it operates smoothly with the commonly used build automation software like Make, CMake and SCons.\n\n## Installation\n\nAs a regular user:\n\n```bash\npip install yasha\n```\n\nor if you like to get the latest development version:\n\n```bash\npip install git+https://github.com/kblomqvist/yasha.git\n```\n\nor if you would like to take part into the development process:\n\n```bash\ngit clone https://github.com/kblomqvist/yasha.git\npip install -e yasha\n```\n\n## Usage\n\n```\nUsage: yasha [OPTIONS] [TEMPLATE_VARIABLES]... TEMPLATE\n\n  Reads the given Jinja TEMPLATE and renders its content into a new file.\n  For example, a template called 'foo.c.j2' will be written into 'foo.c' in\n  case the output file is not explicitly given.\n\n  Template variables can be defined in a separate file or given as part of\n  the command-line call, e.g.\n\n      yasha --hello=world -o output.txt template.j2\n\n  defines a variable 'hello' for a template like:\n\n      Hello {{ hello }} !\n\nOptions:\n  -o, --output FILENAME         Place the rendered template into FILENAME.\n  -v, --variables FILENAME      Read template variables from FILENAME. Built-\n                                in parsers are JSON, YAML, TOML, INI, XML and CSV.\n  -e, --extensions FILENAME     Read template extensions from FILENAME. A\n                                Python file is expected.\n  -c, --encoding TEXT           Default is UTF-8.\n  -I, --include_path DIRECTORY  Add DIRECTORY to the list of directories to be\n                                searched for the referenced templates.\n  --no-variable-file            Omit template variable file.\n  --no-extension-file           Omit template extension file.\n  --no-trim-blocks              Load Jinja with trim_blocks=False.\n  --no-lstrip-blocks            Load Jinja with lstrip_blocks=False.\n  --remove-trailing-newline     Load Jinja with keep_trailing_newline=False.\n  --mode [pedantic|debug]       In pedantic mode Yasha becomes extremely picky\n                                on templates, e.g. undefined variables will\n                                raise an error. In debug mode undefined\n                                variables will print as is.\n  -M                            Outputs Makefile compatible list of\n                                dependencies. Doesn't render the template.\n  -MD                           Creates Makefile compatible .d file alongside\n                                the rendered template.\n  --version                     Print version and exit.\n  -h, --help                    Show this message and exit.\n```\n\n## Template variables\n\nTemplate variables can be defined in a separate file. By default [JSON](http://www.json.org), [YAML](http://www.yaml.org/start.html), [TOML](https://github.com/toml-lang/toml), [INI](https://docs.python.org/3/library/configparser.html#supported-ini-file-structure), [XML](https://github.com/martinblech/xmltodict) and [CSV](https://tools.ietf.org/html/rfc4180#section-2) formats are supported.\n\n```bash\nyasha -v variables.yaml template.j2\n```\n\nIn case multiple files are given, the variables redefined in later files will take precedence.\n\n```bash\nyasha -v variables.yaml -v additional_variables.yaml template.j2\n```\n\nAdditionally you may define variables as part of the command-line call. A variable defined via command-line will overwrite a variable defined in a file.\n\n```bash\nyasha --foo=bar -v variables.yaml template.j2\n```\n\n### CSV files\n\nto use the data stored in a csv variable file in templates, the name of the variable in the template has to match the name of the csv variable file.\n\nFor example, consider the following template and variable files\n\n```\ntemplate.j2\nmydata.csv\n```\n\nAnd the following contents in `mydata.csv`\n\n```csv\ncell1,cell2,cell3\ncell4,cell5,cell6\n```\n\nto access the rows of cells, you use the following syntax in your template (note that 'mydata' here matches the file name of the csv file)\n\n```jinja2\n{% for row in mydata %}\ncell 1's value is {{row[0]}},\ncell 2's value is {{row[1]}}\n{% endfor %}\n```\n\nBy default, each row in the csv file is accessed in the template as a list of values (`row[0]`, `row[1]`, etc). \nYou can make each row accessible instead as a mapping by adding a header to the csv file.\n\nFor example, consider the following contents of `mydata.csv`\n\n```csv\nfirst_column,column2,third column\ncell1,cell2,cell3\ncell4,cell5,cell6\n```\n\nand the following Jinja template\n\n```jinja2\n{% for row in mydata %}\ncell 1's value is {{row.first_column}},\ncell 2's value is {{row.column2}},\ncell 3's value is {{row['third column']}}\n{% endfor %}\n```\n\nAs you can see, cells can be accessed by column name instead of column index. \nIf the column name has no spaces in it, the cell can be accessed with 'dotted notation' (ie `row.first_column`) or 'square-bracket notation' (ie `row['third column']`.\nIf the column name has a space in it, the cell can only be accessed with 'square-bracket notation'\n\n### Automatic file variables look up\n\nIf no variable file is explicitly given, Yasha will look for one by searching for a file named in the same way than the corresponding template but with the file extension either `.json`, `.yaml`, `.yml`, `.toml`, or `.xml`.\n\nFor example, consider the following template and variable files\n\n```\ntemplate.j2\ntemplate.yaml\n```\n\nBecause of automatic file variables look up, the command-line call\n\n```bash\nyasha template.j2\n```\n\nis equal to\n\n```bash\nyasha -v template.yaml template.j2\n```\n\nIn case you want to omit the file variables in spite of its existence, use ``--no-variable-file`` option flag.\n\n### Shared template file variables\n\nImagine that you would be writing C code and have the following two templates in two different folders\n\n```\nroot/\n    include/foo.h.j2\n    source/foo.c.j2\n```\n\nand you would like to share the same file variables between these two templates. So instead of creating separate `foo.h.yaml` and `foo.c.yaml` you can create `foo.yaml` under the root folder:\n\n```\nroot/\n    include/foo.h.j2\n    source/foo.c.j2\n    foo.yaml\n```\n\nNow when you call\n\n```bash\ncd root\nyasha include/foo.h.j2\nyasha source/foo.c.j2\n```\n\nthe variables defined in `foo.yaml` are used within both templates. This works because subfolders will be checked for the variable file until the current working directory is reached — `root` in this case. For instance, variables are looked for `foo.h.j2` in following order:\n\n```\ninclude/foo.h.yaml\ninclude/foo.yaml\nfoo.h.yaml\nfoo.yaml\n```\n\n## Template extensions\n\nYou can extend Yasha by custom Jinja [extensions](http://jinja.pocoo.org/docs/dev/extensions/#module-jinja2.ext), [tests](http://jinja.pocoo.org/docs/dev/api/#custom-tests) and [filters](http://jinja.pocoo.org/docs/dev/api/#custom-filters) by defining those in a separate Python source file given via command-line option `-e`, or `--extensions` as shown below\n\n```bash\nyasha -e extensions.py -v variables.yaml template.j2\n```\n\nLike for variable file, Yasha supports automatic extension file look up and sharing too. To avoid file collisions consider using the following naming convention for your template, extension, and variable files:\n\n```\ntemplate.py.j2\ntemplate.py.py\ntemplate.py.yaml\n```\n\nNow the command-line call\n\n```bash\nyasha template.py.j2\n```\n\nis equal to\n\n```bash\nyasha -e template.py.py -v template.py.yaml template.py.j2\n```\n\n### Tests\n\nFunctions intended to work as a test have to be either prefixed by `test_`\n\n```python\ndef test_even(number):\n    return number % 2 == 0\n```\n\nof defined in `TESTS` dictionary\n\n```python\ndef is_even(number):\n    return number % 2 == 0\n\nTESTS = {\n    'even': is_even,\n}\n```\n\n### Filters\n\nFunctions intended to work as a filter have to be either prefixed by `filter_`\n\n```python\ndef filter_replace(s, old, new):\n    return s.replace(old, new)\n```\n\nor defined in `FILTERS` dictionary\n\n```python\ndef do_replace(s, old, new):\n    return s.replace(old, new)\n\nFILTERS = {\n    'replace': do_replace,\n}\n```\n\n### Classes\n\nAll classes derived from `jinja2.ext.Extension` are considered as Jinja extensions and will be added to the environment used to render the template.\n\n### Parsers\n\nIf none of the built-in parsers fit into your needs, it's possible to declare your own parser within the extension file. Either create a function named as `parse_` + `\u003cfile extension\u003e`, or define the parse-function in `PARSERS` dictionary with the key indicating the file extension. Yasha will then pass the variable file object for the function to be parsed and expects to get dictionary as a return value.\n\nFor example, below is shown an example XML file and a custom parser for that.\n\n```xml\n\u003c!-- variables.xml --\u003e\n\u003cpersons\u003e\n    \u003cperson\u003e\n        \u003cname\u003eFoo\u003c/name\u003e\n        \u003caddress\u003eFoo Valley\u003c/address\u003e\n    \u003c/person\u003e\n    \u003cperson\u003e\n        \u003cname\u003eBar\u003c/name\u003e\n        \u003caddress\u003eBar Valley\u003c/address\u003e\n    \u003c/person\u003e\n\u003c/persons\u003e\n```\n\n```python\n# extensions.py\nimport xml.etree.ElementTree as et\n\ndef parse_xml(file):\n    assert file.name.endswith('.xml')\n    tree = et.parse(file.name)\n    root = tree.getroot()\n\n    persons = []\n    for elem in root.iter('person'):\n        persons.append({\n            'name': elem.find('name').text,\n            'address': elem.find('address').text,\n        })\n\n    return dict(persons=persons)\n```\n\n### Template syntax\n\nYou may change the template syntax via file extensions by redefining\nthe Jinja parser / lexer. The example below mimics the LaTeX environment.\n\n```python\n# extensions.py\nBLOCK_START_STRING = '\u003c%'\nBLOCK_END_STRING = '%\u003e'\nVARIABLE_START_STRING = '\u003c\u003c'\nVARIABLE_END_STRING = '\u003e\u003e'\nCOMMENT_START_STRING = '\u003c#'\nCOMMENT_END_STRING = '#\u003e'\n```\n\n## Built-in filters\n\n### env\n\nReads system environment variable in a template like\n\n```jinja\nsqlalchemy:\n  url: {{ 'POSTGRES_URL' | env }}\n```\n\nParams: *default=None*\n\n### shell\n\nAllows to spawn new processes and connect to their standard output. The output is decoded and stripped by default.\n\n```jinja\nos:\n  type: {{ \"lsb_release -a | grep Distributor | awk '{print $3}'\" | shell }}\n  version: {{ 'cat /etc/debian_version' | shell }}\n```\n\n```yaml\nos:\n  type: Debian\n  version: 9.1\n```\n\nRequires: *Python \u003e= 3.5*  \nParams: *strip=True, check=True, timeout=2*\n\n### subprocess\n\nAllows to spawn new processes, but unlike `shell` behaves like Python's standard library.\n\n```jinja\n{% set r = \"uname\" | subprocess(check=False) %}\n{# Returns either CompletedPorcess or CalledProcessError instance #}\n\n{% if r.returncode -%}\n  platform: Unknown\n{% else -%}\n  platform: {{ r.stdout.decode() }}\n{%- endif %}\n```\n\n```yaml\nplatform: Linux\n```\n\nRequires: *Python \u003e= 3.5*  \nParams: *stdout=True, stderr=True, check=True, timeout=2*\n\n## Tips and tricks\n\n### Working with STDIN and STDOUT\n\nYasha can render templates from STDIN to STDOUT. For example, the below command-line call will render template from STDIN to STDOUT.\n\n```bash\ncat template.j2 | yasha -v variables.yaml -\n```\n\n### Python literals as part of the command-line call\n\nVariables given as part of the command-line call can be Python literals, e.g. a list would be defined like this\n\n```bash\nyasha --lst=\"['foo', 'bar', 'baz']\" template.j2\n```\n\nThe following is also interpreted as a list\n\n```bash\nyasha --lst=foo,bar,baz template.j2\n```\n\nNote that in case you like to pass a string with commas as a variable you have to quote it as\n\n```bash\nyasha --str='\"foo,bar,baz\"' template.j2\n```\n\nOther possible literals are:\n\n- `-1`, `0`, `1`, `2` (an integer)\n- `2+3j`, `0+5j` (a complex number)\n- `3.5`, `-2.7` (a float)\n- `(1,)`, `(1, 2)` (a tuple)\n- `{'a': 2}` (a dict)\n- `{1, 2, 3}` (a set)\n- `True`, `False` (boolean)\n\n### Common file extensions\n\nSometimes it would make sense to have common extensions over multiple templates, e.g. for the sake of filters. This can be achieved by setting `YASHA_EXTENSIONS` environment variable.\n\n```bash\nexport YASHA_EXTENSIONS=$HOME/.yasha/extensions.py\nyasha -v variables.yaml -o output.txt template.j2\n```\n\n### Append search path for referenced templates\n\nBy default the referenced templates, i.e. files referred to via Jinja's [extends](http://jinja.pocoo.org/docs/dev/templates/#extends), [include](http://jinja.pocoo.org/docs/dev/templates/#include) or [import](http://jinja.pocoo.org/docs/dev/templates/#import) statements, are searched in relation to the template location. To extend the search path you can use the command-line option `-I` — like you would do with GCC to include C header files.\n\n```bash\nyasha -v variables.yaml -I $HOME/.yasha template.j2\n```\n\n```jinja\n{% extends \"skeleton.j2\" %}\n{# 'skeleton.j2' is searched also from $HOME/.yasha #}\n\n{% block main %}\n    {{ super() }}\n    ...\n{% endblock %}\n```\n\n### Variable pre-processing before template rendering\n\nIf you need to pre-process template variables before those are passed into the template, you can do that via file extensions by wrapping the built-in parsers.\n\n```python\n# extensions.py\nfrom yasha.parsers import PARSERS\n\ndef wrapper(parse):\n   def postprocess(file):\n       variables = parse(file)\n       variables['foo'] = 'bar' # foo should always be bar\n       return variables\n   return postprocess\n\nfor name, function in PARSERS.items():\n    PARSERS[name] = wrapper(function)\n```\n\n### Using tests and filters from Ansible\n\n[Ansible](http://docs.ansible.com/ansible/latest/intro.html) is an IT automation platform that makes your applications and systems easier to deploy. It is based on Jinja2 and offers a large set of [custom tests and filters](http://docs.ansible.com/ansible/latest/playbooks_templating.html), which can be easily taken into use via Yasha's file extensions.\n\n```bash\npip install ansible\n```\n\n```python\n# extensions.py\nfrom ansible.plugins.test.core import TestModule\nfrom ansible.plugins.filter.core import FilterModule\n\nFILTERS = FilterModule().filters()\nFILTERS.update(TestModule().tests())  # Ansible tests are filter like\n```\n\n### Using Python objects of any type in YAML\n\nFor security reasons, the built-in YAML parser is using the `safe_load` of [PyYaml](http://pyyaml.org/wiki/PyYAML). This limits variables to simple Python objects like integers or lists. To work with a Python object of any type, you can overwrite the built-in implementation of the parser.\n\n```python\n# extensions.py\nimport yaml\n\ndef parse_yaml(file):\n    assert file.name.endswith(('.yaml', '.yml'))\n    variables = yaml.load(file)\n    return variables if variables else dict()\n\ndef parse_yml(file):\n    return parse_yaml(file)\n```\n\n## Build automation\n\nYasha command-line options `-M` and `-MD` return the list of the template dependencies in a Makefile compatible format. The later creates the separate `.d` file alongside the template rendering instead of printing to stdout. These options allow integration with the build automation tools. Below are given examples for C files using CMake, Make and SCons.\n\n### CMake\n\n```CMake\n# CMakeList.txt\n\ncmake_minimum_required(VERSION 2.8.7)\nproject(yasha)\n\nfile(GLOB sources \"src/*.c\")\nfile(GLOB templates \"src/*.jinja\")\n\nforeach(template ${templates})\n    string(REGEX REPLACE \"\\\\.[^.]*$\" \"\" output ${template})\n    execute_process(\n        COMMAND yasha -M ${template}\n        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}\n        OUTPUT_VARIABLE deps\n    )\n    string(REGEX REPLACE \"^.*: \" \"\" deps ${deps})\n    string(REPLACE \" \" \";\" deps ${deps})\n    add_custom_command(\n        OUTPUT ${output}\n        COMMAND yasha -o ${output} ${template}\n        DEPENDS ${deps}\n    )\n    list(APPEND sources ${output})\nendforeach()\n\nadd_executable(a.out ${sources})\n```\n\n### GNU Make\n\n```Makefile\n# Makefile\n\n# User variables\nSOURCES    = $(wildcard src/*.c)\nTEMPLATES  = $(wildcard src/*.jinja)\nEXECUTABLE = build/a.out\n\n# Add rendered .c templates to sources list\nSOURCES += $(filter %.c, $(basename $(TEMPLATES)))\n\n# Resolve build dir from executable\nBUILDDIR = $(dir $(EXECUTABLE))\n\n# Resolve object files\nOBJECTS = $(addprefix $(BUILDDIR), $(SOURCES:.c=.o))\n\n# Resolve .d files which list what files the object\n# and template files depend on\nOBJECTS_D   = $(OBJECTS:.o=.d)\nTEMPLATES_D = $(addsuffix .d,$(basename $(TEMPLATES)))\n\n$(EXECUTABLE) : $(OBJECTS)\n    $(CC) $^ -o $@\n\n$(BUILDDIR)%.o : %.c | $(filter %.h, $(basename $(TEMPLATES)))\n    @mkdir -p $(dir $@)\n    $(CC) -MMD -MP $\u003c -c -o $@\n\n%.c : %.c.jinja\n    yasha -MD $\u003c -o $@\n\n%.h : %.h.jinja\n    yasha -MD $\u003c -o $@\n\n# Make sure that the following built-in implicit rule is cancelled\n%.o : %.c\n\n# Pull in dependency info for existing .o and template files\n-include $(OBJECTS_D) $(TEMPLATES_D)\n\n# Prevent Make to consider rendered templates as intermediate file\n.secondary : $(basename $(TEMPLATES))\n\nclean :\nifeq ($(BUILDDIR),./)\n    -rm -f $(EXECUTABLE)\n    -rm -f $(OBJECTS)\n    -rm -f $(OBJECTS_D)\nelse\n    -rm -rf $(BUILDDIR)\nendif\n    -rm -f $(TEMPLATES_D)\n    -rm -f $(basename $(TEMPLATES))\n\n.phony : clean\n```\n\n### SCons\n\n```python\n# SConstruct\n\nimport os\nimport yasha.scons\n\nenv = Environment(\n    ENV = os.environ,\n    BUILDERS = {\"Yasha\": yasha.scons.CBuilder()}\n)\n\nsources = [\"main.c\"]\nsources += env.Yasha([\"foo.c.jinja\", \"foo.h.jinja\"]) # foo.h not appended to sources\nenv.Program(\"a.out\", sources)\n```\n\nAnother example with separate `build` and `src` directories.\n\n```python\n# SConstruct\n\nimport os\nimport yasha.scons\n\nenv = Environment(\n    ENV = os.environ,\n    BUILDERS = {\"Yasha\": yasha.scons.CBuilder()}\n)\n\nsources = [\"build/main.c\"]\n\nduplicate = 0 # See how the duplication affects to the file paths\nenv.VariantDir(\"build\", \"src\", duplicate=duplicate)\n\nif duplicate:\n    tmpl = [\"build/foo.c.jinja\", \"build/foo.h.jinja\"]\n    sources += env.Yasha(tmpl)\n\nelse:\n    tmpl = [\"src/foo.c.jinja\", \"src/foo.h.jinja\"]\n    sources += env.Yasha(tmpl)\n\nenv.Program(\"build/a.out\", sources)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkblomqvist%2Fyasha","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkblomqvist%2Fyasha","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkblomqvist%2Fyasha/lists"}