Skip to content

TypeError using doit forget with no default tasks specified #478

Description

@hwswdude

Executing doit run does build all tasks if no default_tasks are specified.
Executing doit forget throws an exception if no default_tasks are specified.

I can try to create a pull request. Would be my first.

How to fail

Use (any) dodo.py without default_tasks`

Steps

  • Execute doit run -> all tasks get build
  • Execute doit forget -> get NoneType exception. I'm expecting: a) forgets all tasks or b) forget every task
  • Execute doit forget --all -> forgets all tasks
(.venv) :~/doit_bug/test$ doit
.  test
(.venv) :~/doit_bug/test$ doit
-- test
(.venv) :~/doit_bug/test$ doit forget
Traceback (most recent call last):
  File "~/doit_bug/.venv/lib/python3.14/site-packages/doit/doit_cmd.py", line 294, in run
    return command.parse_execute(args)
           ~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "~/doit_bug/.venv/lib/python3.14/site-packages/doit/cmd_base.py", line 150, in parse_execute
    return self.execute(params, args)
           ~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "~/doit_bug/.venv/lib/python3.14/site-packages/doit/cmd_base.py", line 570, in execute
    return self._execute(**exec_params)
           ~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "~/doit_bug/.venv/lib/python3.14/site-packages/doit/cmd_forget.py", line 62, in _execute
    for name in forget_list:
                ^^^^^^^^^^^
TypeError: 'NoneType' object is not iterable
(.venv) :~/doit_bug/test$ doit forget --all
forgetting all tasks
(.venv) :~/doit_bug/test$ doit
.  test

What I found

class Forget(DoitCmdBase):
    doc_purpose = "clear successful run status from internal DB"
    doc_usage = "[TASK ...]"
    doc_description = None

    cmd_options = (opt_forget_taskdep, opt_disable_default, opt_forget_all)

def _execute(self, forget_sub, forget_disable_default, forget_all):
        """remove saved data successful runs from DB
        """
## Does not handle special case: self.sel_tasks is None
## Could execute forget_all if self.sel_default_tasks and not forget_disable_default
        if forget_all:
            self.dep_manager.remove_all()
            self.outstream.write("forgetting all tasks\n")
## Does not care about empty default_tasks->
        elif self.sel_default_tasks and forget_disable_default:
            self.outstream.write(
                "no tasks specified, pass task name, --enable-default or --all\n")

        # forget tasks from list
        else:
            tasks = dict([(t.name, t) for t in self.task_list])
## check_tasks_exist() returns instead of throwing an error message like
## "no tasks specified, pass task name or --all\n")
            check_tasks_exist(tasks, self.sel_tasks)
            forget_list = self.sel_tasks

            if forget_sub:
                to_forget = list(tasks_and_deps_iter(tasks, forget_list, True))
            else:
                to_forget = []
                for name in forget_list:
                    task = tasks[name]
                    to_forget.append(task)
                    to_forget.extend(subtasks_iter(tasks, task))
## Fails as to_forget has never had a value other than initialized to None
            for task in to_forget:
                # forget it - remove from dependency file
                self.dep_manager.remove(task.name)
                self.outstream.write("forgetting %s\n" % task.name)
        self.dep_manager.close()

Environment

  1. OS: Ubuntu
  2. python version: Python3.14
  3. doit version: 0.36.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions