Hello community,

here is the log from the commit of package python-taskw for openSUSE:Factory 
checked in at 2020-12-09 22:21:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-taskw (Old)
 and      /work/SRC/openSUSE:Factory/.python-taskw.new.2328 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-taskw"

Wed Dec  9 22:21:40 2020 rev:2 rq:854125 version:1.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-taskw/python-taskw.changes        
2019-10-21 12:32:25.720234664 +0200
+++ /work/SRC/openSUSE:Factory/.python-taskw.new.2328/python-taskw.changes      
2020-12-09 22:21:40.975691296 +0100
@@ -1,0 +2,16 @@
+Tue Dec  8 11:22:08 UTC 2020 - John Vandenberg <[email protected]>
+
+- Update to v1.3.0
+  * Pass taskrc via environment variable to subprocess.
+  * Adds testing for Python 3.7 and 3.8
+  * Fix error raised when taskwarrior is not installed.
+  * Fix bug on deletion of completed task; disable confirmation for
+    recurring tasks; fix bug in numeric deserialization.
+  * Fixes bug in which UUIDs were improperly parsed
+    when creating recurring tasks.
+  * Fix a bug in which configuration values having an equal
+    sign in their value would be improperly parsed.
+  * Switched from nose to pytest.
+  * Dropped automated testing for Python 3.4.
+
+-------------------------------------------------------------------

Old:
----
  taskw-1.2.0.tar.gz

New:
----
  taskw-1.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-taskw.spec ++++++
--- /var/tmp/diff_new_pack.awMo7f/_old  2020-12-09 22:21:41.595691924 +0100
+++ /var/tmp/diff_new_pack.awMo7f/_new  2020-12-09 22:21:41.595691924 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-taskw
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-taskw
-Version:        1.2.0
+Version:        1.3.0
 Release:        0
 Summary:        Python bindings for taskwarrior
 License:        GPL-3.0-or-later
@@ -36,7 +36,7 @@
 BuildArch:      noarch
 # SECTION test requirements
 BuildRequires:  %{python_module kitchen}
-BuildRequires:  %{python_module nose >= 1.3.4}
+BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module python-dateutil}
 BuildRequires:  %{python_module pytz}
 BuildRequires:  %{python_module six}
@@ -49,9 +49,6 @@
 
 %prep
 %setup -q -n taskw-%{version}
-sed -i '/tox/d' test_requirements.txt
-# https://github.com/ralphbean/taskw/pull/128
-sed -i 's/in e:/in str(e):/' taskw/warrior.py
 
 %build
 %python_build
@@ -61,7 +58,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%python_exec setup.py test
+%pytest
 
 %files %{python_files}
 %doc README.rst

++++++ taskw-1.2.0.tar.gz -> taskw-1.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/PKG-INFO new/taskw-1.3.0/PKG-INFO
--- old/taskw-1.2.0/PKG-INFO    2016-10-28 16:27:07.000000000 +0200
+++ new/taskw-1.3.0/PKG-INFO    2020-12-08 05:46:26.158625600 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: taskw
-Version: 1.2.0
+Version: 1.3.0
 Summary: Python bindings for your taskwarrior database
 Home-page: http://github.com/ralphbean/taskw
 Author: Ralph Bean
@@ -153,10 +153,10 @@
 Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.2
-Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
 Classifier: License :: OSI Approved :: GNU General Public License (GPL)
 Classifier: Intended Audience :: Developers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/setup.cfg new/taskw-1.3.0/setup.cfg
--- old/taskw-1.2.0/setup.cfg   2016-10-28 16:27:07.000000000 +0200
+++ new/taskw-1.3.0/setup.cfg   2020-12-08 05:46:26.158625600 +0100
@@ -1,8 +1,8 @@
-[pytest]
+[tool:pytest]
 norecursedirs = lib
+addopts = -p no:warnings
 
 [egg_info]
 tag_build = 
 tag_date = 0
-tag_svn_revision = 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/setup.py new/taskw-1.3.0/setup.py
--- old/taskw-1.2.0/setup.py    2016-10-28 16:26:58.000000000 +0200
+++ new/taskw-1.3.0/setup.py    2020-12-07 01:27:37.000000000 +0100
@@ -1,9 +1,9 @@
 import os
-import multiprocessing
 import sys
-from setuptools import setup, find_packages
 import uuid
 
+from setuptools import setup, find_packages
+
 f = open('README.rst')
 long_description = f.read().strip()
 long_description = long_description.split('split here', 1)[1]
@@ -42,17 +42,17 @@
     REQUIREMENTS['install'].append('ordereddict')
 
 setup(name='taskw',
-      version='1.2.0',
+      version='1.3.0',
       description="Python bindings for your taskwarrior database",
       long_description=long_description,
       classifiers=[
           "Development Status :: 5 - Production/Stable",
           "Programming Language :: Python :: 2",
-          "Programming Language :: Python :: 2.6",
           "Programming Language :: Python :: 2.7",
           "Programming Language :: Python :: 3",
-          "Programming Language :: Python :: 3.2",
-          "Programming Language :: Python :: 3.3",
+          "Programming Language :: Python :: 3.4",
+          "Programming Language :: Python :: 3.5",
+          "Programming Language :: Python :: 3.6",
           "License :: OSI Approved :: GNU General Public License (GPL)",
           "Intended Audience :: Developers",
       ],
@@ -65,8 +65,6 @@
       include_package_data=True,
       zip_safe=False,
       install_requires=REQUIREMENTS['install'],
-      test_suite='nose.collector',
-      tests_require=REQUIREMENTS['test'],
       entry_points="""
       # -*- Entry points: -*-
       """,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/fields/numeric.py 
new/taskw-1.3.0/taskw/fields/numeric.py
--- old/taskw-1.2.0/taskw/fields/numeric.py     2015-01-19 16:12:46.000000000 
+0100
+++ new/taskw-1.3.0/taskw/fields/numeric.py     2020-12-06 23:56:58.000000000 
+0100
@@ -13,14 +13,21 @@
     def deserialize(self, value):
         if value is None:
             return value
-        try:
-            return int(value)
-        except ValueError:
-            pass
-        try:
-            return float(value)
-        except ValueError:
-            pass
+        elif isinstance(value, str):
+            try:
+                return int(value)
+            except ValueError:
+                pass
+            try:
+                return float(value)
+            except ValueError:
+                pass
+        elif isinstance(value, int) or isinstance(value, float):
+            # already desialized
+            return value
+        else:
+            raise ValueError("Unhandled type [{}] passed during 
deserialization for value [{}]"
+                             .format(type(value), value))
 
         # If we've made it this far, somehow Taskwarrior has
         # a non-numeric value stored in this field; this shouldn't
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/task.py 
new/taskw-1.3.0/taskw/task.py
--- old/taskw-1.2.0/taskw/task.py       2015-09-10 19:35:54.000000000 +0200
+++ new/taskw-1.3.0/taskw/task.py       2020-12-06 23:55:32.000000000 +0100
@@ -1,4 +1,7 @@
+import json
 import logging
+import os
+import sys
 
 import six
 
@@ -90,6 +93,25 @@
         return cls(processed, udas)
 
     @classmethod
+    def from_input(cls, input_file=sys.stdin, modify=False, udas=None):
+        """
+        Create a Task directly from stdin by reading one line. If modify=True,
+        two lines are expected, which is consistent with the Taskwarrior hook
+        system. The first line is interpreted as the original state of the 
Task,
+        and the second one as the new, modified state.
+
+        :param input_file: Input file. Defaults to sys.stdin.
+        :param modify: Flag for on-modify hook event. Defaults to False.
+        :param udas: Taskrc udas. Defaults to None.
+        :return Task
+        """
+        original_task = input_file.readline().strip()
+        if modify:
+            modified_task = input_file.readline().strip()
+            return cls(json.loads(modified_task), udas=udas)
+        return cls(json.loads(original_task), udas=udas)
+
+    @classmethod
     def _get_converter_for_field(cls, field, default=None, fields=None):
         fields = fields or {}
         converter = fields.get(field, None)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/taskrc.py 
new/taskw-1.3.0/taskw/taskrc.py
--- old/taskw-1.2.0/taskw/taskrc.py     2014-12-09 15:46:59.000000000 +0100
+++ new/taskw-1.3.0/taskw/taskrc.py     2020-12-07 00:01:31.000000000 +0100
@@ -114,7 +114,7 @@
                         )
                 else:
                     try:
-                        left, right = line.split('=')
+                        left, right = line.split('=', 1)
                         key = left.strip()
                         value = right.strip()
                         config = self._add_to_tree(config, key, value)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/test/test_datas.py 
new/taskw-1.3.0/taskw/test/test_datas.py
--- old/taskw-1.2.0/taskw/test/test_datas.py    2016-10-03 22:12:30.000000000 
+0200
+++ new/taskw-1.3.0/taskw/test/test_datas.py    2020-12-07 01:20:52.000000000 
+0100
@@ -1,11 +1,11 @@
-import nose
-from nose.tools import eq_, ok_, raises
 import os
 import shutil
 import tempfile
 import datetime
 import dateutil.tz
 
+import pytest
+
 from taskw import TaskWarriorDirect, TaskWarriorShellout
 
 
@@ -21,7 +21,7 @@
 
         # Sometimes the 'task' command line tool is not installed.
         if self.should_skip():
-            raise nose.SkipTest(
+            pytest.skip(
                 "%r unsupported on this system" % (self.class_to_test)
             )
 
@@ -63,87 +63,87 @@
 
     def test_has_two_categories(self):
         tasks = self.tw.load_tasks()
-        eq_(len(tasks), 2)
-        ok_('pending' in tasks)
-        ok_('completed' in tasks)
+        assert len(tasks) == 2
+        assert 'pending' in tasks
+        assert 'completed' in tasks
 
     def test_empty_db(self):
         tasks = self.tw.load_tasks()
-        eq_(len(sum(tasks.values(), [])), 0)
+        assert len(sum(tasks.values(), [])) == 0
 
     def test_add(self):
         self.tw.task_add("foobar")
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
+        assert len(tasks['pending']) == 1
 
     def test_unchanging_load_tasks(self):
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 0)
+        assert len(tasks['pending']) == 0
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 0)
+        assert len(tasks['pending']) == 0
 
-    @raises(KeyError)
     def test_completion_raising_unspecified(self):
-        self.tw.task_done()
+        with pytest.raises(KeyError):
+            self.tw.task_done()
 
     def test_completing_task_by_id_unspecified(self):
         self.tw.task_add("foobar")
         self.tw.task_done(id=1)
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 0)
-        eq_(len(tasks['completed']), 1)
-        eq_(len(sum(tasks.values(), [])), 1)
-        ok_(tasks['completed'][0]['end'] is not None)
-        eq_(tasks['completed'][0]['status'], 'completed')
+        assert len(tasks['pending']) == 0
+        assert len(tasks['completed']) == 1
+        assert len(sum(tasks.values(), [])) == 1
+        assert tasks['completed'][0]['end'] is not None
+        assert tasks['completed'][0]['status'] == 'completed'
 
     def test_completing_task_by_id_specified(self):
         self.tw.task_add("foobar")
         self.tw.task_done(id=1)
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 0)
-        eq_(len(tasks['completed']), 1)
-        eq_(len(sum(tasks.values(), [])), 1)
-        eq_(tasks['completed'][0]['status'], 'completed')
+        assert len(tasks['pending']) == 0
+        assert len(tasks['completed']) == 1
+        assert len(sum(tasks.values(), [])) == 1
+        assert tasks['completed'][0]['status'] == 'completed'
 
     def test_completing_task_by_id_retrieved(self):
         task = self.tw.task_add("foobar")
         self.tw.task_done(id=task['id'])
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 0)
-        eq_(len(tasks['completed']), 1)
-        eq_(len(sum(tasks.values(), [])), 1)
-        eq_(tasks['completed'][0]['status'], 'completed')
+        assert len(tasks['pending']) == 0
+        assert len(tasks['completed']) == 1
+        assert len(sum(tasks.values(), [])) == 1
+        assert tasks['completed'][0]['status'] == 'completed'
 
     def test_completing_task_by_uuid(self):
         self.tw.task_add("foobar")
         uuid = self.tw.load_tasks()['pending'][0]['uuid']
         self.tw.task_done(uuid=uuid)
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 0)
-        eq_(len(tasks['completed']), 1)
-        eq_(len(sum(tasks.values(), [])), 1)
-        eq_(tasks['completed'][0]['status'], 'completed')
+        assert len(tasks['pending']) == 0
+        assert len(tasks['completed']) == 1
+        assert len(sum(tasks.values(), [])) == 1
+        assert tasks['completed'][0]['status'] == 'completed'
 
-    @raises(KeyError)
     def test_get_task_mismatch(self):
         self.tw.task_add("foobar")
         self.tw.task_add("bazbar")
         uuid = self.tw.load_tasks()['pending'][0]['uuid']
-        self.tw.get_task(id=2, uuid=uuid)  # which one?
+        with pytest.raises(KeyError):
+            self.tw.get_task(id=2, uuid=uuid)  # which one?
 
     def test_updating_task(self):
         self.tw.task_add("foobar")
 
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
+        assert len(tasks['pending']) == 1
 
         task = tasks['pending'][0]
         task["priority"] = "L"
         self.tw.task_update(task)
 
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
-        eq_(tasks['pending'][0]['priority'], 'L')
+        assert len(tasks['pending']) == 1
+        assert tasks['pending'][0]['priority'] == 'L'
 
         # For compatibility with the direct and shellout modes.
         # Shellout returns more information.
@@ -158,19 +158,19 @@
 
             # Task 2.2.0 adds a "modified" field, so delete this.
             del tasks['pending'][0]['modified']
-        except:
+        except Exception:
             pass
 
         # But Task 2.4.0 puts the modified field in earlier
         if 'modified' in task:
             del task['modified']
 
-        eq_(tasks['pending'][0], task)
+        assert tasks['pending'][0] == task
 
-    @raises(KeyError)
     def test_update_exc(self):
         task = dict(description="lol")
-        self.tw.task_update(task)
+        with pytest.raises(KeyError):
+            self.tw.task_update(task)
 
     def test_add_complicated(self):
         self.tw.task_add(
@@ -179,7 +179,7 @@
             project="some_project"
         )
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
+        assert len(tasks['pending']) == 1
 
     def test_add_timestamp(self):
         self.tw.task_add(
@@ -189,8 +189,8 @@
             entry="20110101T000000Z",
         )
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
-        eq_(tasks['pending'][0]['entry'], "20110101T000000Z")
+        assert len(tasks['pending']) == 1
+        assert tasks['pending'][0]['entry'] == "20110101T000000Z"
 
     def test_add_datetime(self):
         self.tw.task_add(
@@ -200,7 +200,7 @@
             entry=datetime.datetime(2011, 1, 1, tzinfo=dateutil.tz.tzutc()),
         )
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
+        assert len(tasks['pending']) == 1
         # The exact string we get back is dependent on your current TZ
         # ... we'll just "roughly" test it instead of mocking.
         assert(tasks['pending'][0]['entry'].startswith("20110101T"))
@@ -211,10 +211,10 @@
             somestring="this is a uda",
         )
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
+        assert len(tasks['pending']) == 1
         task = tasks['pending'][0]
 
-        eq_(task['somestring'], "this is a uda")
+        assert task['somestring'] == "this is a uda"
 
     def test_add_with_uda_date(self):
         self.tw.task_add(
@@ -222,12 +222,11 @@
             somedate=datetime.datetime(2011, 1, 1, tzinfo=dateutil.tz.tzutc()),
         )
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
+        assert len(tasks['pending']) == 1
         task = tasks['pending'][0]
 
         assert(task['somedate'].startswith("20110101T"))
 
-    @raises(KeyError)
     def test_remove_uda_string(self):
         # Check that a string UDA is removed from a task when its
         # value is set to None
@@ -237,9 +236,9 @@
         )
         task['somestring'] = None
         id, task = self.tw.task_update(task)
-        task['somestring']
+        with pytest.raises(KeyError):
+            task['somestring']
 
-    @raises(KeyError)
     def test_remove_uda_date(self):
         # Check that a date UDA is removed from a task when its
         # value is set to None
@@ -249,9 +248,9 @@
         )
         task['somedate'] = None
         id, task = self.tw.task_update(task)
-        task['somedate']
+        with pytest.raises(KeyError):
+            task['somedate']
 
-    @raises(KeyError)
     def test_remove_uda_numeric(self):
         # Check that a numeric UDA is removed from a task when its
         # value is set to None
@@ -261,76 +260,73 @@
         )
         task['somenumber'] = None
         id, task = self.tw.task_update(task)
-        task['somenumber']
+        with pytest.raises(KeyError):
+            task['somenumber']
 
-    @raises(ValueError)
     def test_completing_completed_task(self):
         task = self.tw.task_add("foobar")
         self.tw.task_done(uuid=task['uuid'])
-        self.tw.task_done(uuid=task['uuid'])
+        with pytest.raises(ValueError):
+            self.tw.task_done(uuid=task['uuid'])
 
     def test_updating_completed_task(self):
         task = self.tw.task_add("foobar")
         task = self.tw.task_done(uuid=task['uuid'])
         task['priority'] = 'L'
         id, task = self.tw.task_update(task)
-        eq_(task['priority'], 'L')
+        assert task['priority'] == 'L'
 
     def test_get_task_completed(self):
         task = self.tw.task_add("foobar")
         task = self.tw.task_done(uuid=task['uuid'])
 
         id, _task = self.tw.get_task(uuid=task['uuid'])
-        eq_(id, None)
-        eq_(_task['uuid'], task['uuid'])
+        assert id is None
+        assert _task['uuid'] == task['uuid']
 
     def test_load_task_pending_command(self):
         tasks = self.tw.load_tasks(command='pending')
-        eq_(len(tasks), 1)
-        ok_('pending' in tasks)
+        assert len(tasks) == 1
+        assert 'pending' in tasks
 
     def test_load_task_completed_command(self):
         tasks = self.tw.load_tasks(command='completed')
-        eq_(len(tasks), 1)
-        ok_('completed' in tasks)
+        assert len(tasks) == 1
+        assert 'completed' in tasks
 
-    @raises(ValueError)
     def test_load_task_with_unknown_command(self):
-        tasks = self.tw.load_tasks(command='foobar')
+        with pytest.raises(ValueError):
+            self.tw.load_tasks(command='foobar')
 
     def test_updating_deleted_task(self):
         task = self.tw.task_add("foobar")
         task = self.tw.task_delete(uuid=task['uuid'])
         task['priority'] = 'L'
         id, task = self.tw.task_update(task)
-        eq_(task['priority'], 'L')
+        assert task['priority'] == 'L'
 
     def test_delete(self):
         task = self.tw.task_add("foobar")
         self.tw.task_delete(uuid=task['uuid'])
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 0)
-        # The shellout and direct methods behave differently here
-        #eq_(len(tasks['completed']), 1)
-        #ok_(not tasks['completed'][0]['end'] is None)
-        #eq_(tasks['completed'][0]['status'], 'deleted')
+        assert len(tasks['pending']) == 0
 
-    @raises(ValueError)
     def test_delete_already_deleted(self):
         task = self.tw.task_add("foobar")
         self.tw.task_delete(uuid=task['uuid'])
-        self.tw.task_delete(uuid=task['uuid'])
+        with pytest.raises(ValueError):
+            self.tw.task_delete(uuid=task['uuid'])
 
     def test_load_tasks_with_one_each(self):
-        task1 = self.tw.task_add("foobar1")
+        self.tw.task_add("foobar1")
         task2 = self.tw.task_add("foobar2")
         task2 = self.tw.task_done(uuid=task2['uuid'])
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 1)
-        eq_(len(tasks['completed']), 1)
+        assert len(tasks['pending']) == 1
+        assert len(tasks['completed']) == 1
 
         # For issue #26, I thought this would raise an exception...
-        task = self.tw.get_task(description='foobar1')
+        self.tw.get_task(description='foobar1')
 
 
 class TestDBDirect(_BaseTestDB):
@@ -341,9 +337,8 @@
         task = self.tw.task_done(uuid=task['uuid'])
         self.tw.task_delete(uuid=task['uuid'])
         tasks = self.tw.load_tasks()
-        eq_(len(tasks['pending']), 0)
-        eq_(len(tasks['completed']), 1)
-        #eq_(tasks['completed'][0]['status'], 'deleted')
+        assert len(tasks['pending']) == 0
+        assert len(tasks['completed']) == 1
 
     def should_skip(self):
         return False
@@ -357,151 +352,140 @@
         return not TaskWarriorShellout.can_use()
 
     def test_filtering_simple(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
         tasks = self.tw.filter_tasks({
             'description.contains': 'foobar2',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 2)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 2
 
     def test_filtering_brace(self):
-        task1 = self.tw.task_add("[foobar1]")
-        task2 = self.tw.task_add("[foobar2]")
+        self.tw.task_add("[foobar1]")
+        self.tw.task_add("[foobar2]")
         tasks = self.tw.filter_tasks({
             'description.contains': '[foobar2]',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 2)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 2
 
     def test_filtering_quote(self):
-        task1 = self.tw.task_add("[foobar1]")
-        task2 = self.tw.task_add("\"foobar2\"")
+        self.tw.task_add("[foobar1]")
+        self.tw.task_add("\"foobar2\"")
         tasks = self.tw.filter_tasks({
             'description.contains': '"foobar2"',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 2)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 2
 
     def test_filtering_plus(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foobar+")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foobar+")
         tasks = self.tw.filter_tasks({
             'description.contains': 'foobar+',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 3)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 3
 
     def test_filtering_minus(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foobar-")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foobar-")
         tasks = self.tw.filter_tasks({
             'description.contains': 'foobar-',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 3)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 3
 
     def test_filtering_colon(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foobar:")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foobar:")
         tasks = self.tw.filter_tasks({
             'description.contains': 'foobar:',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 3)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 3
 
     def test_filtering_qmark(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foo?bar")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foo?bar")
         tasks = self.tw.filter_tasks({
                 'description.contains': 'oo?ba',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 2)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 2
 
     def test_filtering_qmark_not_contains(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foo?bar")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foo?bar")
         tasks = self.tw.filter_tasks({
                 'description': 'foo?bar',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 2)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 2
 
     def test_filtering_semicolon(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foo;bar")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foo;bar")
         tasks = self.tw.filter_tasks({
             'description.contains': 'foo;bar',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 3)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 3
 
     def test_filtering_question_mark(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foo?bar")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foo?bar")
         tasks = self.tw.filter_tasks({
             'description.contains': 'foo?bar',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 3)
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 3
 
     def test_filtering_slash(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foo/bar")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foo/bar")
         tasks = self.tw.filter_tasks({
             'description.contains': 'foo/bar',
         })
-        eq_(len(tasks), 1)
-        eq_(tasks[0]['id'], 3)
-
-    #def test_filtering_double_dash(self):
-    #    task1 = self.tw.task_add("foobar1")
-    #    task2 = self.tw.task_add("foobar2")
-    #    task2 = self.tw.task_add("foo -- bar")
-    #    tasks = self.tw.filter_tasks({
-    #        'description.contains': 'foo -- bar',
-    #    })
-    #    eq_(len(tasks), 1)
-    #    eq_(tasks[0]['id'], 3)
-    #    eq_(tasks[0]['description'], 'foo -- bar')
+        assert len(tasks) == 1
+        assert tasks[0]['id'] == 3
 
     def test_filtering_logic_disjunction(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foobar3")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foobar3")
         tasks = self.tw.filter_tasks({
             'or': [
                 ('description.has', 'foobar1'),
                 ('description.has', 'foobar3'),
             ]
         })
-        eq_(len(tasks), 2)
-        eq_(tasks[0]['id'], 1)
-        eq_(tasks[1]['id'], 3)
+        assert len(tasks) == 2
+        assert tasks[0]['id'] == 1
+        assert tasks[1]['id'] == 3
 
     def test_filtering_logic_conjunction(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foobar3")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foobar3")
         tasks = self.tw.filter_tasks({
             'and': [
                 ('description.has', 'foobar1'),
                 ('description.has', 'foobar3'),
             ]
         })
-        eq_(len(tasks), 0)
+        assert len(tasks) == 0
 
     def test_filtering_logic_conjunction_junction_whats_your_function(self):
-        task1 = self.tw.task_add("foobar1")
-        task2 = self.tw.task_add("foobar2")
-        task2 = self.tw.task_add("foobar3")
+        self.tw.task_add("foobar1")
+        self.tw.task_add("foobar2")
+        self.tw.task_add("foobar3")
         tasks = self.tw.filter_tasks({
             'and': [
                 ('description', 'foobar1'),
@@ -511,7 +495,7 @@
                 ('status', 'waiting'),
             ]
         })
-        eq_(len(tasks), 1)
+        assert len(tasks) == 1
 
     def test_annotation_escaping(self):
         original = {'description': 're-opening the issue'}
@@ -524,10 +508,9 @@
         task = self.tw.load_tasks()['pending'][0]
         self.tw.task_update(task)
 
-        eq_(len(task['annotations']), 1)
-        eq_(task['annotations'][0]['description'], original['description'])
+        assert len(task['annotations']) == 1
+        assert task['annotations'][0]['description'] == original['description']
 
-    @raises(KeyError)
     def test_remove_uda_string_marshal(self):
         # Check that a string UDA is removed from a task when its
         # value is set to None
@@ -537,9 +520,9 @@
         )
         task['somestring'] = None
         id, task = self.tw_marshal.task_update(task)
-        task['somestring']
+        with pytest.raises(KeyError):
+            task['somestring']
 
-    @raises(KeyError)
     def test_remove_uda_date_marshal(self):
         # Check that a date UDA is removed from a task when its
         # value is set to None
@@ -549,9 +532,9 @@
         )
         task['somedate'] = None
         id, task = self.tw_marshal.task_update(task)
-        task['somedate']
+        with pytest.raises(KeyError):
+            task['somedate']
 
-    @raises(KeyError)
     def test_remove_uda_numeric_marshal(self):
         # Check that a numeric UDA is removed from a task when its
         # value is set to None
@@ -561,7 +544,8 @@
         )
         task['somenumber'] = None
         id, task = self.tw_marshal.task_update(task)
-        task['somenumber']
+        with pytest.raises(KeyError):
+            task['somenumber']
 
     def test_add_and_retrieve_uda_string_url(self):
         arbitrary_url = "http://www.someurl.com/1084/";
@@ -579,9 +563,9 @@
         results = self.tw.filter_tasks({
             'someurl.is': arbitrary_url
         })
-        eq_(len(results), 1)
+        assert len(results) == 1
         task = results[0]
-        eq_(task['someurl'], arbitrary_url)
+        assert task['someurl'] == arbitrary_url
 
     def test_add_and_retrieve_uda_string_url_in_parens(self):
         arbitrary_url = "http://www.someurl.com/1084/";
@@ -601,6 +585,6 @@
                 ('someurl.is', arbitrary_url),
             ],
         })
-        eq_(len(results), 1)
+        assert len(results) == 1
         task = results[0]
-        eq_(task['someurl'], arbitrary_url)
+        assert task['someurl'] == arbitrary_url
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/test/test_recursive.py 
new/taskw-1.3.0/taskw/test/test_recursive.py
--- old/taskw-1.2.0/taskw/test/test_recursive.py        2015-09-10 
19:35:54.000000000 +0200
+++ new/taskw-1.3.0/taskw/test/test_recursive.py        2020-12-07 
01:20:52.000000000 +0100
@@ -1,9 +1,9 @@
-import nose
-from nose.tools import eq_
 import os
 import shutil
 import tempfile
 
+import pytest
+
 from taskw import TaskWarriorShellout
 
 
@@ -18,7 +18,7 @@
     def setup(self):
         if not TaskWarriorShellout.can_use():
             # Sometimes the 'task' command line tool is not installed.
-            raise nose.SkipTest("taskwarrior not installed")
+            pytest.skip("taskwarrior not installed")
 
         # Create some temporary config stuff
         fd, fname = tempfile.mkstemp(prefix='taskw-testsrc')
@@ -53,11 +53,11 @@
     def test_set_dep_on_one_uuid(self):
         task1 = self.tw.task_add('task1')
         task2 = self.tw.task_add('task2', depends=[task1['uuid']])
-        eq_(task2['depends'][0], task1['uuid'])
+        assert task2['depends'][0] == task1['uuid']
 
     def test_set_dep_on_two_uuid(self):
         task1 = self.tw.task_add('task1')
         task2 = self.tw.task_add('task2')
         depends = [task1['uuid'], task2['uuid']]
         task3 = self.tw.task_add('task3', depends=depends)
-        eq_(task3['depends'], [task1['uuid'], task2['uuid']])
+        assert task3['depends'] == [task1['uuid'], task2['uuid']]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/test/test_task.py 
new/taskw-1.3.0/taskw/test/test_task.py
--- old/taskw-1.2.0/taskw/test/test_task.py     2015-01-19 16:12:46.000000000 
+0100
+++ new/taskw-1.3.0/taskw/test/test_task.py     2020-12-06 23:55:32.000000000 
+0100
@@ -1,18 +1,14 @@
 import copy
 import datetime
-import sys
 import uuid
+from unittest import TestCase
 
 import pytz
 import six
+from dateutil.tz import tzutc
 
 from taskw.task import Task
 
-if sys.version_info >= (2, 7):
-    from unittest import TestCase
-else:
-    from unittest2 import TestCase
-
 
 class TestTaskDirtyability(TestCase):
     def setUp(self):
@@ -156,7 +152,6 @@
             'urgency': 10,
             'uuid': str(uuid.uuid4()),
         }
-        task = Task(arbitrary_serialized_data)
         expected_result = arbitrary_serialized_data
 
         after_composition = Task(
@@ -168,3 +163,42 @@
         ).serialized()
 
         self.assertEqual(after_composition, expected_result)
+
+    def test_from_input(self):
+        input_add_data = six.StringIO(
+            '{'
+            '"description":"Go to Camelot",'
+            '"entry":"20180618T030242Z",'
+            '"status":"pending",'
+            '"start":"20181012T110605Z",'
+            '"uuid":"daa3ff05-f716-482e-bc35-3e1601e50778"'
+            '}')
+
+        input_modify_data = six.StringIO(
+            '\n'.join([
+                input_add_data.getvalue(),
+                (
+                    '{'
+                    '"description":"Go to Camelot again",'
+                    '"entry":"20180618T030242Z",'
+                    '"status":"pending",'
+                    '"start":"20181012T110605Z",'
+                    '"uuid":"daa3ff05-f716-482e-bc35-3e1601e50778"'
+                    '}'
+                ),
+            ]),
+        )
+
+        on_add_task = Task.from_input(input_file=input_add_data)
+        assert on_add_task.get('description') == "Go to Camelot"
+        assert on_add_task.get('entry') == datetime.datetime(2018, 6, 18, 3, 
2, 42, tzinfo=tzutc())
+        assert on_add_task.get('status') == "pending"
+        assert on_add_task.get('start') == datetime.datetime(2018, 10, 12, 11, 
6, 5, tzinfo=tzutc())
+        assert on_add_task.get('uuid') == 
uuid.UUID("daa3ff05-f716-482e-bc35-3e1601e50778")
+
+        on_modify_task = Task.from_input(input_file=input_modify_data, 
modify=True)
+        assert on_modify_task.get('description') == "Go to Camelot again"
+        assert on_modify_task.get('entry') == datetime.datetime(2018, 6, 18, 
3, 2, 42, tzinfo=tzutc())
+        assert on_modify_task.get('status') == "pending"
+        assert on_modify_task.get('start') == datetime.datetime(2018, 10, 12, 
11, 6, 5, tzinfo=tzutc())
+        assert on_modify_task.get('uuid') == 
uuid.UUID("daa3ff05-f716-482e-bc35-3e1601e50778")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/test/test_utils.py 
new/taskw-1.3.0/taskw/test/test_utils.py
--- old/taskw-1.2.0/taskw/test/test_utils.py    2016-10-28 16:18:35.000000000 
+0200
+++ new/taskw-1.3.0/taskw/test/test_utils.py    2020-12-07 01:20:52.000000000 
+0100
@@ -2,7 +2,6 @@
 import random
 
 import dateutil.tz
-from nose.tools import eq_
 import pytz
 import six
 
@@ -38,40 +37,40 @@
     def test_no_side_effects(self):
         orig = TASK.copy()
         decode_task(encode_task(TASK))
-        eq_(orig, TASK)
+        assert orig == TASK
 
     def test_with_escaped_quotes(self):
         expected = {'this': r'has a "quote" in it.'}
         line = r'[this:"has a \"quote\" in it."]'
         r = decode_task(line)
-        eq_(r, expected)
+        assert r == expected
 
     def test_with_escaped_quotes_roundtrip(self):
         expected = {'this': r'has a "quote" in it.'}
         line = r'[this:"has a \"quote\" in it."]'
         r = decode_task(encode_task(decode_task(line)))
-        eq_(r, expected)
+        assert r == expected
 
     def test_with_escaped_quotes_full(self):
         line = r'[this:"has a \"quote\" in it."]'
         r = encode_task(decode_task(line))
-        eq_(r, r)
+        assert r == r
 
     def test_with_backticks(self):
         expected = {'this': r'has a fucking `backtick` in it'}
         line = r'[this:"has a fucking `backtick` in it"]'
         r = decode_task(line)
-        eq_(r, expected)
+        assert r == expected
         r = decode_task(encode_task(decode_task(line)))
-        eq_(r, expected)
+        assert r == expected
 
     def test_with_backslashes(self):
         expected = {'andthis': r'has a fucking \backslash in it'}
         line = r'[andthis:"has a fucking \\backslash in it"]'
         r = decode_task(line)
-        eq_(r, expected)
+        assert r == expected
         r = decode_task(encode_task(decode_task(line)))
-        eq_(r, expected)
+        assert r == expected
 
     def test_with_unicode(self):
         expected = {
@@ -81,28 +80,28 @@
         }
         line = r'[andthis:"has a fucking \\backslash in it"]'
         r = decode_task(line)
-        eq_(r, expected)
+        assert r == expected
         r = decode_task(encode_task(decode_task(line)))
-        eq_(r, expected)
+        assert r == expected
 
     def test_decode(self):
         r = decode_task(encode_task(TASK))
-        eq_(r, TASK)
+        assert r == TASK
 
     def test_decode_leading_whitespace_in_value(self):
         r = decode_task(encode_task(TASK_LEADING_WS))
-        eq_(r, TASK_LEADING_WS)
+        assert r == TASK_LEADING_WS
 
     def test_composition(self):
-        eq_(TASK, decode_task(encode_task(TASK)))
+        assert TASK == decode_task(encode_task(TASK))
 
     def test_double_composition(self):
-        eq_(TASK, decode_task(encode_task(decode_task(encode_task(TASK)))))
+        assert TASK == decode_task(encode_task(decode_task(encode_task(TASK))))
 
     def test_ordering(self):
         task1 = dict(shuffled(TASK.items()))
         task2 = dict(shuffled(TASK.items()))
-        eq_(encode_task(task1), encode_task(task2))
+        assert encode_task(task1) == encode_task(task2)
 
     def test_taskwarrior_null_encoding_bug_workaround(self):
         task = {
@@ -111,10 +110,7 @@
         actual_encoded = encode_task_experimental(task)[0]
         expected_encoded = "priority:"
 
-        eq_(
-            actual_encoded,
-            expected_encoded
-        )
+        assert actual_encoded == expected_encoded
 
     def test_encodes_dates(self):
         arbitrary_date = datetime.date(2014, 3, 2)
@@ -129,10 +125,7 @@
             }
         )
 
-        eq_(
-            actual_encoded_task,
-            expected_encoded_task,
-        )
+        assert actual_encoded_task == expected_encoded_task
 
     def test_encodes_naive_datetimes(self):
         arbitrary_naive_datetime = datetime.datetime.now()
@@ -151,10 +144,7 @@
             }
         )
 
-        eq_(
-            actual_encoded_task,
-            expected_encoded_task,
-        )
+        assert actual_encoded_task == expected_encoded_task
 
     def test_encodes_zoned_datetimes(self):
         arbitrary_timezone = pytz.timezone('America/Los_Angeles')
@@ -175,10 +165,7 @@
             }
         )
 
-        eq_(
-            actual_encoded_task,
-            expected_encoded_task,
-        )
+        assert actual_encoded_task == expected_encoded_task
 
     def test_convert_dict_to_override_args(self):
         overrides = {
@@ -200,15 +187,15 @@
         ]
         actual_overrides = convert_dict_to_override_args(overrides)
 
-        eq_(set(actual_overrides), set(expected_overrides))
+        assert set(actual_overrides) == set(expected_overrides)
 
 
 class TestCleanExecArg(object):
     def test_clean_null(self):
-        eq_(b"", clean_ctrl_chars(b"\x00"))
+        assert b"" == clean_ctrl_chars(b"\x00")
 
     def test_all_ctrl_chars(self):
         """ Test that most (but not all) control characters are removed """
         # input = bytes(range(0x20))
-        input = 
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f'
 # For python 2 compatibility
-        eq_(b"\t\n\v\f\r", clean_ctrl_chars(input))
+        input = 
b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f'
  # For python 2 compatibility
+        assert b"\t\n\v\f\r" == clean_ctrl_chars(input)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/test/test_warrior.py 
new/taskw-1.3.0/taskw/test/test_warrior.py
--- old/taskw-1.2.0/taskw/test/test_warrior.py  2016-10-28 16:18:35.000000000 
+0200
+++ new/taskw-1.3.0/taskw/test/test_warrior.py  2020-12-07 01:20:52.000000000 
+0100
@@ -1,11 +1,12 @@
 import tempfile
 import os
 import shutil
+from unittest import TestCase
 
 from taskw.warrior import TaskWarrior
 
 
-class TestTaskWarrior(object):
+class TestTaskWarrior(TestCase):
     def setUp(self):
         self.taskdata = tempfile.mkdtemp()
         taskrc = os.path.join(os.path.dirname(__file__), 'data/empty.taskrc')
@@ -37,3 +38,14 @@
         tasks = self.taskwarrior.load_tasks()
         assert len(tasks['pending']) == 1
         assert tasks['pending'][0]['description'] == 'foobar'
+
+    def test_add_task_recurs(self):
+        """ Try adding a task with `recur` to ensure the uuid can be parsed """
+        self.taskwarrior.task_add("foobar weekly", due="tomorrow", 
recur="weekly")
+        tasks = self.taskwarrior.load_tasks()
+
+        assert len(tasks['pending']) == 1
+        assert tasks['pending'][0]['description'] == 'foobar weekly'
+        assert tasks['pending'][0]['recur'] == 'weekly'
+        assert tasks['pending'][0]['parent'] is not None
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw/warrior.py 
new/taskw-1.3.0/taskw/warrior.py
--- old/taskw-1.2.0/taskw/warrior.py    2016-10-28 16:18:35.000000000 +0200
+++ new/taskw-1.3.0/taskw/warrior.py    2020-12-07 01:21:35.000000000 +0100
@@ -15,11 +15,11 @@
 from distutils.version import LooseVersion
 import logging
 import os
+import re
 import time
 import uuid
 import subprocess
 import json
-import errno
 
 import kitchen.text.converters
 
@@ -399,6 +399,9 @@
         self._task_remove(line, Status.to_file(original_status))
         return task
 
+# This regex is used to parse UUIDs from messages output
+# by the shell client when creating tasks.
+UUID_REGEX = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
 
 class TaskWarriorShellout(TaskWarriorBase):
     """ Interacts with taskwarrior by invoking shell commands.
@@ -417,6 +420,9 @@
         'dependency': {
             'confirmation': 'no',
         },
+        'recurrence': {
+            'confirmation': 'no'
+        },
     }
 
     def __init__(
@@ -447,11 +453,12 @@
         command = (
             [
                 'task',
-                'rc:%s' % self.config_filename,
             ]
             + self.get_configuration_override_args()
             + [six.text_type(arg) for arg in args]
         )
+        env = os.environ.copy()
+        env['TASKRC'] = self.config_filename
 
         # subprocess is expecting bytestrings only, so nuke unicode if present
         # and remove control characters
@@ -463,14 +470,15 @@
         try:
             proc = subprocess.Popen(
                 command,
+                env=env,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE,
             )
             stdout, stderr = proc.communicate()
-        except OSError as e:
-            if e.errno == errno.ENOENT:
-                raise OSError("Unable to find the 'task' command-line tool.")
-            raise
+        except FileNotFoundError:
+            raise FileNotFoundError(
+                "Unable to find the 'task' command-line tool."
+            )
 
         if proc.returncode != 0:
             raise TaskwarriorError(command, stderr, stdout, proc.returncode)
@@ -541,8 +549,8 @@
         """
         try:
             return cls.get_version() > LooseVersion('2')
-        except OSError:
-            # OSError is raised if subprocess.Popen fails to find
+        except FileNotFoundError:
+            # FileNotFound is raised if subprocess.Popen fails to find
             # the executable.
             return False
 
@@ -553,10 +561,10 @@
                 ['task', '--version'],
                 stdout=subprocess.PIPE
             ).communicate()[0]
-        except OSError as e:
-            if 'No such file or directory' in e:
-                raise OSError("Unable to find the 'task' command-line tool.")
-            raise
+        except FileNotFoundError:
+            raise FileNotFoundError(
+                "Unable to find the 'task' command-line tool."
+            )
         return LooseVersion(taskwarrior_version.decode())
 
     def sync(self, init=False):
@@ -686,7 +694,7 @@
         # when adding a task.  Instead, you have to specify rc.verbose=new-uuid
         # and then parse the assigned uuid out from stdout.
         if self.get_version() >= LooseVersion('2.4'):
-            task['uuid'] = stdout.strip().split()[-1].strip('.')
+            task['uuid'] = re.search(UUID_REGEX, stdout).group(0)
 
         id, added_task = self.get_task(uuid=task['uuid'])
 
@@ -821,7 +829,7 @@
         if task['status'] == Status.DELETED:
             raise ValueError("Task is already deleted.")
 
-        self._execute(id, 'delete')
+        self._execute(task['uuid'], 'delete')
         return self.get_task(uuid=task['uuid'])[1]
 
     def task_start(self, **kw):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw.egg-info/PKG-INFO 
new/taskw-1.3.0/taskw.egg-info/PKG-INFO
--- old/taskw-1.2.0/taskw.egg-info/PKG-INFO     2016-10-28 16:27:03.000000000 
+0200
+++ new/taskw-1.3.0/taskw.egg-info/PKG-INFO     2020-12-08 05:46:26.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: taskw
-Version: 1.2.0
+Version: 1.3.0
 Summary: Python bindings for your taskwarrior database
 Home-page: http://github.com/ralphbean/taskw
 Author: Ralph Bean
@@ -153,10 +153,10 @@
 Platform: UNKNOWN
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.2
-Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
 Classifier: License :: OSI Approved :: GNU General Public License (GPL)
 Classifier: Intended Audience :: Developers
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw.egg-info/SOURCES.txt 
new/taskw-1.3.0/taskw.egg-info/SOURCES.txt
--- old/taskw-1.2.0/taskw.egg-info/SOURCES.txt  2016-10-28 16:27:07.000000000 
+0200
+++ new/taskw-1.3.0/taskw.egg-info/SOURCES.txt  2020-12-08 05:46:26.000000000 
+0100
@@ -17,7 +17,6 @@
 taskw.egg-info/dependency_links.txt
 taskw.egg-info/entry_points.txt
 taskw.egg-info/not-zip-safe
-taskw.egg-info/pbr.json
 taskw.egg-info/requires.txt
 taskw.egg-info/top_level.txt
 taskw/fields/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw.egg-info/pbr.json 
new/taskw-1.3.0/taskw.egg-info/pbr.json
--- old/taskw-1.2.0/taskw.egg-info/pbr.json     2015-10-22 02:58:41.000000000 
+0200
+++ new/taskw-1.3.0/taskw.egg-info/pbr.json     1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-{"is_release": false, "git_version": "ac720a5"}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/taskw.egg-info/requires.txt 
new/taskw-1.3.0/taskw.egg-info/requires.txt
--- old/taskw-1.2.0/taskw.egg-info/requires.txt 2016-10-28 16:27:03.000000000 
+0200
+++ new/taskw-1.3.0/taskw.egg-info/requires.txt 2020-12-08 05:46:26.000000000 
+0100
@@ -1,4 +1,4 @@
-six
+kitchen
 python-dateutil
 pytz
-kitchen
+six
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/test_requirements.txt 
new/taskw-1.3.0/test_requirements.txt
--- old/taskw-1.2.0/test_requirements.txt       2015-02-11 16:34:51.000000000 
+0100
+++ new/taskw-1.3.0/test_requirements.txt       2020-12-07 01:20:52.000000000 
+0100
@@ -1,2 +1,2 @@
-nose>=1.3.4,<2
-tox>=1.8.1,<2
+pytest
+tox<3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/taskw-1.2.0/tox.ini new/taskw-1.3.0/tox.ini
--- old/taskw-1.2.0/tox.ini     2016-10-03 22:26:46.000000000 +0200
+++ new/taskw-1.3.0/tox.ini     2020-12-07 01:20:52.000000000 +0100
@@ -1,28 +1,21 @@
 [tox]
-envlist = {py27,py35}-tw{22,23,24,241,242,250,251}
+envlist = py{27,35,36,37,38}-tw{250,251}
 downloadcache = {toxworkdir}/_download/
 
 [testenv]
 basepython =
-    py26: python2.6
     py27: python2.7
-    py33: python3.3
-    py34: python3.4
     py35: python3.5
+    py36: python3.6
+    py37: python3.7
+    py38: python3.8
 deps =
     -r{toxinidir}/requirements.txt
     -r{toxinidir}/test_requirements.txt
-    py26: unittest2
-    py26: ordereddict
 setenv = 
-    tw22:  TASKWARRIOR=v2.2.0
-    tw23:  TASKWARRIOR=v2.3.0
-    tw24:  TASKWARRIOR=v2.4.0
-    tw241: TASKWARRIOR=v2.4.1
-    tw242: TASKWARRIOR=v2.4.2
     tw250: TASKWARRIOR=v2.5.0
-    tw251: TASKWARRIOR=2.5.1
+    tw251: TASKWARRIOR=v2.5.1
 sitepackages = False
 commands =
     {toxinidir}/.tox_build_taskwarrior.sh "{envdir}" "{toxinidir}"
-    nosetests {posargs}
+    pytest {posargs}
_______________________________________________
openSUSE Commits mailing list -- [email protected]
To unsubscribe, email [email protected]
List Netiquette: https://en.opensuse.org/openSUSE:Mailing_list_netiquette
List Archives: 
https://lists.opensuse.org/archives/list/[email protected]

Reply via email to