Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
e652465
Fix issue #70: [BUG] `#` character accumulation in markdown frontmatt…
bm-claudeai Apr 6, 2025
3611b00
Add pull_request_target trigger to test workflow with explanatory com…
phernandez Apr 6, 2025
50409e5
Fix issue #70: Prevent # character accumulation in frontmatter tags
phernandez Apr 6, 2025
8caeb7e
Fix issue #70: Properly handle stripping of # characters in tags
phernandez Apr 6, 2025
32b4146
Merge branch 'main' into fix-issue-70-20250406011950
phernandez Apr 6, 2025
2a696c5
Update claude-code-github-action to v0.11.0 with backtick handling fix
phernandez Apr 6, 2025
32e40c6
Fix issue #70: [BUG] `#` character accumulation in markdown frontmatt…
bm-claudeai Apr 6, 2025
74380a6
Add pull_request_target trigger to test workflow with explanatory com…
phernandez Apr 6, 2025
72e1450
Fix issue #70: Prevent # character accumulation in frontmatter tags
phernandez Apr 6, 2025
b53fd9a
Fix issue #70: Properly handle stripping of # characters in tags
phernandez Apr 6, 2025
8ab84fc
fix: [BUG] Some notes never exit "modified" status (#77)
github-actions[bot] Apr 6, 2025
628c231
docs: Add VS Code instructions to README (#76)
mbaiza27 Apr 6, 2025
fe08669
docs: Updated basicmachines.co links to be https (#69)
jasonnoble Apr 6, 2025
086aa44
fix: set default mcp log level to ERROR (#81)
phernandez Apr 6, 2025
d9cc21c
fix: [BUG] write_note Tool Fails to Update Existing Files in Some Sit…
github-actions[bot] Apr 6, 2025
c95731e
Merge branch 'fix-issue-70-20250406011950' of github.com:basicmachine…
phernandez Apr 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/basic_memory/services/entity_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ async def update_entity_relations(
except IntegrityError:
# Unique constraint violation - relation already exists
logger.debug(
f"Skipping duplicate relation {rel.type} from {db_entity.permalink} target: {rel.target}, type: {rel.type}"
f"Skipping duplicate relation {rel.type} from {db_entity.permalink} target: {rel.target}"
)
continue

Expand Down
12 changes: 10 additions & 2 deletions src/basic_memory/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,23 @@ def parse_tags(tags: Union[List[str], str, None]) -> List[str]:

Returns:
A list of tag strings, or an empty list if no tags

Note:
This function strips leading '#' characters from tags to prevent
their accumulation when tags are processed multiple times.
"""
if tags is None:
return []

# Process list of tags
if isinstance(tags, list):
return tags
# First strip whitespace, then strip leading '#' characters to prevent accumulation
return [tag.strip().lstrip('#') for tag in tags if tag and tag.strip()]

# Process comma-separated string of tags
if isinstance(tags, str):
return [tag.strip() for tag in tags.split(",") if tag.strip()]
# Split by comma, strip whitespace, then strip leading '#' characters
return [tag.strip().lstrip('#') for tag in tags.split(",") if tag and tag.strip()]

# For any other type, try to convert to string and parse
try: # pragma: no cover
Expand Down
51 changes: 51 additions & 0 deletions tests/utils/test_parse_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"""Tests for parse_tags utility function."""

from typing import List, Union

import pytest

from basic_memory.utils import parse_tags


@pytest.mark.parametrize(
"input_tags,expected",
[
# None input
(None, []),
# List inputs
([], []),
(["tag1", "tag2"], ["tag1", "tag2"]),
(["tag1", "", "tag2"], ["tag1", "tag2"]), # Empty tags are filtered
([" tag1 ", " tag2 "], ["tag1", "tag2"]), # Whitespace is stripped
# String inputs
("", []),
("tag1", ["tag1"]),
("tag1,tag2", ["tag1", "tag2"]),
("tag1, tag2", ["tag1", "tag2"]), # Whitespace after comma is stripped
("tag1,,tag2", ["tag1", "tag2"]), # Empty tags are filtered
# Tags with leading '#' characters - these should be stripped
(["#tag1", "##tag2"], ["tag1", "tag2"]),
("#tag1,##tag2", ["tag1", "tag2"]),
(["tag1", "#tag2", "##tag3"], ["tag1", "tag2", "tag3"]),
# Mixed whitespace and '#' characters
([" #tag1 ", " ##tag2 "], ["tag1", "tag2"]),
(" #tag1 , ##tag2 ", ["tag1", "tag2"]),
],
)
def test_parse_tags(
input_tags: Union[List[str], str, None], expected: List[str]
) -> None:
"""Test tag parsing with various input formats."""
result = parse_tags(input_tags)
assert result == expected


def test_parse_tags_special_case() -> None:
"""Test parsing from non-string, non-list types."""
# Test with custom object that has __str__ method
class TagObject:
def __str__(self) -> str:
return "tag1,tag2"

result = parse_tags(TagObject()) # pyright: ignore [reportArgumentType]
assert result == ["tag1", "tag2"]
Loading