From 82e0e5b5bf50980054a6ab5e2547b6a52b57c9e8 Mon Sep 17 00:00:00 2001 From: Kyle Bowman Date: Sat, 25 Jan 2025 12:13:46 -0500 Subject: [PATCH] feat: add nom entry update; adapt show --- src/nom/base.py | 12 ++++-------- src/nom/main.py | 25 +++++++++++++++---------- tests/test_base.py | 16 ++++++++++++++++ tests/test_cli.py | 4 ++++ 4 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 tests/test_base.py diff --git a/src/nom/base.py b/src/nom/base.py index 77a89ef..ad13ae4 100644 --- a/src/nom/base.py +++ b/src/nom/base.py @@ -59,16 +59,11 @@ class NomList(set): print(item.to_str(delimeter="\t")) - # NOTE: To get the interface that I want (i.e `from_csv(path)`) - # each subclass must override from_csv and pass in the NomListItem - # that has a to_dict() method. For example, for EntryList: - # ``` - # @classmethod - # def from_csv(cls, path): - # return super().from_csv(path, EntryListItem) - # ```` @classmethod def from_csv(cls, file: Path, nlitem: NomListItem, delimiter="|"): + # To parse NomListItems in a file, specify a specific NomListItem + if nlitem == NomListItem or type(nlitem) == NomListItem: + raise NotImplementedError(f"Override this method with super().__init__(file, {str(cls()).replace('()','')}Item) to enforce item parsing.") items = [] dialect = excel_tab dialect.delimiter=delimiter @@ -82,6 +77,7 @@ class NomList(set): def to_csv(self, file: Path, delimiter="|"): if not self: raise NomError("There are no entries to write.") + file.parent.mkdir(parents=True,exist_ok=True) fieldnames=next(iter(self)).get_fieldnames() dialect = excel_tab diff --git a/src/nom/main.py b/src/nom/main.py index f0e625e..6b62e68 100644 --- a/src/nom/main.py +++ b/src/nom/main.py @@ -8,24 +8,25 @@ from nom.entry import EntryList # Globals. Sue me. FEED_CACHE=Path.home() / ".cache" / "nom" / "feeds" -FEED_LIST=Path.home() / ".local" / "share" / "nom" / "feedlist" / "default" - +FEED_LIST=Path.home() / ".local" / "share" / "nom" / "feedlist" / "default" +ENTRY_LIST=Path.home() / ".local" / "share" / "nom" / "entrylist" / "default" def cli(): parser = ArgumentParser(description="Nom Script") subparsers = parser.add_subparsers(dest='command', help='Sub-command help') # Entry subcommand - entry_parser = subparsers.add_parser('entry', help='Entry related commands') - entry_subparsers = entry_parser.add_subparsers(dest='entry_command', help='Entry sub-command help') - entry_show_parser = entry_subparsers.add_parser('show', help='Show entries') + entry_parser = subparsers.add_parser('entry', help='Dispatches commands that operate on a table of entries.') + entry_subparsers = entry_parser.add_subparsers(dest='entry_command', help='Dispatches entry commands.') + entry_show_parser = entry_subparsers.add_parser('show', help='Show entries.') + entry_update_parser = entry_subparsers.add_parser('update', help='Update entry data.') # Feed subcommand - feed_parser = subparsers.add_parser('feed', help='Feed related commands') - feed_subparsers = feed_parser.add_subparsers(dest='feed_command', help='Feed sub-command help') + feed_parser = subparsers.add_parser('feed', help='Dispatches commands that operate on a table of feeds.') + feed_subparsers = feed_parser.add_subparsers(dest='feed_command', help='Dispatches feed commands.') feed_update_parser = feed_subparsers.add_parser('update', help='Update feed') - feed_update_parser = feed_subparsers.add_parser('show', help='Show feeds') - + feed_show_parser = feed_subparsers.add_parser('show', help='Show feeds') + return parser @@ -35,10 +36,14 @@ def main(args=['nom'].append(sys.argv)): # Dispatch Logic feedlist=FeedList.from_csv(FEED_LIST) - if args.command == "entry" and args.entry_command == "show": + if args.command == "entry" and args.entry_command == "update": elist=EntryList() for flitem in feedlist: elist += flitem.to_feed().to_entrylist() + print(f"Updating from [{str(flitem)}]") + elist.to_csv(ENTRY_LIST) + elif args.command == "entry" and args.entry_command == "show": + elist = EntryList.from_csv(ENTRY_LIST) elist.to_stdout() elif args.command == "feed" and args.feed_command == "update": feedlist.fetch_feeds(FEED_CACHE) diff --git a/tests/test_base.py b/tests/test_base.py new file mode 100644 index 0000000..492a89c --- /dev/null +++ b/tests/test_base.py @@ -0,0 +1,16 @@ +# Note: The base module isn't meant to be used directly, but instead is meant +# to be subclassed from. In general, it makes more sense to test the subclasses +# than it does to test the base class. + +import pytest +from pathlib import Path +from nom.base import NomList, NomListItem + + + +def test_from_csv_error(): + class DummyList(NomList): + pass + path = Path(__file__).parent / "data" / "entry_single.csv" + with pytest.raises(NotImplementedError): + nlist=DummyList.from_csv(path, NomListItem) diff --git a/tests/test_cli.py b/tests/test_cli.py index 7e7036b..8713778 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -11,4 +11,8 @@ def test_nom_feed_update(): def test_nom_feed_show(): main(args='feed show'.split(' ')) + assert True + +def test_nom_entry_update(): + main(args='entry update'.split(' ')) assert True \ No newline at end of file -- 2.39.5