From f0e194b62012c1e9e6b8a219c894f1020694a81a Mon Sep 17 00:00:00 2001 From: Kyron Longwood Date: Wed, 17 Apr 2024 23:42:50 -0400 Subject: [PATCH 1/2] Fixes kiwiz/gkeepapi#122 --- src/gkeepapi/node.py | 35 +++++++++++++++++++++++++++++++++++ test/test_nodes.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/gkeepapi/node.py b/src/gkeepapi/node.py index 1b9cc53..80d5233 100644 --- a/src/gkeepapi/node.py +++ b/src/gkeepapi/node.py @@ -1726,6 +1726,22 @@ def _get_text_node(self) -> ListItem | None: break return node + + def to_list(self) -> "List": + """Converts note to a list. + + Returns: + List node. + """ + node = List() + if self.title is not None: + node.title = self.title + + sort = random.randint(1000000000, 9999999999) # noqa: S311 + for text in self.text.split("\n"): + node.add(text, False, sort) + sort -= List.SORT_DELTA + return node @property def text(self) -> str: # noqa: D102 @@ -1846,6 +1862,25 @@ def key_func(x: ListItem) -> T: return T((int(x.sort),)) return sorted(items, key=key_func, reverse=True) + + def to_note(self) -> Note: + """Converts list to a note. + + Returns: + Note node. + """ + node = Note() + if self.title is not None: + node.title = self.title + + if self.text is not None: + node.text = "\n".join([n.text for n in self.items]) + else: + node.text = "" + return node + + + def _items(self, checked: bool | None = None) -> list[ListItem]: return [ diff --git a/test/test_nodes.py b/test/test_nodes.py index 0ea29ab..8a6b65e 100644 --- a/test/test_nodes.py +++ b/test/test_nodes.py @@ -506,7 +506,25 @@ def test_str(self): n.text = TEXT self.assertEqual("%s\n%s" % (TITLE, TEXT), str(n)) self.assertEqual(TEXT, n.text) + + def test_to_list(self): + n_note = node.Note() + TEXT = "a\nb\nc\nd\ne\nf" + n_note.text = TEXT + + n_list = node.List() + + n_list.add("a", sort=5) + n_list.add("b", sort=4) + n_list.add("c", sort=3) + n_list.add("d", sort=2) + n_list.add("e", sort=1) + n_list.add("f", sort=0) + + n = n_note.to_list() + + self.assertEqual(n_list.text, n.text) class ListTests(unittest.TestCase): def test_fields(self): @@ -623,6 +641,24 @@ def test_str(self): self.assertEqual(n_str, str(n)) self.assertEqual(n_text, n.text) + def test_to_note(self): + n_list = node.List() + + n_list.add("a", sort=5) + n_list.add("b", sort=4) + n_list.add("c", sort=3) + n_list.add("d", sort=2) + n_list.add("e", sort=1) + n_list.add("f", sort=0) + + n_note = node.Note() + + TEXT = "a\nb\nc\nd\ne\nf" + n_note.text = TEXT + + n = n_list.to_note() + + self.assertEqual(n_note.text, n.text) class ListItemTests(unittest.TestCase): def test_fields(self): From 3b821339b2a59057d0a0e37fbc8376f3856717c0 Mon Sep 17 00:00:00 2001 From: Kyron Longwood Date: Sun, 7 Jun 2026 09:55:43 -0400 Subject: [PATCH 2/2] Add Note/List conversion methods with metadata preservation --- src/gkeepapi/__init__.py | 28 ++++++++++++++++++++++++++++ src/gkeepapi/node.py | 33 ++++++++++++++++++++++----------- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/src/gkeepapi/__init__.py b/src/gkeepapi/__init__.py index b2185c1..0715a92 100644 --- a/src/gkeepapi/__init__.py +++ b/src/gkeepapi/__init__.py @@ -958,6 +958,34 @@ def createList( self.add(node) return node + def convertToList(self, note: _node.Note) -> _node.List: + """Convert a Note to a List. The note is trashed and the new list is registered for syncing. + + Args: + note: The note to convert. + + Returns: + The new list. + """ + node = note.to_list() + self.add(node) + note.trash() + return node + + def convertToNote(self, lst: _node.List) -> _node.Note: + """Convert a List to a Note. The list is trashed and the new note is registered for syncing. + + Args: + lst: The list to convert. + + Returns: + The new note. + """ + node = lst.to_note() + self.add(node) + lst.trash() + return node + def createLabel(self, name: str) -> _node.Label: """Create a new label. diff --git a/src/gkeepapi/node.py b/src/gkeepapi/node.py index 80d5233..77fe7f9 100644 --- a/src/gkeepapi/node.py +++ b/src/gkeepapi/node.py @@ -1734,9 +1734,16 @@ def to_list(self) -> "List": List node. """ node = List() - if self.title is not None: - node.title = self.title - + node.title = self.title + node.color = self._color + node.archived = self._archived + node.pinned = self._pinned + node.sort = self._sort + for label in self.labels.all(): + node.labels.add(label) + for email in self.collaborators.all(): + node.collaborators.add(email) + sort = random.randint(1000000000, 9999999999) # noqa: S311 for text in self.text.split("\n"): node.add(text, False, sort) @@ -1863,20 +1870,24 @@ def key_func(x: ListItem) -> T: return sorted(items, key=key_func, reverse=True) - def to_note(self) -> Note: + def to_note(self) -> "Note": """Converts list to a note. Returns: Note node. """ node = Note() - if self.title is not None: - node.title = self.title - - if self.text is not None: - node.text = "\n".join([n.text for n in self.items]) - else: - node.text = "" + node.title = self.title + node.color = self._color + node.archived = self._archived + node.pinned = self._pinned + node.sort = self._sort + for label in self.labels.all(): + node.labels.add(label) + for email in self.collaborators.all(): + node.collaborators.add(email) + + node.text = "\n".join(item.text for item in self.items) return node