mirror of
https://github.com/natelandau/obsidian-metadata.git
synced 2025-11-08 05:03:47 -05:00
refactor: pave the way for non-regex key/value deletions
This commit is contained in:
@@ -129,7 +129,7 @@ class Application:
|
||||
|
||||
choices = [
|
||||
questionary.Separator(),
|
||||
{"name": "Delete inline tag", "value": "delete_inline_tag"},
|
||||
{"name": "Delete inline tag", "value": "delete_tag"},
|
||||
{"name": "Delete key", "value": "delete_key"},
|
||||
{"name": "Delete value", "value": "delete_value"},
|
||||
questionary.Separator(),
|
||||
@@ -142,8 +142,8 @@ class Application:
|
||||
self.delete_key()
|
||||
case "delete_value":
|
||||
self.delete_value()
|
||||
case "delete_inline_tag":
|
||||
self.delete_inline_tag()
|
||||
case "delete_tag":
|
||||
self.delete_tag()
|
||||
case _: # pragma: no cover
|
||||
return
|
||||
|
||||
@@ -153,7 +153,7 @@ class Application:
|
||||
|
||||
choices = [
|
||||
questionary.Separator(),
|
||||
{"name": "Rename inline tag", "value": "rename_inline_tag"},
|
||||
{"name": "Rename inline tag", "value": "rename_tag"},
|
||||
{"name": "Rename key", "value": "rename_key"},
|
||||
{"name": "Rename value", "value": "rename_value"},
|
||||
questionary.Separator(),
|
||||
@@ -166,8 +166,8 @@ class Application:
|
||||
self.rename_key()
|
||||
case "rename_value":
|
||||
self.rename_value()
|
||||
case "rename_inline_tag":
|
||||
self.rename_inline_tag()
|
||||
case "rename_tag":
|
||||
self.rename_tag()
|
||||
case _: # pragma: no cover
|
||||
return
|
||||
|
||||
@@ -213,7 +213,7 @@ class Application:
|
||||
self._load_vault()
|
||||
|
||||
case "apply_tag_filter":
|
||||
tag = self.questions.ask_existing_inline_tag()
|
||||
tag = self.questions.ask_existing_tag()
|
||||
if tag is None or not tag:
|
||||
return
|
||||
|
||||
@@ -482,11 +482,11 @@ class Application:
|
||||
|
||||
return True
|
||||
|
||||
def delete_inline_tag(self) -> None:
|
||||
def delete_tag(self) -> None:
|
||||
"""Delete an inline tag."""
|
||||
tag = self.questions.ask_existing_inline_tag(question="Which tag would you like to delete?")
|
||||
tag = self.questions.ask_existing_tag(question="Which tag would you like to delete?")
|
||||
|
||||
num_changed = self.vault.delete_inline_tag(tag)
|
||||
num_changed = self.vault.delete_tag(tag)
|
||||
if num_changed == 0:
|
||||
alerts.warning("No notes were changed")
|
||||
return
|
||||
@@ -502,7 +502,9 @@ class Application:
|
||||
if key_to_delete is None: # pragma: no cover
|
||||
return
|
||||
|
||||
num_changed = self.vault.delete_metadata(key_to_delete)
|
||||
num_changed = self.vault.delete_metadata(
|
||||
key=key_to_delete, area=MetadataType.ALL, is_regex=True
|
||||
)
|
||||
if num_changed == 0:
|
||||
alerts.warning(f"No notes found with a key matching: [reverse]{key_to_delete}[/]")
|
||||
return
|
||||
@@ -524,7 +526,9 @@ class Application:
|
||||
if value is None: # pragma: no cover
|
||||
return
|
||||
|
||||
num_changed = self.vault.delete_metadata(key, value)
|
||||
num_changed = self.vault.delete_metadata(
|
||||
key=key, value=value, area=MetadataType.ALL, is_regex=True
|
||||
)
|
||||
if num_changed == 0:
|
||||
alerts.warning(f"No notes found matching: {key}: {value}")
|
||||
return
|
||||
@@ -577,9 +581,9 @@ class Application:
|
||||
f"Renamed [reverse]{original_key}[/] to [reverse]{new_key}[/] in {num_changed} notes"
|
||||
)
|
||||
|
||||
def rename_inline_tag(self) -> None:
|
||||
def rename_tag(self) -> None:
|
||||
"""Rename an inline tag."""
|
||||
original_tag = self.questions.ask_existing_inline_tag(question="Which tag to rename?")
|
||||
original_tag = self.questions.ask_existing_tag(question="Which tag to rename?")
|
||||
if original_tag is None: # pragma: no cover
|
||||
return
|
||||
|
||||
@@ -587,7 +591,7 @@ class Application:
|
||||
if new_tag is None: # pragma: no cover
|
||||
return
|
||||
|
||||
num_changed = self.vault.rename_inline_tag(original_tag, new_tag)
|
||||
num_changed = self.vault.rename_tag(original_tag, new_tag)
|
||||
if num_changed == 0:
|
||||
alerts.warning("No notes were changed")
|
||||
return
|
||||
|
||||
@@ -289,10 +289,11 @@ class Frontmatter:
|
||||
"""
|
||||
return dict_contains(self.dict, key, value, is_regex)
|
||||
|
||||
def delete(self, key: str, value_to_delete: str = None) -> bool:
|
||||
def delete(self, key: str, value_to_delete: str = None, is_regex: bool = False) -> bool:
|
||||
"""Delete a value or key in the frontmatter. Regex is supported to allow deleting more than one key or value.
|
||||
|
||||
Args:
|
||||
is_regex (bool, optional): Use regex to check. Defaults to False.
|
||||
key (str): If no value, key to delete. If value, key containing the value.
|
||||
value_to_delete (str, optional): Value to delete.
|
||||
|
||||
@@ -303,7 +304,7 @@ class Frontmatter:
|
||||
dictionary=self.dict,
|
||||
key=key,
|
||||
value=value_to_delete,
|
||||
is_regex=True,
|
||||
is_regex=is_regex,
|
||||
)
|
||||
|
||||
if new_dict != self.dict:
|
||||
@@ -459,10 +460,11 @@ class InlineMetadata:
|
||||
"""
|
||||
return dict_contains(self.dict, key, value, is_regex)
|
||||
|
||||
def delete(self, key: str, value_to_delete: str = None) -> bool:
|
||||
def delete(self, key: str, value_to_delete: str = None, is_regex: bool = False) -> bool:
|
||||
"""Delete a value or key in the inline metadata. Regex is supported to allow deleting more than one key or value.
|
||||
|
||||
Args:
|
||||
is_regex (bool, optional): If True, key and value are treated as regex. Defaults to False.
|
||||
key (str): If no value, key to delete. If value, key containing the value.
|
||||
value_to_delete (str, optional): Value to delete.
|
||||
|
||||
@@ -473,7 +475,7 @@ class InlineMetadata:
|
||||
dictionary=self.dict,
|
||||
key=key,
|
||||
value=value_to_delete,
|
||||
is_regex=True,
|
||||
is_regex=is_regex,
|
||||
)
|
||||
|
||||
if new_dict != self.dict:
|
||||
|
||||
@@ -37,8 +37,9 @@ class Note:
|
||||
dry_run (bool): Whether to run in dry-run mode.
|
||||
file_content (str): Total contents of the note file (frontmatter and content).
|
||||
frontmatter (dict): Frontmatter of the note.
|
||||
inline_tags (list): List of inline tags in the note.
|
||||
tags (list): List of inline tags in the note.
|
||||
inline_metadata (dict): Dictionary of inline metadata in the note.
|
||||
original_file_content (str): Original contents of the note file (frontmatter and content)
|
||||
"""
|
||||
|
||||
def __init__(self, note_path: Path, dry_run: bool = False) -> None:
|
||||
@@ -59,7 +60,7 @@ class Note:
|
||||
alerts.error(f"Note {self.note_path} has invalid frontmatter.\n{e}")
|
||||
raise typer.Exit(code=1) from e
|
||||
|
||||
self.inline_tags: InlineTags = InlineTags(self.file_content)
|
||||
self.tags: InlineTags = InlineTags(self.file_content)
|
||||
self.inline_metadata: InlineMetadata = InlineMetadata(self.file_content)
|
||||
self.original_file_content: str = self.file_content
|
||||
|
||||
@@ -68,7 +69,7 @@ class Note:
|
||||
yield "note_path", self.note_path
|
||||
yield "dry_run", self.dry_run
|
||||
yield "frontmatter", self.frontmatter
|
||||
yield "inline_tags", self.inline_tags
|
||||
yield "tags", self.tags
|
||||
yield "inline_metadata", self.inline_metadata
|
||||
|
||||
def add_metadata( # noqa: C901
|
||||
@@ -114,8 +115,8 @@ class Note:
|
||||
case MetadataType.TAGS:
|
||||
new_values = []
|
||||
if isinstance(value, list):
|
||||
new_values = [_v for _v in value if self.inline_tags.add(_v)]
|
||||
elif self.inline_tags.add(value):
|
||||
new_values = [_v for _v in value if self.tags.add(_v)]
|
||||
elif self.tags.add(value):
|
||||
new_values = [value]
|
||||
|
||||
if new_values:
|
||||
@@ -153,7 +154,7 @@ class Note:
|
||||
alerts.error(f"Note {p} not found. Exiting")
|
||||
raise typer.Exit(code=1) from e
|
||||
|
||||
def contains_inline_tag(self, tag: str, is_regex: bool = False) -> bool:
|
||||
def contains_tag(self, tag: str, is_regex: bool = False) -> bool:
|
||||
"""Check if a note contains the specified inline tag.
|
||||
|
||||
Args:
|
||||
@@ -163,7 +164,7 @@ class Note:
|
||||
Returns:
|
||||
bool: Whether the note has inline tags.
|
||||
"""
|
||||
return self.inline_tags.contains(tag, is_regex=is_regex)
|
||||
return self.tags.contains(tag, is_regex=is_regex)
|
||||
|
||||
def contains_metadata(self, key: str, value: str = None, is_regex: bool = False) -> bool:
|
||||
"""Check if a note has a key or a key-value pair in its Frontmatter or InlineMetadata.
|
||||
@@ -195,14 +196,14 @@ class Note:
|
||||
for key in self.inline_metadata.dict:
|
||||
self.delete_metadata(key=key, area=MetadataType.INLINE)
|
||||
|
||||
for tag in self.inline_tags.list:
|
||||
self.delete_inline_tag(tag=tag)
|
||||
for tag in self.tags.list:
|
||||
self.delete_tag(tag=tag)
|
||||
|
||||
self.frontmatter.delete_all()
|
||||
self.write_frontmatter()
|
||||
|
||||
def delete_inline_tag(self, tag: str) -> bool:
|
||||
"""Delete an inline tag from the `inline_tags` attribute AND removes the tag from the text of the note if it exists.
|
||||
def delete_tag(self, tag: str) -> bool:
|
||||
"""Delete an inline tag from the `tags` attribute AND removes the tag from the text of the note if it exists.
|
||||
|
||||
Args:
|
||||
tag (str): Tag to delete.
|
||||
@@ -210,30 +211,35 @@ class Note:
|
||||
Returns:
|
||||
bool: Whether the tag was deleted.
|
||||
"""
|
||||
new_list = self.inline_tags.list.copy()
|
||||
new_list = self.tags.list.copy()
|
||||
|
||||
for _t in new_list:
|
||||
if re.search(tag, _t):
|
||||
_t = re.escape(_t)
|
||||
self.sub(rf"#{_t}([ \|,;:\*\(\)\[\]\\\.\n#&])", r"\1", is_regex=True)
|
||||
self.inline_tags.delete(tag)
|
||||
self.tags.delete(tag)
|
||||
|
||||
if new_list != self.inline_tags.list:
|
||||
if new_list != self.tags.list:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def delete_metadata(
|
||||
self, key: str, value: str = None, area: MetadataType = MetadataType.ALL
|
||||
self,
|
||||
key: str,
|
||||
value: str = None,
|
||||
area: MetadataType = MetadataType.ALL,
|
||||
is_regex: bool = False,
|
||||
) -> bool:
|
||||
"""Delete a key or key-value pair from the note's Metadata object and the content of the note. Regex is supported.
|
||||
|
||||
If no value is provided, will delete an entire specified key.
|
||||
|
||||
Args:
|
||||
area (MetadataType, optional): Area to delete metadata from. Defaults to MetadataType.ALL.
|
||||
is_regex (bool, optional): Whether to use regex to match the key/value.
|
||||
key (str): Key to delete.
|
||||
value (str, optional): Value to delete.
|
||||
area (MetadataType, optional): Area to delete metadata from. Defaults to MetadataType.ALL.
|
||||
|
||||
Returns:
|
||||
bool: Whether the key or key-value pair was deleted.
|
||||
@@ -242,15 +248,15 @@ class Note:
|
||||
|
||||
if (
|
||||
area == MetadataType.FRONTMATTER or area == MetadataType.ALL
|
||||
) and self.frontmatter.delete(key, value):
|
||||
) and self.frontmatter.delete(key=key, value_to_delete=value, is_regex=is_regex):
|
||||
self.write_frontmatter()
|
||||
changed_value = True
|
||||
|
||||
if (
|
||||
area == MetadataType.INLINE or area == MetadataType.ALL
|
||||
) and self.inline_metadata.contains(key, value):
|
||||
self.write_delete_inline_metadata(key, value)
|
||||
self.inline_metadata.delete(key, value)
|
||||
self.write_delete_inline_metadata(key=key, value=value, is_regex=is_regex)
|
||||
self.inline_metadata.delete(key=key, value_to_delete=value, is_regex=is_regex)
|
||||
changed_value = True
|
||||
|
||||
if changed_value:
|
||||
@@ -266,7 +272,7 @@ class Note:
|
||||
if self.frontmatter.has_changes():
|
||||
return True
|
||||
|
||||
if self.inline_tags.has_changes():
|
||||
if self.tags.has_changes():
|
||||
return True
|
||||
|
||||
if self.inline_metadata.has_changes():
|
||||
@@ -298,7 +304,7 @@ class Note:
|
||||
"""Print the note to the console."""
|
||||
console.print(self.file_content)
|
||||
|
||||
def rename_inline_tag(self, tag_1: str, tag_2: str) -> bool:
|
||||
def rename_tag(self, tag_1: str, tag_2: str) -> bool:
|
||||
"""Rename an inline tag. Updates the Metadata object and the text of the note.
|
||||
|
||||
Args:
|
||||
@@ -308,13 +314,13 @@ class Note:
|
||||
Returns:
|
||||
bool: Whether the tag was renamed.
|
||||
"""
|
||||
if tag_1 in self.inline_tags.list:
|
||||
if tag_1 in self.tags.list:
|
||||
self.sub(
|
||||
rf"#{tag_1}([ \|,;:\*\(\)\[\]\\\.\n#&])",
|
||||
rf"#{tag_2}\1",
|
||||
is_regex=True,
|
||||
)
|
||||
self.inline_tags.rename(tag_1, tag_2)
|
||||
self.tags.rename(tag_1, tag_2)
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -447,12 +453,15 @@ class Note:
|
||||
|
||||
return False
|
||||
|
||||
def write_delete_inline_metadata(self, key: str = None, value: str = None) -> bool:
|
||||
def write_delete_inline_metadata(
|
||||
self, key: str = None, value: str = None, is_regex: bool = False
|
||||
) -> bool:
|
||||
"""For a given inline metadata key and/or key-value pair, delete it from the text of the note. If no key is provided, will delete all inline metadata from the text of the note.
|
||||
|
||||
IMPORTANT: This method makes no changes to the InlineMetadata object.
|
||||
|
||||
Args:
|
||||
is_regex (bool, optional): Whether the key is a regex pattern or plain text. Defaults to False.
|
||||
key (str, optional): Key to delete.
|
||||
value (str, optional): Value to delete.
|
||||
|
||||
@@ -469,13 +478,15 @@ class Note:
|
||||
return True
|
||||
|
||||
for _k, _v in self.inline_metadata.dict.items():
|
||||
if re.search(key, _k):
|
||||
if (is_regex and re.search(key, _k)) or (not is_regex and key == _k):
|
||||
for _value in _v:
|
||||
if value is None:
|
||||
_k = re.escape(_k)
|
||||
_value = re.escape(_value)
|
||||
self.sub(rf"\[?{_k}:: \[?\[?{_value}\]?\]?", "", is_regex=True)
|
||||
elif re.search(value, _value):
|
||||
elif (is_regex and re.search(value, _value)) or (
|
||||
not is_regex and value == _value
|
||||
):
|
||||
_k = re.escape(_k)
|
||||
_value = re.escape(_value)
|
||||
self.sub(rf"\[?({_k}::) ?\[?\[?{_value}\]?\]?", r"\1", is_regex=True)
|
||||
|
||||
@@ -86,7 +86,7 @@ class Questions:
|
||||
self.vault = vault
|
||||
self.key = key
|
||||
|
||||
def _validate_existing_inline_tag(self, text: str) -> bool | str:
|
||||
def _validate_existing_tag(self, text: str) -> bool | str:
|
||||
"""Validate an existing inline tag.
|
||||
|
||||
Returns:
|
||||
@@ -344,11 +344,11 @@ class Questions:
|
||||
question, default=default, style=self.style, qmark="INPUT |"
|
||||
).ask()
|
||||
|
||||
def ask_existing_inline_tag(self, question: str = "Enter a tag") -> str: # pragma: no cover
|
||||
def ask_existing_tag(self, question: str = "Enter a tag") -> str: # pragma: no cover
|
||||
"""Ask the user for an existing inline tag."""
|
||||
return questionary.text(
|
||||
question,
|
||||
validate=self._validate_existing_inline_tag,
|
||||
validate=self._validate_existing_tag,
|
||||
style=self.style,
|
||||
qmark="INPUT |",
|
||||
).ask()
|
||||
|
||||
@@ -107,7 +107,7 @@ class Vault:
|
||||
]
|
||||
|
||||
if _filter.tag_filter is not None:
|
||||
notes_list = [n for n in notes_list if n.contains_inline_tag(_filter.tag_filter)]
|
||||
notes_list = [n for n in notes_list if n.contains_tag(_filter.tag_filter)]
|
||||
|
||||
if _filter.key_filter is not None and _filter.value_filter is not None:
|
||||
notes_list = [
|
||||
@@ -187,7 +187,7 @@ class Vault:
|
||||
)
|
||||
self.metadata.index_metadata(
|
||||
area=MetadataType.TAGS,
|
||||
metadata=_note.inline_tags.list,
|
||||
metadata=_note.tags.list,
|
||||
)
|
||||
|
||||
def add_metadata(
|
||||
@@ -273,7 +273,7 @@ class Vault:
|
||||
else:
|
||||
alerts.info("No backup found")
|
||||
|
||||
def delete_inline_tag(self, tag: str) -> int:
|
||||
def delete_tag(self, tag: str) -> int:
|
||||
"""Delete an inline tag in the vault.
|
||||
|
||||
Args:
|
||||
@@ -285,7 +285,7 @@ class Vault:
|
||||
num_changed = 0
|
||||
|
||||
for _note in self.notes_in_scope:
|
||||
if _note.delete_inline_tag(tag):
|
||||
if _note.delete_tag(tag):
|
||||
log.trace(f"Deleted tag from {_note.note_path}")
|
||||
num_changed += 1
|
||||
|
||||
@@ -294,10 +294,18 @@ class Vault:
|
||||
|
||||
return num_changed
|
||||
|
||||
def delete_metadata(self, key: str, value: str = None) -> int:
|
||||
def delete_metadata(
|
||||
self,
|
||||
key: str,
|
||||
value: str = None,
|
||||
area: MetadataType = MetadataType.ALL,
|
||||
is_regex: bool = False,
|
||||
) -> int:
|
||||
"""Delete metadata in the vault.
|
||||
|
||||
Args:
|
||||
area (MetadataType): Area of metadata to delete from.
|
||||
is_regex (bool): Whether to use regex for key and value. Defaults to False.
|
||||
key (str): Key to delete. Regex is supported
|
||||
value (str, optional): Value to delete. Regex is supported
|
||||
|
||||
@@ -307,7 +315,7 @@ class Vault:
|
||||
num_changed = 0
|
||||
|
||||
for _note in self.notes_in_scope:
|
||||
if _note.delete_metadata(key, value):
|
||||
if _note.delete_metadata(key=key, value=value, area=area, is_regex=is_regex):
|
||||
log.trace(f"Deleted metadata from {_note.note_path}")
|
||||
num_changed += 1
|
||||
|
||||
@@ -394,7 +402,7 @@ class Vault:
|
||||
]
|
||||
)
|
||||
|
||||
for tag in _note.inline_tags.list:
|
||||
for tag in _note.tags.list:
|
||||
writer.writerow(
|
||||
[_note.note_path.relative_to(self.vault_path), "tag", "", f"{tag}"]
|
||||
)
|
||||
@@ -463,7 +471,7 @@ class Vault:
|
||||
"""Count number of excluded notes."""
|
||||
return len(self.all_notes) - len(self.notes_in_scope)
|
||||
|
||||
def rename_inline_tag(self, old_tag: str, new_tag: str) -> int:
|
||||
def rename_tag(self, old_tag: str, new_tag: str) -> int:
|
||||
"""Rename an inline tag in the vault.
|
||||
|
||||
Args:
|
||||
@@ -476,7 +484,7 @@ class Vault:
|
||||
num_changed = 0
|
||||
|
||||
for _note in self.notes_in_scope:
|
||||
if _note.rename_inline_tag(old_tag, new_tag):
|
||||
if _note.rename_tag(old_tag, new_tag):
|
||||
log.trace(f"Renamed inline tag in {_note.note_path}")
|
||||
num_changed += 1
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ def test_add_metadata_tag(test_application, mocker, capsys) -> None:
|
||||
assert captured == Regex(r"SUCCESS +\| Added metadata to \d+ notes", re.DOTALL)
|
||||
|
||||
|
||||
def test_delete_inline_tag_1(test_application, mocker, capsys) -> None:
|
||||
def test_delete_tag_1(test_application, mocker, capsys) -> None:
|
||||
"""Test renaming an inline tag.
|
||||
|
||||
GIVEN an application
|
||||
@@ -159,10 +159,10 @@ def test_delete_inline_tag_1(test_application, mocker, capsys) -> None:
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_selection",
|
||||
side_effect=["delete_inline_tag", "back"],
|
||||
side_effect=["delete_tag", "back"],
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_existing_inline_tag",
|
||||
"obsidian_metadata.models.application.Questions.ask_existing_tag",
|
||||
return_value="breakfast",
|
||||
)
|
||||
|
||||
@@ -172,7 +172,7 @@ def test_delete_inline_tag_1(test_application, mocker, capsys) -> None:
|
||||
assert captured == Regex(r"SUCCESS +\| Deleted inline tag: breakfast in \d+ notes", re.DOTALL)
|
||||
|
||||
|
||||
def test_delete_inline_tag_2(test_application, mocker, capsys) -> None:
|
||||
def test_delete_tag_2(test_application, mocker, capsys) -> None:
|
||||
"""Test renaming an inline tag.
|
||||
|
||||
GIVEN an application
|
||||
@@ -187,10 +187,10 @@ def test_delete_inline_tag_2(test_application, mocker, capsys) -> None:
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_selection",
|
||||
side_effect=["delete_inline_tag", "back"],
|
||||
side_effect=["delete_tag", "back"],
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_existing_inline_tag",
|
||||
"obsidian_metadata.models.application.Questions.ask_existing_tag",
|
||||
return_value="not_a_tag_in_vault",
|
||||
)
|
||||
|
||||
@@ -388,7 +388,7 @@ def test_inspect_metadata_all(test_application, mocker, capsys) -> None:
|
||||
assert captured == Regex(r"type +│ article", re.DOTALL)
|
||||
|
||||
|
||||
def test_rename_inline_tag(test_application, mocker, capsys) -> None:
|
||||
def test_rename_tag(test_application, mocker, capsys) -> None:
|
||||
"""Test renaming an inline tag."""
|
||||
app = test_application
|
||||
app._load_vault()
|
||||
@@ -398,10 +398,10 @@ def test_rename_inline_tag(test_application, mocker, capsys) -> None:
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_selection",
|
||||
side_effect=["rename_inline_tag", "back"],
|
||||
side_effect=["rename_tag", "back"],
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_existing_inline_tag",
|
||||
"obsidian_metadata.models.application.Questions.ask_existing_tag",
|
||||
return_value="not_a_tag",
|
||||
)
|
||||
mocker.patch(
|
||||
@@ -420,10 +420,10 @@ def test_rename_inline_tag(test_application, mocker, capsys) -> None:
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_selection",
|
||||
side_effect=["rename_inline_tag", "back"],
|
||||
side_effect=["rename_tag", "back"],
|
||||
)
|
||||
mocker.patch(
|
||||
"obsidian_metadata.models.application.Questions.ask_existing_inline_tag",
|
||||
"obsidian_metadata.models.application.Questions.ask_existing_tag",
|
||||
return_value="breakfast",
|
||||
)
|
||||
mocker.patch(
|
||||
|
||||
@@ -324,7 +324,7 @@ def test_delete_3():
|
||||
THEN return False
|
||||
"""
|
||||
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
|
||||
assert frontmatter.delete(r"\d{3}") is False
|
||||
assert frontmatter.delete(r"\d{3}", is_regex=True) is False
|
||||
|
||||
|
||||
def test_delete_4():
|
||||
@@ -335,7 +335,7 @@ def test_delete_4():
|
||||
THEN return False
|
||||
"""
|
||||
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
|
||||
assert frontmatter.delete("tags", r"\d{5}") is False
|
||||
assert frontmatter.delete("tags", r"\d{5}", is_regex=True) is False
|
||||
|
||||
|
||||
def test_delete_5():
|
||||
@@ -371,7 +371,7 @@ def test_delete_7():
|
||||
THEN return True and delete the matching keys from the dict
|
||||
"""
|
||||
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
|
||||
assert frontmatter.delete(r"front\w+") is True
|
||||
assert frontmatter.delete(r"front\w+", is_regex=True) is True
|
||||
assert "frontmatter_Key1" not in frontmatter.dict
|
||||
assert "frontmatter_Key2" not in frontmatter.dict
|
||||
|
||||
@@ -384,7 +384,7 @@ def test_delete_8():
|
||||
THEN return True and delete the matching values
|
||||
"""
|
||||
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
|
||||
assert frontmatter.delete("tags", r"\w+_[23]") is True
|
||||
assert frontmatter.delete("tags", r"\w+_[23]", is_regex=True) is True
|
||||
assert "tag_2" not in frontmatter.dict["tags"]
|
||||
assert "📅/tag_3" not in frontmatter.dict["tags"]
|
||||
assert "tag_1" in frontmatter.dict["tags"]
|
||||
|
||||
@@ -289,7 +289,7 @@ def test_delete_3():
|
||||
THEN return False
|
||||
"""
|
||||
inline = InlineMetadata(INLINE_CONTENT)
|
||||
assert inline.delete(r"\d{3}") is False
|
||||
assert inline.delete(r"\d{3}", is_regex=True) is False
|
||||
|
||||
|
||||
def test_delete_4():
|
||||
@@ -300,7 +300,7 @@ def test_delete_4():
|
||||
THEN return False
|
||||
"""
|
||||
inline = InlineMetadata(INLINE_CONTENT)
|
||||
assert inline.delete("key1", r"\d{5}") is False
|
||||
assert inline.delete("key1", r"\d{5}", is_regex=True) is False
|
||||
|
||||
|
||||
def test_delete_5():
|
||||
@@ -336,7 +336,7 @@ def test_delete_7():
|
||||
THEN return True and delete the matching keys from the dict
|
||||
"""
|
||||
inline = InlineMetadata(INLINE_CONTENT)
|
||||
assert inline.delete(r"key\w+") is True
|
||||
assert inline.delete(r"key\w+", is_regex=True) is True
|
||||
assert "key1" not in inline.dict
|
||||
assert "key2" not in inline.dict
|
||||
|
||||
@@ -349,7 +349,7 @@ def test_delete_8():
|
||||
THEN return True and delete the matching values
|
||||
"""
|
||||
inline = InlineMetadata(INLINE_CONTENT)
|
||||
assert inline.delete("key1", r"\w+\d") is True
|
||||
assert inline.delete("key1", r"\w+\d", is_regex=True) is True
|
||||
assert "value1" not in inline.dict["key1"]
|
||||
assert "value2" not in inline.dict["key1"]
|
||||
assert "value3" not in inline.dict["key1"]
|
||||
|
||||
@@ -48,7 +48,7 @@ def test_create_note_1(sample_note):
|
||||
],
|
||||
}
|
||||
|
||||
assert note.inline_tags.list == [
|
||||
assert note.tags.list == [
|
||||
"inline_tag_bottom1",
|
||||
"inline_tag_bottom2",
|
||||
"inline_tag_top1",
|
||||
@@ -233,12 +233,12 @@ def test_add_metadata_method_10(sample_note):
|
||||
THEN the tag is added to the InlineTags object and the file content
|
||||
"""
|
||||
note = Note(note_path=sample_note)
|
||||
assert "new_tag2" not in note.inline_tags.list
|
||||
assert "new_tag2" not in note.tags.list
|
||||
assert (
|
||||
note.add_metadata(MetadataType.TAGS, value="new_tag2", location=InsertLocation.BOTTOM)
|
||||
is True
|
||||
)
|
||||
assert "new_tag2" in note.inline_tags.list
|
||||
assert "new_tag2" in note.tags.list
|
||||
assert "#new_tag2" in note.file_content
|
||||
|
||||
|
||||
@@ -279,19 +279,19 @@ def test_commit_2(sample_note) -> None:
|
||||
assert "Heading 1" in note.file_content
|
||||
|
||||
|
||||
def test_contains_inline_tag(sample_note) -> None:
|
||||
"""Test contains_inline_tag method.
|
||||
def test_contains_tag(sample_note) -> None:
|
||||
"""Test contains_tag method.
|
||||
|
||||
GIVEN a note object
|
||||
WHEN contains_inline_tag() is called
|
||||
WHEN contains_tag() is called
|
||||
THEN the method returns True if the tag is found and False if not
|
||||
|
||||
"""
|
||||
note = Note(note_path=sample_note)
|
||||
assert note.contains_inline_tag("intext_tag1") is True
|
||||
assert note.contains_inline_tag("nonexistent_tag") is False
|
||||
assert note.contains_inline_tag(r"\d$", is_regex=True) is True
|
||||
assert note.contains_inline_tag(r"^\d", is_regex=True) is False
|
||||
assert note.contains_tag("intext_tag1") is True
|
||||
assert note.contains_tag("nonexistent_tag") is False
|
||||
assert note.contains_tag(r"\d$", is_regex=True) is True
|
||||
assert note.contains_tag(r"^\d", is_regex=True) is False
|
||||
|
||||
|
||||
def test_contains_metadata(sample_note) -> None:
|
||||
@@ -323,7 +323,7 @@ def test_delete_all_metadata(sample_note):
|
||||
"""
|
||||
note = Note(note_path=sample_note)
|
||||
note.delete_all_metadata()
|
||||
assert note.inline_tags.list == []
|
||||
assert note.tags.list == []
|
||||
assert note.frontmatter.dict == {}
|
||||
assert note.inline_metadata.dict == {}
|
||||
assert note.file_content == Regex("consequat. Duis")
|
||||
@@ -332,17 +332,17 @@ def test_delete_all_metadata(sample_note):
|
||||
assert "---" not in note.file_content
|
||||
|
||||
|
||||
def test_delete_inline_tag(sample_note) -> None:
|
||||
"""Test delete_inline_tag method.
|
||||
def test_delete_tag(sample_note) -> None:
|
||||
"""Test delete_tag method.
|
||||
|
||||
GIVEN a note object
|
||||
WHEN delete_inline_tag() is called
|
||||
WHEN delete_tag() is called
|
||||
THEN the method returns True if the tag is found and deleted and False if not
|
||||
"""
|
||||
note = Note(note_path=sample_note)
|
||||
assert note.delete_inline_tag("not_a_tag") is False
|
||||
assert note.delete_inline_tag("intext_tag[1]") is True
|
||||
assert "intext_tag1" not in note.inline_tags.list
|
||||
assert note.delete_tag("not_a_tag") is False
|
||||
assert note.delete_tag("intext_tag[1]") is True
|
||||
assert "intext_tag1" not in note.tags.list
|
||||
assert note.file_content == Regex("consequat. Duis")
|
||||
|
||||
|
||||
@@ -454,7 +454,7 @@ def test_has_changes(sample_note) -> None:
|
||||
|
||||
note = Note(note_path=sample_note)
|
||||
assert note.has_changes() is False
|
||||
note.delete_inline_tag("intext_tag1")
|
||||
note.delete_tag("intext_tag1")
|
||||
assert note.has_changes() is True
|
||||
|
||||
|
||||
@@ -494,29 +494,29 @@ def test_print_note(sample_note, capsys) -> None:
|
||||
assert "#shared_tag" in captured.out
|
||||
|
||||
|
||||
def test_rename_inline_tag_1(sample_note) -> None:
|
||||
"""Test rename_inline_tag() method.
|
||||
def test_rename_tag_1(sample_note) -> None:
|
||||
"""Test rename_tag() method.
|
||||
|
||||
GIVEN a note object
|
||||
WHEN rename_inline_tag() is called with a tag that does not exist
|
||||
WHEN rename_tag() is called with a tag that does not exist
|
||||
THEN the method returns False
|
||||
"""
|
||||
note = Note(note_path=sample_note)
|
||||
assert note.rename_inline_tag("no_note_tag", "intext_tag2") is False
|
||||
assert note.rename_tag("no_note_tag", "intext_tag2") is False
|
||||
|
||||
|
||||
def test_rename_inline_tag_2(sample_note) -> None:
|
||||
"""Test rename_inline_tag() method.
|
||||
def test_rename_tag_2(sample_note) -> None:
|
||||
"""Test rename_tag() method.
|
||||
|
||||
GIVEN a note object
|
||||
WHEN rename_inline_tag() is called with a tag exists
|
||||
THEN the tag is renamed in the InlineTags object and the file content
|
||||
WHEN rename_tag() is called with a tag exists
|
||||
THEN the tag is renamed in the InlineTag object and the file content
|
||||
"""
|
||||
note = Note(note_path=sample_note)
|
||||
assert "intext_tag1" in note.inline_tags.list
|
||||
assert note.rename_inline_tag("intext_tag1", "intext_tag26") is True
|
||||
assert "intext_tag1" not in note.inline_tags.list
|
||||
assert "intext_tag26" in note.inline_tags.list
|
||||
assert "intext_tag1" in note.tags.list
|
||||
assert note.rename_tag("intext_tag1", "intext_tag26") is True
|
||||
assert "intext_tag1" not in note.tags.list
|
||||
assert "intext_tag26" in note.tags.list
|
||||
assert note.file_content == Regex(r"#intext_tag26")
|
||||
assert note.file_content != Regex(r"#intext_tag1")
|
||||
|
||||
@@ -846,7 +846,7 @@ def test_write_delete_inline_metadata_2(sample_note) -> None:
|
||||
|
||||
"""
|
||||
note = Note(note_path=sample_note)
|
||||
note.write_delete_inline_metadata("intext_key")
|
||||
note.write_delete_inline_metadata("intext_key", is_regex=False)
|
||||
assert note.file_content == Regex(r"dolore eu fugiat", re.DOTALL)
|
||||
|
||||
|
||||
@@ -858,7 +858,7 @@ def test_write_delete_inline_metadata_3(sample_note) -> None:
|
||||
THEN the key/value is removed from the note content
|
||||
"""
|
||||
note = Note(note_path=sample_note)
|
||||
note.write_delete_inline_metadata("bottom_key2", "bottom_key2_value")
|
||||
note.write_delete_inline_metadata("bottom_key2", "bottom_key2_value", is_regex=False)
|
||||
assert note.file_content != Regex(r"bottom_key2_value")
|
||||
assert note.file_content == Regex(r"bottom_key2::")
|
||||
note.write_delete_inline_metadata("bottom_key1")
|
||||
|
||||
@@ -68,12 +68,12 @@ def test_validate_number() -> None:
|
||||
assert questions._validate_number("1") is True
|
||||
|
||||
|
||||
def test_validate_existing_inline_tag() -> None:
|
||||
def test_validate_existing_tag() -> None:
|
||||
"""Test existing tag validation."""
|
||||
questions = Questions(vault=VAULT)
|
||||
assert "Tag cannot be empty" in questions._validate_existing_inline_tag("")
|
||||
assert "'test' does not exist" in questions._validate_existing_inline_tag("test")
|
||||
assert questions._validate_existing_inline_tag("shared_tag") is True
|
||||
assert "Tag cannot be empty" in questions._validate_existing_tag("")
|
||||
assert "'test' does not exist" in questions._validate_existing_tag("test")
|
||||
assert questions._validate_existing_tag("shared_tag") is True
|
||||
|
||||
|
||||
def test_validate_key_exists_regex() -> None:
|
||||
|
||||
@@ -315,16 +315,16 @@ def test_delete_backup_2(test_vault, capsys):
|
||||
assert vault.backup_path.exists() is True
|
||||
|
||||
|
||||
def test_delete_inline_tag_1(test_vault) -> None:
|
||||
"""Test delete_inline_tag() method.
|
||||
def test_delete_tag_1(test_vault) -> None:
|
||||
"""Test delete_tag() method.
|
||||
|
||||
GIVEN a vault object
|
||||
WHEN the delete_inline_tag method is called
|
||||
WHEN the delete_tag method is called
|
||||
THEN the inline tag is deleted
|
||||
"""
|
||||
vault = Vault(config=test_vault)
|
||||
|
||||
assert vault.delete_inline_tag("intext_tag2") == 1
|
||||
assert vault.delete_tag("intext_tag2") == 1
|
||||
assert vault.metadata.tags == [
|
||||
"inline_tag_bottom1",
|
||||
"inline_tag_bottom2",
|
||||
@@ -335,16 +335,16 @@ def test_delete_inline_tag_1(test_vault) -> None:
|
||||
]
|
||||
|
||||
|
||||
def test_delete_inline_tag_2(test_vault) -> None:
|
||||
"""Test delete_inline_tag() method.
|
||||
def test_delete_tag_2(test_vault) -> None:
|
||||
"""Test delete_tag() method.
|
||||
|
||||
GIVEN a vault object
|
||||
WHEN the delete_inline_tag method is called with a tag that does not exist
|
||||
WHEN the delete_tag method is called with a tag that does not exist
|
||||
THEN no changes are made
|
||||
"""
|
||||
vault = Vault(config=test_vault)
|
||||
|
||||
assert vault.delete_inline_tag("no tag") == 0
|
||||
assert vault.delete_tag("no tag") == 0
|
||||
|
||||
|
||||
def test_delete_metadata_1(test_vault) -> None:
|
||||
@@ -594,16 +594,16 @@ def test_move_inline_metadata_1(test_vault) -> None:
|
||||
assert vault.move_inline_metadata(location=InsertLocation.TOP) == 1
|
||||
|
||||
|
||||
def test_rename_inline_tag_1(test_vault) -> None:
|
||||
"""Test rename_inline_tag() method.
|
||||
def test_rename_tag_1(test_vault) -> None:
|
||||
"""Test rename_tag() method.
|
||||
|
||||
GIVEN a vault object
|
||||
WHEN the rename_inline_tag() method is called with a tag that is found
|
||||
WHEN the rename_tag() method is called with a tag that is found
|
||||
THEN the inline tag is renamed
|
||||
"""
|
||||
vault = Vault(config=test_vault)
|
||||
|
||||
assert vault.rename_inline_tag("intext_tag2", "new_tag") == 1
|
||||
assert vault.rename_tag("intext_tag2", "new_tag") == 1
|
||||
assert vault.metadata.tags == [
|
||||
"inline_tag_bottom1",
|
||||
"inline_tag_bottom2",
|
||||
@@ -615,16 +615,16 @@ def test_rename_inline_tag_1(test_vault) -> None:
|
||||
]
|
||||
|
||||
|
||||
def test_rename_inline_tag_2(test_vault) -> None:
|
||||
"""Test rename_inline_tag() method.
|
||||
def test_rename_tag_2(test_vault) -> None:
|
||||
"""Test rename_tag() method.
|
||||
|
||||
GIVEN a vault object
|
||||
WHEN the rename_inline_tag() method is called with a tag that is not found
|
||||
WHEN the rename_tag() method is called with a tag that is not found
|
||||
THEN the inline tag is not renamed
|
||||
"""
|
||||
vault = Vault(config=test_vault)
|
||||
|
||||
assert vault.rename_inline_tag("no tag", "new_tag") == 0
|
||||
assert vault.rename_tag("no tag", "new_tag") == 0
|
||||
|
||||
|
||||
def test_rename_metadata_1(test_vault) -> None:
|
||||
@@ -773,7 +773,7 @@ def test_update_from_dict_3(test_vault):
|
||||
assert vault.get_changed_notes()[0].note_path.name == "test1.md"
|
||||
assert vault.get_changed_notes()[0].frontmatter.dict == {"new_key": ["new_value"]}
|
||||
assert vault.get_changed_notes()[0].inline_metadata.dict == {"new_key2": ["new_value"]}
|
||||
assert vault.get_changed_notes()[0].inline_tags.list == ["new_tag"]
|
||||
assert vault.get_changed_notes()[0].tags.list == ["new_tag"]
|
||||
assert vault.metadata.frontmatter == {"new_key": ["new_value"]}
|
||||
assert vault.metadata.inline_metadata == {"new_key2": ["new_value"]}
|
||||
assert vault.metadata.tags == ["new_tag"]
|
||||
|
||||
Reference in New Issue
Block a user