Skip to content

Commit bebca90

Browse files
committed
Merge branch 'develop'
2 parents 63243ba + 71822a7 commit bebca90

File tree

8 files changed

+63
-81
lines changed

8 files changed

+63
-81
lines changed

.travis.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
language: python
22
env:
3-
- TASK_VERSION=v2.1.1
4-
- TASK_VERSION=v2.1.2
5-
- TASK_VERSION=v2.2.0
6-
- TASK_VERSION=v2.3.0
73
- TASK_VERSION=v2.4.0
84
- TASK_VERSION=v2.4.1
95
- TASK_VERSION=v2.4.2
106
- TASK_VERSION=v2.4.3
117
- TASK_VERSION=v2.4.4
128
- TASK_VERSION=v2.5.0
139
- TASK_VERSION=v2.5.1
10+
- TASK_VERSION=v2.5.2
11+
- TASK_VERSION=v2.5.3
1412
python:
1513
- "3.5"
1614
- "3.6"
1715
- "3.7"
1816
- "3.8"
17+
- "3.9"
1918
install:
2019
- pip install -e .
2120
- pip install coveralls

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Requirements
1414
------------
1515

1616
* Python 3.5 or above
17-
* taskwarrior_ v2.1.x or above.
17+
* taskwarrior_ v2.4.x or above.
1818

1919
Older versions of taskwarrior are untested and may not work.
2020

docs/conf.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,16 @@
4444

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

4949
# The version info for the project you're documenting, acts as replacement for
5050
# |version| and |release|, also used in various other places throughout the
5151
# built documents.
5252
#
5353
# The short X.Y version.
54-
version = '2.3.0'
54+
version = '2.4.0'
5555
# The full version, including alpha/beta/rc tags.
56-
release = '2.3.0'
56+
release = '2.4.0'
5757

5858
# The language for content autogenerated by Sphinx. Refer to documentation
5959
# for a list of supported languages.

docs/index.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ Welcome to tasklib's documentation!
44
tasklib is a Python library for interacting with taskwarrior_ databases, using
55
a queryset API similar to that of Django's ORM.
66

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

1010
Requirements
1111
------------
1212

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

1515
Installation
1616
------------

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
install_requirements = ['pytz', 'tzlocal']
44

5-
version = '2.3.0'
5+
version = '2.4.0'
66

77
try:
88
import importlib
@@ -31,6 +31,7 @@
3131
"Programming Language :: Python :: 3.6",
3232
"Programming Language :: Python :: 3.7",
3333
"Programming Language :: Python :: 3.8",
34+
"Programming Language :: Python :: 3.9",
3435
'License :: OSI Approved :: BSD License',
3536
'Topic :: Software Development :: Libraries :: Python Modules',
3637
'Intended Audience :: Developers',

tasklib/backends.py

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,6 @@ class TaskWarriorException(Exception):
8484

8585
class TaskWarrior(Backend):
8686

87-
VERSION_2_1_0 = '2.1.0'
88-
VERSION_2_2_0 = '2.2.0'
89-
VERSION_2_3_0 = '2.3.0'
9087
VERSION_2_4_0 = '2.4.0'
9188
VERSION_2_4_1 = '2.4.1'
9289
VERSION_2_4_2 = '2.4.2'
@@ -218,31 +215,17 @@ def format_depends(self, task):
218215
)
219216

220217
def format_description(self, task):
221-
# Task version older than 2.4.0 ignores first word of the
222-
# task description if description: prefix is used
223-
if self.version < self.VERSION_2_4_0:
224-
return task._data['description']
225-
else:
226-
return "description:'{0}'".format(
227-
task._data['description'] or '',
228-
)
218+
return "description:'{0}'".format(
219+
task._data['description'] or '',
220+
)
229221

230222
def convert_datetime_string(self, value):
231-
232-
if self.version >= self.VERSION_2_4_0:
233-
# For strings, use 'calc' to evaluate the string to datetime
234-
# available since TW 2.4.0
235-
args = value.split()
236-
result = self.execute_command(['calc'] + args)
237-
naive = datetime.datetime.strptime(result[0], DATE_FORMAT_CALC)
238-
localized = local_zone.localize(naive)
239-
else:
240-
raise ValueError(
241-
'Provided value could not be converted to '
242-
'datetime, its type is not supported: {}'
243-
.format(type(value)),
244-
)
245-
223+
# For strings, use 'calc' to evaluate the string to datetime
224+
# available since TW 2.4.0
225+
args = value.split()
226+
result = self.execute_command(['calc'] + args)
227+
naive = datetime.datetime.strptime(result[0], DATE_FORMAT_CALC)
228+
localized = local_zone.localize(naive)
246229
return localized
247230

248231
@property
@@ -329,7 +312,7 @@ def get_task(self, uuid):
329312

330313
def filter_tasks(self, filter_obj):
331314
self.enforce_recurrence()
332-
args = ['export'] + filter_obj.get_filter_params()
315+
args = filter_obj.get_filter_params() + ["export"]
333316
tasks = []
334317
for line in self.execute_command(args):
335318
if line:
@@ -347,16 +330,19 @@ def save_task(self, task):
347330

348331
args = [task['uuid'], 'modify'] if task.saved else ['add']
349332
args.extend(self._get_modified_task_fields_as_args(task))
350-
output = self.execute_command(args)
333+
output = self.execute_command(
334+
args,
335+
config_override={'verbose': 'new-uuid'}
336+
)
351337

352338
# Parse out the new ID, if the task is being added for the first time
353339
if not task.saved:
354340
id_lines = [l for l in output if l.startswith('Created task ')]
355341

356342
# Complain loudly if it seems that more tasks were created
357343
# Should not happen.
358-
# Expected output: Created task 1.
359-
# Created task 1 (recurrence template).
344+
# Expected output: Created task bd23f69a-a078-48a4-ac11-afba0643eca9.
345+
# Created task bd23f69a-a078-48a4-ac11-afba0643eca9 (recurrence template).
360346
if len(id_lines) != 1 or len(id_lines[0].split(' ')) not in (3, 5):
361347
raise TaskWarriorException(
362348
'Unexpected output when creating '
@@ -366,11 +352,8 @@ def save_task(self, task):
366352
# Circumvent the ID storage, since ID is considered read-only
367353
identifier = id_lines[0].split(' ')[2].rstrip('.')
368354

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

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

389372
def complete_task(self, task):
390-
# Older versions of TW do not stop active task at completion
391-
if self.version < self.VERSION_2_4_0 and task.active:
392-
task.stop()
393-
394373
self.execute_command([task['uuid'], 'done'])
395374

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

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

430-
output = self.execute_command(['export'] +
431-
taskfilter.get_filter_params())
413+
output = self.execute_command(taskfilter.get_filter_params() + ['export'])
432414

433415
# If more than 1 task has been matched still, raise an exception
434416
if not valid(output):

tasklib/serializing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .lazy import LazyUUIDTaskSet, LazyUUIDTask
99

1010
DATE_FORMAT = '%Y%m%dT%H%M%SZ'
11-
local_zone = tzlocal.get_localzone()
11+
local_zone = pytz.timezone(str(tzlocal.get_localzone()))
1212

1313

1414
class SerializingObject(object):

tasklib/tests.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def test_custom_command(self):
7272
tw = self.get_taskwarrior(
7373
task_command='wsl task',
7474
# prevent `_get_version` from running as `wsl` may not exist
75-
version_override=os.getenv('TASK_VERSION'),
75+
version_override=os.getenv('TASK_VERSION', 'v1.2.3'),
7676
)
7777
self.assertEqual(tw._get_task_command(), ['wsl', 'task'])
7878

@@ -1229,21 +1229,21 @@ def test_simple_eoy_conversion(self):
12291229
t = Task(self.tw, description='test task', due='eoy')
12301230
now = local_zone.localize(datetime.datetime.now())
12311231
eoy = local_zone.localize(datetime.datetime(
1232-
year=now.year+1,
1233-
month=1,
1234-
day=1,
1235-
hour=0,
1236-
minute=0,
1237-
second=0,
1232+
year=now.year,
1233+
month=12,
1234+
day=31,
1235+
hour=23,
1236+
minute=59,
1237+
second=59,
12381238
))
1239-
if self.tw.version < '2.5.2':
1239+
if self.tw.version >= '2.5.2' and self.tw.version < '2.6.0':
12401240
eoy = local_zone.localize(datetime.datetime(
1241-
year=now.year,
1242-
month=12,
1243-
day=31,
1244-
hour=23,
1245-
minute=59,
1246-
second=59,
1241+
year=now.year+1,
1242+
month=1,
1243+
day=1,
1244+
hour=0,
1245+
minute=0,
1246+
second=0,
12471247
))
12481248
self.assertEqual(eoy, t['due'])
12491249

@@ -1260,23 +1260,23 @@ def test_complex_eoy_conversion(self):
12601260
now = local_zone.localize(datetime.datetime.now())
12611261
due_date = local_zone.localize(
12621262
datetime.datetime(
1263-
year=now.year+1,
1264-
month=1,
1265-
day=1,
1266-
hour=0,
1267-
minute=0,
1268-
second=0,
1263+
year=now.year,
1264+
month=12,
1265+
day=31,
1266+
hour=23,
1267+
minute=59,
1268+
second=59,
12691269
)
12701270
) - datetime.timedelta(0, 4 * 30 * 86400)
1271-
if self.tw.version < '2.5.2':
1271+
if self.tw.version >= '2.5.2' and self.tw.version < '2.6.0':
12721272
due_date = local_zone.localize(
12731273
datetime.datetime(
1274-
year=now.year,
1275-
month=12,
1276-
day=31,
1277-
hour=23,
1278-
minute=59,
1279-
second=59,
1274+
year=now.year+1,
1275+
month=1,
1276+
day=1,
1277+
hour=0,
1278+
minute=0,
1279+
second=0,
12801280
)
12811281
) - datetime.timedelta(0, 4 * 30 * 86400)
12821282
self.assertEqual(due_date, t['due'])

0 commit comments

Comments
 (0)