From 868ddec8ccc4678165c6d9aa71fc836cf40e7b9c Mon Sep 17 00:00:00 2001 From: DeutscheGabanna Date: Fri, 2 Aug 2024 18:11:04 +0200 Subject: [PATCH] fix(#21): Fix typo in CLI options - Fix a bug not caught by automated testing in PR #21 - unknown variable `frontmatter_tags` (actual variable: `front_matter_tags`) - Nest EntryBuilder inside EntriesFromBuilder instead of having them decoupled (why would you ever use an EntriesFromBuilder to create files if you won't populate them with actual Entries, therefore the use of EntryBuilder is almost unavoidable) - Improve `__repr__` method for `Librarian` class - Change the default front-matter tag from `daily` to `daylio` - Output entry time in 24-hour format --- src/daylio_to_md/__main__.py | 5 ++--- src/daylio_to_md/config.py | 10 ++++----- src/daylio_to_md/group.py | 18 +++++++++++++-- src/daylio_to_md/librarian.py | 12 +++++++++- tests/files/scenarios/ok/expect/2022-10-25.md | 8 +++---- tests/files/scenarios/ok/expect/2022-10-26.md | 14 ++++++------ tests/files/scenarios/ok/expect/2022-10-27.md | 6 ++--- tests/files/scenarios/ok/expect/2022-10-30.md | 4 ++-- tests/test_librarian.py | 22 +++++++++---------- tests/test_output.py | 21 +++++++++++------- 10 files changed, 74 insertions(+), 46 deletions(-) diff --git a/src/daylio_to_md/__main__.py b/src/daylio_to_md/__main__.py index d875cff..a5af0f6 100644 --- a/src/daylio_to_md/__main__.py +++ b/src/daylio_to_md/__main__.py @@ -24,14 +24,13 @@ def main(): cli_options.suffix ) file_template = EntriesFromBuilder( - cli_options.frontmatter_tags, + cli_options.front_matter_tags, entry_template ) Librarian( cli_options.filepath, cli_options.destination, - entries_from_builder=file_template, - entry_builder=entry_template + entries_from_builder=file_template ).output_all() diff --git a/src/daylio_to_md/config.py b/src/daylio_to_md/config.py index 4358084..5ad7234 100755 --- a/src/daylio_to_md/config.py +++ b/src/daylio_to_md/config.py @@ -41,7 +41,7 @@ "force", "csv_delimiter", "header_level", - "frontmatter_tags", + "front_matter_tags", "prefix", "suffix", "tag_activities", @@ -101,11 +101,11 @@ def parse_console(args: List[Any]) -> argparse.Namespace: "File structure" ) file_structure_settings.add_argument( - "--frontmatter_tags", + "--front_matter_tags", help="Tags in the YAML of each note.", nargs='*', # this allows, for example, "--frontmatter_tags one two three" --> ["one", "two", "three"] - default=DEFAULTS.frontmatter_tags, - dest="TAGS" + default=DEFAULTS.front_matter_tags, + dest="front_matter_tags" ) """------------------------------------------------------------------------------------------------------------- JOURNAL ENTRY FORMATTING SETTINGS TO ARGPARSE @@ -128,7 +128,7 @@ def parse_console(args: List[Any]) -> argparse.Namespace: journal_entry_settings.add_argument( "--tag_activities", "-a", default=DEFAULTS.tag_activities, - help="Tries to convert activities into valid frontmatter tags.", + help="Tries to convert activities into valid front-matter tags.", dest="tag_activities" ) journal_entry_settings.add_argument( diff --git a/src/daylio_to_md/group.py b/src/daylio_to_md/group.py index ae205c0..f645a12 100644 --- a/src/daylio_to_md/group.py +++ b/src/daylio_to_md/group.py @@ -60,7 +60,7 @@ class EntriesFromBuilder: :param front_matter_tags: Tags in the YAML front-matter of each note :param entries_builder: Builder configured to create new :class:`Entry` objects """ - front_matter_tags: tuple[str] = DEFAULTS.frontmatter_tags + front_matter_tags: tuple[str] = DEFAULTS.front_matter_tags entries_builder: journal_entry.EntryBuilder = field(default_factory=journal_entry.EntryBuilder) def build(self, @@ -110,6 +110,11 @@ def __init__(self, entries_builder: journal_entry.EntryBuilder = journal_entry.EntryBuilder(), mood_set: Moodverse = Moodverse()): + # __new__ calls __init__ every time, even if it only returns the reference to an already existing object + # this skips __init__ if returning such an instance, since initialisation has already been done + if hasattr(self, "_initialised"): + return + self.__logger = logging.getLogger(self.__class__.__name__) super().__init__(utils.guess_date_type(date)) @@ -119,6 +124,8 @@ def __init__(self, self.__known_entries: dict[datetime.time, Entry] = {} self.__known_moods: Moodverse = mood_set + self._initialised = True + def create_entry(self, line: dict[str, str]) -> None: """ Create :class:`Entry` object with the specified parameters. @@ -221,7 +228,7 @@ def output(self, stream: io.IOBase | typing.IO) -> int: # > use a single '\n' instead, on all platforms. # https://docs.python.org/3.10/library/os.html#os.linesep chars_written += stream.write("---" + "\n") - chars_written += stream.write("frontmatter_tags: " + ",".join(valid_tags) + "\n") + chars_written += stream.write("tags: " + ",".join(valid_tags) + "\n") chars_written += stream.write("---" + "\n" * 2) # THE ACTUAL ENTRY CONTENTS @@ -258,3 +265,10 @@ def __eq__(self, other) -> bool: def __str__(self): """:return: the date that groups entries written on that day in ``YYYY-MM-DD`` format""" return self.uid.strftime("%Y-%m-%d") + + def __len__(self): + """:return: how many entries it groups on that particular date""" + return len(self.__known_entries) + + def __repr__(self): + return f"{self.__class__.__name__}(date={self.date}, entries={len(self.__known_entries)})" diff --git a/src/daylio_to_md/librarian.py b/src/daylio_to_md/librarian.py index 5f8a785..a85c1bc 100644 --- a/src/daylio_to_md/librarian.py +++ b/src/daylio_to_md/librarian.py @@ -123,6 +123,7 @@ def __init__(self, :raises EmptyJournalError: if the file does not produce any valid results after processing. """ self.__logger = logging.getLogger(self.__class__.__name__) + self.__filepath = path_to_file self.__known_dates: dict[datetime.date, EntriesFrom] = {} self.__entries_from_builder = entries_from_builder self.__entry_builder = entry_builder @@ -315,5 +316,14 @@ def __setitem__(self, self.__known_dates[date] = value @property - def current_mood_set(self): + def mood_set(self): return self.__mood_set + + def __repr__(self): + total_entries = sum(len(entries_on_that_day) for entries_on_that_day in self.__known_dates.values()) + str_entries_from = [str(entry) for entry in self.__known_dates.keys()] + return (f"{self.__class__.__name__}(" + f"from={self.__filepath}, " + f"to={self.__destination}, " + f"total_entries={total_entries}, " + f"entries_from={str_entries_from})") diff --git a/tests/files/scenarios/ok/expect/2022-10-25.md b/tests/files/scenarios/ok/expect/2022-10-25.md index f0ec8a9..e6d6bef 100644 --- a/tests/files/scenarios/ok/expect/2022-10-25.md +++ b/tests/files/scenarios/ok/expect/2022-10-25.md @@ -1,13 +1,13 @@ --- -tags: daily +tags: daylio --- -## hungry | 11:36 PM | Mauris vitae nunc vel arcu consequat auctor +## hungry | 23:36 | Mauris vitae nunc vel arcu consequat auctor #allegro #working-remotely #colleague-interaction Nulla vel risus eget magna lacinia aliquam ac in arcu. -## rad | 11:40 PM +## rad | 23:40 Uet nulla nunc lobortis quisque. -## vaguely ok | 5:00 PM +## vaguely ok | 17:00 diff --git a/tests/files/scenarios/ok/expect/2022-10-26.md b/tests/files/scenarios/ok/expect/2022-10-26.md index b22e48e..3b3afa6 100644 --- a/tests/files/scenarios/ok/expect/2022-10-26.md +++ b/tests/files/scenarios/ok/expect/2022-10-26.md @@ -1,28 +1,28 @@ --- -tags: daily +tags: daylio --- -## captivated | 10:00 PM +## captivated | 22:00 #at-the-office #board-game #colleague-interaction #big-social-gathering Sed ut est interdum -## tired | 8:00 PM | Mauris rutrum diam +## tired | 20:00 | Mauris rutrum diam #allegro #at-the-office #board-game #colleague-interaction #big-social-gathering Quisque dictum odio quis augue consectetur, at convallis żodio aliquam. -## grateful | 7:30 PM | Aliquam nec sem semper +## grateful | 19:30 | Aliquam nec sem semper #allegro #at-the-office #acknowledged-efforts #colleague-interaction Nulla aćcumsan sem sit amet lectus pretium, ac interdum tellus porta. -## blissful | 1:00 PM | Vestibulum sagittis leo eu sodales +## blissful | 13:00 | Vestibulum sagittis leo eu sodales #allegro #at-the-office Ut et elit id lectus hendrerit ełementum quis auctor ipsum. -## in awe | 9:00 AM | Integer elementum +## in awe | 09:00 | Integer elementum #allegro #at-the-office #outdoors #notable-event Nunc lobortis enim eu nisi ultrices, sit amet sagittis lacus venenatis. -## lifeless | 7:50 AM | Nulla quis lectus pulvinar +## lifeless | 07:50 | Nulla quis lectus pulvinar #podcast #politics #world-event Etiam commódo enim ut orci varius viverra. diff --git a/tests/files/scenarios/ok/expect/2022-10-27.md b/tests/files/scenarios/ok/expect/2022-10-27.md index 6166989..d95c568 100644 --- a/tests/files/scenarios/ok/expect/2022-10-27.md +++ b/tests/files/scenarios/ok/expect/2022-10-27.md @@ -1,12 +1,12 @@ --- -tags: daily +tags: daylio --- -## vaguely good | 1:49 PM | Cras pretium +## vaguely good | 13:49 | Cras pretium #chess Lorem ipsum dolor sit amet, consectetur adipiscing elit. -## fatigued | 12:00 AM | Suspendisse sit amet +## fatigued | 00:00 | Suspendisse sit amet #allegro #working-remotely Phaśellus pharetra justo ac dui lacinia ullamcorper. diff --git a/tests/files/scenarios/ok/expect/2022-10-30.md b/tests/files/scenarios/ok/expect/2022-10-30.md index 3c88ad3..16c0647 100644 --- a/tests/files/scenarios/ok/expect/2022-10-30.md +++ b/tests/files/scenarios/ok/expect/2022-10-30.md @@ -1,8 +1,8 @@ --- -tags: daily +tags: daylio --- -## vaguely ok | 10:04 AM | Dolomet +## vaguely ok | 10:04 | Dolomet #2ćities-skylines #dólóó-fas_ą Lorem ipsum sit dolomet amęt. diff --git a/tests/test_librarian.py b/tests/test_librarian.py index a978887..ee9d5f2 100644 --- a/tests/test_librarian.py +++ b/tests/test_librarian.py @@ -88,13 +88,13 @@ def test_custom_moods_when_passed_correctly(self): self.assertTrue(Librarian( path_to_file="tests/files/all-valid.csv", path_to_moods="tests/files/all-valid.json" - ).current_mood_set.get_custom_moods) + ).mood_set.get_custom_moods) @suppress.out def test_custom_moods_when_not_passed(self): """Pass no moods and see if it know it only has standard moods available.""" lib = Librarian(path_to_file="tests/files/all-valid.csv") - self.assertEqual(0, len(lib.current_mood_set.get_custom_moods), msg=lib.current_mood_set) + self.assertEqual(0, len(lib.mood_set.get_custom_moods), msg=lib.mood_set) @suppress.out def test_custom_moods_with_invalid_jsons(self): @@ -103,7 +103,7 @@ def test_custom_moods_with_invalid_jsons(self): path_to_file="tests/files/all-valid.csv", path_to_moods="tests/files/scenarios/fail/empty.csv" ) - self.assertEqual(0, len(lib.current_mood_set.get_custom_moods)) + self.assertEqual(0, len(lib.mood_set.get_custom_moods)) @suppress.out def test_custom_moods_when_json_invalid(self): @@ -112,9 +112,9 @@ def test_custom_moods_when_json_invalid(self): path_to_moods="tests/files/scenarios/fail/empty.csv" ) default = Moodverse() - self.assertDictEqual(lib.current_mood_set.get_moods, default.get_moods, + self.assertDictEqual(lib.mood_set.get_moods, default.get_moods, msg="\n".join([ - "current ID:\t" + str(id(lib.current_mood_set)), + "current ID:\t" + str(id(lib.mood_set)), "default object ID:\t" + str(id(default)) ]) ) @@ -122,16 +122,16 @@ def test_custom_moods_when_json_invalid(self): path_to_file="tests/files/all-valid.csv", path_to_moods="tests/files/scenarios/fail/empty.csv" ) - self.assertDictEqual(lib.current_mood_set.get_moods, default.get_moods, + self.assertDictEqual(lib.mood_set.get_moods, default.get_moods, msg="\n".join([ - "current ID:\t" + str(id(lib.current_mood_set)), + "current ID:\t" + str(id(lib.mood_set)), "default object ID:\t" + str(id(default)) ]) ) # TODO: move locked folder and locked file tests into Docker run - self.assertDictEqual(lib.current_mood_set.get_moods, default.get_moods, + self.assertDictEqual(lib.mood_set.get_moods, default.get_moods, msg="\n".join([ - "current ID:\t" + str(id(lib.current_mood_set)), + "current ID:\t" + str(id(lib.mood_set)), "default object ID:\t" + str(id(default)) ]) ) @@ -150,5 +150,5 @@ def test_custom_moods_that_are_incomplete(self): entries_from_builder=custom_config ) # There are 11 moods, out of which one is a duplicate of a default mood, so 10 custom in total - self.assertEqual(10, len(lib_to_test.current_mood_set.get_custom_moods), - msg=lib_to_test.current_mood_set.get_custom_moods.keys()) + self.assertEqual(10, len(lib_to_test.mood_set.get_custom_moods), + msg=lib_to_test.mood_set.get_custom_moods.keys()) diff --git a/tests/test_output.py b/tests/test_output.py index 7b1b109..a6ac7d7 100644 --- a/tests/test_output.py +++ b/tests/test_output.py @@ -170,6 +170,11 @@ def test_header_multiplier(self): class TestDatedEntriesGroup(TestCase): + def setUp(self): + # It's okay to store information on created instances in a single run for a normal user, not for repeated tests + # Therefore we reset the memory of the class before every test + EntriesFrom._instances = {} + @suppress.out def test_outputting_day_with_one_entry(self): """ @@ -192,7 +197,7 @@ def test_outputting_day_with_one_entry(self): # Then create another stream and fill it with the same content, but written directly, not through object with io.StringIO() as compare_stream: compare_stream.write("---" + "\n") - compare_stream.write("frontmatter_tags: daylio" + "\n") + compare_stream.write("tags: daylio" + "\n") compare_stream.write("---" + "\n" * 2) compare_stream.write("## vaguely ok | 10:00" + "\n" * 2) @@ -230,7 +235,7 @@ def test_outputting_day_with_two_entries(self): # Then create another stream and fill it with the same content, but written directly, not through object with io.StringIO() as compare_stream: compare_stream.write("---" + "\n") - compare_stream.write("frontmatter_tags: daylio" + "\n") + compare_stream.write("tags: daylio" + "\n") compare_stream.write("---" + "\n" * 2) compare_stream.write("## vaguely ok | 10:00" + "\n") @@ -314,7 +319,7 @@ def test_outputting_day_with_two_entries_and_partially_valid_filetags(self): # Then create another stream and fill it with the same content, but written directly, not through object with io.StringIO() as compare_stream: compare_stream.write("---" + "\n") - compare_stream.write("frontmatter_tags: bar,foo" + "\n") + compare_stream.write("tags: bar,foo" + "\n") compare_stream.write("---" + "\n" * 2) compare_stream.write("## vaguely ok | 10:00" + "\n") @@ -337,25 +342,25 @@ class TestOutputFileStructure(TestCase): @suppress.out def test_directory_loop(self): """ - Loops through known dates and asks each :class:`DatedEntriesGroup` to output its contents to a specified file. + Loops through known dates and asks each :class:`EntriesFrom` to output its contents to a specified file. """ lib = Librarian("tests/files/all-valid.csv", path_to_output="tests/files/scenarios/ok/out") lib.output_all() - with open("tests/files/scenarios/ok/expect/2022-10-25.md", encoding="UTF-8") as parsed_result, \ + with open("tests/files/scenarios/ok/out/2022/10/2022-10-25.md", encoding="UTF-8") as parsed_result, \ open("tests/files/scenarios/ok/expect/2022-10-25.md", encoding="UTF-8") as expected_result: self.assertListEqual(expected_result.readlines(), parsed_result.readlines()) - with open("tests/files/scenarios/ok/expect//2022-10-26.md", encoding="UTF-8") as parsed_result, \ + with open("tests/files/scenarios/ok/out/2022/10/2022-10-26.md", encoding="UTF-8") as parsed_result, \ open("tests/files/scenarios/ok/expect/2022-10-26.md", encoding="UTF-8") as expected_result: self.assertListEqual(expected_result.readlines(), parsed_result.readlines()) - with open("tests/files/scenarios/ok/expect/2022-10-27.md", encoding="UTF-8") as parsed_result, \ + with open("tests/files/scenarios/ok/out/2022/10/2022-10-27.md", encoding="UTF-8") as parsed_result, \ open("tests/files/scenarios/ok/expect/2022-10-27.md", encoding="UTF-8") as expected_result: self.assertListEqual(expected_result.readlines(), parsed_result.readlines()) - with open("tests/files/scenarios/ok/expect/2022-10-30.md", encoding="UTF-8") as parsed_result, \ + with open("tests/files/scenarios/ok/out/2022/10/2022-10-30.md", encoding="UTF-8") as parsed_result, \ open("tests/files/scenarios/ok/expect/2022-10-30.md", encoding="UTF-8") as expected_result: self.assertListEqual(expected_result.readlines(), parsed_result.readlines())