epics-containers / ibek

IOC Builder for EPICS and Kubernetes
https://epics-containers.github.io/ibek
Apache License 2.0
10 stars 4 forks source link

Support YAML args should all be able to be Jinja Templated #153

Closed gilesknap closed 4 weeks ago

gilesknap commented 7 months ago

Ibek Schema Proposal

The problem

At present the Support Yaml Args must be set to type str if they are ever allowed to have Jinja templating.

This is counter productive because:

The solution

@GDYendell and @gilesknap propose that we make all arguments templatable as follows:

Additionally

As part of this change we also propose that the Jinja rendering be run repeatedly as follows

This means that we can have nested references to rendered values. For example:

  - type: motorSim.simMotorAxis
    controller: controllerOne
    M: CS_M{{ADDR}}
    ADDR: "{{ 1 + axis_start | int }}"
    DESC: "CS Motor {{ADDR}}"
    home: 100
    CS_NUM: 3
    is_cs: true

Without a second pass of this we would have DESC = CS Motor {{ 1 + axis_start | int }}

The downside of this approach is that there is no possibility of using escaping to put {{ and }} in the final result.

@coretl I would like to get your sign off on this Additionally feature - what do you think?

coretl commented 7 months ago

I'm still slightly nervous of not being able to include escaping, seems like it might cause difficult to change issues down the line.

Also, how would a pathological case like this render?

- type: motorSim.simMotorAxis
  DESC: "{{ ADDR }}"
  ADDR: "{{ DESC }}"
coretl commented 7 months ago

I've got a potential idea, instead of populating the context with the values, populate them with deferred renderers, e.g.

@dataclass
Class DeferredRender:
    value: str
    context: Dict[str, Any]
    @lru_cache  # maybe?
    def __str__(self) -> str:
        return render(self.value, self.context)

context = {}
for arg _name, arg_value in args.items():
    context[arg_name] = DeferredRender(arg_value, context)

Then let Python's recursion size limit catch the recursive case

GDYendell commented 7 months ago

DeferredRender seems really neat.

gilesknap commented 7 months ago

that is pretty cool 🤓

gilesknap commented 7 months ago

Note that we don't want to do this for objects because we want to use dot-member.

gilesknap commented 4 weeks ago

The rendering as of 3.0.0b6 is all done during the model validator for the IOC instance. All typed fields are also allowed to be str as long as the str contains {{.*}}.

https://github.com/epics-containers/ibek/blob/list-arg2dict-param/src/ibek/ioc.py#L97-L122