--- /dev/null
+Copyright (c) 2013, Rob Golding. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Rob Golding, nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- /dev/null
+from setuptools import setup, find_packages
+
+setup(
+ name='tasklib',
+ version='0.1',
+ description='Python Task Warrior library',
+ long_description=open('README.md').read(),
+ author='Rob Golding',
+ author_email='rob@robgolding.com',
+ license='BSD',
+ url='https://github.com/robgolding63/tasklib',
+ download_url='https://github.com/robgolding63/tasklib/downloads',
+ packages=find_packages(),
+ include_package_data=True,
+ classifiers=[
+ 'Development Status :: 3 - Alpha',
+ 'License :: OSI Approved :: BSD License',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Programming Language :: Python',
+ 'Intended Audience :: Developers',
+ ],
+)
--- /dev/null
+import json
+import os
+import subprocess
+import tempfile
+import uuid
+
+
+PENDING = 'pending'
+
+
+class TaskWarriorException(Exception):
+ pass
+
+
+class Task(object):
+
+ def __init__(self, warrior, data={}):
+ self.warrior = warrior
+ self._data = data
+
+ def __getitem__(self, key):
+ return self._data.get(key)
+
+ def __setitem__(self, key, val):
+ self._data[key] = val
+
+ def __unicode__(self):
+ return self._data.get('description')
+
+ def regenerate_uuid(self):
+ self['uuid'] = str(uuid.uuid4())
+
+ def delete(self):
+ self.warrior.delete_task(self['uuid'])
+
+ def done(self):
+ self.warrior.complete_task(self['uuid'])
+
+ def save(self, delete_first=True):
+ if self['uuid'] and delete_first:
+ self.delete()
+ if not self['uuid'] or delete_first:
+ self.regenerate_uuid()
+ self.warrior.import_tasks([self._data])
+
+ __repr__ = __unicode__
+
+
+class TaskWarrior(object):
+
+ def __init__(self, data_location='~/.task', create=True):
+ if not os.path.exists(data_location):
+ os.makedirs(data_location)
+ self.config = {
+ 'data.location': os.path.expanduser(data_location),
+ }
+
+ def _generate_command(self, command):
+ args = ['task', 'rc:/']
+ for item in self.config.items():
+ args.append('rc.{0}={1}'.format(*item))
+ args.append(command)
+ return ' '.join(args)
+
+ def _execute(self, command):
+ p = subprocess.Popen(self._generate_command(command), shell=True,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ if p.returncode:
+ raise TaskWarriorException(stderr.strip())
+ return stdout.strip().split('\n')
+
+ def get_tasks(self, project=None, status=PENDING):
+ command = 'export status:{0}'.format(status)
+ if project is not None:
+ command += ' project:{0}'.format(project)
+ tasks = []
+ for line in self._execute(command):
+ if line:
+ tasks.append(Task(self, json.loads(line.strip(','))))
+ return tasks
+
+ def get_task(self, task_id):
+ command = '{0} export'.format(task_id)
+ return Task(self, json.loads(self._execute(command)[0]))
+
+ def add_task(self, description, project=None):
+ args = ['add', description]
+ if project is not None:
+ args.append('project:{0}'.format(project))
+ self._execute(' '.join(args))
+
+ def delete_task(self, task_id):
+ self._execute('{0} rc.confirmation:no delete'.format(task_id))
+
+ def complete_task(self, task_id):
+ self._execute('{0} done'.format(task_id))
+
+ def import_tasks(self, tasks):
+ fd, path = tempfile.mkstemp()
+ with open(path, 'w') as f:
+ f.write(json.dumps(tasks))
+ self._execute('import {0}'.format(path))