X-Git-Url: https://git.madduck.net/etc/taskwarrior.git/blobdiff_plain/a4523acd2a9a8837eadac8b2d099fd64db47e939..f24e18261a3d19b01bca32d5471b84729ec9efa9:/tasklib/backends.py diff --git a/tasklib/backends.py b/tasklib/backends.py index 25193cc..9110e12 100644 --- a/tasklib/backends.py +++ b/tasklib/backends.py @@ -75,7 +75,7 @@ class Backend(object): Converts TW syntax datetime string to a localized datetime object. This method is not mandatory. """ - raise NotImplemented + raise NotImplementedError class TaskWarriorException(Exception): @@ -94,7 +94,8 @@ class TaskWarrior(Backend): VERSION_2_4_4 = six.u('2.4.4') VERSION_2_4_5 = six.u('2.4.5') - def __init__(self, data_location=None, create=True, taskrc_location='~/.taskrc'): + def __init__(self, data_location=None, create=True, + taskrc_location='~/.taskrc'): self.taskrc_location = os.path.expanduser(taskrc_location) # If taskrc does not exist, pass / to use defaults and avoid creating @@ -132,7 +133,10 @@ class TaskWarrior(Backend): overrides.update(config_override or dict()) for item in overrides.items(): command_args.append('rc.{0}={1}'.format(*item)) - command_args.extend(map(six.text_type, args)) + command_args.extend([ + x.decode('utf-8') if isinstance(x, six.binary_type) + else six.text_type(x) for x in args + ]) return command_args def _get_version(self): @@ -171,11 +175,17 @@ class TaskWarrior(Backend): if task.saved: for field in task._modified_fields: add_field(field) + # For new tasks, pass all fields that make sense else: for field in task._data.keys(): + # We cannot set stuff that's read only (ID, UUID, ..) if field in task.read_only_fields: continue + # We do not want to do field deletion for new tasks + if task._data[field] is None: + continue + # Otherwise we're fine add_field(field) return args @@ -205,7 +215,9 @@ class TaskWarrior(Backend): if self.version < self.VERSION_2_4_0: return task._data['description'] else: - return six.u("description:'{0}'").format(task._data['description'] or '') + return six.u("description:'{0}'").format( + task._data['description'] or '', + ) def convert_datetime_string(self, value): @@ -217,9 +229,11 @@ class TaskWarrior(Backend): naive = datetime.datetime.strptime(result[0], DATE_FORMAT_CALC) localized = local_zone.localize(naive) else: - raise ValueError("Provided value could not be converted to " - "datetime, its type is not supported: {}" - .format(type(value))) + raise ValueError( + 'Provided value could not be converted to ' + 'datetime, its type is not supported: {}' + .format(type(value)), + ) return localized @@ -242,7 +256,7 @@ class TaskWarrior(Backend): ) config = dict() - config_regex = re.compile(r'^(?P[^\s]+)\s+(?P[^\s].+$)') + config_regex = re.compile(r'^(?P[^\s]+)\s+(?P[^\s].*$)') for line in raw_output: match = config_regex.match(line) @@ -258,7 +272,8 @@ class TaskWarrior(Backend): return_all=False): command_args = self._get_command_args( args, config_override=config_override) - logger.debug(' '.join(command_args)) + logger.debug(u' '.join(command_args)) + p = subprocess.Popen(command_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = [x.decode('utf-8') for x in p.communicate()] @@ -267,6 +282,7 @@ class TaskWarrior(Backend): error_msg = stderr.strip() else: error_msg = stdout.strip() + error_msg += u'\nCommand used: ' + u' '.join(command_args) raise TaskWarriorException(error_msg) # Return all whole triplet only if explicitly asked for @@ -298,7 +314,7 @@ class TaskWarrior(Backend): def filter_tasks(self, filter_obj): self.enforce_recurrence() - args = ['export', '--'] + filter_obj.get_filter_params() + args = ['export'] + filter_obj.get_filter_params() tasks = [] for line in self.execute_command(args): if line: @@ -323,10 +339,14 @@ class TaskWarrior(Backend): id_lines = [l for l in output if l.startswith('Created task ')] # Complain loudly if it seems that more tasks were created - # Should not happen - if len(id_lines) != 1 or len(id_lines[0].split(' ')) != 3: - raise TaskWarriorException("Unexpected output when creating " - "task: %s" % '\n'.join(id_lines)) + # Should not happen. + # Expected output: Created task 1. + # Created task 1 (recurrence template). + if len(id_lines) != 1 or len(id_lines[0].split(' ')) not in (3, 5): + raise TaskWarriorException( + 'Unexpected output when creating ' + 'task: %s' % '\n'.join(id_lines), + ) # Circumvent the ID storage, since ID is considered read-only identifier = id_lines[0].split(' ')[2].rstrip('.') @@ -392,14 +412,14 @@ class TaskWarrior(Backend): for key, value in data.items(): taskfilter.add_filter_param(key, value) - output = self.execute_command(['export', '--'] + + output = self.execute_command(['export'] + taskfilter.get_filter_params()) # If more than 1 task has been matched still, raise an exception if not valid(output): raise TaskWarriorException( - "Unique identifiers {0} with description: {1} matches " - "multiple tasks: {2}".format( + 'Unique identifiers {0} with description: {1} matches ' + 'multiple tasks: {2}'.format( task['uuid'] or task['id'], task['description'], output) )