refactor: pave the way for non-regex key/value deletions

This commit is contained in:
Nathaniel Landau
2023-03-21 22:50:01 -04:00
parent 08999cb055
commit fdb1b8b5bc
11 changed files with 154 additions and 129 deletions

View File

@@ -129,7 +129,7 @@ class Application:
choices = [ choices = [
questionary.Separator(), 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 key", "value": "delete_key"},
{"name": "Delete value", "value": "delete_value"}, {"name": "Delete value", "value": "delete_value"},
questionary.Separator(), questionary.Separator(),
@@ -142,8 +142,8 @@ class Application:
self.delete_key() self.delete_key()
case "delete_value": case "delete_value":
self.delete_value() self.delete_value()
case "delete_inline_tag": case "delete_tag":
self.delete_inline_tag() self.delete_tag()
case _: # pragma: no cover case _: # pragma: no cover
return return
@@ -153,7 +153,7 @@ class Application:
choices = [ choices = [
questionary.Separator(), 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 key", "value": "rename_key"},
{"name": "Rename value", "value": "rename_value"}, {"name": "Rename value", "value": "rename_value"},
questionary.Separator(), questionary.Separator(),
@@ -166,8 +166,8 @@ class Application:
self.rename_key() self.rename_key()
case "rename_value": case "rename_value":
self.rename_value() self.rename_value()
case "rename_inline_tag": case "rename_tag":
self.rename_inline_tag() self.rename_tag()
case _: # pragma: no cover case _: # pragma: no cover
return return
@@ -213,7 +213,7 @@ class Application:
self._load_vault() self._load_vault()
case "apply_tag_filter": case "apply_tag_filter":
tag = self.questions.ask_existing_inline_tag() tag = self.questions.ask_existing_tag()
if tag is None or not tag: if tag is None or not tag:
return return
@@ -482,11 +482,11 @@ class Application:
return True return True
def delete_inline_tag(self) -> None: def delete_tag(self) -> None:
"""Delete an inline tag.""" """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: if num_changed == 0:
alerts.warning("No notes were changed") alerts.warning("No notes were changed")
return return
@@ -502,7 +502,9 @@ class Application:
if key_to_delete is None: # pragma: no cover if key_to_delete is None: # pragma: no cover
return 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: if num_changed == 0:
alerts.warning(f"No notes found with a key matching: [reverse]{key_to_delete}[/]") alerts.warning(f"No notes found with a key matching: [reverse]{key_to_delete}[/]")
return return
@@ -524,7 +526,9 @@ class Application:
if value is None: # pragma: no cover if value is None: # pragma: no cover
return 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: if num_changed == 0:
alerts.warning(f"No notes found matching: {key}: {value}") alerts.warning(f"No notes found matching: {key}: {value}")
return return
@@ -577,9 +581,9 @@ class Application:
f"Renamed [reverse]{original_key}[/] to [reverse]{new_key}[/] in {num_changed} notes" 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.""" """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 if original_tag is None: # pragma: no cover
return return
@@ -587,7 +591,7 @@ class Application:
if new_tag is None: # pragma: no cover if new_tag is None: # pragma: no cover
return 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: if num_changed == 0:
alerts.warning("No notes were changed") alerts.warning("No notes were changed")
return return

View File

@@ -289,10 +289,11 @@ class Frontmatter:
""" """
return dict_contains(self.dict, key, value, is_regex) 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. """Delete a value or key in the frontmatter. Regex is supported to allow deleting more than one key or value.
Args: 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. key (str): If no value, key to delete. If value, key containing the value.
value_to_delete (str, optional): Value to delete. value_to_delete (str, optional): Value to delete.
@@ -303,7 +304,7 @@ class Frontmatter:
dictionary=self.dict, dictionary=self.dict,
key=key, key=key,
value=value_to_delete, value=value_to_delete,
is_regex=True, is_regex=is_regex,
) )
if new_dict != self.dict: if new_dict != self.dict:
@@ -459,10 +460,11 @@ class InlineMetadata:
""" """
return dict_contains(self.dict, key, value, is_regex) 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. """Delete a value or key in the inline metadata. Regex is supported to allow deleting more than one key or value.
Args: 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. key (str): If no value, key to delete. If value, key containing the value.
value_to_delete (str, optional): Value to delete. value_to_delete (str, optional): Value to delete.
@@ -473,7 +475,7 @@ class InlineMetadata:
dictionary=self.dict, dictionary=self.dict,
key=key, key=key,
value=value_to_delete, value=value_to_delete,
is_regex=True, is_regex=is_regex,
) )
if new_dict != self.dict: if new_dict != self.dict:

View File

@@ -37,8 +37,9 @@ class Note:
dry_run (bool): Whether to run in dry-run mode. dry_run (bool): Whether to run in dry-run mode.
file_content (str): Total contents of the note file (frontmatter and content). file_content (str): Total contents of the note file (frontmatter and content).
frontmatter (dict): Frontmatter of the note. 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. 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: 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}") alerts.error(f"Note {self.note_path} has invalid frontmatter.\n{e}")
raise typer.Exit(code=1) from 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.inline_metadata: InlineMetadata = InlineMetadata(self.file_content)
self.original_file_content: str = self.file_content self.original_file_content: str = self.file_content
@@ -68,7 +69,7 @@ class Note:
yield "note_path", self.note_path yield "note_path", self.note_path
yield "dry_run", self.dry_run yield "dry_run", self.dry_run
yield "frontmatter", self.frontmatter yield "frontmatter", self.frontmatter
yield "inline_tags", self.inline_tags yield "tags", self.tags
yield "inline_metadata", self.inline_metadata yield "inline_metadata", self.inline_metadata
def add_metadata( # noqa: C901 def add_metadata( # noqa: C901
@@ -114,8 +115,8 @@ class Note:
case MetadataType.TAGS: case MetadataType.TAGS:
new_values = [] new_values = []
if isinstance(value, list): if isinstance(value, list):
new_values = [_v for _v in value if self.inline_tags.add(_v)] new_values = [_v for _v in value if self.tags.add(_v)]
elif self.inline_tags.add(value): elif self.tags.add(value):
new_values = [value] new_values = [value]
if new_values: if new_values:
@@ -153,7 +154,7 @@ class Note:
alerts.error(f"Note {p} not found. Exiting") alerts.error(f"Note {p} not found. Exiting")
raise typer.Exit(code=1) from e 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. """Check if a note contains the specified inline tag.
Args: Args:
@@ -163,7 +164,7 @@ class Note:
Returns: Returns:
bool: Whether the note has inline tags. 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: 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. """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: for key in self.inline_metadata.dict:
self.delete_metadata(key=key, area=MetadataType.INLINE) self.delete_metadata(key=key, area=MetadataType.INLINE)
for tag in self.inline_tags.list: for tag in self.tags.list:
self.delete_inline_tag(tag=tag) self.delete_tag(tag=tag)
self.frontmatter.delete_all() self.frontmatter.delete_all()
self.write_frontmatter() self.write_frontmatter()
def delete_inline_tag(self, tag: str) -> bool: def delete_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. """Delete an inline tag from the `tags` attribute AND removes the tag from the text of the note if it exists.
Args: Args:
tag (str): Tag to delete. tag (str): Tag to delete.
@@ -210,30 +211,35 @@ class Note:
Returns: Returns:
bool: Whether the tag was deleted. bool: Whether the tag was deleted.
""" """
new_list = self.inline_tags.list.copy() new_list = self.tags.list.copy()
for _t in new_list: for _t in new_list:
if re.search(tag, _t): if re.search(tag, _t):
_t = re.escape(_t) _t = re.escape(_t)
self.sub(rf"#{_t}([ \|,;:\*\(\)\[\]\\\.\n#&])", r"\1", is_regex=True) 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 True
return False return False
def delete_metadata( 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: ) -> bool:
"""Delete a key or key-value pair from the note's Metadata object and the content of the note. Regex is supported. """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. If no value is provided, will delete an entire specified key.
Args: 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. key (str): Key to delete.
value (str, optional): Value to delete. value (str, optional): Value to delete.
area (MetadataType, optional): Area to delete metadata from. Defaults to MetadataType.ALL.
Returns: Returns:
bool: Whether the key or key-value pair was deleted. bool: Whether the key or key-value pair was deleted.
@@ -242,15 +248,15 @@ class Note:
if ( if (
area == MetadataType.FRONTMATTER or area == MetadataType.ALL 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() self.write_frontmatter()
changed_value = True changed_value = True
if ( if (
area == MetadataType.INLINE or area == MetadataType.ALL area == MetadataType.INLINE or area == MetadataType.ALL
) and self.inline_metadata.contains(key, value): ) and self.inline_metadata.contains(key, value):
self.write_delete_inline_metadata(key, value) self.write_delete_inline_metadata(key=key, value=value, is_regex=is_regex)
self.inline_metadata.delete(key, value) self.inline_metadata.delete(key=key, value_to_delete=value, is_regex=is_regex)
changed_value = True changed_value = True
if changed_value: if changed_value:
@@ -266,7 +272,7 @@ class Note:
if self.frontmatter.has_changes(): if self.frontmatter.has_changes():
return True return True
if self.inline_tags.has_changes(): if self.tags.has_changes():
return True return True
if self.inline_metadata.has_changes(): if self.inline_metadata.has_changes():
@@ -298,7 +304,7 @@ class Note:
"""Print the note to the console.""" """Print the note to the console."""
console.print(self.file_content) 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. """Rename an inline tag. Updates the Metadata object and the text of the note.
Args: Args:
@@ -308,13 +314,13 @@ class Note:
Returns: Returns:
bool: Whether the tag was renamed. bool: Whether the tag was renamed.
""" """
if tag_1 in self.inline_tags.list: if tag_1 in self.tags.list:
self.sub( self.sub(
rf"#{tag_1}([ \|,;:\*\(\)\[\]\\\.\n#&])", rf"#{tag_1}([ \|,;:\*\(\)\[\]\\\.\n#&])",
rf"#{tag_2}\1", rf"#{tag_2}\1",
is_regex=True, is_regex=True,
) )
self.inline_tags.rename(tag_1, tag_2) self.tags.rename(tag_1, tag_2)
return True return True
return False return False
@@ -447,12 +453,15 @@ class Note:
return False 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. """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. IMPORTANT: This method makes no changes to the InlineMetadata object.
Args: Args:
is_regex (bool, optional): Whether the key is a regex pattern or plain text. Defaults to False.
key (str, optional): Key to delete. key (str, optional): Key to delete.
value (str, optional): Value to delete. value (str, optional): Value to delete.
@@ -469,13 +478,15 @@ class Note:
return True return True
for _k, _v in self.inline_metadata.dict.items(): 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: for _value in _v:
if value is None: if value is None:
_k = re.escape(_k) _k = re.escape(_k)
_value = re.escape(_value) _value = re.escape(_value)
self.sub(rf"\[?{_k}:: \[?\[?{_value}\]?\]?", "", is_regex=True) 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) _k = re.escape(_k)
_value = re.escape(_value) _value = re.escape(_value)
self.sub(rf"\[?({_k}::) ?\[?\[?{_value}\]?\]?", r"\1", is_regex=True) self.sub(rf"\[?({_k}::) ?\[?\[?{_value}\]?\]?", r"\1", is_regex=True)

View File

@@ -86,7 +86,7 @@ class Questions:
self.vault = vault self.vault = vault
self.key = key 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. """Validate an existing inline tag.
Returns: Returns:
@@ -344,11 +344,11 @@ class Questions:
question, default=default, style=self.style, qmark="INPUT |" question, default=default, style=self.style, qmark="INPUT |"
).ask() ).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.""" """Ask the user for an existing inline tag."""
return questionary.text( return questionary.text(
question, question,
validate=self._validate_existing_inline_tag, validate=self._validate_existing_tag,
style=self.style, style=self.style,
qmark="INPUT |", qmark="INPUT |",
).ask() ).ask()

View File

@@ -107,7 +107,7 @@ class Vault:
] ]
if _filter.tag_filter is not None: 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: if _filter.key_filter is not None and _filter.value_filter is not None:
notes_list = [ notes_list = [
@@ -187,7 +187,7 @@ class Vault:
) )
self.metadata.index_metadata( self.metadata.index_metadata(
area=MetadataType.TAGS, area=MetadataType.TAGS,
metadata=_note.inline_tags.list, metadata=_note.tags.list,
) )
def add_metadata( def add_metadata(
@@ -273,7 +273,7 @@ class Vault:
else: else:
alerts.info("No backup found") 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. """Delete an inline tag in the vault.
Args: Args:
@@ -285,7 +285,7 @@ class Vault:
num_changed = 0 num_changed = 0
for _note in self.notes_in_scope: 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}") log.trace(f"Deleted tag from {_note.note_path}")
num_changed += 1 num_changed += 1
@@ -294,10 +294,18 @@ class Vault:
return num_changed 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. """Delete metadata in the vault.
Args: 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 key (str): Key to delete. Regex is supported
value (str, optional): Value to delete. Regex is supported value (str, optional): Value to delete. Regex is supported
@@ -307,7 +315,7 @@ class Vault:
num_changed = 0 num_changed = 0
for _note in self.notes_in_scope: 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}") log.trace(f"Deleted metadata from {_note.note_path}")
num_changed += 1 num_changed += 1
@@ -394,7 +402,7 @@ class Vault:
] ]
) )
for tag in _note.inline_tags.list: for tag in _note.tags.list:
writer.writerow( writer.writerow(
[_note.note_path.relative_to(self.vault_path), "tag", "", f"{tag}"] [_note.note_path.relative_to(self.vault_path), "tag", "", f"{tag}"]
) )
@@ -463,7 +471,7 @@ class Vault:
"""Count number of excluded notes.""" """Count number of excluded notes."""
return len(self.all_notes) - len(self.notes_in_scope) 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. """Rename an inline tag in the vault.
Args: Args:
@@ -476,7 +484,7 @@ class Vault:
num_changed = 0 num_changed = 0
for _note in self.notes_in_scope: 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}") log.trace(f"Renamed inline tag in {_note.note_path}")
num_changed += 1 num_changed += 1

View File

@@ -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) 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. """Test renaming an inline tag.
GIVEN an application GIVEN an application
@@ -159,10 +159,10 @@ def test_delete_inline_tag_1(test_application, mocker, capsys) -> None:
) )
mocker.patch( mocker.patch(
"obsidian_metadata.models.application.Questions.ask_selection", "obsidian_metadata.models.application.Questions.ask_selection",
side_effect=["delete_inline_tag", "back"], side_effect=["delete_tag", "back"],
) )
mocker.patch( mocker.patch(
"obsidian_metadata.models.application.Questions.ask_existing_inline_tag", "obsidian_metadata.models.application.Questions.ask_existing_tag",
return_value="breakfast", 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) 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. """Test renaming an inline tag.
GIVEN an application GIVEN an application
@@ -187,10 +187,10 @@ def test_delete_inline_tag_2(test_application, mocker, capsys) -> None:
) )
mocker.patch( mocker.patch(
"obsidian_metadata.models.application.Questions.ask_selection", "obsidian_metadata.models.application.Questions.ask_selection",
side_effect=["delete_inline_tag", "back"], side_effect=["delete_tag", "back"],
) )
mocker.patch( 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", 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) 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.""" """Test renaming an inline tag."""
app = test_application app = test_application
app._load_vault() app._load_vault()
@@ -398,10 +398,10 @@ def test_rename_inline_tag(test_application, mocker, capsys) -> None:
) )
mocker.patch( mocker.patch(
"obsidian_metadata.models.application.Questions.ask_selection", "obsidian_metadata.models.application.Questions.ask_selection",
side_effect=["rename_inline_tag", "back"], side_effect=["rename_tag", "back"],
) )
mocker.patch( mocker.patch(
"obsidian_metadata.models.application.Questions.ask_existing_inline_tag", "obsidian_metadata.models.application.Questions.ask_existing_tag",
return_value="not_a_tag", return_value="not_a_tag",
) )
mocker.patch( mocker.patch(
@@ -420,10 +420,10 @@ def test_rename_inline_tag(test_application, mocker, capsys) -> None:
) )
mocker.patch( mocker.patch(
"obsidian_metadata.models.application.Questions.ask_selection", "obsidian_metadata.models.application.Questions.ask_selection",
side_effect=["rename_inline_tag", "back"], side_effect=["rename_tag", "back"],
) )
mocker.patch( mocker.patch(
"obsidian_metadata.models.application.Questions.ask_existing_inline_tag", "obsidian_metadata.models.application.Questions.ask_existing_tag",
return_value="breakfast", return_value="breakfast",
) )
mocker.patch( mocker.patch(

View File

@@ -324,7 +324,7 @@ def test_delete_3():
THEN return False THEN return False
""" """
frontmatter = Frontmatter(FRONTMATTER_CONTENT) 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(): def test_delete_4():
@@ -335,7 +335,7 @@ def test_delete_4():
THEN return False THEN return False
""" """
frontmatter = Frontmatter(FRONTMATTER_CONTENT) 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(): def test_delete_5():
@@ -371,7 +371,7 @@ def test_delete_7():
THEN return True and delete the matching keys from the dict THEN return True and delete the matching keys from the dict
""" """
frontmatter = Frontmatter(FRONTMATTER_CONTENT) 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_Key1" not in frontmatter.dict
assert "frontmatter_Key2" 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 THEN return True and delete the matching values
""" """
frontmatter = Frontmatter(FRONTMATTER_CONTENT) 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_2" not in frontmatter.dict["tags"]
assert "📅/tag_3" not in frontmatter.dict["tags"] assert "📅/tag_3" not in frontmatter.dict["tags"]
assert "tag_1" in frontmatter.dict["tags"] assert "tag_1" in frontmatter.dict["tags"]

View File

@@ -289,7 +289,7 @@ def test_delete_3():
THEN return False THEN return False
""" """
inline = InlineMetadata(INLINE_CONTENT) 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(): def test_delete_4():
@@ -300,7 +300,7 @@ def test_delete_4():
THEN return False THEN return False
""" """
inline = InlineMetadata(INLINE_CONTENT) 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(): def test_delete_5():
@@ -336,7 +336,7 @@ def test_delete_7():
THEN return True and delete the matching keys from the dict THEN return True and delete the matching keys from the dict
""" """
inline = InlineMetadata(INLINE_CONTENT) 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 "key1" not in inline.dict
assert "key2" 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 THEN return True and delete the matching values
""" """
inline = InlineMetadata(INLINE_CONTENT) 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 "value1" not in inline.dict["key1"]
assert "value2" not in inline.dict["key1"] assert "value2" not in inline.dict["key1"]
assert "value3" not in inline.dict["key1"] assert "value3" not in inline.dict["key1"]

View File

@@ -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_bottom1",
"inline_tag_bottom2", "inline_tag_bottom2",
"inline_tag_top1", "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 THEN the tag is added to the InlineTags object and the file content
""" """
note = Note(note_path=sample_note) note = Note(note_path=sample_note)
assert "new_tag2" not in note.inline_tags.list assert "new_tag2" not in note.tags.list
assert ( assert (
note.add_metadata(MetadataType.TAGS, value="new_tag2", location=InsertLocation.BOTTOM) note.add_metadata(MetadataType.TAGS, value="new_tag2", location=InsertLocation.BOTTOM)
is True is True
) )
assert "new_tag2" in note.inline_tags.list assert "new_tag2" in note.tags.list
assert "#new_tag2" in note.file_content 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 assert "Heading 1" in note.file_content
def test_contains_inline_tag(sample_note) -> None: def test_contains_tag(sample_note) -> None:
"""Test contains_inline_tag method. """Test contains_tag method.
GIVEN a note object 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 THEN the method returns True if the tag is found and False if not
""" """
note = Note(note_path=sample_note) note = Note(note_path=sample_note)
assert note.contains_inline_tag("intext_tag1") is True assert note.contains_tag("intext_tag1") is True
assert note.contains_inline_tag("nonexistent_tag") is False assert note.contains_tag("nonexistent_tag") is False
assert note.contains_inline_tag(r"\d$", is_regex=True) is True assert note.contains_tag(r"\d$", is_regex=True) is True
assert note.contains_inline_tag(r"^\d", is_regex=True) is False assert note.contains_tag(r"^\d", is_regex=True) is False
def test_contains_metadata(sample_note) -> None: 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 = Note(note_path=sample_note)
note.delete_all_metadata() note.delete_all_metadata()
assert note.inline_tags.list == [] assert note.tags.list == []
assert note.frontmatter.dict == {} assert note.frontmatter.dict == {}
assert note.inline_metadata.dict == {} assert note.inline_metadata.dict == {}
assert note.file_content == Regex("consequat. Duis") assert note.file_content == Regex("consequat. Duis")
@@ -332,17 +332,17 @@ def test_delete_all_metadata(sample_note):
assert "---" not in note.file_content assert "---" not in note.file_content
def test_delete_inline_tag(sample_note) -> None: def test_delete_tag(sample_note) -> None:
"""Test delete_inline_tag method. """Test delete_tag method.
GIVEN a note object 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 THEN the method returns True if the tag is found and deleted and False if not
""" """
note = Note(note_path=sample_note) note = Note(note_path=sample_note)
assert note.delete_inline_tag("not_a_tag") is False assert note.delete_tag("not_a_tag") is False
assert note.delete_inline_tag("intext_tag[1]") is True assert note.delete_tag("intext_tag[1]") is True
assert "intext_tag1" not in note.inline_tags.list assert "intext_tag1" not in note.tags.list
assert note.file_content == Regex("consequat. Duis") assert note.file_content == Regex("consequat. Duis")
@@ -454,7 +454,7 @@ def test_has_changes(sample_note) -> None:
note = Note(note_path=sample_note) note = Note(note_path=sample_note)
assert note.has_changes() is False assert note.has_changes() is False
note.delete_inline_tag("intext_tag1") note.delete_tag("intext_tag1")
assert note.has_changes() is True assert note.has_changes() is True
@@ -494,29 +494,29 @@ def test_print_note(sample_note, capsys) -> None:
assert "#shared_tag" in captured.out assert "#shared_tag" in captured.out
def test_rename_inline_tag_1(sample_note) -> None: def test_rename_tag_1(sample_note) -> None:
"""Test rename_inline_tag() method. """Test rename_tag() method.
GIVEN a note object 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 THEN the method returns False
""" """
note = Note(note_path=sample_note) 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: def test_rename_tag_2(sample_note) -> None:
"""Test rename_inline_tag() method. """Test rename_tag() method.
GIVEN a note object GIVEN a note object
WHEN rename_inline_tag() is called with a tag exists WHEN rename_tag() is called with a tag exists
THEN the tag is renamed in the InlineTags object and the file content THEN the tag is renamed in the InlineTag object and the file content
""" """
note = Note(note_path=sample_note) note = Note(note_path=sample_note)
assert "intext_tag1" in note.inline_tags.list assert "intext_tag1" in note.tags.list
assert note.rename_inline_tag("intext_tag1", "intext_tag26") is True assert note.rename_tag("intext_tag1", "intext_tag26") is True
assert "intext_tag1" not in note.inline_tags.list assert "intext_tag1" not in note.tags.list
assert "intext_tag26" in note.inline_tags.list assert "intext_tag26" in note.tags.list
assert note.file_content == Regex(r"#intext_tag26") assert note.file_content == Regex(r"#intext_tag26")
assert note.file_content != Regex(r"#intext_tag1") 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 = 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) 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 THEN the key/value is removed from the note content
""" """
note = Note(note_path=sample_note) 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_value")
assert note.file_content == Regex(r"bottom_key2::") assert note.file_content == Regex(r"bottom_key2::")
note.write_delete_inline_metadata("bottom_key1") note.write_delete_inline_metadata("bottom_key1")

View File

@@ -68,12 +68,12 @@ def test_validate_number() -> None:
assert questions._validate_number("1") is True assert questions._validate_number("1") is True
def test_validate_existing_inline_tag() -> None: def test_validate_existing_tag() -> None:
"""Test existing tag validation.""" """Test existing tag validation."""
questions = Questions(vault=VAULT) questions = Questions(vault=VAULT)
assert "Tag cannot be empty" in questions._validate_existing_inline_tag("") assert "Tag cannot be empty" in questions._validate_existing_tag("")
assert "'test' does not exist" in questions._validate_existing_inline_tag("test") assert "'test' does not exist" in questions._validate_existing_tag("test")
assert questions._validate_existing_inline_tag("shared_tag") is True assert questions._validate_existing_tag("shared_tag") is True
def test_validate_key_exists_regex() -> None: def test_validate_key_exists_regex() -> None:

View File

@@ -315,16 +315,16 @@ def test_delete_backup_2(test_vault, capsys):
assert vault.backup_path.exists() is True assert vault.backup_path.exists() is True
def test_delete_inline_tag_1(test_vault) -> None: def test_delete_tag_1(test_vault) -> None:
"""Test delete_inline_tag() method. """Test delete_tag() method.
GIVEN a vault object 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 THEN the inline tag is deleted
""" """
vault = Vault(config=test_vault) vault = Vault(config=test_vault)
assert vault.delete_inline_tag("intext_tag2") == 1 assert vault.delete_tag("intext_tag2") == 1
assert vault.metadata.tags == [ assert vault.metadata.tags == [
"inline_tag_bottom1", "inline_tag_bottom1",
"inline_tag_bottom2", "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: def test_delete_tag_2(test_vault) -> None:
"""Test delete_inline_tag() method. """Test delete_tag() method.
GIVEN a vault object 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 THEN no changes are made
""" """
vault = Vault(config=test_vault) 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: 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 assert vault.move_inline_metadata(location=InsertLocation.TOP) == 1
def test_rename_inline_tag_1(test_vault) -> None: def test_rename_tag_1(test_vault) -> None:
"""Test rename_inline_tag() method. """Test rename_tag() method.
GIVEN a vault object 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 THEN the inline tag is renamed
""" """
vault = Vault(config=test_vault) 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 == [ assert vault.metadata.tags == [
"inline_tag_bottom1", "inline_tag_bottom1",
"inline_tag_bottom2", "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: def test_rename_tag_2(test_vault) -> None:
"""Test rename_inline_tag() method. """Test rename_tag() method.
GIVEN a vault object 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 THEN the inline tag is not renamed
""" """
vault = Vault(config=test_vault) 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: 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].note_path.name == "test1.md"
assert vault.get_changed_notes()[0].frontmatter.dict == {"new_key": ["new_value"]} 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_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.frontmatter == {"new_key": ["new_value"]}
assert vault.metadata.inline_metadata == {"new_key2": ["new_value"]} assert vault.metadata.inline_metadata == {"new_key2": ["new_value"]}
assert vault.metadata.tags == ["new_tag"] assert vault.metadata.tags == ["new_tag"]