TASKLIB(1) tasklib TASKLIB(1)

tasklib - مستندات tasklib

کتابخانه tasklib یک کتابخانه پایتون برای تعامل با پایگاه‌داده‌های taskwarrior http://taskwarrior.org با استفاده از یک API از نوع queryset مشابه ORM در Django است.

از Python 3.5 به بالا، به همراه taskwarrior نسخه 2.4.x به بالا پشتیبانی می‌کند. نسخه‌های قدیمی‌تر taskwarrior آزمایش نشده‌اند و ممکن است کار نکنند.

•
برنامه taskwarrior http://taskwarrior.org نسخه v2.4.x یا بالاتر، هرچند استفاده از جدیدترین انتشار جزئی توصیه می‌شود.

نصب از طریق pip (توصیه شده):

pip install tasklib

یا کلون کردن از github:

git clone https://github.com/robgolding/tasklib.git
cd tasklib
python setup.py install

به‌صورت اختیاری نمونهٔ TaskWarrior را با data_location (دایرکتوری پایگاه‌داده) مقداردهی اولیه کنید. اگر این دایرکتوری از پیش وجود نداشته باشد، به‌طور خودکار ایجاد خواهد شد مگر اینکه create=False تنظیم شده باشد.

مسیر پیش‌فرض مشابه مسیر پیش‌فرض taskwarrior است:

>>> tw = TaskWarrior(data_location='~/.task', create=True)

نمونهٔ TaskWarrior همچنین از پیکربندی .taskrc شما استفاده خواهد کرد (به‌طوری که همان UDAهای فایل باینری task شما را شناسایی کند، از همان پیکربندی استفاده کند و غیره). برای بازنویسی مسیر فایل .taskrc، از taskrc_location=~/some/different/path استفاده کنید..SH "ایجاد وظایف (CREATING TASKS)"

برای ایجاد یک وظیفه، کافی است یک شیء جدید از Task بسازید:

>>> new_task = Task(tw, description="throw out the trash")

این وظیفه تا زمانی که متد .save() را فراخوانی نکنید، در TaskWarrior ذخیره نخواهد شد (مشابه با Django):

>>> new_task.save()

می‌توانید هر ویژگی را به عنوان یک آرگومان کلیدواژه‌ای برای شیء Task تعیین کنید:

>>> complex_task = Task(tw, description="finally fix the shower", due=datetime(2015,2,14,8,0,0), priority='H')

یا اینکه ویژگی‌ها را یکی‌یکی مقداردهی نمایید:

>>> complex_task = Task(tw)
>>> complex_task['description'] = "finally fix the shower"
>>> complex_task['due'] = datetime(2015,2,14,8,0,0)
>>> complex_task['priority'] = 'H'

برای تغییر یک شیء Task ایجادشده یا بازیابی‌شده، از دسترسی شبه‌دیکشنری استفاده کنید:

>>> homework = tw.tasks.get(tags=['chores'])
>>> homework['project'] = 'Home'

تغییرات اعمال‌شده تا زمانی که متد save() را فراخوانی نکنید، به TaskWarrior منتقل نخواهند شد:

>>> homework.save()

ویژگی‌هایی که به اشیاء بومی پایتون متناظر هستند تبدیل خواهند شد. بخش «ویژگی‌های وظیفه» را ببینید.

ویژگی‌های اشیاء وظیفه از طریق نمایه‌ها (indexها) قابل دسترسی هستند، بدین صورت:

>>> task = tw.tasks.pending().get(tags__contain='work')  # There is only one pending task with 'work' tag
>>> task['description']
'Upgrade Ubuntu Server'
>>> task['id']
15
>>> task['due']
datetime.datetime(2015, 2, 5, 0, 0, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
>>> task['tags']
['work', 'servers']

فیلدهای زیر به اشیاء پایتون تبدیل (deserialize) می‌شوند:

  • due، wait، scheduled، until، entry: به یک شیء datetime تبدیل می‌شوند
  • annotations: به فهرستی از اشیاء TaskAnnotation تبدیل می‌شوند
  • tags: به فهرستی از رشته‌ها تبدیل می‌شوند
  • depends: به مجموعه‌ای از اشیاء Task تبدیل می‌شوند

ویژگی‌ها باید با استفاده از نمایش صحیح پایتونی مقداردهی شوند؛ این مقادیر هنگام ذخیره شدن وظیفه، به قالب مناسب سریال‌سازی (serialize) خواهند شد..SH "ویژگی‌های وظیفه (TASK PROPERTIES)"

کتابخانه Tasklib برای راحتی، چندین ویژگی روی شیء Task تعریف می‌کند:

>>> t.save()
>>> t.saved
True
>>> t.pending
True
>>> t.active
False
>>> t.start()
>>> t.active
True
>>> t.done()
>>> t.completed
True
>>> t.pending
False
>>> t.delete()
>>> t.deleted
True

پس از تغییر دادن یک یا چند مشخصه، به سادگی save() را فراخوانی کنید تا آن تغییرات در پایگاه‌داده ذخیره شوند:

>>> task = tw.tasks.pending().get(tags__contain='work')
>>> task['due'] = datetime(year=2014, month=1, day=5)
>>> task.save()

برای علامت‌گذاری یک وظیفه به عنوان انجام‌شده، از done() استفاده کنید:

>>> task = tw.tasks.pending().get(tags__contain='work')
>>> task.done()
>>> len(tw.tasks.pending().filter(tags__contain='work'))
0

برای حذف یک وظیفه، از delete() استفاده کنید:

>>> task = tw.tasks.get(description="task added by mistake")
>>> task.delete()

برای به‌روزرسانی یک شیء وظیفه با مقادیر پایگاه‌داده TaskWarrior، از refresh() استفاده کنید. مثال:

>>> task = Task(tw, description="learn to cook")
>>> task.save()
>>> task['id']
5
>>> task['tags']
[]

اکنون فرض کنید وظیفه را با استفاده از رابط TaskWarrior در یک پایانه دیگر تغییر می‌دهیم:

$ task 5 modify +someday
Task 5 modified.

بازگشت به پردازه باز python:

>>> task['tags']
[]
>>> task.refresh()
>>> task['tags']
['someday']

وظایف همچنین می‌توانند شروع و متوقف شوند. به ترتیب از start() و stop() استفاده کنید:

>>> task.start()
>>> task['start']
datetime.datetime(2015, 7, 16, 18, 48, 28, tzinfo=<DstTzInfo 'Europe/Prague' CEST+2:00:00 DST>)
>>> task.stop()
>>> task['start']
>>> task.done()
>>> task['end']
datetime.datetime(2015, 7, 16, 18, 49, 2, tzinfo=<DstTzInfo 'Europe/Prague' CEST+2:00:00 DST>)

tw.tasks یک شیء TaskQuerySet است که API مربوط به Django QuerySet را شبیه‌سازی می‌کند. برای دریافت همه وظایف (از جمله موارد تکمیل‌شده):

>>> tw.tasks.all()
['First task', 'Completed task', 'Deleted task', ...]

وظایف را با استفاده از همان ساختار نحوی آشنا فیلتر کنید:

>>> tw.tasks.filter(status='pending', tags__contains=['work'])
['Upgrade Ubuntu Server']

آرگومان‌های فیلتر به دستور task ارسال می‌شوند (__ با یک نقطه جایگزین می‌شود)، بنابراین مثال بالا معادل دستور زیر است:

$ task status:pending tags.contain=work

وظایف همچنین می‌توانند با استفاده از دستورات خام فیلتر شوند، مانند زیر:

>>> tw.tasks.filter('status:pending +work')
['Upgrade Ubuntu Server']

اگرچه این روش توصیه نمی‌شود، زیرا با استفاده از دستورات خام ممکن است بخشی از سازگاری و انتقال‌پذیری دستورهای خود را در نسخه‌های مختلف TaskWarrior از دست بدهید.

با این حال، می‌توانید همانند مثال ارائه‌شده، دستورات خام را با فیلترهای کلیدواژه‌ای ترکیب کنید:

>>> tw.tasks.filter('+BLOCKING', project='Home')  # Gets all blocking tasks in project Home
['Fix the toilette']

این می‌تواند روش مناسبی برای استفاده از ساختار نحوی باشد که هنوز توسط tasklib پشتیبانی نمی‌شود. نمونه بالا یک مثال عالی است، زیرا برچسب‌های مجازی همانند برچسب‌های عادی کار نمی‌کنند؛ یعنی:

>>> tw.tasks.filter(tags=['BLOCKING'])
>>> []

کار نخواهد کرد.

توابع توکاری برای بازیابی وظایف معلق (pending) و تکمیل‌شده وجود دارند:

>>> tw.tasks.pending().filter(tags__contain='work')
['Upgrade Ubuntu Server']
>>> len(tw.tasks.completed())
227

از get() برای بازگرداندن تنها وظیفه موجود در یک TaskQuerySet یا ایجاد یک استثنا استفاده کنید:

>>> tw.tasks.get(tags__contain='work')['status']
'pending'
>>> tw.tasks.get(status='completed', tags__contains='work')  # Status of only task with the work tag is pending, so this should fail
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tasklib/task.py", line 224, in get
    'Lookup parameters were {0}'.format(kwargs))
tasklib.task.DoesNotExist: Task matching query does not exist. Lookup parameters were {'status': 'completed', 'tags__contains': ['work']}
>>> tw.tasks.get(status='pending')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "tasklib/task.py", line 227, in get
    'Lookup parameters were {1}'.format(num, kwargs))
ValueError: get() returned more than one Task -- it returned 23! Lookup parameters were {'status': 'pending'}

علاوه بر این، از آنجا که فیلترها TaskQuerySet بازمی‌گردانند، می‌توانید فیلترها را روی یکدیگر اعمال (stack) کنید:

>>> home_tasks = tw.tasks.filter(project='Wife')
>>> home_tasks.filter(due__before=datetime(2015,2,14,14,14,14))  # What I have to do until Valentine's day
['Prepare surprise birthday party']

دو شیء Task در صورتی برابر در نظر گرفته می‌شوند که دارای UUID یکسان باشند:

>>> task1 = Task(tw, description="Pet the dog")
>>> task1.save()
>>> task2 = tw.tasks.get(description="Pet the dog")
>>> task1 == task2
True

اگر دو وظیفهٔ ذخیره‌نشده را مقایسه کنید، تنها در صورتی برابر در نظر گرفته می‌شوند که دقیقاً همان شیء Python باشند:

>>> task1 = Task(tw, description="Pet the cat")
>>> task2 = Task(tw, description="Pet the cat")
>>> task1 == task2
False
>>> task3 = task1
>>> task3 == task1
True

برای دسترسی به وضعیت ذخیره‌شدهٔ Task، از دسترسی شبه‌دیکشنری با استفاده از ویژگی original استفاده کنید:

>>> t = Task(tw, description="tidy up")
>>> t.save()
>>> t['description'] = "tidy up the kitchen and bathroom"
>>> t['description']
"tidy up the kitchen and bathroom"
>>> t.original['description']
"tidy up"

هنگامی که وظیفه را ذخیره می‌کنید، مقادیر اصلی به‌روزرسانی می‌شوند تا بازتاب‌دهندهٔ وضعیت ذخیره‌شدهٔ وظیفه باشند:

>>> t.save()
>>> t.original['description']
"tidy up the kitchen and bathroom"

تمام ویژگی‌های شبه‌برچسب زمانی (timestamp-like) وظایف، به اشیاء datetime دارای منطقهٔ زمانی (timezone-aware) تبدیل می‌شوند. برای دستیابی به این هدف، Tasklib از ماژول پایتون zoneinfo بهره می‌برد که پایگاه‌دادهٔ منطقهٔ زمانی Olsen را به پایتون می‌آورد.

این ویژگی شما را از درگیر شدن با جزئیات آزاردهندهٔ تغییرات ساعت تابستانی (Daylight Saving Time) یا تبدیل میان مناطق زمانی مختلف مصون می‌دارد. برای نمونه، جهت فهرست کردن تمام وظایفی که سررسید آن‌ها تا نیمه‌شب است (در صورتی که اکنون در برلین باشید):

>>> myzone = zoneinfo.ZoneInfo('Europe/Berlin')
>>> midnight = datetime(2015,2,2,0,0,0,tzinfo=myzone)
>>> tw.tasks.filter(due__before=midnight)

با این حال، این روش هنوز کمی خسته‌کننده است. به همین دلیل شیء TaskWarrior با استفاده از ماژول پایتون tzlocal قادر به تشخیص خودکار منطقهٔ زمانی است. اگر منطقهٔ زمانی سیستم شما روی 'Europe/Berlin' تنظیم شده باشد، مثال زیر دقیقاً همانند مثال پیشین عمل خواهد کرد:

>>> tw.tasks.filter(due__before=datetime(2015,2,2,0,0,0))

همچنین می‌توانید هنگام فیلتر کردن از تاریخ‌های ساده استفاده کنید:

>>> tw.tasks.filter(due__before=date(2015,2,2))

در چنین حالتی، مقدار 00:00:00 به عنوان مؤلفهٔ زمان در نظر گرفته می‌شود.

البته می‌توانید هنگام مقداردهی اولیه به شیء Task یا انتساب مقادیر به ویژگی‌های datetime، از اشیاء datetime فاقد منطقهٔ زمانی (naive) نیز استفاده کنید:

>>> t = Task(tw, description="Buy new shoes", due=date(2015,2,5))
>>> t['due']
datetime.datetime(2015, 2, 5, 0, 0, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
>>> t['due'] = date(2015,2,6,15,15,15)
>>> t['due']
datetime.datetime(2015, 2, 6, 15, 15, 15, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)

با این حال، از آنجا که در پایتون مقادیر datetime دارای منطقهٔ زمانی (timezone-aware) و فاقد منطقهٔ زمانی (timezone-naive) با یکدیگر قابل مقایسه نیستند، این امر می‌تواند باعث رفتارهای غیرمنتظره‌ای شود:

>>> from datetime import datetime
>>> now = datetime.now()
>>> t = Task(tw, description="take out the trash now")
>>> t['due'] = now
>>> now
datetime.datetime(2015, 2, 1, 19, 44, 4, 770001)
>>> t['due']
datetime.datetime(2015, 2, 1, 19, 44, 4, 770001, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
>>> t['due'] == now
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: can't compare offset-naive and offset-aware datetimes

اگر می‌خواهید یک مقدار datetime دارای منطقهٔ زمانی را با یک مقدار بدون منطقهٔ زمانی مقایسه کنید، باید ابتدا مقدار بدون منطقهٔ زمانی را محلی‌سازی (localize) کنید:

>>> from datetime import datetime
>>> now = datetime.now().astimezone()
>>> t['due'] = now
>>> now
datetime.datetime(2015, 2, 1, 19, 44, 4, 770001, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
>>> t['due'] == now
True

همچنین توجه داشته باشید که اهمیتی ندارد اشیاء datetime دارای منطقهٔ زمانی، روی منطقهٔ زمانی یکسانی تنظیم شده باشند یا خیر:

>>> import zoneinfo
>>> t['due']
datetime.datetime(2015, 2, 1, 19, 44, 4, 770001, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
>>> now.astimezone(zoneinfo.ZoneInfo('UTC'))
datetime.datetime(2015, 2, 1, 18, 44, 4, 770001, tzinfo=<UTC>)
>>> t['due'] == now.astimezone(zoneinfo.ZoneInfo('UTC'))
True

نکته: رفتار زیر تنها در TaskWarrior >= 2.4.0 در دسترس است.

رویکرد سومی نیز برای تنظیم مقادیر تاریخ و زمان وجود دارد که از دستور 'task calc' استفاده می‌کند. می‌توانید به‌سادگی هر ویژگی datetime را به هر رشته‌ای که شامل یک عبارت زمانی معتبر با قالب‌بندی TaskWarrior باشد، نسبت دهید:

$ task calc now + 1d
2015-07-17T21:17:54

از این نحو (syntax) می‌توان در مفسر پایتون به شکل زیر استفاده کرد:

>>> t['due'] = "now + 1d"
>>> t['due']
datetime.datetime(2015, 7, 17, 21, 19, 31, tzinfo=<DstTzInfo 'Europe/Berlin' CEST+2:00:00 DST>)

به‌وضوح مشخص است رشته‌ای که دارای عبارت زمانی با قالب TaskWarrior است، به‌طور خودکار به شیء datetime بومی در منطقهٔ زمانی محلی تبدیل می‌شود.

برای دسترسی به فهرست قالب‌ها و کلمات کلیدی مجاز، لطفاً مراجعه کنید به:

حاشیه‌نویسی‌های وظایف در tasklib توسط شیءهای TaskAnnotation نشان داده می‌شوند. این شیءها بسیار شبیه به شیءهای Task هستند، هرچند بسیار ساده‌تر شده‌اند.

>>> annotated_task = tw.tasks.get(description='Annotated task')
>>> annotated_task['annotations']
[Yeah, I am annotated!]

حاشیه‌نویسی‌ها تنها دارای مقادیر تعریف‌شدهٔ entry و description هستند:

>>> annotation = annotated_task['annotations'][0]
>>> annotation['entry']
datetime.datetime(2015, 1, 3, 21, 13, 55, tzinfo=<DstTzInfo 'Europe/Berlin' CET+1:00:00 STD>)
>>> annotation['description']
u'Yeah, I am annotated!'

برای افزودن یک حاشیه‌نویسی به یک Task، از add_annotation() استفاده کنید:

>>> task = Task(tw, description="new task")
>>> task.add_annotation("we can annotate any task")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    File "build/bdist.linux-x86_64/egg/tasklib/task.py", line 355, in add_annotation
tasklib.task.NotSaved: Task needs to be saved to add annotation

با این حال، پیش از آنکه بتوانید حاشیه‌نویسی را به یک Task بیفزایید، باید آن را ذخیره کنید:

>>> task.save()
>>> task.add_annotation("we can annotate saved tasks")
>>> task['annotations']
[we can annotate saved tasks]

برای حذف حاشیه‌نویسی، شرح آن را به متد remove_annotation() ارسال کنید:

>>> task.remove_annotation("we can annotate saved tasks")

همچنین می‌توانید خود شیء TaskAnnotation را ارسال کنید:

>>> task.remove_annotation(task['annotations'][0])

برای اجرای دستورهای سفارشی، از متد execute_command() شیء TaskWarrior استفاده کنید:

>>> tw = TaskWarrior()
>>> tw.execute_command(['log', 'Finish high school.'])
[u'Logged task.']

می‌توانید از آرگومان کلیدواژه‌ای config_override برای مشخص کردن دیکشنری‌ای از بازنویسی‌های پیکربندی استفاده کنید:

>>> tw.execute_command(['3', 'done'], config_override={'gc': 'off'}) # Will mark 3 as completed and it will retain its ID

علاوه بر این، می‌توانید از پرچم return_all=True استفاده کنید که سه‌تایی (stdout, sterr, return_code) را بازمی‌گرداند، و همچنین allow_failure=False که در صورت بازگرداندن کد وضعیت خروج غیرصفر توسط فایل اجرایی task، از بالا آمدن استثنا توسط tasklib جلوگیری می‌کند:

>>> tw.execute_command(['invalidcommand'], allow_failure=False, return_all=True)
([u''],
 [u'Using alternate .taskrc file /home/tbabej/.taskrc',
  u"[task next rc:/home/tbabej/.taskrc rc.recurrence.confirmation=no rc.json.array=off rc.confirmation=no rc.bulk=0 rc.dependency.confirmation=no description ~ 'invalidcommand']",
  u'Configuration override rc.recurrence.confirmation:no',
  u'Configuration override rc.json.array:off',
  u'Configuration override rc.confirmation:no',
  u'Configuration override rc.bulk:0',
  u'Configuration override rc.dependency.confirmation:no',
  u'No matches.',
  u'There are local changes.  Sync required.'],
 1)

به‌طور پیش‌فرض، TaskWarrior از مقادیر پیکربندی ذخیره‌شده در .taskrc شما استفاده می‌کند. برای مشاهدهٔ اینکه چه مقادیر بازنویسی پیکربندی‌ای (overrides) به هر دستور task اجرا شده ارسال می‌شوند، نگاهی به صفت overrides در شیء TaskWarrior بیندازید:

>>> tw.overrides
{'confirmation': 'no', 'data.location': '/home/tbabej/.task'}

برای اعمال مقادیر بازنویسی پیکربندی سفارشی خود، تنها کافی است این دیکشنری را به‌روزرسانی کنید:

>>> tw.overrides.update({'hooks': 'off'})  # tasklib will not trigger hooks

از نسخهٔ 2.4.0، برنامهٔ TaskWarrior از اسکریپت‌های قلاب (hook scripts) پشتیبانی می‌کند. tasklib ابزارهای کمکی بسیار مفیدی را برای نوشتن آن‌ها فراهم کرده است. با tasklib، نوشتن این اسکریپت‌ها بسیار آسان می‌شود:

#!/usr/bin/python
from tasklib.task import Task
task = Task.from_input()
# ... <custom logic>
print task.export_data()

برای نمونه، پلاگینی که اولویت "H" را به هر تسکی که شامل سه علامت تعجب در توضیحاتش باشد اختصاص می‌دهد، به شکل زیر خواهد بود:

#!/usr/bin/python
from tasklib.task import Task
task = Task.from_input()
if "!!!" in task['description']:
    task['priority'] = "H"
print task.export_data()

کتابخانهٔ tasklib می‌تواند به‌طور خودکار تشخیص دهد که در رویداد on-modify در حال اجرا است یا خیر؛ این رویداد ورودی بیشتری نسبت به رویداد on-add فراهم می‌کند و داده‌ها را بر همان اساس می‌خواند.

این بدان معناست که مثال بالا هم برای رویداد on-add و هم برای on-modify کار می‌کند!

در نتیجه، می‌توانید تنها یک فایل قلاب برای هر دو رویداد on-add و on-modify ایجاد کرده و برای دیگری فقط یک پیوند نمادین (symlink) بسازید. این کار نیاز به نگهداری دو نسخه از یک کد و یا کدهای تکراری (boilerplate) را از بین می‌برد.

در رویدادهای on-modify، کتابخانهٔ tasklib هم نسخهٔ اصلی و هم نسخهٔ تغییریافتهٔ تسک را در شیء Task بازگردانده‌شده بارگذاری می‌کند. برای دسترسی به داده‌های اولیه (به‌صورت فقط‌خواندنی)، از صفت شبه‌دیکشنری original استفاده کنید:

>>> t = Task.from_input()
>>> t['description']
"Modified description"
>>> t.original['description']
"Original description"

از آنجا که TaskWarrior فایل .taskrc شما را می‌خواند، نیازی نیست همان‌طور که در بالا توضیح داده شد هیچ UDAای را در دیکشنری config مربوط به TaskWarrior تعریف کنید. فرض کنید یک UDA به نام estimate در .taskrc داریم:
uda.estimate.type = numeric

می‌توانیم به‌سادگی و بدون نیاز به تنظیمات اضافی، با استفاده از UDA به نام estimate تسک‌ها را فیلتر و ایجاد کنیم:

>>> tw = TaskWarrior()
>>> task = Task(tw, description="Long task", estimate=1000)
>>> task.save()
>>> task['id']
1

این مورد به عنوان UDA در TaskWarrior ذخیره می‌شود:

$ task 1 export
{"id":1,"description":"Long task","estimate":1000, ...}

همچنین می‌توانیم UDAها را به عنوان آرگومان در TaskFilter مشخص کنیم:

>>> tw.tasks.filter(estimate=1000)
Long task

اگر متغیرهای پیکربندی لازم را در .taskrc خود مقداردهی کرده باشید، همگام‌سازی به همین سادگی است:

>>> tw = TaskWarrior()
>>> tw.execute_command(['sync'])

اگر می‌خواهید از سرور/اعتبارنامه‌های غیراستاندارد استفاده کنید، باید بازنویسی‌های پیکربندی را به نمونهٔ TaskWarrior ارائه دهید. دیکشنری config را با مقادیری که می‌خواهید جایگزین شوند به‌روزرسانی کنید، و سپس می‌توانیم دستور sync را با استفاده از متد execute_command() اجرا کنیم:

>>> tw = TaskWarrior()
>>> sync_config = {
...     'taskd.certificate': '/home/tbabej/.task/tbabej.cert.pem',
...     'taskd.credentials': 'Public/tbabej/34af54de-3cb2-4d3d-82be-33ddb8fd3e66',
...     'taskd.server': 'task.server.com:53589',
...     'taskd.ca': '/home/tbabej/.task/ca.cert.pem',
...     'taskd.trust': 'ignore hostname'}
>>> tw.config.update(sync_config)
>>> tw.execute_command(['sync'])
Rob Golding

2014 - 2021, Rob Golding & Gothenburg Bit Factory

December 14, 2025 2.5.1