From 3eacff4a6694ca2b9de669520a2663492bfe5ad2 Mon Sep 17 00:00:00 2001 From: schettino72 Date: Tue, 6 Jan 2015 18:51:40 +0800 Subject: [PATCH] refs #14. delayed-task-creation. fix command that dont execute tasks... --- doit/cmd_auto.py | 1 + doit/cmd_base.py | 13 ++++++--- doit/cmd_run.py | 1 + doit/loader.py | 69 ++++++++++++++++++++++++++++++------------------ 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/doit/cmd_auto.py b/doit/cmd_auto.py index b18eaad8..57dcf3c2 100644 --- a/doit/cmd_auto.py +++ b/doit/cmd_auto.py @@ -32,6 +32,7 @@ class Auto(DoitCmdBase): doc_purpose = "automatically execute tasks when a dependency changes" doc_usage = "[TASK ...]" doc_description = None + execute_tasks = True cmd_options = (opt_verbosity, opt_reporter) diff --git a/doit/cmd_base.py b/doit/cmd_base.py index eeb57d41..c7609234 100644 --- a/doit/cmd_base.py +++ b/doit/cmd_base.py @@ -47,6 +47,11 @@ class Command(object): # sequence of dicts cmd_options = tuple() + # `execute_tasks` indicates wheather this command execute task's actions. + # This is used by the loader to indicate when delayed task creation + # should be used. + execute_tasks = False + def __init__(self): self.name = self.name or self.__class__.__name__.lower() Command.CMD_LIST.append(self.name) @@ -172,13 +177,13 @@ def load_tasks(self, cmd, opt_values, pos_args): # pragma: no cover raise NotImplementedError() @staticmethod - def _load_from(namespace, cmd_list): + def _load_from(cmd, namespace, cmd_list): """load task from a module or dict with module members""" if inspect.ismodule(namespace): members = dict(inspect.getmembers(namespace)) else: members = namespace - task_list = loader.load_tasks(members, cmd_list) + task_list = loader.load_tasks(members, cmd_list, cmd.execute_tasks) doit_config = loader.load_doit_config(members) return task_list, doit_config @@ -193,7 +198,7 @@ def __init__(self, mod_dict): self.mod_dict = mod_dict def load_tasks(self, cmd, params, args): - return self._load_from(self.mod_dict, cmd.CMD_LIST) + return self._load_from(cmd, self.mod_dict, cmd.CMD_LIST) class DodoTaskLoader(TaskLoader): @@ -203,7 +208,7 @@ class DodoTaskLoader(TaskLoader): def load_tasks(self, cmd, params, args): dodo_module = loader.get_module(params['dodoFile'], params['cwdPath'], params['seek_file']) - return self._load_from(dodo_module, cmd.CMD_LIST) + return self._load_from(cmd, dodo_module, cmd.CMD_LIST) diff --git a/doit/cmd_run.py b/doit/cmd_run.py index 46bc8e6a..3b182c6e 100644 --- a/doit/cmd_run.py +++ b/doit/cmd_run.py @@ -123,6 +123,7 @@ class Run(DoitCmdBase): doc_purpose = "run tasks" doc_usage = "[TASK/TARGET...]" doc_description = None + execute_tasks = True cmd_options = (opt_always, opt_continue, opt_verbosity, opt_reporter, opt_outfile, opt_num_process, diff --git a/doit/loader.py b/doit/loader.py index 34e0d378..f1bff3fa 100644 --- a/doit/loader.py +++ b/doit/loader.py @@ -42,7 +42,7 @@ def decorated(func): def get_module(dodo_file, cwd=None, seek_parent=False): """ - The python file defining tasks is called "dodo" file. + Find python module defining tasks, it is called "dodo" file. @param dodo_file(str): path to file containing the tasks @param cwd(str): path to be used cwd, if None use path from dodo_file @@ -102,21 +102,53 @@ def exist_or_raise(path): return __import__(os.path.splitext(file_name)[0]) -def load_tasks(task_creators, command_names=()): - """Get task generators and generate tasks +def load_tasks(namespace, command_names=(), allow_delayed=False): + """Find task-creators and create tasks - @param task_creators: (dict) containing the task creators, it might + @param namespace: (dict) containing the task creators, it might contain other stuff @param command_names: (list - str) blacklist for task names + @param load_all: (bool) if True ignore doit_crate_after['executed'] + + `load_all == False` is used by the runner to delay the creation of + tasks until a dependent task is executed. This is only used by the `run` + command, other commands should always load all tasks since it wont execute + any task. + @return task_list (list) of Tasks in the order they were defined on the file """ + funcs = _get_task_creators(namespace, command_names) + # sort by the order functions were defined (line number) + # TODO: this ordering doesnt make sense when generators come + # from different modules + funcs.sort(key=lambda obj:obj[2]) + + task_list = [] + for name, ref, line in funcs: + dep_task = (allow_delayed and + hasattr(ref, 'doit_create_after') and + ref.doit_create_after.get('executed')) + + if dep_task: + task_list.append(Task(name, None, loader=(ref, dep_task))) + else: + task_list.extend(generate_tasks(name, ref(), ref.__doc__)) + return task_list + - # get functions defined in the module and select the task generators - # a task generator function name starts with the string TASK_STRING +def _get_task_creators(namespace, command_names): + """get functions defined in the `namespace` and select the task-creators + + A task-creator is a function that: + - name starts with the string TASK_STRING + - has the attribute `create_doit_tasks` + + @return (list - func) task-creators + """ funcs = [] prefix_len = len(TASK_STRING) - # get all functions that are task_creators - for name, ref in six.iteritems(task_creators): + # get all functions that are task-creators + for name, ref in six.iteritems(namespace): # function is a task creator because of its name if ((inspect.isfunction(ref) or inspect.ismethod(ref)) and @@ -139,7 +171,7 @@ def load_tasks(task_creators, command_names=()): elif True: # coverage can't get "else: continue" continue - # tasks cant have name of commands + # tasks can't have the same name of a commands if task_name in command_names: msg = ("Task can't be called '%s' because this is a command name."+ " Please choose another name.") @@ -149,22 +181,7 @@ def load_tasks(task_creators, command_names=()): # add to list task generator functions funcs.append((task_name, ref, line)) - # sort by the order functions were defined (line number) - # TODO: this ordering doesnt make sense when generators come - # from different modules - funcs.sort(key=lambda obj:obj[2]) - - task_list = [] - for name, ref, line in funcs: - after = None - if hasattr(ref, 'doit_create_after'): - after = ref.doit_create_after.get('executed') - - if after: - task_list.append(Task(name, None, loader=(ref, after))) - else: - task_list.extend(generate_tasks(name, ref(), ref.__doc__)) - return task_list + return funcs def load_doit_config(dodo_module): @@ -259,7 +276,7 @@ def generate_tasks(func_name, gen_result, gen_doc=None): @param gen_result: value returned by a task generator function it can be a dict or generator (generating dicts) @param gen_doc: (string/None) docstring from the task generator function - @return: (tuple) task, list of subtasks + @return: (list - Task) """ # task described as a dictionary if isinstance(gen_result, dict):