mirror of
https://github.com/natelandau/obsidian-metadata.git
synced 2025-11-13 15:33:47 -05:00
feat: select insert location for new inline metadata
This commit is contained in:
@@ -94,35 +94,6 @@ class Note:
|
|||||||
_v = re.escape(_v)
|
_v = re.escape(_v)
|
||||||
self.sub(rf"({_k}::) ?{_v}", r"\1", is_regex=True)
|
self.sub(rf"({_k}::) ?{_v}", r"\1", is_regex=True)
|
||||||
|
|
||||||
def _rename_inline_metadata(self, key: str, value_1: str, value_2: str = None) -> None:
|
|
||||||
"""Replace the inline metadata in the note with the current inline metadata object.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key (str): Key to rename.
|
|
||||||
value_1 (str): Value to replace OR new key name (if value_2 is None).
|
|
||||||
value_2 (str, optional): New value.
|
|
||||||
|
|
||||||
"""
|
|
||||||
all_results = PATTERNS.find_inline_metadata.findall(self.file_content)
|
|
||||||
stripped_null_values = [tuple(filter(None, x)) for x in all_results]
|
|
||||||
|
|
||||||
for _k, _v in stripped_null_values:
|
|
||||||
if re.search(key, _k):
|
|
||||||
if value_2 is None:
|
|
||||||
if re.search(rf"{key}[^\w\d_-]+", _k):
|
|
||||||
key_text = re.split(r"[^\w\d_-]+$", _k)[0]
|
|
||||||
key_markdown = re.split(r"^[\w\d_-]+", _k)[1]
|
|
||||||
self.sub(
|
|
||||||
rf"{key_text}{key_markdown}::",
|
|
||||||
rf"{value_1}{key_markdown}::",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.sub(f"{_k}::", f"{value_1}::")
|
|
||||||
elif re.search(key, _k) and re.search(value_1, _v):
|
|
||||||
_k = re.escape(_k)
|
|
||||||
_v = re.escape(_v)
|
|
||||||
self.sub(f"{_k}:: ?{_v}", f"{_k}:: {value_2}", is_regex=True)
|
|
||||||
|
|
||||||
def add_metadata( # noqa: C901
|
def add_metadata( # noqa: C901
|
||||||
self,
|
self,
|
||||||
area: MetadataType,
|
area: MetadataType,
|
||||||
@@ -143,13 +114,13 @@ class Note:
|
|||||||
"""
|
"""
|
||||||
match area:
|
match area:
|
||||||
case MetadataType.FRONTMATTER if self.frontmatter.add(key, value):
|
case MetadataType.FRONTMATTER if self.frontmatter.add(key, value):
|
||||||
self.update_frontmatter()
|
self.write_frontmatter()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
case MetadataType.INLINE:
|
case MetadataType.INLINE:
|
||||||
if value is None and self.inline_metadata.add(key):
|
if value is None and self.inline_metadata.add(key):
|
||||||
line = f"{key}::"
|
line = f"{key}::"
|
||||||
self.insert(new_string=line, location=location)
|
self.write_string(new_string=line, location=location)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
new_values = []
|
new_values = []
|
||||||
@@ -160,7 +131,7 @@ class Note:
|
|||||||
|
|
||||||
if new_values:
|
if new_values:
|
||||||
for value in new_values:
|
for value in new_values:
|
||||||
self.insert(new_string=f"{key}:: {value}", location=location)
|
self.write_string(new_string=f"{key}:: {value}", location=location)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
case MetadataType.TAGS:
|
case MetadataType.TAGS:
|
||||||
@@ -175,7 +146,7 @@ class Note:
|
|||||||
_v = value
|
_v = value
|
||||||
if _v.startswith("#"):
|
if _v.startswith("#"):
|
||||||
_v = _v[1:]
|
_v = _v[1:]
|
||||||
self.insert(new_string=f"#{_v}", location=location)
|
self.write_string(new_string=f"#{_v}", location=location)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
@@ -183,6 +154,28 @@ class Note:
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def commit(self, path: Path = None) -> None:
|
||||||
|
"""Write the note's content to disk. This is a destructive action.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path (Path): Path to write the note to. Defaults to the note's path.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
typer.Exit: If the note's path is not found.
|
||||||
|
"""
|
||||||
|
p = self.note_path if path is None else path
|
||||||
|
if self.dry_run:
|
||||||
|
log.trace(f"DRY RUN: Writing note {p} to disk")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(p, "w") as f:
|
||||||
|
log.trace(f"Writing note {p} to disk")
|
||||||
|
f.write(self.file_content)
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
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_inline_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.
|
||||||
|
|
||||||
@@ -196,7 +189,7 @@ class Note:
|
|||||||
return self.inline_tags.contains(tag, is_regex=is_regex)
|
return self.inline_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 metadata.
|
"""Check if a note has a key or a key-value pair in its Frontmatter or InlineMetadata.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
key (str): Key to check for.
|
key (str): Key to check for.
|
||||||
@@ -245,7 +238,7 @@ class Note:
|
|||||||
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
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Delete a key or key-value pair from the note's metadata. Regex is supported.
|
"""Delete a key or key-value pair from the note's Frontmatter or InlineMetadata. Regex is supported.
|
||||||
|
|
||||||
If no value is provided, will delete an entire key.
|
If no value is provided, will delete an entire key.
|
||||||
|
|
||||||
@@ -263,7 +256,7 @@ class Note:
|
|||||||
if (
|
if (
|
||||||
area == MetadataType.FRONTMATTER or area == MetadataType.ALL
|
area == MetadataType.FRONTMATTER or area == MetadataType.ALL
|
||||||
) and self.frontmatter.delete(key):
|
) and self.frontmatter.delete(key):
|
||||||
self.update_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
|
||||||
@@ -274,7 +267,7 @@ 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, value):
|
||||||
self.update_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
|
||||||
@@ -306,53 +299,6 @@ class Note:
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def insert(
|
|
||||||
self,
|
|
||||||
new_string: str,
|
|
||||||
location: InsertLocation,
|
|
||||||
allow_multiple: bool = False,
|
|
||||||
) -> None:
|
|
||||||
"""Insert a string at the top of a note.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
new_string (str): String to insert at the top of the note.
|
|
||||||
allow_multiple (bool): Whether to allow inserting the string if it already exists in the note.
|
|
||||||
location (InsertLocation): Location to insert the string.
|
|
||||||
"""
|
|
||||||
if not allow_multiple and len(re.findall(re.escape(new_string), self.file_content)) > 0:
|
|
||||||
return
|
|
||||||
|
|
||||||
match location:
|
|
||||||
case InsertLocation.BOTTOM:
|
|
||||||
self.file_content += f"\n{new_string}"
|
|
||||||
case InsertLocation.TOP:
|
|
||||||
try:
|
|
||||||
top = PATTERNS.frontmatter_block.search(self.file_content).group("frontmatter")
|
|
||||||
except AttributeError:
|
|
||||||
top = ""
|
|
||||||
|
|
||||||
if top == "":
|
|
||||||
self.file_content = f"{new_string}\n{self.file_content}"
|
|
||||||
else:
|
|
||||||
new_string = f"{top}\n{new_string}"
|
|
||||||
top = re.escape(top)
|
|
||||||
self.sub(top, new_string, is_regex=True)
|
|
||||||
case InsertLocation.AFTER_TITLE:
|
|
||||||
try:
|
|
||||||
top = PATTERNS.top_with_header.search(self.file_content).group("top")
|
|
||||||
except AttributeError:
|
|
||||||
top = ""
|
|
||||||
|
|
||||||
if top == "":
|
|
||||||
self.file_content = f"{new_string}\n{self.file_content}"
|
|
||||||
else:
|
|
||||||
new_string = f"{top}\n{new_string}"
|
|
||||||
top = re.escape(top)
|
|
||||||
self.sub(top, new_string, is_regex=True)
|
|
||||||
case _:
|
|
||||||
raise ValueError(f"Invalid location: {location}")
|
|
||||||
pass
|
|
||||||
|
|
||||||
def print_note(self) -> None:
|
def print_note(self) -> None:
|
||||||
"""Print the note to the console."""
|
"""Print the note to the console."""
|
||||||
console.print(self.file_content)
|
console.print(self.file_content)
|
||||||
@@ -395,7 +341,7 @@ class Note:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def rename_metadata(self, key: str, value_1: str, value_2: str = None) -> bool:
|
def rename_metadata(self, key: str, value_1: str, value_2: str = None) -> bool:
|
||||||
"""Rename a key or key-value pair in the note's metadata.
|
"""Rename a key or key-value pair in the note's InlineMetadata and Frontmatter objects.
|
||||||
|
|
||||||
If no value is provided, will rename an entire key.
|
If no value is provided, will rename an entire key.
|
||||||
|
|
||||||
@@ -410,17 +356,17 @@ class Note:
|
|||||||
changed_value: bool = False
|
changed_value: bool = False
|
||||||
if value_2 is None:
|
if value_2 is None:
|
||||||
if self.frontmatter.rename(key, value_1):
|
if self.frontmatter.rename(key, value_1):
|
||||||
self.update_frontmatter()
|
self.write_frontmatter()
|
||||||
changed_value = True
|
changed_value = True
|
||||||
if self.inline_metadata.rename(key, value_1):
|
if self.inline_metadata.rename(key, value_1):
|
||||||
self._rename_inline_metadata(key, value_1)
|
self.write_metadata(key, value_1)
|
||||||
changed_value = True
|
changed_value = True
|
||||||
else:
|
else:
|
||||||
if self.frontmatter.rename(key, value_1, value_2):
|
if self.frontmatter.rename(key, value_1, value_2):
|
||||||
self.update_frontmatter()
|
self.write_frontmatter()
|
||||||
changed_value = True
|
changed_value = True
|
||||||
if self.inline_metadata.rename(key, value_1, value_2):
|
if self.inline_metadata.rename(key, value_1, value_2):
|
||||||
self._rename_inline_metadata(key, value_1, value_2)
|
self.write_metadata(key, value_1, value_2)
|
||||||
changed_value = True
|
changed_value = True
|
||||||
|
|
||||||
if changed_value:
|
if changed_value:
|
||||||
@@ -520,7 +466,7 @@ class Note:
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def update_frontmatter(self, sort_keys: bool = False) -> None:
|
def write_frontmatter(self, sort_keys: bool = False) -> None:
|
||||||
"""Replace the frontmatter in the note with the current frontmatter object."""
|
"""Replace the frontmatter in the note with the current frontmatter object."""
|
||||||
try:
|
try:
|
||||||
current_frontmatter = PATTERNS.frontmatter_block.search(self.file_content).group(
|
current_frontmatter = PATTERNS.frontmatter_block.search(self.file_content).group(
|
||||||
@@ -542,24 +488,78 @@ class Note:
|
|||||||
current_frontmatter = f"{re.escape(current_frontmatter)}\n?"
|
current_frontmatter = f"{re.escape(current_frontmatter)}\n?"
|
||||||
self.sub(current_frontmatter, new_frontmatter, is_regex=True)
|
self.sub(current_frontmatter, new_frontmatter, is_regex=True)
|
||||||
|
|
||||||
def write(self, path: Path = None) -> None:
|
def write_metadata(self, key: str, value_1: str, value_2: str = None) -> None:
|
||||||
"""Write the note's content to disk.
|
"""Write changes to a specific inline metadata key or value.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
path (Path): Path to write the note to. Defaults to the note's path.
|
key (str): Key to rename.
|
||||||
|
value_1 (str): Value to replace OR new key name (if value_2 is None).
|
||||||
|
value_2 (str, optional): New value.
|
||||||
|
|
||||||
Raises:
|
|
||||||
typer.Exit: If the note's path is not found.
|
|
||||||
"""
|
"""
|
||||||
p = self.note_path if path is None else path
|
all_results = PATTERNS.find_inline_metadata.findall(self.file_content)
|
||||||
if self.dry_run:
|
stripped_null_values = [tuple(filter(None, x)) for x in all_results]
|
||||||
log.trace(f"DRY RUN: Writing note {p} to disk")
|
|
||||||
|
for _k, _v in stripped_null_values:
|
||||||
|
if re.search(key, _k):
|
||||||
|
if value_2 is None:
|
||||||
|
if re.search(rf"{key}[^\w\d_-]+", _k):
|
||||||
|
key_text = re.split(r"[^\w\d_-]+$", _k)[0]
|
||||||
|
key_markdown = re.split(r"^[\w\d_-]+", _k)[1]
|
||||||
|
self.sub(
|
||||||
|
rf"{key_text}{key_markdown}::",
|
||||||
|
rf"{value_1}{key_markdown}::",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.sub(f"{_k}::", f"{value_1}::")
|
||||||
|
elif re.search(key, _k) and re.search(value_1, _v):
|
||||||
|
_k = re.escape(_k)
|
||||||
|
_v = re.escape(_v)
|
||||||
|
self.sub(f"{_k}:: ?{_v}", f"{_k}:: {value_2}", is_regex=True)
|
||||||
|
|
||||||
|
def write_string(
|
||||||
|
self,
|
||||||
|
new_string: str,
|
||||||
|
location: InsertLocation,
|
||||||
|
allow_multiple: bool = False,
|
||||||
|
) -> None:
|
||||||
|
"""Insert a string into the note at a requested location.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
new_string (str): String to insert at the top of the note.
|
||||||
|
allow_multiple (bool): Whether to allow inserting the string if it already exists in the note.
|
||||||
|
location (InsertLocation): Location to insert the string.
|
||||||
|
"""
|
||||||
|
if not allow_multiple and len(re.findall(re.escape(new_string), self.file_content)) > 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
match location:
|
||||||
with open(p, "w") as f:
|
case InsertLocation.BOTTOM:
|
||||||
log.trace(f"Writing note {p} to disk")
|
self.file_content += f"\n{new_string}"
|
||||||
f.write(self.file_content)
|
case InsertLocation.TOP:
|
||||||
except FileNotFoundError as e:
|
try:
|
||||||
alerts.error(f"Note {p} not found. Exiting")
|
top = PATTERNS.frontmatter_block.search(self.file_content).group("frontmatter")
|
||||||
raise typer.Exit(code=1) from e
|
except AttributeError:
|
||||||
|
top = ""
|
||||||
|
|
||||||
|
if top == "":
|
||||||
|
self.file_content = f"{new_string}\n{self.file_content}"
|
||||||
|
else:
|
||||||
|
new_string = f"{top}\n{new_string}"
|
||||||
|
top = re.escape(top)
|
||||||
|
self.sub(top, new_string, is_regex=True)
|
||||||
|
case InsertLocation.AFTER_TITLE:
|
||||||
|
try:
|
||||||
|
top = PATTERNS.top_with_header.search(self.file_content).group("top")
|
||||||
|
except AttributeError:
|
||||||
|
top = ""
|
||||||
|
|
||||||
|
if top == "":
|
||||||
|
self.file_content = f"{new_string}\n{self.file_content}"
|
||||||
|
else:
|
||||||
|
new_string = f"{top}\n{new_string}"
|
||||||
|
top = re.escape(top)
|
||||||
|
self.sub(top, new_string, is_regex=True)
|
||||||
|
case _:
|
||||||
|
raise ValueError(f"Invalid location: {location}")
|
||||||
|
pass
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class Vault:
|
|||||||
return notes_list
|
return notes_list
|
||||||
|
|
||||||
def _find_insert_location(self) -> InsertLocation:
|
def _find_insert_location(self) -> InsertLocation:
|
||||||
"""Find the insert location for a note.
|
"""Find the insert location for a note from the configuration file.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
InsertLocation: Insert location for the note.
|
InsertLocation: Insert location for the note.
|
||||||
@@ -130,6 +130,24 @@ class Vault:
|
|||||||
|
|
||||||
return InsertLocation.BOTTOM
|
return InsertLocation.BOTTOM
|
||||||
|
|
||||||
|
@property
|
||||||
|
def insert_location(self) -> InsertLocation:
|
||||||
|
"""Location to insert new or reorganized metadata.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
InsertLocation: The insert location.
|
||||||
|
"""
|
||||||
|
return self._insert_location
|
||||||
|
|
||||||
|
@insert_location.setter
|
||||||
|
def insert_location(self, value: InsertLocation) -> None:
|
||||||
|
"""Set the insert location for the vault.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (InsertLocation): The insert location to set.
|
||||||
|
"""
|
||||||
|
self._insert_location = value
|
||||||
|
|
||||||
def _find_markdown_notes(self) -> list[Path]:
|
def _find_markdown_notes(self) -> list[Path]:
|
||||||
"""Build list of all markdown files in the vault.
|
"""Build list of all markdown files in the vault.
|
||||||
|
|
||||||
@@ -234,7 +252,7 @@ class Vault:
|
|||||||
for _note in self.notes_in_scope:
|
for _note in self.notes_in_scope:
|
||||||
if _note.has_changes():
|
if _note.has_changes():
|
||||||
log.trace(f"writing to {_note.note_path}")
|
log.trace(f"writing to {_note.note_path}")
|
||||||
_note.write()
|
_note.commit()
|
||||||
|
|
||||||
def delete_backup(self) -> None:
|
def delete_backup(self) -> None:
|
||||||
"""Delete the vault backup."""
|
"""Delete the vault backup."""
|
||||||
|
|||||||
@@ -297,7 +297,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.insert("This is a test string.", location=InsertLocation.BOTTOM)
|
note.write_string("This is a test string.", location=InsertLocation.BOTTOM)
|
||||||
assert note.has_changes() is True
|
assert note.has_changes() is True
|
||||||
|
|
||||||
note = Note(note_path=sample_note)
|
note = Note(note_path=sample_note)
|
||||||
@@ -316,7 +316,7 @@ def test_has_changes(sample_note) -> None:
|
|||||||
assert note.has_changes() is True
|
assert note.has_changes() is True
|
||||||
|
|
||||||
|
|
||||||
def test_insert_bottom(short_note) -> None:
|
def test_write_string_bottom(short_note) -> None:
|
||||||
"""Test inserting metadata to bottom of note."""
|
"""Test inserting metadata to bottom of note."""
|
||||||
path1, path2 = short_note
|
path1, path2 = short_note
|
||||||
note = Note(note_path=str(path1))
|
note = Note(note_path=str(path1))
|
||||||
@@ -353,20 +353,20 @@ Lorem ipsum dolor sit amet.
|
|||||||
|
|
||||||
This is a test string.
|
This is a test string.
|
||||||
"""
|
"""
|
||||||
note.insert(new_string=string1, location=InsertLocation.BOTTOM)
|
note.write_string(new_string=string1, location=InsertLocation.BOTTOM)
|
||||||
assert note.file_content == correct_content.strip()
|
assert note.file_content == correct_content.strip()
|
||||||
|
|
||||||
note.insert(new_string=string2, location=InsertLocation.BOTTOM)
|
note.write_string(new_string=string2, location=InsertLocation.BOTTOM)
|
||||||
assert note.file_content == correct_content.strip()
|
assert note.file_content == correct_content.strip()
|
||||||
|
|
||||||
note.insert(new_string=string2, allow_multiple=True, location=InsertLocation.BOTTOM)
|
note.write_string(new_string=string2, allow_multiple=True, location=InsertLocation.BOTTOM)
|
||||||
assert note.file_content == correct_content2.strip()
|
assert note.file_content == correct_content2.strip()
|
||||||
|
|
||||||
note2.insert(new_string=string1, location=InsertLocation.BOTTOM)
|
note2.write_string(new_string=string1, location=InsertLocation.BOTTOM)
|
||||||
assert note2.file_content == correct_content3.strip()
|
assert note2.file_content == correct_content3.strip()
|
||||||
|
|
||||||
|
|
||||||
def test_insert_after_frontmatter(short_note) -> None:
|
def test_write_string_after_frontmatter(short_note) -> None:
|
||||||
"""Test inserting metadata to bottom of note."""
|
"""Test inserting metadata to bottom of note."""
|
||||||
path1, path2 = short_note
|
path1, path2 = short_note
|
||||||
note = Note(note_path=path1)
|
note = Note(note_path=path1)
|
||||||
@@ -401,17 +401,17 @@ This is a test string.
|
|||||||
Lorem ipsum dolor sit amet.
|
Lorem ipsum dolor sit amet.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
note.insert(new_string=string1, location=InsertLocation.TOP)
|
note.write_string(new_string=string1, location=InsertLocation.TOP)
|
||||||
assert note.file_content.strip() == correct_content.strip()
|
assert note.file_content.strip() == correct_content.strip()
|
||||||
|
|
||||||
note.insert(new_string=string2, allow_multiple=True, location=InsertLocation.TOP)
|
note.write_string(new_string=string2, allow_multiple=True, location=InsertLocation.TOP)
|
||||||
assert note.file_content.strip() == correct_content2.strip()
|
assert note.file_content.strip() == correct_content2.strip()
|
||||||
|
|
||||||
note2.insert(new_string=string1, location=InsertLocation.TOP)
|
note2.write_string(new_string=string1, location=InsertLocation.TOP)
|
||||||
assert note2.file_content.strip() == correct_content3.strip()
|
assert note2.file_content.strip() == correct_content3.strip()
|
||||||
|
|
||||||
|
|
||||||
def test_insert_after_title(short_note) -> None:
|
def test_write_string_after_title(short_note) -> None:
|
||||||
"""Test inserting metadata to bottom of note."""
|
"""Test inserting metadata to bottom of note."""
|
||||||
path1, path2 = short_note
|
path1, path2 = short_note
|
||||||
note = Note(note_path=path1)
|
note = Note(note_path=path1)
|
||||||
@@ -446,13 +446,13 @@ This is a test string.
|
|||||||
Lorem ipsum dolor sit amet.
|
Lorem ipsum dolor sit amet.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
note.insert(new_string=string1, location=InsertLocation.AFTER_TITLE)
|
note.write_string(new_string=string1, location=InsertLocation.AFTER_TITLE)
|
||||||
assert note.file_content.strip() == correct_content.strip()
|
assert note.file_content.strip() == correct_content.strip()
|
||||||
|
|
||||||
note.insert(new_string=string2, allow_multiple=True, location=InsertLocation.AFTER_TITLE)
|
note.write_string(new_string=string2, allow_multiple=True, location=InsertLocation.AFTER_TITLE)
|
||||||
assert note.file_content.strip() == correct_content2.strip()
|
assert note.file_content.strip() == correct_content2.strip()
|
||||||
|
|
||||||
note2.insert(new_string=string1, location=InsertLocation.AFTER_TITLE)
|
note2.write_string(new_string=string1, location=InsertLocation.AFTER_TITLE)
|
||||||
assert note2.file_content.strip() == correct_content3.strip()
|
assert note2.file_content.strip() == correct_content3.strip()
|
||||||
|
|
||||||
|
|
||||||
@@ -470,7 +470,7 @@ def test_print_diff(sample_note, capsys) -> None:
|
|||||||
"""Test printing diff."""
|
"""Test printing diff."""
|
||||||
note = Note(note_path=sample_note)
|
note = Note(note_path=sample_note)
|
||||||
|
|
||||||
note.insert("This is a test string.", location=InsertLocation.BOTTOM)
|
note.write_string("This is a test string.", location=InsertLocation.BOTTOM)
|
||||||
note.print_diff()
|
note.print_diff()
|
||||||
captured = capsys.readouterr()
|
captured = capsys.readouterr()
|
||||||
assert "+ This is a test string." in captured.out
|
assert "+ This is a test string." in captured.out
|
||||||
@@ -513,20 +513,20 @@ def test_rename_inline_tag(sample_note) -> None:
|
|||||||
assert note.file_content != Regex(r"#intext_tag1")
|
assert note.file_content != Regex(r"#intext_tag1")
|
||||||
|
|
||||||
|
|
||||||
def test_rename_inline_metadata(sample_note) -> None:
|
def test_write_metadata(sample_note) -> None:
|
||||||
"""Test renaming inline metadata."""
|
"""Test renaming inline metadata."""
|
||||||
note = Note(note_path=sample_note)
|
note = Note(note_path=sample_note)
|
||||||
|
|
||||||
note._rename_inline_metadata("nonexistent_key", "new_key")
|
note.write_metadata("nonexistent_key", "new_key")
|
||||||
assert note.file_content == note.original_file_content
|
assert note.file_content == note.original_file_content
|
||||||
note._rename_inline_metadata("bottom_key1", "no_value", "new_value")
|
note.write_metadata("bottom_key1", "no_value", "new_value")
|
||||||
assert note.file_content == note.original_file_content
|
assert note.file_content == note.original_file_content
|
||||||
|
|
||||||
note._rename_inline_metadata("bottom_key1", "new_key")
|
note.write_metadata("bottom_key1", "new_key")
|
||||||
assert note.file_content != Regex(r"bottom_key1::")
|
assert note.file_content != Regex(r"bottom_key1::")
|
||||||
assert note.file_content == Regex(r"new_key::")
|
assert note.file_content == Regex(r"new_key::")
|
||||||
|
|
||||||
note._rename_inline_metadata("key📅", "📅_key_value", "new_value")
|
note.write_metadata("key📅", "📅_key_value", "new_value")
|
||||||
assert note.file_content != Regex(r"key📅:: ?📅_key_value")
|
assert note.file_content != Regex(r"key📅:: ?📅_key_value")
|
||||||
assert note.file_content == Regex(r"key📅:: ?new_value")
|
assert note.file_content == Regex(r"key📅:: ?new_value")
|
||||||
|
|
||||||
@@ -804,12 +804,12 @@ def test_transpose_frontmatter(sample_note) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_update_frontmatter(sample_note) -> None:
|
def test_write_frontmatter(sample_note) -> None:
|
||||||
"""Test replacing frontmatter."""
|
"""Test replacing frontmatter."""
|
||||||
note = Note(note_path=sample_note)
|
note = Note(note_path=sample_note)
|
||||||
|
|
||||||
note.rename_metadata("frontmatter_Key1", "author name", "some_new_key_here")
|
note.rename_metadata("frontmatter_Key1", "author name", "some_new_key_here")
|
||||||
note.update_frontmatter()
|
note.write_frontmatter()
|
||||||
new_frontmatter = """---
|
new_frontmatter = """---
|
||||||
date_created: '2022-12-22'
|
date_created: '2022-12-22'
|
||||||
tags:
|
tags:
|
||||||
@@ -831,9 +831,9 @@ shared_key2: shared_key2_value1
|
|||||||
assert "```python" in note.file_content
|
assert "```python" in note.file_content
|
||||||
|
|
||||||
note2 = Note(note_path="tests/fixtures/test_vault/no_metadata.md")
|
note2 = Note(note_path="tests/fixtures/test_vault/no_metadata.md")
|
||||||
note2.update_frontmatter()
|
note2.write_frontmatter()
|
||||||
note2.frontmatter.dict = {"key1": "value1", "key2": "value2"}
|
note2.frontmatter.dict = {"key1": "value1", "key2": "value2"}
|
||||||
note2.update_frontmatter()
|
note2.write_frontmatter()
|
||||||
new_frontmatter = """---
|
new_frontmatter = """---
|
||||||
key1: value1
|
key1: value1
|
||||||
key2: value2
|
key2: value2
|
||||||
@@ -842,18 +842,18 @@ key2: value2
|
|||||||
assert "Lorem ipsum dolor sit amet" in note2.file_content
|
assert "Lorem ipsum dolor sit amet" in note2.file_content
|
||||||
|
|
||||||
|
|
||||||
def test_write(sample_note, tmp_path) -> None:
|
def test_commit(sample_note, tmp_path) -> None:
|
||||||
"""Test writing note to file."""
|
"""Test writing note to file."""
|
||||||
note = Note(note_path=sample_note)
|
note = Note(note_path=sample_note)
|
||||||
note.sub(pattern="Heading 1", replacement="Heading 2")
|
note.sub(pattern="Heading 1", replacement="Heading 2")
|
||||||
|
|
||||||
note.write()
|
note.commit()
|
||||||
note = Note(note_path=sample_note)
|
note = Note(note_path=sample_note)
|
||||||
assert "Heading 2" in note.file_content
|
assert "Heading 2" in note.file_content
|
||||||
assert "Heading 1" not in note.file_content
|
assert "Heading 1" not in note.file_content
|
||||||
|
|
||||||
new_path = Path(tmp_path / "new_note.md")
|
new_path = Path(tmp_path / "new_note.md")
|
||||||
note.write(new_path)
|
note.commit(new_path)
|
||||||
note2 = Note(note_path=new_path)
|
note2 = Note(note_path=new_path)
|
||||||
assert "Heading 2" in note2.file_content
|
assert "Heading 2" in note2.file_content
|
||||||
assert "Heading 1" not in note2.file_content
|
assert "Heading 1" not in note2.file_content
|
||||||
|
|||||||
@@ -95,6 +95,20 @@ def test_vault_creation(test_vault):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def set_insert_location(test_vault):
|
||||||
|
"""Test setting a new insert location."""
|
||||||
|
vault_path = test_vault
|
||||||
|
config = Config(config_path="tests/fixtures/test_vault_config.toml", vault_path=vault_path)
|
||||||
|
vault_config = config.vaults[0]
|
||||||
|
vault = Vault(config=vault_config)
|
||||||
|
|
||||||
|
assert vault.name == "vault"
|
||||||
|
assert vault.vault_path == vault_path
|
||||||
|
assert vault.insert_location == InsertLocation.BOTTOM
|
||||||
|
vault.insert_location = InsertLocation.TOP
|
||||||
|
assert vault.insert_location == InsertLocation.TOP
|
||||||
|
|
||||||
|
|
||||||
def test_add_metadata(test_vault) -> None:
|
def test_add_metadata(test_vault) -> None:
|
||||||
"""Test adding metadata to the vault."""
|
"""Test adding metadata to the vault."""
|
||||||
vault_path = test_vault
|
vault_path = test_vault
|
||||||
|
|||||||
Reference in New Issue
Block a user