Replies: 3 comments
-
|
Thinking a bit about implementation techniques for these template expressions. While we could use the jinja2 library, it has a lot more functionality than I think we want to pull in, and it would be nice to find a simple way to control what's permitted. The jinja sandbox documentation says "Access to attributes, method calls, operators, mutating data structures, and string formatting can be intercepted and prohibited." That's an opt-out approach, but it would be nicer to have an opt-in implementation where we explicitly specify permitted expressions compared to identifying and preventing the patterns we don't want. The Python standard library ast module looks like it fits the bill for an implementation, as long as we keep the syntax as a subset of Python. There are other implementations of Python parsing available, for example for Rust there is rustpython-parser. For the >>> import ast
>>> def parse(expr):
... node = ast.parse(expr, mode="eval")
... print(ast.dump(node, indent=2))
...
>>> parse("len(Task.Param.Frame)")
Expression(
body=Call(
func=Name(id='len', ctx=Load()),
args=[
Attribute(
value=Attribute(
value=Name(id='Task', ctx=Load()),
attr='Param',
ctx=Load()),
attr='Frame',
ctx=Load())],
keywords=[]))
>>> parse("Task.Param.Frame[-1]")
Expression(
body=Subscript(
value=Attribute(
value=Attribute(
value=Name(id='Task', ctx=Load()),
attr='Param',
ctx=Load()),
attr='Frame',
ctx=Load()),
slice=UnaryOp(
op=USub(),
operand=Constant(value=1)),
ctx=Load()))
>>> parse("path_to_posix(Param.PathValue)")
Expression(
body=Call(
func=Name(id='path_to_posix', ctx=Load()),
args=[
Attribute(
value=Name(id='Param', ctx=Load()),
attr='PathValue',
ctx=Load())],
keywords=[]))
>>> parse("100 if Param.BigNumber else 1")
Expression(
body=IfExp(
test=Attribute(
value=Name(id='Param', ctx=Load()),
attr='BigNumber',
ctx=Load()),
body=Constant(value=100),
orelse=Constant(value=1)))We could implement a NodeVisitor subclass to handle processing of the permitted node types and evaluate the expression. |
Beta Was this translation helpful? Give feedback.
-
|
Created a refactoring PR to make experimenting with this idea easier: OpenJobDescription/openjd-model-for-python#182 |
Beta Was this translation helpful? Give feedback.
-
|
I've written a set of three RFCs for this, and created a fully-functioning prototype implementation of it. Have a look and provide review feedback here: #113 |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Open Job Description launched with a minimal template substitution syntax, that only can substitute untransformed literal text. It is a subset of jinja expressions, with the door open to either continue adding jinja syntax, or to select alternative expression syntax. Sticking to a jinja subset that's supported by multiple potential implementation, e.g. by the Rust minijinja library, seems like a good way to extend it. Adding list/array, bool, and likely optional types to the supported job parameter types along with the template language complements extending the syntax and many other ways to extend Open Job Description features, so I think it is good to bundle that in as well. Extension name TEMPLATE_EXPR.
Some motivational cases include:
"{{Param.FrameStart + Param.FramesPerTask - 1}}for the linked discussion or{{Task.Param.NodeIndex * 2}},{{Task.Param.NodeIndex * 2 + 1}}to form a range expression for dependencies in a node of a full binary tree applicable to the per-task dependencies case below.CHUNK[INT]value. We considered whether to Extend template substitution syntax for the CHUNK[INT] type, and deferred it. Having a chunk behave like a sorted list of integers, to query its length or get the first and last values would simplify templates that use chunking.{{ len(Task.Param.Frame) }}= task count in the chunk,{{ Task.Param.Frame[0] }}= smallest value in the chunk,{{ Task.Param.Frame[-1] }}= largest value in the chunk,{{ tojson(Task.Param.Frame) }}= chunk as a list of integers in JSON format "[1,2,3,5,7]" for chunk "1-3,5,7".{{ tojson(Param.StrValue) }}to print as a JSON object, or{{ path_to_posix(Param.PathValue) }}to always use/for the path separator.userInterfacejob parameter metadata to show/hide controls depending on parameter values from other controls. Feature idea: conditionally show job parameter UI elements based on other parameter values #42LIST[STRING]type that is forwarded to a task parameter would allow for choosing a list of cameras to render without having to embed the cameras in the job template itself. ALIST[PATH]type withINdata flow andFILE(or alternativelyDIRECTORY) object type would allow for the submitter to more flexibly specify inputs as job parametersDo you have more example use cases, either for job parameter types or for template substitutions?
Beta Was this translation helpful? Give feedback.
All reactions