Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
tbabej committed Sep 19, 2021
2 parents 63243ba + 71822a7 commit bebca90
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 81 deletions.
7 changes: 3 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
language: python
env:
- TASK_VERSION=v2.1.1
- TASK_VERSION=v2.1.2
- TASK_VERSION=v2.2.0
- TASK_VERSION=v2.3.0
- TASK_VERSION=v2.4.0
- TASK_VERSION=v2.4.1
- TASK_VERSION=v2.4.2
- TASK_VERSION=v2.4.3
- TASK_VERSION=v2.4.4
- TASK_VERSION=v2.5.0
- TASK_VERSION=v2.5.1
- TASK_VERSION=v2.5.2
- TASK_VERSION=v2.5.3
python:
- "3.5"
- "3.6"
- "3.7"
- "3.8"
- "3.9"
install:
- pip install -e .
- pip install coveralls
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Requirements
------------

* Python 3.5 or above
* taskwarrior_ v2.1.x or above.
* taskwarrior_ v2.4.x or above.

Older versions of taskwarrior are untested and may not work.

Expand Down
6 changes: 3 additions & 3 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@

# General information about the project.
project = u'tasklib'
copyright = u'2014, Rob Golding'
copyright = u'2014 - 2021, Rob Golding & Gothenburg Bit Factory'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2.3.0'
version = '2.4.0'
# The full version, including alpha/beta/rc tags.
release = '2.3.0'
release = '2.4.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ Welcome to tasklib's documentation!
tasklib is a Python library for interacting with taskwarrior_ databases, using
a queryset API similar to that of Django's ORM.

Supports Python 3.5 and above, with taskwarrior 2.1.x and above.
Supports Python 3.5 and above, with taskwarrior 2.4.x and above.
Older versions of taskwarrior are untested and may not work.

Requirements
------------

* taskwarrior_ v2.1.x or above, although newest minor release is recommended.
* taskwarrior_ v2.4.x or above, although newest minor release is recommended.

Installation
------------
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

install_requirements = ['pytz', 'tzlocal']

version = '2.3.0'
version = '2.4.0'

try:
import importlib
Expand Down Expand Up @@ -31,6 +31,7 @@
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
'License :: OSI Approved :: BSD License',
'Topic :: Software Development :: Libraries :: Python Modules',
'Intended Audience :: Developers',
Expand Down
66 changes: 24 additions & 42 deletions tasklib/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,6 @@ class TaskWarriorException(Exception):

class TaskWarrior(Backend):

VERSION_2_1_0 = '2.1.0'
VERSION_2_2_0 = '2.2.0'
VERSION_2_3_0 = '2.3.0'
VERSION_2_4_0 = '2.4.0'
VERSION_2_4_1 = '2.4.1'
VERSION_2_4_2 = '2.4.2'
Expand Down Expand Up @@ -218,31 +215,17 @@ def format_depends(self, task):
)

def format_description(self, task):
# Task version older than 2.4.0 ignores first word of the
# task description if description: prefix is used
if self.version < self.VERSION_2_4_0:
return task._data['description']
else:
return "description:'{0}'".format(
task._data['description'] or '',
)
return "description:'{0}'".format(
task._data['description'] or '',
)

def convert_datetime_string(self, value):

if self.version >= self.VERSION_2_4_0:
# For strings, use 'calc' to evaluate the string to datetime
# available since TW 2.4.0
args = value.split()
result = self.execute_command(['calc'] + args)
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)),
)

# For strings, use 'calc' to evaluate the string to datetime
# available since TW 2.4.0
args = value.split()
result = self.execute_command(['calc'] + args)
naive = datetime.datetime.strptime(result[0], DATE_FORMAT_CALC)
localized = local_zone.localize(naive)
return localized

@property
Expand Down Expand Up @@ -329,7 +312,7 @@ def get_task(self, uuid):

def filter_tasks(self, filter_obj):
self.enforce_recurrence()
args = ['export'] + filter_obj.get_filter_params()
args = filter_obj.get_filter_params() + ["export"]
tasks = []
for line in self.execute_command(args):
if line:
Expand All @@ -347,16 +330,19 @@ def save_task(self, task):

args = [task['uuid'], 'modify'] if task.saved else ['add']
args.extend(self._get_modified_task_fields_as_args(task))
output = self.execute_command(args)
output = self.execute_command(
args,
config_override={'verbose': 'new-uuid'}
)

# Parse out the new ID, if the task is being added for the first time
if not task.saved:
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.
# Expected output: Created task 1.
# Created task 1 (recurrence template).
# Expected output: Created task bd23f69a-a078-48a4-ac11-afba0643eca9.
# Created task bd23f69a-a078-48a4-ac11-afba0643eca9 (recurrence template).
if len(id_lines) != 1 or len(id_lines[0].split(' ')) not in (3, 5):
raise TaskWarriorException(
'Unexpected output when creating '
Expand All @@ -366,11 +352,8 @@ def save_task(self, task):
# Circumvent the ID storage, since ID is considered read-only
identifier = id_lines[0].split(' ')[2].rstrip('.')

# Identifier can be either ID or UUID for completed tasks
try:
task._data['id'] = int(identifier)
except ValueError:
task._data['uuid'] = identifier
# Identifier is UUID, because we used new-uuid verbosity override
task._data['uuid'] = identifier

# Refreshing is very important here, as not only modification time
# is updated, but arbitrary attribute may have changed due hooks
Expand All @@ -387,10 +370,6 @@ def stop_task(self, task):
self.execute_command([task['uuid'], 'stop'])

def complete_task(self, task):
# Older versions of TW do not stop active task at completion
if self.version < self.VERSION_2_4_0 and task.active:
task.stop()

self.execute_command([task['uuid'], 'done'])

def annotate_task(self, task, annotation):
Expand All @@ -406,7 +385,11 @@ def refresh_task(self, task, after_save=False):
# of newly saved tasks. Any other place in the code is fine
# with using UUID only.
args = [task['uuid'] or task['id'], 'export']
output = self.execute_command(args)
output = self.execute_command(
args,
# Supress GC, which can change ID numbers (undesirable for refresh)
config_override={'gc': '0'}
)

def valid(output):
return len(output) == 1 and output[0].startswith('{')
Expand All @@ -427,8 +410,7 @@ def valid(output):
for key, value in data.items():
taskfilter.add_filter_param(key, value)

output = self.execute_command(['export'] +
taskfilter.get_filter_params())
output = self.execute_command(taskfilter.get_filter_params() + ['export'])

# If more than 1 task has been matched still, raise an exception
if not valid(output):
Expand Down
2 changes: 1 addition & 1 deletion tasklib/serializing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .lazy import LazyUUIDTaskSet, LazyUUIDTask

DATE_FORMAT = '%Y%m%dT%H%M%SZ'
local_zone = tzlocal.get_localzone()
local_zone = pytz.timezone(str(tzlocal.get_localzone()))


class SerializingObject(object):
Expand Down
54 changes: 27 additions & 27 deletions tasklib/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def test_custom_command(self):
tw = self.get_taskwarrior(
task_command='wsl task',
# prevent `_get_version` from running as `wsl` may not exist
version_override=os.getenv('TASK_VERSION'),
version_override=os.getenv('TASK_VERSION', 'v1.2.3'),
)
self.assertEqual(tw._get_task_command(), ['wsl', 'task'])

Expand Down Expand Up @@ -1229,21 +1229,21 @@ def test_simple_eoy_conversion(self):
t = Task(self.tw, description='test task', due='eoy')
now = local_zone.localize(datetime.datetime.now())
eoy = local_zone.localize(datetime.datetime(
year=now.year+1,
month=1,
day=1,
hour=0,
minute=0,
second=0,
year=now.year,
month=12,
day=31,
hour=23,
minute=59,
second=59,
))
if self.tw.version < '2.5.2':
if self.tw.version >= '2.5.2' and self.tw.version < '2.6.0':
eoy = local_zone.localize(datetime.datetime(
year=now.year,
month=12,
day=31,
hour=23,
minute=59,
second=59,
year=now.year+1,
month=1,
day=1,
hour=0,
minute=0,
second=0,
))
self.assertEqual(eoy, t['due'])

Expand All @@ -1260,23 +1260,23 @@ def test_complex_eoy_conversion(self):
now = local_zone.localize(datetime.datetime.now())
due_date = local_zone.localize(
datetime.datetime(
year=now.year+1,
month=1,
day=1,
hour=0,
minute=0,
second=0,
year=now.year,
month=12,
day=31,
hour=23,
minute=59,
second=59,
)
) - datetime.timedelta(0, 4 * 30 * 86400)
if self.tw.version < '2.5.2':
if self.tw.version >= '2.5.2' and self.tw.version < '2.6.0':
due_date = local_zone.localize(
datetime.datetime(
year=now.year,
month=12,
day=31,
hour=23,
minute=59,
second=59,
year=now.year+1,
month=1,
day=1,
hour=0,
minute=0,
second=0,
)
) - datetime.timedelta(0, 4 * 30 * 86400)
self.assertEqual(due_date, t['due'])
Expand Down

0 comments on commit bebca90

Please sign in to comment.