feat: bulk update metadata from a CSV file

This commit is contained in:
Nathaniel Landau
2023-03-20 00:16:19 -04:00
parent 593dbc3b55
commit d636fb2672
14 changed files with 521 additions and 115 deletions

View File

@@ -58,7 +58,8 @@ def test_usage(capsys):
assert captured.out == "USAGE | This prints in usage\n"
alerts.usage(
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua"
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua",
width=80,
)
captured = capsys.readouterr()
assert "USAGE | Lorem ipsum dolor sit amet" in captured.out

View File

@@ -68,8 +68,13 @@ repeated_key:: repeated_key_value2
"""
def test_frontmatter_create() -> None:
"""Test frontmatter creation."""
def test_frontmatter_create_1() -> None:
"""Test frontmatter creation.
GIVEN valid frontmatter content
WHEN a Frontmatter object is created
THEN parse the YAML frontmatter and add it to the object
"""
frontmatter = Frontmatter(INLINE_CONTENT)
assert frontmatter.dict == {}
@@ -88,11 +93,11 @@ def test_frontmatter_create() -> None:
}
def test_frontmatter_create_error() -> None:
def test_frontmatter_create_2() -> None:
"""Test frontmatter creation error.
GIVEN frontmatter content
WHEN frontmatter is invalid
GIVEN invalid frontmatter content
WHEN a Frontmatter object is created
THEN raise ValueError
"""
fn = """---
@@ -104,21 +109,118 @@ invalid = = "content"
Frontmatter(fn)
def test_frontmatter_contains() -> None:
"""Test frontmatter contains."""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
def test_frontmatter_create_3():
"""Test frontmatter creation error.
GIVEN empty frontmatter content
WHEN a Frontmatter object is created
THEN set the dict to an empty dict
"""
content = "---\n\n---"
frontmatter = Frontmatter(content)
assert frontmatter.dict == {}
def test_frontmatter_create_4():
"""Test frontmatter creation error.
GIVEN empty frontmatter content with a yaml marker
WHEN a Frontmatter object is created
THEN set the dict to an empty dict
"""
content = "---\n-\n---"
frontmatter = Frontmatter(content)
assert frontmatter.dict == {}
def test_frontmatter_contains_1():
"""Test frontmatter contains() method.
GIVEN a Frontmatter object
WHEN the contains() method is called with a key
THEN return True if the key is found
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains("frontmatter_Key1") is True
def test_frontmatter_contains_2():
"""Test frontmatter contains() method.
GIVEN a Frontmatter object
WHEN the contains() method is called with a key
THEN return False if the key is not found
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains("no_key") is False
def test_frontmatter_contains_3():
"""Test frontmatter contains() method.
GIVEN a Frontmatter object
WHEN the contains() method is called with a key and a value
THEN return True if the key and value is found
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains("frontmatter_Key2", "article") is True
assert frontmatter.contains("frontmatter_Key3") is False
def test_frontmatter_contains_4():
"""Test frontmatter contains() method.
GIVEN a Frontmatter object
WHEN the contains() method is called with a key and a value
THEN return False if the key and value is not found
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains("frontmatter_Key2", "no value") is False
def test_frontmatter_contains_5():
"""Test frontmatter contains() method.
GIVEN a Frontmatter object
WHEN the contains() method is called with a key regex
THEN return True if a key matches the regex
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains(r"\d$", is_regex=True) is True
def test_frontmatter_contains_6():
"""Test frontmatter contains() method.
GIVEN a Frontmatter object
WHEN the contains() method is called with a key regex
THEN return False if no key matches the regex
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains(r"^\d", is_regex=True) is False
assert frontmatter.contains("key", r"_\d", is_regex=True) is False
def test_frontmatter_contains_7():
"""Test frontmatter contains() method.
GIVEN a Frontmatter object
WHEN the contains() method is called with a key and value regex
THEN return True if a value matches the regex
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains("key", r"\w\d_", is_regex=True) is True
def test_frontmatter_contains_8():
"""Test frontmatter contains() method.
GIVEN a Frontmatter object
WHEN the contains() method is called with a key and value regex
THEN return False if a value does not match the regex
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
assert frontmatter.contains("key", r"_\d", is_regex=True) is False
def test_frontmatter_add() -> None:
"""Test frontmatter add."""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
@@ -233,6 +335,18 @@ def test_frontmatter_delete() -> None:
assert frontmatter.dict == {"shared_key1": []}
def test_frontmatter_delete_all():
"""Test Frontmatter delete_all method.
GIVEN Frontmatter with multiple keys
WHEN delete_all is called
THEN all keys and values are deleted
"""
frontmatter = Frontmatter(FRONTMATTER_CONTENT)
frontmatter.delete_all()
assert frontmatter.dict == {}
def test_frontmatter_yaml_conversion():
"""Test Frontmatter to_yaml method."""
new_frontmatter: str = """\

View File

@@ -229,16 +229,17 @@ def test_add_metadata_method_10(sample_note):
"""Test add_metadata() method.
GIVEN a note object
WHEN add_metadata() is with a new tag
WHEN add_metadata() is called with a new tag
THEN the tag is added to the InlineTags object and the file content
"""
note = Note(note_path=sample_note)
assert "new_tag" not in note.inline_tags.list
assert "new_tag2" not in note.inline_tags.list
assert (
note.add_metadata(MetadataType.TAGS, value="new_tag", location=InsertLocation.TOP) is True
note.add_metadata(MetadataType.TAGS, value="new_tag2", location=InsertLocation.BOTTOM)
is True
)
assert "new_tag" in note.inline_tags.list
assert "#new_tag" in note.file_content
assert "new_tag2" in note.inline_tags.list
assert "#new_tag2" in note.file_content
def test_commit_1(sample_note, tmp_path) -> None:
@@ -313,6 +314,24 @@ def test_contains_metadata(sample_note) -> None:
assert note.contains_metadata(r"bottom_key\d$", r"bottom_key\d_value", is_regex=True) is True
def test_delete_all_metadata(sample_note):
"""Test delete_all_metadata() method.
GIVEN a note object
WHEN delete_all_metadata() is called
THEN all tags, frontmatter, and inline metadata are deleted
"""
note = Note(note_path=sample_note)
note.delete_all_metadata()
assert note.inline_tags.list == []
assert note.frontmatter.dict == {}
assert note.inline_metadata.dict == {}
assert note.file_content == Regex("consequat. Duis")
assert "codeblock_key:: some text" in note.file_content
assert "#ffffff" in note.file_content
assert "---" not in note.file_content
def test_delete_inline_tag(sample_note) -> None:
"""Test delete_inline_tag method.

View File

@@ -431,6 +431,38 @@ def test_export_json(tmp_path, test_vault):
assert '"frontmatter": {' in export_file.read_text()
def test_export_notes_to_csv_1(tmp_path, test_vault):
"""Test export_notes_to_csv() method.
GIVEN a vault object
WHEN the export_notes_to_csv method is called with a path
THEN the notes are exported to a CSV file
"""
vault = Vault(config=test_vault)
export_file = Path(f"{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()
def test_export_notes_to_csv_2(test_vault):
"""Test export_notes_to_csv() method.
GIVEN a vault object
WHEN the export_notes_to_csv method is called with a path where the parent directory does not exist
THEN an error is raised
"""
vault = Vault(config=test_vault)
export_file = Path("/I/do/not/exist/export.csv")
with pytest.raises(typer.Exit):
vault.export_notes_to_csv(path=export_file)
def test_get_filtered_notes_1(sample_vault) -> None:
"""Test filtering notes.
@@ -688,3 +720,60 @@ def test_transpose_metadata(test_vault) -> None:
)
== 0
)
def test_update_from_dict_1(test_vault):
"""Test update_from_dict() method.
GIVEN a vault object and an update dictionary
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"},
}
assert vault.update_from_dict(update_dict) == 0
assert vault.get_changed_notes() == []
def test_update_from_dict_2(test_vault):
"""Test update_from_dict() method.
GIVEN a vault object and an update dictionary
WHEN the dictionary is empty
THEN no notes are updated and 0 is returned
"""
vault = Vault(config=test_vault)
update_dict = {}
assert vault.update_from_dict(update_dict) == 0
assert vault.get_changed_notes() == []
def test_update_from_dict_3(test_vault):
"""Test update_from_dict() method.
GIVEN a vault object and an update dictionary
WHEN a dictionary key matches a path in the vault
THEN the note is updated to match the dictionary values
"""
vault = Vault(config=test_vault)
update_dict = {
"test1.md": [
{"type": "frontmatter", "key": "new_key", "value": "new_value"},
{"type": "inline_metadata", "key": "new_key2", "value": "new_value"},
{"type": "tags", "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].inline_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"]