def __check_datestamp_correctness(self, datestamp): """ Checks a datestamp 'YYYY.MM.DD' if its components are a valid date. """ if len(datestamp) != 10: return False try: year = int(datestamp[:4]) month = int(datestamp[5:7]) day = int(datestamp[8:10]) except ValueError: logging.debug( '__check_datestamp_correctness(' + str(datestamp) + ') does not follow YYYY-MM-DD with integers as components for year, month, day.' ) return False if year < 1900 or \ year > 2100 or \ month < 1 or \ month > 12 or \ day < 1 or \ day > 31: logging.debug('__check_datestamp_correctness(' + str(datestamp) + ') NEGATIVE') return False else: try: orgdate = OrgFormat.strdate(datestamp) except ValueError: return False return True
def test_strdate(self): self.assertEqual(OrgFormat.strdate('2011-11-03'), '<2011-11-03 Thu>') self.assertEqual(OrgFormat.strdate('2011-11-3'), '<2011-11-03 Thu>') self.assertEqual(OrgFormat.strdate('2011-1-3'), '<2011-01-03 Mon>') with self.assertRaises(TimestampParseException): OrgFormat.strdate('11-1-3') self.assertEqual(OrgFormat.strdate('2011-11-03', show_time=True), '<2011-11-03 Thu 00:00>') self.assertEqual(OrgFormat.strdate('2011-11-03', inactive=True), '[2011-11-03 Thu]') self.assertEqual(OrgFormat.strdate('2011-11-03', inactive=True, show_time=True), '[2011-11-03 Thu 00:00]') self.assertEqual(OrgFormat.strdate('2011-11-03 23:59'), '<2011-11-03 Thu>') self.assertEqual(OrgFormat.strdate('2011-11-03 23:59:00'), '<2011-11-03 Thu>') self.assertEqual(OrgFormat.strdate('2011-11-03 23:59', show_time=True), '<2011-11-03 Thu 23:59>') self.assertEqual(OrgFormat.strdate('2011-11-03 23:59:00', show_time=True), '<2011-11-03 Thu 23:59>') self.assertEqual(OrgFormat.strdate('2011-1-2 3:4:5', show_time=True), '<2011-01-02 Sun 03:04>') self.assertEqual(OrgFormat.strdate('2011-11-03 23:59', show_time=False), '<2011-11-03 Thu>') self.assertEqual(OrgFormat.strdate('2011-11-03 23:59', inactive=True, show_time=True), '[2011-11-03 Thu 23:59]') self.assertEqual(OrgFormat.strdate('2011-11-03T23:59'), '<2011-11-03 Thu>') self.assertEqual(OrgFormat.strdate('2011-11-03T23:59:58'), '<2011-11-03 Thu>') self.assertEqual(OrgFormat.strdate('2011-11-03T23.59'), '<2011-11-03 Thu>') self.assertEqual(OrgFormat.strdate('2011-11-03T23.59:58'), '<2011-11-03 Thu>') with self.assertRaises(TimestampParseException): OrgFormat.strdate('foo') with self.assertRaises(TimestampParseException): OrgFormat.strdate('2019-04-31 23:59') self.assertEqual(OrgFormat.strdate('2011-11-30T21.06', show_time=True), '<2011-11-30 Wed 21:06>') self.assertEqual(OrgFormat.strdate('2011-11-30T21.06.00', show_time=True), '<2011-11-30 Wed 21:06>') self.assertEqual(OrgFormat.strdate('2011-11-30T21.06.02', show_time=True), '<2011-11-30 Wed 21:06>') self.assertEqual(OrgFormat.strdate('1899-12-30T21.06.02', show_time=True), '<1899-12-30 Sat 21:06>') self.assertEqual(OrgFormat.strdate('2011-11-30 21.06', show_time=True), '<2011-11-30 Wed 21:06>') self.assertEqual(OrgFormat.strdate('2011-11-30 21.06.02', show_time=True), '<2011-11-30 Wed 21:06>') self.assertEqual(OrgFormat.strdate('2011-11-30 21:06:02', show_time=True), '<2011-11-30 Wed 21:06>') self.assertEqual(OrgFormat.strdate('2011-11-30 21:06', show_time=True), '<2011-11-30 Wed 21:06>')
def test_generate_heading(self): ## minimal heading with all parameters provided: self.assertEqual( OrgFormat.generate_heading(level=2, keyword=None, priority=None, title=None, tags=None, scheduled_timestamp=None, deadline_timestamp=None, properties=None, section=None), '** \n') ## maximal heading with all parameters as named parameters: self.assertEqual( OrgFormat.generate_heading( level=1, keyword='TODO', priority='A', title='This is my title', tags=['foo', 'bar_baz'], scheduled_timestamp='<2019-12-29 Sun 11:35>', deadline_timestamp='<2019-12-30 Mon 23:59>', properties=[('CREATED', OrgFormat.strdate('2011-11-03 23:59', inactive=True, show_time=True)), ('myproperty', 'foo bar baz')], section=' With this being\nthe content of the heading section.' ), '''* TODO [#A] This is my title :foo:bar_baz: SCHEDULED: <2019-12-29 Sun 11:35> DEADLINE: <2019-12-30 Mon 23:59> :PROPERTIES: :CREATED: [2011-11-03 Thu 23:59] :myproperty: foo bar baz :END: With this being the content of the heading section. ''') ## heading with title + one property with all named parameters: self.assertEqual( OrgFormat.generate_heading(level=3, keyword=None, priority=None, title='This is my title', tags=None, properties=[('CREATED', OrgFormat.strdate( '2011-11-03 23:59', inactive=True, show_time=True))], section=None), '''*** This is my title :PROPERTIES: :CREATED: [2011-11-03 Thu 23:59] :END: ''') ## heading with title + one property with selected named parameters: self.assertEqual( OrgFormat.generate_heading(level=3, title='This is my title', properties=[('CREATED', OrgFormat.strdate( '2011-11-03 23:59', inactive=True, show_time=True))]), '''*** This is my title :PROPERTIES: :CREATED: [2011-11-03 Thu 23:59] :END: ''') ## simple heading: self.assertEqual( OrgFormat.generate_heading(7, title='This is my title'), '''******* This is my title ''') ## simple heading with section: self.assertEqual( OrgFormat.generate_heading(7, title='This is my title', section='Let\'s test the format here.'), '''******* This is my title Let's test the format here. ''') ## simple heading with section and DEADLINE: self.assertEqual( OrgFormat.generate_heading(7, deadline_timestamp='<2019-12-29 Sun>', title='This is my title', section='Let\'s test the format here.'), '''******* This is my title DEADLINE: <2019-12-29 Sun> Let's test the format here. ''') ## simple heading with section and SCHEDULED: self.assertEqual( OrgFormat.generate_heading(7, scheduled_timestamp='<2019-12-29 Sun>', title='This is my title', section='Let\'s test the format here.'), '''******* This is my title SCHEDULED: <2019-12-29 Sun> Let's test the format here. ''')
def __handle_file(self, file, rootdir): """ handles a file (except ending with a tilde) """ # don't handle emacs tmp files (file~) if file[-1:] == '~': return link = os.path.join(rootdir, file) logging.debug('__handle_file: ' + '#' * 50) logging.debug('__handle_file: ' + link) orgdate = False # set to default value if self._args.force_filedate_extraction: # in this case, skip any clever # extraction mechanism to extract # date/time from file name and use # the mtime instead: logging.debug( '__handle_file: force_filedate_extraction: using datetime from mtime of file' ) file_datetime = time.localtime(os.path.getmtime(link)) orgdate = OrgFormat.date(file_datetime, show_time=True) self.__write_file(file, link, orgdate) return # very basic checks for correctness (e.g., month=20, hour=70) # are part of these RegEx (and do not have to be checked # below) filename_timestamp_match = DATETIME_REGEX.match(file) logging.debug('__handle_file: filename_timestamp_match? ' + str(filename_timestamp_match is True)) if filename_timestamp_match: # day1/2 are like 'YYYY-MM-DD' time1/2 like 'HH:MM': has_1ymd, has_1ymdhm, has_2ymd, has_2ymdhm, \ day1, time1, day2, time2 = self.__extract_days_and_times(filename_timestamp_match) # Note: following things are available for formatting: # self._args.inactive_timestamps -> Bool # OrgFormat.strdate('YYYY-MM-DD', inactive=False) -> <YYYY-MM-DD Sun> # OrgFormat.strdate('YYYY-MM-DD HH:MM', inactive=False, show_time=True) -> <YYYY-MM-DD Sun HH:MM> assert (has_1ymd) try: if has_1ymdhm: if self.__check_datestamp_correctness(day1): if self.__check_timestamp_correctness(time1): orgdate = OrgFormat.strdate( day1 + ' ' + time1, inactive=self._args.inactive_timestamps, show_time=True) else: logging.warning( 'File "' + file + '" has an invalid timestamp (' + str(time1) + '). Skipping this faulty time-stamp.') orgdate = OrgFormat.strdate( day1, inactive=self._args.inactive_timestamps) else: logging.warning('File "' + file + '" has an invalid datestamp (' + str(day1) + ').') # omit optional second day if first has an issue: has_2ymd = False has_2ymdhm = False orgdate = False elif has_1ymd: # missing time-stamp for day1 if self.__check_datestamp_correctness(day1): if not self._args.skip_filetime_extraction: # we've got only a day but we're able to determine # time from file mtime, if same as ISO day in file # name: logging.debug( '__handle_file: try to get file time from mtime if days match between mtime and filename ISO ...' ) file_datetime = time.localtime( os.path.getmtime(link)) if self.__check_if_days_in_timestamps_are_same( file_datetime, day1): orgdate = OrgFormat.date( file_datetime, inactive=self._args.inactive_timestamps, show_time=True) else: logging.debug( '__handle_file: day of mtime and filename ISO differs, using filename ISO day' ) orgdate = OrgFormat.strdate( day1, inactive=self._args.inactive_timestamps) else: # we've got only a day and determining mtime # is not planned, so use the day as date-stamp orgdate = OrgFormat.strdate( day1, inactive=self._args.inactive_timestamps) else: logging.warning('File "' + file + '" has an invalid datestamp (' + str(day1) + ').') orgdate = False else: logging.warning('File "' + file + '" has an invalid datestamp (' + str(day1) + '). Skipping this faulty date.') # omit optional second day if first has an issue: has_2ymd = False has_2ymdhm = False # there is a time range: if has_2ymdhm: assert (day2) if self.__check_datestamp_correctness(day2): if self.__check_timestamp_correctness(time2): orgdate += '--' + OrgFormat.strdate( day2 + ' ' + time2, inactive=self._args.inactive_timestamps, show_time=True) else: logging.warning( 'File "' + file + '" has an invalid timestamp (' + str(time2) + '). Skipping this faulty time-stamp.') orgdate += '--' + OrgFormat.strdate( day2, inactive=self._args.inactive_timestamps) else: logging.warning('File "' + file + '" has an invalid datestamp (' + str(day2) + '). Skipping this faulty date.') elif has_2ymd: assert (day2) if self.__check_datestamp_correctness(day2): orgdate += '--' + OrgFormat.strdate( day2, inactive=self._args.inactive_timestamps) else: logging.warning('File "' + file + '" has an invalid datestamp (' + str(day2) + '). Skipping this faulty date.') except TimestampParseException: logging.error( 'File "' + str(file) + '" has in invalid date- or timestamp. OrgFormat of one of day1: "' + str(day1) + '" time1: "' + str(time1) + '" day2: "' + str(day2) + '" time2: "' + str(time2) + '" ' + 'failed with TimestampParseException. Skipping this faulty date.' ) orgdate = False else: logging.debug('__handle_file: no date- nor timestamp') orgdate = False if not orgdate and self._args.skip_notimestamp_files: logging.debug( '__handle_file: file had no or wrong time-stamp and you decided to skip them.' ) return self.__write_file(file, link, orgdate) logging.debug('__handle_file: using orgdate: ' + str(orgdate)) return