I would like to use a for loop to generate a set of rules, based on the contents of of the config.yaml
file. Here's a minimum working example.
config={'person1': 'Amy', 'person2': 'Bruce'}
for thiskey,thisperson in config.items():
rule:
name: f'{thisperson}s_rule'
output: f'{thiskey}.txt'
run:
print(f'\n{thiskey} is called {thisperson}!\n')
rule people:
input: [this+'.txt' for this in config.keys()]
If you run it (use the -k
switch to keep going and ignore the missing files), you'll see that the same thing is being written to the screen for both files (person2 is called Bruce!
) whereas you would expect to see a similar messages for both Amy and Bruce.
Is this at all a sensible way to setup rules? Or should I find a workaround?
Thanks,
Mark
config = {'person1': 'Amy', 'person2': 'Bruce'}
def create_rule(thiskey, thisperson):
rule:
name: f"{thisperson}s_rule"
output: f"{thiskey}.txt"
run:
print(f'\n{thiskey} is called {thisperson}!\n')
# Generate rules
for thiskey, thisperson in config.items():
create_rule(thiskey, thisperson)
rule people:
input: [this + '.txt' for this in config.keys()]
TTry to pass the loop variables as default arguments to an inline function, forcing their evaluation at each iteration.
Maybe your real case is more complex, but the typical way of implementing your example would not need to generate rules on the fly:
config={'person1': 'Amy', 'person2': 'Bruce'}
rule people:
input:
expand('{thiskey}.txt', thiskey=config.keys()), # same as: [this+'.txt' for this in config.keys()]
rule make_person:
output:
'{thiskey}.txt',
params:
thisperson=lambda wc: config[wc.thiskey],
run:
print(f'\n{wildcards.thiskey} is called {params.thisperson}!\n')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With