'Use placeholders in yaml

Is there a way to use placeholders in yaml like this:

foo: &FOO
    <<propname>>: 
        type: number 
        default: <<default>>

bar:
    - *FOO 
       propname: "some_prop"
       default: "some default" 


Solution 1:[1]

With Yglu Structural Templating, your example can be written:

foo: !()
  !? $.propname: 
     type: number 
     default: !? $.default

bar:
  !apply .foo: 
    propname: "some_prop"
    default: "some default"

Disclaimer: I am the author or Yglu.

Solution 2:[2]

I suppose https://get-ytt.io/ would be an acceptable solution to your problem

Solution 3:[3]

I wanted to achieve templating in yaml files as well and I found dreftymac's answer really helpful as a starting point. After researching and coding for few hours this is my answer, please let me know if/how I can improve this.

I am not doing anything too special, I try to leverage python's string templating syntax and abuse the string format method a little. So it's all python's string templating and substitution that is doing the magic here. I have modified the way dreftymac's answer templated his yaml file to use as an example.

YAML:

part01_customer_info:
  cust_fname: "Homer"
  cust_lname: "Himpson"
  cust_motto: "I love donuts!"
  cust_email: [email protected]

part01_government_info:
  govt_sales_taxrate: 1.15

part01_purchase_info:
  prch_unit_label: "Bacon-Wrapped Fancy Glazed Donut"
  prch_unit_price: 3.00
  prch_unit_quant: 7
  prch_product_cost: "eval!#{part01_purchase_info[prch_unit_price]} * {part01_purchase_info[prch_unit_quant]}"
  prch_total_cost: "eval!#{part01_purchase_info[prch_product_cost]} * {part01_government_info[govt_sales_taxrate]}"

part02_shipping_info:
  cust_fname: "{part01_customer_info[cust_fname]}"
  cust_lname: "{part01_customer_info[cust_lname]}"
  ship_city: Houston
  ship_state: Hexas

part03_email_info:
  cust_email: "{part01_customer_info[cust_email]}"
  mail_subject: Thanks for your DoughNutz order!
  mail_notes: |
    We want the mail_greeting to have all the expected values
    with filled-in placeholders (and not curly-braces).
  mail_greeting: |
    Greetings {part01_customer_info[cust_fname]} {part01_customer_info[cust_lname]}!

    We love your motto "{part01_customer_info[cust_motto]}" and we agree with you!

    Your total purchase price is {part01_purchase_info[prch_total_cost]}

I have changed {{}} to {} and added eval!# which is an identifier

Python:

from pprint import pprint
import yaml

EVAL_IDENTIFIER = "eval!#"


def eval_math_expr(val):
    if val.startswith(EVAL_IDENTIFIER):
        val = val.replace(EVAL_IDENTIFIER, "")
        val = eval(val)
    return val


def str_template_substitute(full, val=None, initial=True):
    val = val or full if initial else val
    if isinstance(val, dict):
        for k, v in val.items():
            val[k] = str_template_substitute(full, v, False)
    elif isinstance(val, list):
        for idx, i in enumerate(val):
            val[idx] = str_template_substitute(full, i, False)
    elif isinstance(val, str):
        # NOTE:
        # Templating shouldn't be confused or tasked with extra work.
        # I am attaching evaluation to string substitution here,
        # just to prove this can be done.
        val = eval_math_expr(val.format(**full))
    return val


data = yaml.load(open('./data.yml'))
str_template_substitute(data)

pprint(data)

Note: This function is pretty powerful as this can work on dictionaries which is what JSON/YAML and many other formats convert to in python.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Cmag
Solution 3 dreftymac