Fixed a view bugs for the new regeneration mode, plus some additional clean-up of code. In addition fixed a labelling bug on deeper levels, and headered items will be cleaned of old next-action labels.

master
Hoffelhas 2021-01-17 14:58:14 +01:00
parent f97c7e70e0
commit bd9e5d021b
1 changed files with 77 additions and 42 deletions

View File

@ -71,6 +71,9 @@ def query_yes_no(question, default="yes"):
sys.stdout.write("Please respond with 'yes' or 'no' " sys.stdout.write("Please respond with 'yes' or 'no' "
"(or 'y' or 'n').\n") "(or 'y' or 'n').\n")
# Check if label exists, if not, create it
def verify_label_existance(args, api, label_name, prompt_mode): def verify_label_existance(args, api, label_name, prompt_mode):
# Check the regeneration label exists # Check the regeneration label exists
label = api.labels.all(lambda x: x['name'] == label_name) label = api.labels.all(lambda x: x['name'] == label_name)
@ -78,7 +81,7 @@ def verify_label_existance(args, api, label_name, prompt_mode):
if len(label) > 0: if len(label) > 0:
label_id = label[0]['id'] label_id = label[0]['id']
logging.debug('Label \'%s\' found as label id %d', logging.debug('Label \'%s\' found as label id %d',
args.label, label_id) args.label, label_id)
else: else:
# Create a new label in Todoist # Create a new label in Todoist
logging.info( logging.info(
@ -102,7 +105,7 @@ def verify_label_existance(args, api, label_name, prompt_mode):
exit(1) exit(1)
return label_id return label_id
# Initialisation of Autodoist # Initialisation of Autodoist
def initialise(args): def initialise(args):
@ -122,10 +125,16 @@ def initialise(args):
else: else:
pass pass
# Check if proper regeneration mode has been selected
if args.regeneration is not None:
if not set([0,1,2]) & set([args.regeneration]):
logging.error('Wrong regeneration mode. Please choose a number from 0 to 2. Check --help for more information on the available modes.')
exit(1)
# Show which modes are enabled: # Show which modes are enabled:
modes = [] modes = []
m_num = 0 m_num = 0
for x in [args.label, args.recurring, args.end]: for x in [args.label, args.regeneration, args.end]:
if x: if x:
modes.append('Enabled') modes.append('Enabled')
m_num += 1 m_num += 1
@ -160,17 +169,18 @@ def initialise(args):
# Label functionality not needed # Label functionality not needed
label_id = None label_id = None
# If regeneration mode is used logging.info("Autodoist has connected and is running fine!\n")
if args.recurring is not None:
# If regeneration mode is used, verify labels
if args.regeneration is not None:
# Verify the existance of the regeneraton labels; force creation of label # Verify the existance of the regeneraton labels; force creation of label
regen_labels_id = [verify_label_existance(args, api, regen_label, 2) for regen_label in args.regen_label_names] regen_labels_id = [verify_label_existance(
args, api, regen_label, 2) for regen_label in args.regen_label_names]
else: else:
# Label functionality not needed # Label functionality not needed
regen_labels_id = [None, None, None] regen_labels_id = [None, None, None]
logging.info("Autodoist has connected and is running fine!\n")
return api, label_id, regen_labels_id return api, label_id, regen_labels_id
@ -397,6 +407,8 @@ def check_header(level):
return header_all_in_level, unheader_all_in_level return header_all_in_level, unheader_all_in_level
# Check regen mode based on label name # Check regen mode based on label name
def check_regen_mode(api, item, regen_labels_id): def check_regen_mode(api, item, regen_labels_id):
labels = item['labels'] labels = item['labels']
@ -410,7 +422,7 @@ def check_regen_mode(api, item, regen_labels_id):
return None return None
regen_label_id = overlap[0] regen_label_id = overlap[0]
if regen_label_id == regen_labels_id[0]: if regen_label_id == regen_labels_id[0]:
return 0 return 0
elif regen_label_id == regen_labels_id[1]: elif regen_label_id == regen_labels_id[1]:
@ -420,11 +432,13 @@ def check_regen_mode(api, item, regen_labels_id):
else: else:
label_name = api.labels.get_by_id(regen_label_id)['name'] label_name = api.labels.get_by_id(regen_label_id)['name']
logging.debug( logging.debug(
'No regeneration label for item: %s' % label_name) 'No regeneration label for item: %s' % label_name)
return None return None
# Recurring lists logic # Recurring lists logic
def run_recurring_lists_logic(args, api, item, child_items, child_items_all, regen_labels_id): def run_recurring_lists_logic(args, api, item, child_items, child_items_all, regen_labels_id):
if item['parent_id'] == 0: if item['parent_id'] == 0:
@ -439,25 +453,26 @@ def run_recurring_lists_logic(args, api, item, child_items, child_items_all, reg
date_old=item['due']['date']) date_old=item['due']['date'])
# Mark children for action based on mode # Mark children for action based on mode
if args.recurring: if args.regeneration is not None:
# Check if task has a regen label # Check if task has a regen label
regen_mode = check_regen_mode(api, item, regen_labels_id) # TODO: HAS TO OVERRULE GENERAL MODE, BUILD regen_mode = check_regen_mode(
api, item, regen_labels_id)
# If no label, use general mode instead # If no label, use general mode instead
if regen_mode is None: if regen_mode is None:
regen_mode = args.recurring regen_mode = args.regeneration
# Apply tags based on mode # Apply tags based on mode
regen_tag = 0 give_regen_tag = 0
if regen_mode == 1: if regen_mode == 2: # Regen all
regen_tag = 1 give_regen_tag = 1
elif regen_mode == 2: elif regen_mode == 3: # Regen if all sub-tasks completed
if not child_items: if not child_items:
regen_tag = 1 give_regen_tag = 1
if regen_tag == 1: if give_regen_tag == 1:
for child_item in child_items_all: for child_item in child_items_all:
child_item['r_tag'] = 1 child_item['r_tag'] = 1
@ -516,9 +531,9 @@ def run_recurring_lists_logic(args, api, item, child_items, child_items_all, reg
'Parent not recurring: %s' % item['content']) 'Parent not recurring: %s' % item['content'])
pass pass
if args.recurring and item['parent_id'] != 0: if args.regeneration is not None and item['parent_id'] != 0:
try: try:
if item['r_tag'] == 1: # TODO: USE NUMBER FOR MODE if item['r_tag'] == 1:
item.update(checked=0) item.update(checked=0)
item.update(in_history=0) item.update(in_history=0)
item['r_tag'] = 0 item['r_tag'] = 0
@ -639,7 +654,7 @@ def autodoist_magic(args, api, label_id, regen_labels_id):
for ci in child_items] for ci in child_items]
# Logic for recurring lists # Logic for recurring lists
if not args.recurring: if not args.regeneration:
try: try:
# If old label is present, reset it # If old label is present, reset it
if item['r_tag'] == 1: if item['r_tag'] == 1:
@ -649,7 +664,7 @@ def autodoist_magic(args, api, label_id, regen_labels_id):
pass pass
# If options turned on, start recurring lists logic # If options turned on, start recurring lists logic
if args.recurring or args.end: if args.regeneration is not None or args.end:
run_recurring_lists_logic( run_recurring_lists_logic(
args, api, item, child_items, child_items_all, regen_labels_id) args, api, item, child_items, child_items_all, regen_labels_id)
@ -659,6 +674,8 @@ def autodoist_magic(args, api, label_id, regen_labels_id):
if item['checked'] == 1: if item['checked'] == 1:
continue continue
if item['content'].startswith('*'): if item['content'].startswith('*'):
# Remove next action label if it's still present
remove_label(item, label_id, overview_item_ids,overview_item_labels)
continue continue
# Check item type # Check item type
@ -721,9 +738,21 @@ def autodoist_magic(args, api, label_id, regen_labels_id):
[remove_label(child_item, label_id, overview_item_ids, overview_item_labels) [remove_label(child_item, label_id, overview_item_ids, overview_item_labels)
for child_item in child_items] for child_item in child_items]
# If a sub-task, inherit parent task type
if item['parent_id'] !=0:
try:
active_type = item['parent_type']
except:
pass
# Process sequential tagged items (item_type can overrule project_type) # Process sequential tagged items (item_type can overrule project_type)
if active_type == 'sequential' or active_type == 'p-s': if active_type == 'sequential' or active_type == 'p-s':
for child_item in child_items: for child_item in child_items:
# Ignore headered children
if child_item['content'].startswith('*'):
continue
# Pass item_type down to the children # Pass item_type down to the children
child_item['parent_type'] = active_type child_item['parent_type'] = active_type
# Pass label down to the first child # Pass label down to the first child
@ -742,6 +771,11 @@ def autodoist_magic(args, api, label_id, regen_labels_id):
remove_label( remove_label(
item, label_id, overview_item_ids, overview_item_labels) item, label_id, overview_item_ids, overview_item_labels)
for child_item in child_items: for child_item in child_items:
# Ignore headered children
if child_item['content'].startswith('*'):
continue
child_item['parent_type'] = active_type child_item['parent_type'] = active_type
if child_item['checked'] == 0: if child_item['checked'] == 0:
# child_first_found = True # child_first_found = True
@ -842,52 +876,53 @@ def autodoist_magic(args, api, label_id, regen_labels_id):
return overview_item_ids, overview_item_labels return overview_item_ids, overview_item_labels
# Main function # Main
def main(): def main():
# Version # Version
current_version = 'v1.4.1' current_version = 'v1.5'
# Main process functions. # Main process functions.
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
formatter_class=make_wide(argparse.HelpFormatter, w=110, h=50)) formatter_class=make_wide(argparse.HelpFormatter, w=110, h=50))
parser.add_argument('-a', '--api_key', parser.add_argument('-a', '--api_key',
help='Takes your Todoist API Key.', type=str) help='takes your Todoist API Key.', type=str)
parser.add_argument( parser.add_argument(
'-l', '--label', help='Enable next action labelling. Define which label to use.', type=str) '-l', '--label', help='enable next action labelling. Define which label to use.', type=str)
parser.add_argument( parser.add_argument(
'-r', '--recurring', help='Enable regeneration of sub-tasks in recurring lists. Chose active mode: 0 - regen off, 1 - regen on, 2 - regen only if all tasks are completed', type=int) '-r', '--regeneration', help='enable regeneration of sub-tasks in recurring lists. Chose overall mode: 0 - regen off, 1 - regen all, 2 - regen only if all sub-tasks are completed. Task labels can be used to overwrite this mode.', type=int, default=None)
parser.add_argument( parser.add_argument(
'-e', '--end', help='Enable alternative end-of-day time instead of default midnight. Enter a number from 1 to 24 to define which hour is used.', type=int) '-e', '--end', help='enable alternative end-of-day time instead of default midnight. Enter a number from 1 to 24 to define which hour is used.', type=int)
parser.add_argument( parser.add_argument(
'-d', '--delay', help='Specify the delay in seconds between syncs (default 5).', default=5, type=int) '-d', '--delay', help='specify the delay in seconds between syncs (default 5).', default=5, type=int)
parser.add_argument( parser.add_argument(
'-pp', '--pp_suffix', help='Change suffix for parallel-parallel labeling (default "//").', default='//') '-pp', '--pp_suffix', help='change suffix for parallel-parallel labeling (default "//").', default='//')
parser.add_argument( parser.add_argument(
'-ss', '--ss_suffix', help='Change suffix for sequential-sequential labeling (default "--").', default='--') '-ss', '--ss_suffix', help='change suffix for sequential-sequential labeling (default "--").', default='--')
parser.add_argument( parser.add_argument(
'-ps', '--ps_suffix', help='Change suffix for parallel-sequential labeling (default "/-").', default='/-') '-ps', '--ps_suffix', help='change suffix for parallel-sequential labeling (default "/-").', default='/-')
parser.add_argument( parser.add_argument(
'-sp', '--sp_suffix', help='Change suffix for sequential-parallel labeling (default "-/").', default='-/') '-sp', '--sp_suffix', help='change suffix for sequential-parallel labeling (default "-/").', default='-/')
parser.add_argument( parser.add_argument(
'-df', '--dateformat', help='Strptime() format of starting date (default "%%d-%%m-%%Y").', default='%d-%m-%Y') '-df', '--dateformat', help='strptime() format of starting date (default "%%d-%%m-%%Y").', default='%d-%m-%Y')
parser.add_argument( parser.add_argument(
'-hf', '--hide_future', help='Prevent labelling of future tasks beyond a specified number of days.', default=0, type=int) '-hf', '--hide_future', help='prevent labelling of future tasks beyond a specified number of days.', default=0, type=int)
parser.add_argument( parser.add_argument(
'--onetime', help='Update Todoist once and exit.', action='store_true') '--onetime', help='update Todoist once and exit.', action='store_true')
parser.add_argument( parser.add_argument(
'--nocache', help='Disables caching data to disk for quicker syncing.', action='store_true') '--nocache', help='disables caching data to disk for quicker syncing.', action='store_true')
parser.add_argument('--debug', help='Enable detailed debugging in log.', parser.add_argument('--debug', help='Enable debugging and store detailed to a log file.',
action='store_true') action='store_true')
parser.add_argument('--inbox', help='The method the Inbox should be processed with.', parser.add_argument('--inbox', help='The method the Inbox should be processed with.',
default=None, choices=['parallel', 'sequential']) default=None, choices=['parallel', 'sequential'])
args = parser.parse_args() args = parser.parse_args()
#Addition of regeneration labels # Addition of regeneration labels
args.regen_label_names = ('Regen_off', 'Regen_on', 'Regen_if_all_completed') args.regen_label_names = ('Regen_off', 'Regen_all',
'Regen_all_if_completed')
# Set debug # Set debug
if args.debug: if args.debug: