diff --git a/poetry.toml b/poetry.toml index ab1033b..6185022 100644 --- a/poetry.toml +++ b/poetry.toml @@ -1,2 +1,2 @@ [virtualenvs] -in-project = true + in-project = true diff --git a/src/obsidian_metadata/models/metadata.py b/src/obsidian_metadata/models/metadata.py index e7ae940..11d026d 100644 --- a/src/obsidian_metadata/models/metadata.py +++ b/src/obsidian_metadata/models/metadata.py @@ -401,7 +401,7 @@ class InlineMetadata: """ return f"InlineMetadata(inline_metadata={self.dict})" - def add(self, key: str, value: str = None) -> bool: + def add(self, key: str, value: str | list[str] = None) -> bool: """Add a key and value to the inline metadata. Args: @@ -411,23 +411,29 @@ class InlineMetadata: Returns: bool: True if the metadata was added """ - if value is None or value == "" or value == "None": + if value is None: if key not in self.dict: self.dict[key] = [] return True return False if key not in self.dict: + if isinstance(value, list): + self.dict[key] = value + return True + self.dict[key] = [value] return True - if key in self.dict and len(self.dict[key]) > 0: - if value in self.dict[key]: - return False - raise ValueError(f"'{key}' not empty") + if key in self.dict and value not in self.dict[key]: + if isinstance(value, list): + self.dict[key].extend(value) + return True - self.dict[key].append(value) - return True + self.dict[key].append(value) + return True + + return False def contains(self, key: str, value: str = None, is_regex: bool = False) -> bool: """Check if a key or value exists in the inline metadata. @@ -561,7 +567,7 @@ class InlineTags: ) ) - def add(self, new_tag: str) -> bool: + def add(self, new_tag: str | list[str]) -> bool: """Add a new inline tag. Args: @@ -570,13 +576,27 @@ class InlineTags: Returns: bool: True if a tag was added. """ - if new_tag in self.list: - return False + if isinstance(new_tag, list): + for _tag in new_tag: + if _tag.startswith("#"): + _tag = _tag[1:] + if _tag in self.list: + return False + new_list = self.list.copy() + new_list.append(_tag) + self.list = sorted(new_list) + return True + else: + if new_tag.startswith("#"): + new_tag = new_tag[1:] + if new_tag in self.list: + return False + new_list = self.list.copy() + new_list.append(new_tag) + self.list = sorted(new_list) + return True - new_list = self.list.copy() - new_list.append(new_tag) - self.list = sorted(new_list) - return True + return False def contains(self, tag: str, is_regex: bool = False) -> bool: """Check if a tag exists in the metadata. diff --git a/src/obsidian_metadata/models/notes.py b/src/obsidian_metadata/models/notes.py index ffc2c45..dbe05f7 100644 --- a/src/obsidian_metadata/models/notes.py +++ b/src/obsidian_metadata/models/notes.py @@ -135,24 +135,47 @@ class Note: Returns: bool: Whether the metadata was added. """ - if area is MetadataType.FRONTMATTER and self.frontmatter.add(key, value): - self.update_frontmatter() - return True - - try: - if area is MetadataType.INLINE and self.inline_metadata.add(key, str(value)): - line = f"{key}:: " if value is None else f"{key}:: {value}" - self.insert(new_string=line, location=location) + match area: # noqa: E999 + case MetadataType.FRONTMATTER if self.frontmatter.add(key, value): + self.update_frontmatter() return True - except ValueError as e: - log.warning(f"Could not add metadata to {self.note_path}: {e}") - return False + case MetadataType.INLINE: + if value is None: + if self.inline_metadata.add(key): + line = f"{key}::" + self.insert(new_string=line, location=location) + return True - if area is MetadataType.TAGS and self.inline_tags.add(str(value)): - line = f"#{value}" - self.insert(new_string=line, location=location) - return True + new_values = [] + if isinstance(value, list): + new_values = [_v for _v in value if self.inline_metadata.add(key, _v)] + else: + if self.inline_metadata.add(key, value): + new_values = [value] + + if new_values: + for value in new_values: + self.insert(new_string=f"{key}:: {value}", location=location) + return True + + case MetadataType.TAGS: + new_values = [] + if isinstance(value, list): + new_values = [_v for _v in value if self.inline_tags.add(_v)] + else: + if self.inline_tags.add(value): + new_values = [value] + + if new_values: + for value in new_values: + if value.startswith("#"): + value = value[1:] + self.insert(new_string=f"#{value}", location=location) + return True + + case _: + return False return False @@ -284,7 +307,7 @@ class Note: if not allow_multiple and len(re.findall(re.escape(new_string), self.file_content)) > 0: return - match location: # noqa: E999 + match location: case InsertLocation.BOTTOM: self.file_content += f"\n{new_string}" case InsertLocation.TOP: diff --git a/tests/metadata_test.py b/tests/metadata_test.py index 2b9d699..b9221fc 100644 --- a/tests/metadata_test.py +++ b/tests/metadata_test.py @@ -46,7 +46,6 @@ horizontal: rule """ INLINE_CONTENT = """\ repeated_key:: repeated_key_value1 - #inline_tag_top1,#inline_tag_top2 **bold_key1**:: bold_key1_value **bold_key2:: bold_key2_value** @@ -280,9 +279,6 @@ def test_inline_metadata_add() -> None: "tag_key": ["tag_key_value"], } - with pytest.raises(ValueError): - assert inline.add("added_key1", "added_value_2") is True - assert inline.dict == { "added_key": [], "added_key1": ["added_value"], @@ -309,6 +305,8 @@ def test_inline_metadata_add() -> None: "repeated_key": ["repeated_key_value1", "repeated_key_value2"], "tag_key": ["tag_key_value"], } + assert inline.add("repeated_key", "repeated_key_value1") is False + assert inline.add("repeated_key", "new_value") is True def test_inline_metadata_contains() -> None: diff --git a/tests/notes_test.py b/tests/notes_test.py index 2f2a859..ee76a4e 100644 --- a/tests/notes_test.py +++ b/tests/notes_test.py @@ -99,6 +99,21 @@ def test_add_metadata_inline(short_note) -> None: ) assert "new_key2:: new_value1" in note.file_content + assert ( + note.add_metadata( + MetadataType.INLINE, key="new_key2", value="new_value2", location=InsertLocation.BOTTOM + ) + is True + ) + assert "new_key2:: new_value2" in note.file_content + + assert ( + note.add_metadata( + MetadataType.INLINE, key="new_key2", value="new_value2", location=InsertLocation.BOTTOM + ) + is False + ) + def test_add_metadata_frontmatter(sample_note) -> None: """Test adding metadata."""