How can I apply a function call to an alias?
Question
My target is to allow an easy way to “filter” previously defined nodes. Consider this fictional YAML file:
%YAML 1.1
---
- fruit: &fruitref { type: banana, color: yellow }
- another_fruit: !rotten *fruitref
What do I need to define in either the YAML file or the Python code that parses this file in order to call a custom function with *fruitref
(i.e. the previously defined object, in this case a map) as argument and get the return value? The target is as simple and terse a syntax for “filtering” a previously defined value (map, sequence, whatever).
Note
It seems to me that the construct !
tag *
alias is invalid YAML, because of the error:
expected <block end>, but found '<alias>'
in "/tmp/test.yaml", line 4, column 21
which most possibly implies that I won't be able to achieve the required syntax, but I do care about terseness (or rather, the target users will).
Routes taken
YAML: !!python/object/apply:__main__.rotten [*fruitref]
It works but it is too verbose for the intended use; and there is no need for multiple arguments, the use case is ALWAYS a filter for an alias (a previously defined map/sequence/object).
YAML: %TAG !f! !!python/object/apply:__main__.
Perhaps !f!rotten [*fruitref]
would be acceptable, but I can't find how to make use of the %TAG
directive.
EDIT: I discovered that the !!
doesn't work for PyYAML 3.10, it has to be the complete URL like this: %TAG !f! %TAG !f! tag:yaml.org,2002:python/object/apply:__main__.
Python: yaml.add_constructor
I already use add_constructor
for “casting” maps to specific instances of my classes; the caveat is that tag alias seems to be invalid YAML.
Best so far
add_constructor('!rotten', filter_rotten)
in Python and !rotten [*fruitref]
in YAML seem to work, but I'm wondering how to omit the square brackets if possible.
Solution
It seems that it is not possible to apply a tag to an already tagged reference, so:
!tag *reference
is not acceptable. The best possible solution is to enclose the reference to square brackets (create a sequence) and make the tag to be either a function call or a special constructor expecting a sequence of one object, so the tersest syntax available is:
!prefix!suffix [*reference]
or
!tag [*reference]