Before anything else: never use Show
Of this only the first one needs to be given, that should be your So although you could do:
this is inefficient and shows little understanding of how If you want to open the file for reading and writing you have to make sure you both reset the index in the file and truncate its content. This is usually not worth the effort so it is safer to re-open the file for writing:
(of course you make the filename a variable when you want to make sure you overwrite the original, so you cannot mistype it). If you don't specify
The output will not include the superfluous quotes around Replacement is a python utility that parses a yaml template and outputs text. Installing
or, if you use nix:
IntroductionNOTE: the examples given here are further documented in the tests. A A
replacement object contains a list of 1. basic templateA template: --- # simplistic template example # tests/hello.yaml replacement: - text: text input: hello world ... Execute a template using $ replacement -t tests/hello.yaml hello world Blocks always begin with a
In the block above, 2. reading from a fileFile
--- # read from file # tests/file.yaml replacement: - text: file input: hello.out ... $ replacement -t tests/file.yaml hello world Notice that:
intermission: schemaA schema of all the replacement directives is contained in schema.yaml. Here is a snippet showing just the --- ## # format of a block ## block: - yield: inputType # this is a directive input: inputVal ## # definition of schema elements ## schema: # 'yield' : what to output (how to format output) yield: - text # text: a list of newline-separated strings - dict # a dictionary of key-value pairs - meta # output nothing: set a metadata (substitution dictionary) variable # 'input' : where to source data inputType: # we can input everything we output (see 'yield' above) - text - dict - meta # a key-value pair retrieved from substitutions dictionary # we can also input from other sources - file # open a file on disk - eval # python3 eval() statement - func # import and then call call a function - exec # subprocess execution (usually bash) inputVal: input_specific ... 3. metadata and substitutionThe
The
--- # metadata # tests/metadata.yaml replacement: # parse 'input' and insert the resulting dictionary into 'meta' - meta: dict # metadata may be given as an object input: version: 1.1 tag: my_awesome_tag - meta: text # metadata may be given as text which can be parsed as valid YAML input: | --- message: hello world ... - meta: text # metadata may also be given as JSON input: | { "hi": 5 } # use 'proc' to specify that 'str.format(**meta)' should be run on output - text: text proc: format input: | v{version} tag "{tag}" - text: text proc: substitute input: | message $message - text: text proc: safe_substitute input: | hi $hi this value may not exist - $nonexistent ... $ replacement -t tests/metadata.yaml v1.1 tag "my_awesome_tag" message hello world hi 5 this value may not exist - $nonexistent Metadata can also be read from a file. File { "hello": "world", "hi": 5, "list": [ 1, 2, 3, 4 ] } --- # metadata # tests/meta_file.yaml replacement: # parse file, inserting result into metadata dictionary - meta: file input: a.json # string substitution with 'proc' - text: text proc: format input: | hello {hello} hi {hi} list {list} ... $ replacement -t tests/meta_file.yaml hello world hi 5 list [1, 2, 3, 4] 3a. value -> dictionary using key--- # insert contents of file as metadata # tests/file_as_meta.yaml replacement: - text: dict input: # produces {"hello": "hi"} - dict: text key: hello input: | hi - dict: file key: contents input: hello.out - meta: file key: data input: prep.out - dict: dict prep: substitute input: also: $data - meta: file key: largefile input: recurse.out - dict: dict prep: format input: hello: world hi: | {largefile} ... --- hello: hi contents: hello world also: hello world hi: |- recursed inline v1.1 tag "my_awesome_tag" message hello world hi 5 this value may not exist - I exist I promise! ... 4. nesting
--- # nesting and dictionaries # tests/nesting.yaml replacement: # parse 'input' and insert the resulting dictionary into 'meta' - meta: dict input: version: 1.1 # same thing, but parse *text* input, instead of a dictionary - meta: text input: | # note the '|' --- tag: my_awesome_tag ... # use 'proc' to specify that 'str.format(**meta)' should be run on output - text: text proc: format input: | v{version} tag "{tag}" - text: text input: # metadata additions/changes seen by later blocks and any children, # but seen outside this list - meta: dict input: version: 1.0 - text: text proc: format input: | #v{version} tag "{tag}" (version clobbered in inner scope) - text: file input: hello.out # contains 'hello world' - text: text proc: format input: | outer still v{version} ... $ replacement -t tests/nesting.yaml v1.1 tag "my_awesome_tag" #v1.0 tag "my_awesome_tag" (version clobbered in inner scope) hello world outer still v1.1 5. preprocessingSubstitution can also be performed on the values of the block itself before it is parsed. The keyword --- # preprocessing # tests/prep.yaml replacement: - meta: dict input: filename: hello.out # preprocessing will substitute {filename} before evaluating 'file' input - text: file prep: format input: | {filename} ... $ replacement -t tests/prep.yaml hello world 6. access to python eval--- # use of eval # tests/an_eval.yaml replacement: # 'eval' returning a dictionary that can me appended to 'meta' - meta: eval input: | {"hello": 5 + 1} - text: text prep: format input: | hello {hello} # eval returning a scalar value - text: eval prep: format input: | {hello}**3 ... $ replacement -t tests/an_eval.yaml hello 6 216 7. python execSometimes it is advantageous to manipulate the runtime environment. In the below example, this is being used to import a module which will be needed by a subsequency call to --- # use of eval with an exec statement to execute an import call # tests/eval_exec.yaml replacement: - meta: exec input: | global IPv4Network from ipaddress import IPv4Network - meta: eval input: | {'gateway': str([h for h in IPv4Network('192.168.1.0/24').hosts()][-1])} - text: text prep: format input: | my gateway is {gateway} ... $ replacement -t tests/eval_exec.yaml
my gateway is 192.168.1.254
NOTE: python 8. imports and function executionThe --- # function execution # tests/func.yaml replacement: # run a function returning a dictionary, and merge that into 'meta' - meta: func args: existing: {'original': 'thesis'} # NOTE that this is sensitive to PYTHONPATH input: | ret_a_dict ./demo.py - text: text prep: format input: | original {original} secret {secret} # run a function returning a dictionary and export return as JSON - text: func options: - json # emit JSON rather than YAML (the default) args: existing: {'original': 'thesis'} input: | ret_a_dict ./demo.py # run a function returning an IOStream - text: func args: {} input: | ret_a_stream ./demo.py # previous use of non-portable BRAINDEAD python dot.notation # ... will break if 'replacement' (the script) is MOVED vis-a-vis demo.py # (of OF COURSE the CWD is blithely ignored ... why would ANYONE use it LOL) # TLDR: use the '[symbol] [path]' notation just above. # The _original_ call (broken) was: # tests.demo.ret_a_stream # A function returning a list of lines of text # (using the proper, cleaner import strategy) - text: func args: an_arg: ["question"] input: | ret_a_list ./demo.py # a static function inside a class - text: func input: | aClass.invented_list ./demo.py $ replacement -t tests/func.yaml original thesis secret 42 {"secret": 42, "original": "thesis"} 1. hello 2. world 42 meaning question hello from staticmethod 9. RecursionOr, how I learned to stop worrying and have templates import other templates. --- # recursion (nested 'replacement' templates) # tests/recurse.yaml replacement: # parse a 'replacement' template inline - replacement: text input: | --- replacement: - text: text input: | recursed inline ... - meta: dict input: nonexistent: "I exist I promise!" # parse a replacement template from a file # NOTE *relative* path) # NOTE our 'meta' dictionary is propagated to child replacement being parsed - replacement: file input: metadata.yaml ... $ replacement -t tests/recurse.yaml recursed inline v1.1 tag "my_awesome_tag" message hello world hi 5 this value may not exist - I exist I promise! DevelopmentThe recommended development environment is:
NOTES
Project TODOProject TODO list
|