feat: greatly improve capturing all formats of inline metadata (#41)

feat: greatly improve capturing metadata all formats of inline metadata
This commit is contained in:
Nathaniel Landau
2023-05-05 13:09:59 -04:00
committed by GitHub
parent 9ec6919022
commit 2e61a92ad1
38 changed files with 3634 additions and 5955 deletions

View File

@@ -1,16 +1,17 @@
# type: ignore
"""Tests for the Vault module."""
import re
from pathlib import Path
import pytest
import typer
from rich import print
from obsidian_metadata._config import Config
from obsidian_metadata._utils.console import console
from obsidian_metadata.models import Vault, VaultFilter
from obsidian_metadata.models.enums import InsertLocation, MetadataType
from tests.helpers import Regex
from tests.helpers import Regex, strip_ansi
def test_vault_creation(test_vault, tmp_path):
@@ -28,65 +29,33 @@ def test_vault_creation(test_vault, tmp_path):
assert vault.dry_run is False
assert str(vault.exclude_paths[0]) == Regex(r".*\.git")
assert len(vault.all_notes) == 2
assert vault.metadata.dict == {
"bottom_key1": ["bottom_key1_value"],
"bottom_key2": ["bottom_key2_value"],
assert vault.frontmatter == {
"date_created": ["2022-12-22"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_value"],
"key📅": ["📅_key_value"],
"shared_key1": [
"shared_key1_value",
"shared_key1_value2",
"shared_key1_value3",
],
"shared_key2": ["shared_key2_value1", "shared_key2_value2"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value_as_link"],
"frontmatter1": ["foo"],
"frontmatter2": ["bar", "baz", "qux"],
"tags": ["bar", "foo"],
"🌱": ["🌿"],
}
assert vault.metadata.tags == [
"inline_tag_bottom1",
"inline_tag_bottom2",
"inline_tag_top1",
"inline_tag_top2",
"intext_tag1",
"intext_tag2",
"shared_tag",
assert vault.inline_meta == {
"inline1": ["bar baz", "foo"],
"inline2": ["[[foo]]"],
"inline3": ["value"],
"inline4": ["foo"],
"inline5": [],
"intext1": ["foo"],
"intext2": ["foo"],
"key with space": ["foo"],
"🌱": ["🌿"],
}
assert vault.tags == ["tag1", "tag2"]
assert vault.exclude_paths == [
tmp_path / "vault" / ".git",
tmp_path / "vault" / ".obsidian",
tmp_path / "vault" / "ignore_folder",
]
assert vault.metadata.inline_metadata == {
"bottom_key1": ["bottom_key1_value"],
"bottom_key2": ["bottom_key2_value"],
"intext_key": ["intext_value"],
"key📅": ["📅_key_value"],
"shared_key1": ["shared_key1_value", "shared_key1_value2"],
"shared_key2": ["shared_key2_value2"],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value_as_link"],
}
assert vault.metadata.frontmatter == {
"date_created": ["2022-12-22"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"shared_key1": ["shared_key1_value", "shared_key1_value3"],
"shared_key2": ["shared_key2_value1"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
}
assert vault.filters == []
assert len(vault.all_note_paths) == 2
assert len(vault.notes_in_scope) == 2
def set_insert_location(test_vault):
@@ -104,139 +73,36 @@ def set_insert_location(test_vault):
assert vault.insert_location == InsertLocation.BOTTOM
def test_add_metadata_1(test_vault) -> None:
"""Test adding metadata to the vault.
@pytest.mark.parametrize(
("meta_type", "key", "value", "expected"),
[
(MetadataType.FRONTMATTER, "new_key", "new_value", 2),
(MetadataType.FRONTMATTER, "frontmatter1", "new_value", 2),
(MetadataType.INLINE, "new_key", "new_value", 2),
(MetadataType.INLINE, "inline5", "new_value", 2),
(MetadataType.INLINE, "inline1", "foo", 1),
(MetadataType.TAGS, None, "new_value", 2),
(MetadataType.TAGS, None, "tag1", 1),
],
)
def test_add_metadata(test_vault, meta_type, key, value, expected):
"""Test add_metadata method.
GIVEN a vault object
WHEN a new metadata key is added
THEN the metadata is added to the vault
WHEN metadata is added
THEN add the metadata and return the number of notes updated
"""
vault = Vault(config=test_vault)
assert vault.add_metadata(meta_type, key, value) == expected
assert vault.add_metadata(MetadataType.FRONTMATTER, "new_key") == 2
assert vault.metadata.dict == {
"bottom_key1": ["bottom_key1_value"],
"bottom_key2": ["bottom_key2_value"],
"date_created": ["2022-12-22"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_value"],
"key📅": ["📅_key_value"],
"new_key": [],
"shared_key1": [
"shared_key1_value",
"shared_key1_value2",
"shared_key1_value3",
],
"shared_key2": ["shared_key2_value1", "shared_key2_value2"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value_as_link"],
}
assert vault.metadata.frontmatter == {
"date_created": ["2022-12-22"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"new_key": [],
"shared_key1": ["shared_key1_value", "shared_key1_value3"],
"shared_key2": ["shared_key2_value1"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
}
if meta_type == MetadataType.FRONTMATTER:
assert value in vault.frontmatter[key]
if meta_type == MetadataType.INLINE:
assert value in vault.inline_meta[key]
def test_add_metadata_2(test_vault) -> None:
"""Test adding metadata to the vault.
GIVEN a vault object
WHEN a new metadata key and value is added
THEN the metadata is added to the vault
"""
vault = Vault(config=test_vault)
assert vault.add_metadata(MetadataType.FRONTMATTER, "new_key2", "new_key2_value") == 2
assert vault.metadata.dict == {
"bottom_key1": ["bottom_key1_value"],
"bottom_key2": ["bottom_key2_value"],
"date_created": ["2022-12-22"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_value"],
"key📅": ["📅_key_value"],
"new_key2": ["new_key2_value"],
"shared_key1": [
"shared_key1_value",
"shared_key1_value2",
"shared_key1_value3",
],
"shared_key2": ["shared_key2_value1", "shared_key2_value2"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value_as_link"],
}
assert vault.metadata.frontmatter == {
"date_created": ["2022-12-22"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"new_key2": ["new_key2_value"],
"shared_key1": ["shared_key1_value", "shared_key1_value3"],
"shared_key2": ["shared_key2_value1"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
}
def test_commit_changes_1(test_vault, tmp_path):
"""Test committing changes to content in the vault.
GIVEN a vault object
WHEN the commit_changes method is called
THEN the changes are committed to the vault
"""
vault = Vault(config=test_vault)
content = Path(f"{tmp_path}/vault/test1.md").read_text()
assert "new_key: new_key_value" not in content
vault.add_metadata(MetadataType.FRONTMATTER, "new_key", "new_key_value")
vault.commit_changes()
committed_content = Path(f"{tmp_path}/vault/test1.md").read_text()
assert "new_key: new_key_value" in committed_content
def test_commit_changes_2(test_vault, tmp_path):
"""Test committing changes to content in the vault in dry run mode.
GIVEN a vault object
WHEN dry_run is set to True
THEN no changes are committed to the vault
"""
vault = Vault(config=test_vault, dry_run=True)
content = Path(f"{tmp_path}/vault/test1.md").read_text()
assert "new_key: new_key_value" not in content
vault.add_metadata(MetadataType.FRONTMATTER, "new_key", "new_key_value")
vault.commit_changes()
committed_content = Path(f"{tmp_path}/vault/test1.md").read_text()
assert "new_key: new_key_value" not in committed_content
if meta_type == MetadataType.TAGS:
assert value in vault.tags
def test_backup_1(test_vault, capsys):
@@ -276,6 +142,92 @@ def test_backup_2(test_vault, capsys):
assert captured.out == Regex(r"DRYRUN +| Backup up vault to")
@pytest.mark.parametrize(
("meta_type", "key", "value", "is_regex", "expected"),
[
(MetadataType.FRONTMATTER, "frontmatter1", None, False, True),
(MetadataType.FRONTMATTER, "frontmatter1", "foo", False, True),
(MetadataType.FRONTMATTER, "no_key", None, False, False),
(MetadataType.FRONTMATTER, "frontmatter1", "no_value", False, False),
(MetadataType.FRONTMATTER, r"f\w+\d", None, True, True),
(MetadataType.FRONTMATTER, r"f\w+\d", r"\w+", True, True),
(MetadataType.FRONTMATTER, r"^\d+", None, True, False),
(MetadataType.FRONTMATTER, r"frontmatter1", r"^\d+", True, False),
(MetadataType.INLINE, "intext1", None, False, True),
(MetadataType.INLINE, "intext1", "foo", False, True),
(MetadataType.INLINE, "no_key", None, False, False),
(MetadataType.INLINE, "intext1", "no_value", False, False),
(MetadataType.INLINE, r"i\w+\d", None, True, True),
(MetadataType.INLINE, r"i\w+\d", r"\w+", True, True),
(MetadataType.INLINE, r"^\d+", None, True, False),
(MetadataType.INLINE, r"intext1", r"^\d+", True, False),
(MetadataType.TAGS, None, "tag1", False, True),
(MetadataType.TAGS, None, "no tag", False, False),
(MetadataType.TAGS, None, r"^\w+\d", True, True),
(MetadataType.TAGS, None, r"^\d", True, False),
##############3
(MetadataType.META, "frontmatter1", None, False, True),
(MetadataType.META, "frontmatter1", "foo", False, True),
(MetadataType.META, "no_key", None, False, False),
(MetadataType.META, "frontmatter1", "no_value", False, False),
(MetadataType.META, r"f\w+\d", None, True, True),
(MetadataType.META, r"f\w+\d", r"\w+", True, True),
(MetadataType.META, r"^\d+", None, True, False),
(MetadataType.META, r"frontmatter1", r"^\d+", True, False),
(MetadataType.META, r"i\w+\d", None, True, True),
(MetadataType.ALL, None, "tag1", False, True),
(MetadataType.ALL, None, "no tag", False, False),
(MetadataType.ALL, None, r"^\w+\d", True, True),
(MetadataType.ALL, None, r"^\d", True, False),
(MetadataType.ALL, "frontmatter1", "foo", False, True),
(MetadataType.ALL, r"i\w+\d", None, True, True),
],
)
def test_contains_metadata(test_vault, meta_type, key, value, is_regex, expected):
"""Test the contains_metadata method.
GIVEN a vault object
WHEN the contains_metadata method is called
THEN the method returns True if the metadata is found
"""
vault = Vault(config=test_vault)
assert vault.contains_metadata(meta_type, key, value, is_regex) == expected
def test_commit_changes_1(test_vault, tmp_path):
"""Test committing changes to content in the vault.
GIVEN a vault object
WHEN the commit_changes method is called
THEN the changes are committed to the vault
"""
vault = Vault(config=test_vault)
content = Path(f"{tmp_path}/vault/sample_note.md").read_text()
assert "new_key: new_key_value" not in content
vault.add_metadata(MetadataType.FRONTMATTER, "new_key", "new_key_value")
vault.commit_changes()
committed_content = Path(f"{tmp_path}/vault/sample_note.md").read_text()
assert "new_key: new_key_value" in committed_content
def test_commit_changes_2(test_vault, tmp_path):
"""Test committing changes to content in the vault in dry run mode.
GIVEN a vault object
WHEN dry_run is set to True
THEN no changes are committed to the vault
"""
vault = Vault(config=test_vault, dry_run=True)
content = Path(f"{tmp_path}/vault/sample_note.md").read_text()
assert "new_key: new_key_value" not in content
vault.add_metadata(MetadataType.FRONTMATTER, "new_key", "new_key_value")
vault.commit_changes()
committed_content = Path(f"{tmp_path}/vault/sample_note.md").read_text()
assert "new_key: new_key_value" not in committed_content
def test_delete_backup_1(test_vault, capsys):
"""Test deleting the vault backup.
@@ -315,75 +267,64 @@ def test_delete_backup_2(test_vault, capsys):
assert vault.backup_path.exists() is True
def test_delete_tag_1(test_vault) -> None:
"""Test delete_tag() method.
@pytest.mark.parametrize(
("tag_to_delete", "expected"),
[
("tag1", 1),
("tag2", 1),
("tag3", 0),
],
)
def test_delete_tag(test_vault, tag_to_delete, expected):
"""Test delete_tag method.
GIVEN a vault object
WHEN the delete_tag method is called
THEN the inline tag is deleted
THEN delete tags if found and return the number of notes updated
"""
vault = Vault(config=test_vault)
assert vault.delete_tag("intext_tag2") == 1
assert vault.metadata.tags == [
"inline_tag_bottom1",
"inline_tag_bottom2",
"inline_tag_top1",
"inline_tag_top2",
"intext_tag1",
"shared_tag",
]
assert vault.delete_tag(tag_to_delete) == expected
assert tag_to_delete not in vault.tags
def test_delete_tag_2(test_vault) -> None:
"""Test delete_tag() method.
@pytest.mark.parametrize(
("meta_type", "key_to_delete", "value_to_delete", "expected"),
[
(MetadataType.FRONTMATTER, "frontmatter1", "foo", 1),
(MetadataType.FRONTMATTER, "frontmatter1", None, 1),
(MetadataType.FRONTMATTER, "frontmatter1", "bar", 0),
(MetadataType.FRONTMATTER, "frontmatter2", "bar", 1),
(MetadataType.META, "frontmatter1", "foo", 1),
(MetadataType.INLINE, "frontmatter1", "foo", 0),
(MetadataType.INLINE, "inline1", "foo", 1),
(MetadataType.INLINE, "inline1", None, 1),
],
)
def test_delete_metadata(test_vault, meta_type, key_to_delete, value_to_delete, expected):
"""Test delete_metadata method.
GIVEN a vault object
WHEN the delete_tag method is called with a tag that does not exist
THEN no changes are made
WHEN the delete_metadata method is called
THEN delete metadata if found and return the number of notes updated
"""
vault = Vault(config=test_vault)
assert (
vault.delete_metadata(meta_type=meta_type, key=key_to_delete, value=value_to_delete)
== expected
)
assert vault.delete_tag("no tag") == 0
if meta_type == MetadataType.FRONTMATTER or meta_type == MetadataType.META:
if value_to_delete is None:
assert key_to_delete not in vault.frontmatter
elif key_to_delete in vault.frontmatter:
assert value_to_delete not in vault.frontmatter[key_to_delete]
def test_delete_metadata_1(test_vault) -> None:
"""Test deleting a metadata key/value.
GIVEN a vault object
WHEN the delete_metadata method is called with a key and value
THEN the specified metadata key/value is deleted
"""
vault = Vault(config=test_vault)
assert vault.delete_metadata("top_key1", "top_key1_value") == 1
assert vault.metadata.dict["top_key1"] == []
def test_delete_metadata_2(test_vault) -> None:
"""Test deleting a metadata key/value.
GIVEN a vault object
WHEN the delete_metadata method is called with a key
THEN the specified metadata key is deleted
"""
vault = Vault(config=test_vault)
assert vault.delete_metadata("top_key2") == 1
assert "top_key2" not in vault.metadata.dict
def test_delete_metadata_3(test_vault) -> None:
"""Test deleting a metadata key/value.
GIVEN a vault object
WHEN the delete_metadata method is called with a key and/or value that does not exist
THEN no changes are made
"""
vault = Vault(config=test_vault)
assert vault.delete_metadata("no key") == 0
assert vault.delete_metadata("top_key1", "no_value") == 0
if meta_type == MetadataType.INLINE or meta_type == MetadataType.META:
if value_to_delete is None:
assert key_to_delete not in vault.inline_meta
elif key_to_delete in vault.inline_meta:
assert value_to_delete not in vault.inline_meta[key_to_delete]
def test_export_csv_1(tmp_path, test_vault):
@@ -394,11 +335,16 @@ def test_export_csv_1(tmp_path, test_vault):
THEN the vault metadata is exported to a CSV file
"""
vault = Vault(config=test_vault)
export_file = Path(f"{tmp_path}/export.csv")
export_file = tmp_path / "export.csv"
vault.export_metadata(path=export_file, export_format="csv")
assert export_file.exists() is True
assert "frontmatter,date_created,2022-12-22" in export_file.read_text()
result = export_file.read_text()
assert "Metadata Type,Key,Value" in result
assert "frontmatter,date_created,2022-12-22" in result
assert "inline_metadata,🌱,🌿" in result
assert "inline_metadata,inline5,\n" in result
assert "tags,,tag1" in result
def test_export_csv_2(tmp_path, test_vault):
@@ -409,7 +355,7 @@ def test_export_csv_2(tmp_path, test_vault):
THEN an error is raised
"""
vault = Vault(config=test_vault)
export_file = Path(f"{tmp_path}/does_not_exist/export.csv")
export_file = tmp_path / "does_not_exist" / "export.csv"
with pytest.raises(typer.Exit):
vault.export_metadata(path=export_file, export_format="csv")
@@ -424,11 +370,14 @@ def test_export_json(tmp_path, test_vault):
THEN the vault metadata is exported to a JSON file
"""
vault = Vault(config=test_vault)
export_file = Path(f"{tmp_path}/export.json")
export_file = tmp_path / "export.json"
vault.export_metadata(path=export_file, export_format="json")
assert export_file.exists() is True
assert '"frontmatter": {' in export_file.read_text()
result = export_file.read_text()
assert '"frontmatter": {' in result
assert '"inline_metadata": {' in result
assert '"tags": [' in result
def test_export_notes_to_csv_1(tmp_path, test_vault):
@@ -439,15 +388,17 @@ def test_export_notes_to_csv_1(tmp_path, test_vault):
THEN the notes are exported to a CSV file
"""
vault = Vault(config=test_vault)
export_file = Path(f"{tmp_path}/export.csv")
export_file = tmp_path / "export.csv"
vault.export_notes_to_csv(path=export_file)
assert export_file.exists() is True
assert "path,type,key,value" in export_file.read_text()
assert "test1.md,frontmatter,shared_key1,shared_key1_value" in export_file.read_text()
assert "test1.md,inline_metadata,shared_key1,shared_key1_value" in export_file.read_text()
assert "test1.md,tag,,shared_tag" in export_file.read_text()
assert "test1.md,frontmatter,tags,📅/frontmatter_tag3" in export_file.read_text()
assert "test1.md,inline_metadata,key📅,📅_key_value" in export_file.read_text()
result = export_file.read_text()
assert "path,type,key,value" in result
assert "sample_note.md,FRONTMATTER,date_created,2022-12-22" in result
assert "sample_note.md,FRONTMATTER,🌱,🌿" in result
assert "sample_note.md,INLINE,inline2,[[foo]]" in result
assert "sample_note.md,INLINE,inline1,bar baz" in result
assert "sample_note.md,TAGS,,tag1" in result
assert "sample_note.md,INLINE,inline5,\n" in result
def test_export_notes_to_csv_2(test_vault):
@@ -531,7 +482,7 @@ def test_get_filtered_notes_4(sample_vault) -> None:
filters = [VaultFilter(tag_filter="brunch")]
vault = Vault(config=vault_config, filters=filters)
assert len(vault.all_notes) == 13
assert len(vault.notes_in_scope) == 1
assert len(vault.notes_in_scope) == 0
def test_get_filtered_notes_5(sample_vault) -> None:
@@ -550,6 +501,21 @@ def test_get_filtered_notes_5(sample_vault) -> None:
assert len(vault.notes_in_scope) == 0
def test_get_changed_notes(test_vault, tmp_path):
"""Test get_changed_notes() method.
GIVEN a vault object
WHEN the get_changed_notes method is called
THEN the changed notes are returned
"""
vault = Vault(config=test_vault)
assert vault.get_changed_notes() == []
vault.delete_metadata(key="frontmatter1", meta_type=MetadataType.FRONTMATTER)
changed_notes = vault.get_changed_notes()
assert len(changed_notes) == 1
assert changed_notes[0].note_path == tmp_path / "vault" / "sample_note.md"
def test_info(test_vault, capsys):
"""Test info() method.
@@ -561,10 +527,10 @@ def test_info(test_vault, capsys):
vault.info()
captured = capsys.readouterr()
assert captured.out == Regex(r"Vault +\│ /[\d\w]+")
assert captured.out == Regex(r"Notes in scope +\\d+")
assert captured.out == Regex(r"Backup +\│ None")
captured = strip_ansi(capsys.readouterr().out)
assert captured == Regex(r"Vault +\│ /[\d\w]+")
assert captured == Regex(r"Notes in scope +\\d+")
assert captured == Regex(r"Backup +\│ None")
def test_list_editable_notes(test_vault, capsys) -> None:
@@ -579,7 +545,7 @@ def test_list_editable_notes(test_vault, capsys) -> None:
vault.list_editable_notes()
captured = capsys.readouterr()
assert captured.out == Regex("Notes in current scope")
assert captured.out == Regex(r"\d +test1\.md")
assert captured.out == Regex(r"\d +sample_note\.md")
def test_move_inline_metadata_1(test_vault) -> None:
@@ -594,6 +560,40 @@ def test_move_inline_metadata_1(test_vault) -> None:
assert vault.move_inline_metadata(location=InsertLocation.TOP) == 1
@pytest.mark.parametrize(
("meta_type", "expected_regex"),
[
(
MetadataType.ALL,
r"All metadata.*Keys +┃ Values +┃.*frontmatter1 +│ foo.*inline1 +│ bar baz.*tags +│ bar.*All inline tags.*#tag1.*#tag2",
),
(
MetadataType.FRONTMATTER,
r"All frontmatter.*Keys +┃ Values +┃.*frontmatter1 +│ foo.*tags +│ bar",
),
(
MetadataType.INLINE,
r"All inline metadata.*Keys +┃ Values +┃.*inline2 +│ \[\[foo\]\]",
),
(
MetadataType.TAGS,
r"All inline tags.*#tag1.*#tag2",
),
],
)
def test_print_metadata(test_vault, capsys, meta_type, expected_regex) -> None:
"""Test print_metadata() method.
GIVEN a vault object
WHEN the print_metadata() method is called
THEN the metadata is printed
"""
vault = Vault(config=test_vault)
vault.print_metadata(meta_type=meta_type)
captured = strip_ansi(capsys.readouterr().out)
assert captured == Regex(expected_regex, re.DOTALL)
def test_rename_tag_1(test_vault) -> None:
"""Test rename_tag() method.
@@ -603,16 +603,9 @@ def test_rename_tag_1(test_vault) -> None:
"""
vault = Vault(config=test_vault)
assert vault.rename_tag("intext_tag2", "new_tag") == 1
assert vault.metadata.tags == [
"inline_tag_bottom1",
"inline_tag_bottom2",
"inline_tag_top1",
"inline_tag_top2",
"intext_tag1",
"new_tag",
"shared_tag",
]
assert vault.rename_tag("tag1", "new_tag") == 1
assert "tag1" not in vault.tags
assert "new_tag" in vault.tags
def test_rename_tag_2(test_vault) -> None:
@@ -625,9 +618,21 @@ def test_rename_tag_2(test_vault) -> None:
vault = Vault(config=test_vault)
assert vault.rename_tag("no tag", "new_tag") == 0
assert "new_tag" not in vault.tags
def test_rename_metadata_1(test_vault) -> None:
@pytest.mark.parametrize(
("key", "value1", "value2", "expected"),
[
("no key", "new_value", None, 0),
("frontmatter1", "no_value", "new_value", 0),
("frontmatter1", "foo", "new_value", 1),
("inline1", "foo", "new_value", 1),
("frontmatter1", "new_key", None, 1),
("inline1", "new_key", None, 1),
],
)
def test_rename_metadata(test_vault, key, value1, value2, expected) -> None:
"""Test rename_metadata() method.
GIVEN a vault object
@@ -636,90 +641,63 @@ def test_rename_metadata_1(test_vault) -> None:
"""
vault = Vault(config=test_vault)
assert vault.rename_metadata("no key", "new_key") == 0
assert vault.rename_metadata("tags", "nonexistent_value", "new_vaule") == 0
assert vault.rename_metadata(key, value1, value2) == expected
if expected > 0 and value2 is None:
assert key not in vault.frontmatter
assert key not in vault.inline_meta
if expected > 0 and value2:
if key in vault.frontmatter:
assert value1 not in vault.frontmatter[key]
assert value2 in vault.frontmatter[key]
if key in vault.inline_meta:
assert value1 not in vault.inline_meta[key]
assert value2 in vault.inline_meta[key]
def test_rename_metadata_2(test_vault) -> None:
"""Test rename_metadata() method.
GIVEN a vault object
WHEN the rename_metadata() method with a key and no value
THEN the metadata key is renamed
"""
vault = Vault(config=test_vault)
assert vault.rename_metadata("tags", "new_key") == 1
assert "tags" not in vault.metadata.dict
assert vault.metadata.dict["new_key"] == [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
]
def test_rename_metadata_3(test_vault) -> None:
"""Test rename_metadata() method.
GIVEN a vault object
WHEN the rename_metadata() method is called with a key and value
THEN the metadata key/value is renamed
"""
vault = Vault(config=test_vault)
assert vault.rename_metadata("tags", "frontmatter_tag1", "new_vaule") == 1
assert vault.metadata.dict["tags"] == [
"frontmatter_tag2",
"new_vaule",
"shared_tag",
"📅/frontmatter_tag3",
]
def test_transpose_metadata(test_vault) -> None:
@pytest.mark.parametrize(
("begin", "end", "key", "value", "expected"),
[
# no matches
(MetadataType.INLINE, MetadataType.FRONTMATTER, "no key", None, 0),
(MetadataType.INLINE, MetadataType.FRONTMATTER, "no key", "new_value", 0),
(MetadataType.INLINE, MetadataType.FRONTMATTER, "inline1", "new_value", 0),
(MetadataType.FRONTMATTER, MetadataType.INLINE, "no key", None, 0),
(MetadataType.FRONTMATTER, MetadataType.INLINE, "no key", "new_value", 0),
(MetadataType.FRONTMATTER, MetadataType.INLINE, "frontmatter1", "new_value", 0),
# entire keys
(MetadataType.FRONTMATTER, MetadataType.INLINE, "frontmatter1", None, 1),
(MetadataType.FRONTMATTER, MetadataType.INLINE, "frontmatter2", None, 1),
(MetadataType.INLINE, MetadataType.FRONTMATTER, "inline1", None, 1),
# specific values
(MetadataType.FRONTMATTER, MetadataType.INLINE, "frontmatter1", "foo", 1),
(MetadataType.INLINE, MetadataType.FRONTMATTER, "inline1", "bar baz", 1),
(MetadataType.INLINE, MetadataType.FRONTMATTER, "inline2", "[[foo]]", 1),
],
)
def test_transpose_metadata_1(test_vault, begin, end, key, value, expected) -> None:
"""Test transpose_metadata() method.
GIVEN a vault object
WHEN the transpose_metadata() method is called
THEN the metadata is transposed
THEN the number of notes with transposed metadata is returned and the vault metadata is updated
"""
vault = Vault(config=test_vault)
assert vault.transpose_metadata(begin=MetadataType.INLINE, end=MetadataType.FRONTMATTER) == 1
assert vault.transpose_metadata(begin=begin, end=end, key=key, value=value) == expected
assert vault.metadata.inline_metadata == {}
assert vault.metadata.frontmatter == {
"bottom_key1": ["bottom_key1_value"],
"bottom_key2": ["bottom_key2_value"],
"date_created": ["2022-12-22"],
"frontmatter_Key1": ["author name"],
"frontmatter_Key2": ["article", "note"],
"intext_key": ["intext_value"],
"key📅": ["📅_key_value"],
"shared_key1": [
"shared_key1_value",
"shared_key1_value2",
"shared_key1_value3",
],
"shared_key2": ["shared_key2_value1", "shared_key2_value2"],
"tags": [
"frontmatter_tag1",
"frontmatter_tag2",
"shared_tag",
"📅/frontmatter_tag3",
],
"top_key1": ["top_key1_value"],
"top_key2": ["top_key2_value"],
"top_key3": ["top_key3_value_as_link"],
}
assert (
vault.transpose_metadata(
begin=MetadataType.INLINE, end=MetadataType.FRONTMATTER, location=InsertLocation.TOP
)
== 0
)
if expected > 0:
if begin == MetadataType.INLINE and value is None:
assert key not in vault.inline_meta
assert key in vault.frontmatter
elif begin == MetadataType.FRONTMATTER and value is None:
assert key not in vault.frontmatter
assert key in vault.inline_meta
elif begin == MetadataType.INLINE and value:
assert value in vault.frontmatter[key]
elif begin == MetadataType.FRONTMATTER and value:
assert value in vault.inline_meta[key]
def test_update_from_dict_1(test_vault):
@@ -729,11 +707,11 @@ def test_update_from_dict_1(test_vault):
WHEN no dictionary keys match paths in the vault
THEN no notes are updated and 0 is returned
"""
vault = Vault(config=test_vault)
update_dict = {
"path1": {"type": "frontmatter", "key": "new_key", "value": "new_value"},
"path2": {"type": "frontmatter", "key": "new_key", "value": "new_value"},
}
vault = Vault(config=test_vault)
assert vault.update_from_dict(update_dict) == 0
assert vault.get_changed_notes() == []
@@ -763,17 +741,18 @@ def test_update_from_dict_3(test_vault):
vault = Vault(config=test_vault)
update_dict = {
"test1.md": [
"sample_note.md": [
{"type": "frontmatter", "key": "new_key", "value": "new_value"},
{"type": "inline_metadata", "key": "new_key2", "value": "new_value"},
{"type": "tag", "key": "", "value": "new_tag"},
]
}
assert vault.update_from_dict(update_dict) == 1
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].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"]
note = vault.get_changed_notes()[0]
assert note.note_path.name == "sample_note.md"
assert len(note.metadata) == 3
assert vault.frontmatter == {"new_key": ["new_value"]}
assert vault.inline_meta == {"new_key2": ["new_value"]}
assert vault.tags == ["new_tag"]