def cmd_agenda(tl, args): """displays an agenda for a given date """ with ColorRenderer() as cr: agenda_items = [] # if not set, get agenda for today list_all = False if not args.date: args.date = datetime.datetime.now() elif args.date == "*": list_all = True else: args.date = to_date(args.date) if isinstance(args.date, basestring): print(u"Could not parse date argument '{date_str}'".format(date_str = args.date)) quit(-1) for item in tl.list_items(lambda x: True if x.due_date else False): if is_same_day(args.date, item.due_date) or list_all: agenda_items.append(item) # default date used when no done date is specified na_date = datetime.datetime(1970, 1, 1) # sort filtered list by "due" date and whether they are already marked as "done" agenda_items.sort(key=lambda x: (x.done, x.due_date) or (x.done, na_date)) # group report/done items by date for keys, groups in groupby(agenda_items, lambda x: ((x.due_date or na_date).year, (x.due_date or na_date).month, (x.due_date or na_date).day) ): # filter out default dates again if (na_date.year, na_date.month, na_date.day) == keys: print(u"No done date attached") else: print(u"Agenda for {0:d}-{1:02d}-{2:02d}:".format(*keys)) for item in groups: print(" ", cr.render(item)) suppress_if_quiet(u"{nr} todo items displayed.".format(nr = len(agenda_items)), args)
def cmd_archive(tl, args): """archives all non-current todo items and removes them from todo list moves all done / report items to other files (schema is specified in configuration) and removes them from the todo file. Required fields of :param:`args`: """ # base directory of todo file base_dir = os.path.dirname(conf.todo_file) # get list of done and report items report_list = list(tl.list_items(lambda x: x.done or x.is_report)) # default date used when no done date is specified na_date = datetime.datetime(1970, 1, 1) # sort filtered list by "done" date report_list.sort(key=lambda x: x.done_date or na_date, reverse=True) # for mapping items to file names file_map = collections.defaultdict(list) for item in report_list: item_date = item.done_date or na_date if is_same_day(item_date, na_date): dst_fn = conf.archive_unsorted_filename else: dst_fn = os.path.join( base_dir, item_date.strftime(conf.archive_filename_scheme)) # if not existing, create it if not os.path.exists(os.path.dirname(dst_fn)): os.makedirs(os.path.dirname(dst_fn)) # add to file map file_map[dst_fn].append(item) nr_archived = 0 # now we append the items to the right file for dst_fn in file_map: nr_archived += len(file_map[dst_fn]) # open files in append mode with codecs.open(dst_fn, "a", "utf-8") as fp: for item in file_map[dst_fn]: # and write them fp.write(item.text + "\n") # and remove the item from todo list tl.remove_item(item) suppress_if_quiet( u"Successfully archived {nr} todo items.".format(nr=nr_archived), args)
def cmd_archive(tl, args): """archives all non-current todo items and removes them from todo list moves all done / report items to other files (schema is specified in configuration) and removes them from the todo file. Required fields of :param:`args`: """ # base directory of todo file base_dir = os.path.dirname(conf.todo_file) # get list of done and report items report_list = list(tl.list_items(lambda x: x.done or x.is_report)) # default date used when no done date is specified na_date = datetime.datetime(1970, 1, 1) # sort filtered list by "done" date report_list.sort(key=lambda x: x.done_date or na_date, reverse=True) # for mapping items to file names file_map = collections.defaultdict(list) for item in report_list: item_date = item.done_date or na_date if is_same_day(item_date, na_date): dst_fn = conf.archive_unsorted_filename else: dst_fn = os.path.join(base_dir, item_date.strftime(conf.archive_filename_scheme)) # if not existing, create it if not os.path.exists(os.path.dirname(dst_fn)): os.makedirs(os.path.dirname(dst_fn)) # add to file map file_map[dst_fn].append(item) nr_archived = 0 # now we append the items to the right file for dst_fn in file_map: nr_archived += len(file_map[dst_fn]) # open files in append mode with codecs.open(dst_fn, "a", "utf-8") as fp: for item in file_map[dst_fn]: # and write them fp.write(item.text + "\n") # and remove the item from todo list tl.remove_item(item) suppress_if_quiet(u"Successfully archived {nr} todo items.".format(nr = nr_archived), args)
def cmd_agenda(tl, args): """displays an agenda for a given date Required fields of :param:`args`: * date: either a date or a string like 'tomorrow' or '*', default 'today' """ with ColorRenderer() as cr: agenda_items = [] # if not set, get agenda for today list_all = False if not args.date: args.date = datetime.datetime.now() elif args.date == "*": list_all = True else: args.date = to_date(args.date) if isinstance(args.date, basestring): print(u"Could not parse date argument '{date_str}'".format( date_str=args.date)) quit(-1) for item in tl.list_items(lambda x: True if x.due_date else False): if is_same_day(args.date, item.due_date) or list_all: agenda_items.append(item) # default date used when no done date is specified na_date = datetime.datetime(1970, 1, 1) # sort filtered list by "due" date and whether they are already marked as "done" agenda_items.sort( key=lambda x: (x.done, x.due_date) or (x.done, na_date)) # group report/done items by date for keys, groups in groupby( agenda_items, lambda x: ((x.due_date or na_date).year, (x.due_date or na_date).month, (x.due_date or na_date).day)): # filter out default dates again if (na_date.year, na_date.month, na_date.day) == keys: print(u"No done date attached") else: print(u"Agenda for {0:d}-{1:02d}-{2:02d}:".format(*keys)) for item in groups: print(" ", cr.render(item)) suppress_if_quiet( u"{nr} todo items displayed.".format(nr=len(agenda_items)), args)
def cmd_report(tl, args): """shows a daily report of all done and report items :description: This command lists all done and report items for a given date or date range. If no arguments are given, the items of the last 7 days are displayed. Required fields of :param:`args`: * from_date: either a date or a string like 'tomorrow' or '*' * to_date: either a date or a string like 'tomorrow' """ with ColorRenderer() as cr: # default date used when no done date is specified na_date = datetime.datetime(1970, 1, 1, 0, 0, 0, 0) # today now = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) # check from and to date, make them datetime or None # what mode are we in? mode = None if args.from_date in ("*", "all"): mode, args.from_date, args.to_date = "ALL", na_date, now else: args.from_date = to_date(args.from_date) args.to_date = to_date(args.to_date) if isinstance(args.from_date, datetime.datetime): args.from_date = args.from_date.replace(hour=0, minute=0, second=0, microsecond=0) else: logger.debug( u"Cannot parse {date}".format(date=args.from_date)) args.from_date = None if isinstance(args.to_date, datetime.datetime): args.to_date = args.to_date.replace(hour=0, minute=0, second=0, microsecond=0) else: logger.debug(u"Cannot parse {date}".format(date=args.to_date)) args.to_date = None if args.from_date and args.to_date and not mode: mode = "RANGE" elif args.from_date and not args.to_date: mode, args.to_date = "DAY", args.from_date elif not mode: # last 7 days mode, args.from_date, args.to_date = "LASTWEEK", now - datetime.timedelta( days=7), now # swap dates, if necessary if args.from_date > args.to_date: args.from_date, args.to_date = args.to_date, args.from_date # set end date to end of day args.to_date = args.to_date.replace(hour=23, minute=59, second=59) logger.debug(u"Report mode {0}: from {1} to {2}".format( mode, args.from_date, args.to_date)) # get list of done and report items from current todo list report_list = list(tl.list_items(lambda x: (x.done or x.is_report))) # get list of done and report items from un-dated archive file root_dir = os.path.dirname(conf.todo_file) unsorted_fn = os.path.join(root_dir, conf.archive_unsorted_filename) if os.path.exists(unsorted_fn): res = TodoList(unsorted_fn) report_list.extend(res.todolist) # get all archive file names in list file_pattern = re_replace_archive_vars.sub( "*", conf.archive_filename_scheme) file_list = glob.glob(os.path.join(root_dir, file_pattern)) # regex for finding all replaced parts in archive filename scheme re_find_date_str = re_replace_archive_vars.sub( "(.+)", conf.archive_filename_scheme).replace("\\", "\\\\") re_find_date = re.compile(re_find_date_str, re.UNICODE) # loop through all files and see, whether they match the given date range for fn in file_list: # get all replaced values in filename parts = re_find_date.findall(fn)[0] # get the variables responsible for this substitution (e.archived_items. "%Y", "%m", ...) tvars = re_replace_archive_vars.findall( conf.archive_filename_scheme) # create mapping, removing duplicates mapping = dict(zip(tvars, parts)) # create date from mapping tdate = datetime.datetime.strptime(" ".join(mapping.values()), " ".join(mapping)) # if filename matches date range if args.from_date <= tdate <= args.to_date: # load todo list res = TodoList(fn) # get items directly if they are done or report items archived_items = [ item for item in res.todolist if item.done or item.is_report ] for item in archived_items: # replace id with (A) to mark it as archived item.replace_or_add_prop(conf.ID, "(A)") # append it to candidates report_list.extend(archived_items) # sort filtered list by "done" date report_list.sort(key=lambda x: x.done_date or na_date) nr = 0 # group report/done items by date for keys, groups in groupby( report_list, lambda x: ((x.done_date or na_date).year, (x.done_date or na_date).month, (x.done_date or na_date).day)): # we are looking at that date right now temp_date = datetime.datetime(year=keys[0], month=keys[1], day=keys[2]) # that date does not match the requested date range: skip if not args.from_date <= temp_date <= args.to_date: continue # filter out default dates again if is_same_day(na_date, temp_date): print(u"Report for unknown date:") else: print(u"Report for {date}:".format( date=temp_date.strftime("%A, %Y-%m-%d"))) # print the items, finally for item in groups: print(" ", cr.render(item)) nr += 1 suppress_if_quiet(u"{nr} todo items displayed.".format(nr=nr), args)
def cmd_report(tl, args): """shows a daily report of all done and report items """ with ColorRenderer() as cr: # default date used when no done date is specified na_date = datetime.datetime(1970, 1, 1, 0, 0, 0, 0) # today now = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) # check from and to date, make them datetime or None # what mode are we in? mode = None if args.from_date in ("*", "all"): mode, args.from_date, args.to_date = "ALL", na_date, now else: args.from_date = to_date(args.from_date) args.to_date = to_date(args.to_date) if isinstance(args.from_date, datetime.datetime): args.from_date = args.from_date.replace(hour=0, minute=0, second=0, microsecond=0) else: logger.debug(u"Cannot parse {date}".format(date = args.from_date)) args.from_date = None if isinstance(args.to_date, datetime.datetime): args.to_date = args.to_date.replace(hour=0, minute=0, second=0, microsecond=0) else: logger.debug(u"Cannot parse {date}".format(date = args.to_date)) args.to_date = None if args.from_date and args.to_date and not mode: mode = "RANGE" elif args.from_date and not args.to_date: mode, args.to_date = "DAY", args.from_date elif not mode: # last 7 days mode, args.from_date, args.to_date = "LASTWEEK", now - datetime.timedelta(days=7), now # swap dates, if necessary if args.from_date > args.to_date: args.from_date, args.to_date = args.to_date, args.from_date # set end date to end of day args.to_date = args.to_date.replace(hour=23, minute=59, second=59) logger.debug(u"Report mode {0}: from {1} to {2}".format(mode, args.from_date, args.to_date)) # get list of done and report items from current todo list report_list = list(tl.list_items(lambda x: (x.done or x.is_report))) # get list of done and report items from un-dated archive file root_dir = os.path.dirname(conf.todo_file) unsorted_fn = os.path.join(root_dir, conf.archive_unsorted_filename) if os.path.exists(unsorted_fn): res = TodoList(unsorted_fn) report_list.extend(res.todolist) # get all archive file names in list file_pattern = re_replace_archive_vars.sub("*", conf.archive_filename_scheme) file_list = glob.glob(os.path.join(root_dir, file_pattern)) # regex for finding all replaced parts in archive filename scheme re_find_date_str = re_replace_archive_vars.sub("(.+)", conf.archive_filename_scheme).replace("\\", "\\\\") re_find_date = re.compile(re_find_date_str, re.UNICODE) # loop through all files and see, whether they match the given date range for fn in file_list: # get all replaced values in filename parts = re_find_date.findall(fn)[0] # get the variables responsible for this substitution (e.archived_items. "%Y", "%m", ...) tvars = re_replace_archive_vars.findall(conf.archive_filename_scheme) # create mapping, removing duplicates mapping = dict(zip(tvars, parts)) # create date from mapping tdate = datetime.datetime.strptime(" ".join(mapping.values()), " ".join(mapping)) # if filename matches date range if args.from_date <= tdate <= args.to_date: # load todo list res = TodoList(fn) # get items directly if they are done or report items archived_items = [item for item in res.todolist if item.done or item.is_report] for item in archived_items: # replace id with (A) to mark it as archived item.replace_or_add_prop(conf.ID, "(A)") # append it to candidates report_list.extend(archived_items) # sort filtered list by "done" date report_list.sort(key=lambda x: x.done_date or na_date) nr = 0 # group report/done items by date for keys, groups in groupby(report_list, lambda x: ((x.done_date or na_date).year, (x.done_date or na_date).month, (x.done_date or na_date).day) ): # we are looking at that date right now temp_date = datetime.datetime(year=keys[0], month=keys[1], day=keys[2]) # that date does not match the requested date range: skip if not args.from_date <= temp_date <= args.to_date: continue # filter out default dates again if is_same_day(na_date, temp_date): print(u"Report for unknown date:") else: print(u"Report for {date}:".format(date = temp_date.strftime("%A, %Y-%m-%d"))) # print the items, finally for item in groups: print(" ", cr.render(item)) nr += 1 suppress_if_quiet(u"{nr} todo items displayed.".format(nr = nr), args)