From e5435b19ac3c066a5d68c4a39ccba0c08a735cee Mon Sep 17 00:00:00 2001 From: Kyle Bowman Date: Sun, 19 Jan 2025 15:34:11 -0500 Subject: [PATCH] continue abstracting list and listItem --- src/nom/base.py | 51 ++++++++++++++++++++++++++++++++++++-------- src/nom/entry.py | 28 +++++++----------------- tests/data/entry.csv | 3 +++ 3 files changed, 53 insertions(+), 29 deletions(-) create mode 100644 tests/data/entry.csv diff --git a/src/nom/base.py b/src/nom/base.py index 4f90a1e..9b0ac0a 100644 --- a/src/nom/base.py +++ b/src/nom/base.py @@ -1,13 +1,17 @@ from pathlib import Path from csv import DictReader, DictWriter, excel_tab +from abc import abstractmethod +from typing import Sequence from nom.utils import NomError class NomListItem: + @classmethod + def get_fieldnames(cls): + return cls.__dataclass_fields__.keys() - # TODO: This technically doesn't follow the __repr__ pattern. # TODO: What if there's a pipe in one of the fields? def to_str(self, delimiter: str ='|'): return delimiter.join([v for v in self.__dict__.values()]) @@ -20,20 +24,49 @@ class NomListItem: return cls(**dct) -# NOTE: Implementation requires self.delimiter. class NomList: + # TODO: + def __init__(self, items=[], delimiter: str="|"): + self.delimiter=delimiter + self.items : list[NomListItem] = items + + # NOTE: To get the interface that I want (i.e `from_csv(path)`) + # each subclass must override from_csv and pass in the constructor + # of the corresponding ListItem. For example, for EntryList: + # ``` + # @classmethod + # def from_csv(cls, path): + # return super().from_csv(path, EntryListItem) + # ```` @classmethod - def from_csv(cls, file: Path): - pass + def from_csv(cls, file: Path, constructor: NomListItem, delimiter="|"): + items = [] + dialect = excel_tab + dialect.delimiter=delimiter + with open(file, "r") as f: + reader = DictReader(f,dialect=dialect) + for row in reader: + item = constructor(**row) + items.append(item) + return cls(items=items, delimiter=delimiter) def to_csv(self, file: Path): - if not self.dicts: + if not self.items: raise NomError("There are no entries to write.") + + fieldnames=self.items[0].get_fieldnames() + dialect = excel_tab + dialect.delimiter=self.delimiter with open(file, "w") as f: - dialect = excel_tab - dialect.delimiter=self.delimiter - writer = DictWriter(f, fieldnames=self.fieldnames, dialect=dialect) + writer = DictWriter(f, fieldnames=fieldnames, dialect=dialect) writer.writeheader() - writer.writerows(self.dicts) \ No newline at end of file + for item in self.items: + writer.writerow(item.to_dict()) + + def to_stdout(self): + if not self.items: + raise NomError("There are no entries to write.") + for item in self.items: + print(item.to_str()) \ No newline at end of file diff --git a/src/nom/entry.py b/src/nom/entry.py index 4aead27..0597a07 100644 --- a/src/nom/entry.py +++ b/src/nom/entry.py @@ -19,17 +19,11 @@ class EntryListItem(NomListItem): summary: Optional[str] = "" # TODO: Add this when you feel like stripping HTML - class EntryList(NomList): - def __init__(self, delimiter='|'): - self.entries : list[EntryListItem] = [] - self.dicts : list[dict] = [] - self.delimiter = delimiter - self.fieldnames = EntryListItem("","").to_dict().keys() - - def add_entry(self, entry): - self.entries.append(entry) + @classmethod + def from_csv(cls, path: Path): + return super().from_csv(path, EntryListItem) def update_from_feeds(self, feedlist): pass @@ -40,18 +34,12 @@ class EntryList(NomList): def from_stdout(self): pass - # TODO: Fix this with command line option - def to_stdout(self): - for entry in self.entries: - if entry: - print(entry.to_str()) - if __name__ == "__main__": dct = dict(id_="1", title="Entry One", url="https://path/to/entry1.html") path=Path("/home/kyle/projects/nom/tests/data/entry.csv") - elist = EntryList() - entry = EntryListItem.from_dict(dct) - elist.add_entry(entry) - elist.dicts = [entry.__dict__ for entry in elist.entries] - elist.to_csv(path) + #elist = EntryList() + #entry = EntryListItem.from_dict(dct) + #elist.add(entry) + #elist.to_csv(path) + elist=EntryList.from_csv(path) diff --git a/tests/data/entry.csv b/tests/data/entry.csv new file mode 100644 index 0000000..92966eb --- /dev/null +++ b/tests/data/entry.csv @@ -0,0 +1,3 @@ +id_|title|url|date|feed_url|feed_alias|viewed|summary +1|Entry One|https://path/to/entry1.html|test|||False| +2|Entry Two|https://path/to/entry2.html|test|||False| -- 2.39.5