pydoit / doit

CLI task management & automation tool
http://pydoit.org
MIT License
1.84k stars 175 forks source link

Default values for param of type list not being overridden. #436

Open joshuajorel opened 2 years ago

joshuajorel commented 2 years ago

Hi,

When using a param of type list and adding default values in the definition of the param, when invoking the task with list values you specified in the command line, it does not create a new list, but appends to the default list.

doit.py

from doit import task_params

@task_params([{'name': 'some_list', 'type': list, 'default': ['item1', 'item2'], 'short': 'l'}])
def task_list_with_duplicates(some_list):
    for l in some_list:
        yield {
            'name': f'name_of_list_{l}',
            'actions': [f'echo "some action on list {l}"'],
            'verbosity': 2
        }

Execution

> doit list_with_duplicates -l item1
ERROR: Task generation 'list_with_duplicates' has duplicated definition of 'list_with_duplicates:name_of_list_item1'

Environment

  1. OS: MacOS 11.6.8
  2. python version: 3.9.12
  3. doit version: 0.36.0

Fund with Polar

oliverdain commented 2 years ago

I think I just ran into something similar which is, I think, actually the root cause issue here: if an action generator uses yield to generate tasks the params are ignored.

For example, given the following

from doit import task_params

@task_params([
    {'name': 'version', 'long': 'version', 'default': 'v10'},
])
def task_testing(version):
    print('version:', version)
    return {
        'actions': [f'echo {version}'],
        'verbosity': 2,
    }

It works as expected:

$ doit testing --version=hello
version: hello
.  testing
hello

But change it to this:

from doit import task_params

@task_params([
    {'name': 'version', 'long': 'version', 'default': 'v10'},
])
def task_testing(version):
    print('version:', version)
    yield {
        'basename': 'test',
        'actions': [f'echo {version}'],
        'verbosity': 2,
    }

and it ignores the command line argument:

$ doit test --version=hello
version: v10
.  test
v10

You can get it to work again by putting the CLI args on the yielded task:

from doit import task_params

def task_testing():
    yield {
        'basename': 'test',
        'actions': ['echo %(version)s'],
        'verbosity': 2,
        'params': [
            {'name': 'version', 'long': 'version', 'default': 'v10'},
        ],
    }

which works:

$ doit test --version=hello
.  test
hello

But it has some drawbacks as the CLI argument isn't available as a regular Python variable so you can't use it except in the few places doit will expand it (e.g. you couldn't use it in an f-string to generate a title).